View Javadoc

1   /*
2    * Copyright 2012-2013 smartics, Kronseder & Reiner GmbH
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package de.smartics.properties.reports;
17  
18  import java.util.ArrayList;
19  import java.util.Collections;
20  import java.util.List;
21  
22  import javax.annotation.concurrent.NotThreadSafe;
23  
24  import com.google.common.collect.ArrayListMultimap;
25  
26  import de.smartics.properties.api.core.context.alias.AliasException;
27  import de.smartics.properties.api.core.context.alias.AliasTraverser;
28  import de.smartics.properties.api.core.context.alias.PropertyAliasMapping;
29  import de.smartics.properties.api.core.domain.SourceInfo;
30  import de.smartics.properties.report.app.ReportException;
31  import de.smartics.properties.report.data.PropertyReport;
32  import de.smartics.properties.report.data.PropertyReportItem;
33  import de.smartics.properties.report.data.ReportProblem;
34  
35  /**
36   * Writes each report to a file.
37   */
38  @NotThreadSafe
39  public abstract class AbstractPropertyReport implements PropertyReport
40  {
41    // ********************************* Fields *********************************
42  
43    // --- constants ------------------------------------------------------------
44  
45    // --- members --------------------------------------------------------------
46  
47    /**
48     * The list of problems encountered while parsing sources and fetching report
49     * information.
50     */
51    private final List<ReportProblem> problems = new ArrayList<ReportProblem>();
52  
53    /**
54     * The map of aliases to property resources.
55     */
56    private final PropertyAliasMapping aliasMapping = new PropertyAliasMapping();
57  
58    /**
59     * Map to recognize unique key constraint violations.
60     */
61    private final ArrayListMultimap<String, PropertyReportItem> keyUniquenessMap =
62        ArrayListMultimap.create();
63  
64    // ****************************** Initializer *******************************
65  
66    // ****************************** Constructors ******************************
67  
68    /**
69     * Default constructor.
70     */
71    protected AbstractPropertyReport()
72    {
73    }
74  
75    // ****************************** Inner Classes *****************************
76  
77    // ********************************* Methods ********************************
78  
79    // --- init -----------------------------------------------------------------
80  
81    // --- get&set --------------------------------------------------------------
82  
83    /**
84     * {@inheritDoc}
85     *
86     * @see de.smartics.properties.report.data.PropertyReport#getProblems()
87     */
88    public final List<ReportProblem> getProblems()
89    {
90      return Collections.unmodifiableList(problems);
91    }
92  
93    // --- business -------------------------------------------------------------
94  
95    /**
96     * {@inheritDoc}
97     *
98     * @see de.smartics.properties.report.data.PropertyReport#addProblem(de.smartics.properties.report.data.ReportProblem)
99     */
100   @Override
101   public final void addProblem(final ReportProblem problem)
102   {
103     problems.add(problem);
104   }
105 
106   /**
107    * {@inheritDoc}
108    *
109    * @see de.smartics.properties.report.data.PropertyReport#hasProblems()
110    */
111   public final boolean hasProblems()
112   {
113     return !problems.isEmpty();
114   }
115 
116   /**
117    * {@inheritDoc}
118    *
119    * @see de.smartics.properties.report.data.PropertyReport#traverseAliases(de.smartics.properties.api.core.context.alias.AliasTraverser)
120    */
121   @Override
122   public final void traverseAliases(final AliasTraverser traverser)
123   {
124     aliasMapping.traverse(traverser);
125   }
126 
127   /**
128    * {@inheritDoc}
129    * <p>
130    * Registers a report item to manage the alias mapping and check for
131    * uniqueness constraint violations.
132    * </p>
133    *
134    * @see de.smartics.properties.report.data.PropertyReport#handle(de.smartics.properties.report.data.PropertyReportItem)
135    */
136   // CHECKSTYLE:OFF Method can be overridden by sub classes.
137   @Override
138   public void handle(final PropertyReportItem item) throws ReportException
139   // CHECKSTYLE:ON
140   {
141     register(item);
142   }
143 
144   /**
145    * Registers a report item to manage the alias mapping and check for
146    * uniqueness constraint violations.
147    *
148    * @param item the report item to manage.
149    */
150   protected final void register(final PropertyReportItem item)
151   {
152     final String name = item.getName();
153 
154     checkForUniqueness(item, name);
155 
156     registerAlias(item, name);
157   }
158 
159   private void checkForUniqueness(final PropertyReportItem item,
160       final String name)
161   {
162     keyUniquenessMap.put(name, item);
163     final List<PropertyReportItem> items = keyUniquenessMap.get(name);
164     if (items.size() > 1)
165     {
166       final StringBuilder buffer = new StringBuilder(1024);
167       buffer.append("Duplicate key '" + name + "' found:");
168       for (final PropertyReportItem duplicate : items)
169       {
170         buffer.append("\n -> ")
171             .append(duplicate.getSourceInfo().getElementId()).append('/')
172             .append(duplicate.getDescriptor().getKey());
173       }
174       final String message = buffer.toString();
175       final ReportProblem problem = new ReportProblem(message);
176       addProblem(problem);
177     }
178   }
179 
180   private void registerAlias(final PropertyReportItem item, final String name)
181   {
182     // The element ID is easily accessible if the class or source code is
183     // parsed.
184     final SourceInfo sourceInfo = item.getSourceInfo();
185     if (sourceInfo != null)
186     {
187       final String elementId = sourceInfo.getElementId();
188       try
189       {
190         aliasMapping.add(elementId, name);
191       }
192       catch (final AliasException e)
193       {
194         addProblem(new ReportProblem("Cannot register alias '" + elementId
195                                      + "'.", e));
196       }
197     }
198   }
199 
200   // --- object basics --------------------------------------------------------
201 
202 }