View Javadoc

1   /*
2    * Copyright 2008-2010 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  
17  package de.smartics.maven.issues.util;
18  
19  import java.util.ArrayList;
20  import java.util.Collections;
21  import java.util.List;
22  
23  import org.apache.commons.logging.Log;
24  import org.apache.commons.logging.LogFactory;
25  import org.apache.maven.artifact.versioning.ArtifactVersion;
26  import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException;
27  import org.apache.maven.artifact.versioning.VersionRange;
28  import org.apache.maven.model.ReportPlugin;
29  import org.apache.maven.model.ReportSet;
30  import org.apache.maven.model.Reporting;
31  import org.codehaus.plexus.util.xml.Xpp3Dom;
32  
33  /**
34   * Responsible to extract report reference information from the report
35   * configurations that reference previous reports.
36   *
37   * @author <a href="mailto:robert.reiner@smartics.de">Robert Reiner</a>
38   * @version $Revision:591 $
39   */
40  public class ReportReferenceExtractor
41  {
42    // ********************************* Fields *********************************
43  
44    // --- constants ------------------------------------------------------------
45  
46    /**
47     * Reference to the logger for this class.
48     */
49    private final Log log = LogFactory.getLog(ReportReferenceExtractor.class);
50  
51    /**
52     * The reporting section of the POM to analyse.
53     */
54    private final Reporting reporting;
55  
56    /**
57     * The identifier of the report that must match as prefix the
58     * <code>outputName</code> of a report configuration for that configuration to
59     * be eligable for reference.
60     */
61    private final String id;
62  
63    /**
64     * The version of the current report to estimate if the referenced report is
65     * previous.
66     */
67    private final ArtifactVersion version;
68  
69    // --- members --------------------------------------------------------------
70  
71    // ****************************** Initializer *******************************
72  
73    // ****************************** Constructors ******************************
74  
75    /**
76     * Default constructor.
77     *
78     * @param id the identifier of the report that must match as prefix the
79     *          <code>outputName</code> of a report configuration for that
80     *          configuration to be eligable for reference.
81     * @param version the version of the current report to estimate if the
82     *          referenced report is previous.
83     * @param reporting the reporting section of the POM to analyse.
84     */
85    public ReportReferenceExtractor(final String id,
86        final ArtifactVersion version, final Reporting reporting)
87    {
88      this.id = id;
89      this.version = version;
90      this.reporting = reporting;
91    }
92  
93    // ****************************** Inner Classes *****************************
94  
95    // ********************************* Methods ********************************
96  
97    // --- init -----------------------------------------------------------------
98  
99    // --- get&set --------------------------------------------------------------
100 
101   // --- business -------------------------------------------------------------
102 
103   /**
104    * Reads the relevant report references. The reports must match the given
105    * prefix (<code>id</code>), provide a readable version range and the range
106    * must be previous to the current version.
107    *
108    * @return the references that match the criterias.
109    */
110   @SuppressWarnings("unchecked")
111   public List<ReportReference> readReportReferences()
112   {
113     final List<ReportReference> references = new ArrayList<ReportReference>();
114     final List<ReportPlugin> reportPlugins = reporting.getPlugins();
115     for (ReportPlugin plugin : reportPlugins)
116     {
117       if (isIssueReportPlugin(plugin))
118       {
119         if (log.isTraceEnabled())
120         {
121           log.trace("Issue report found: " + plugin.getKey());
122         }
123 
124         final List<ReportSet> reportSets = plugin.getReportSets();
125         for (ReportSet reportSet : reportSets)
126         {
127           final Object object = reportSet.getConfiguration();
128           if (object instanceof Xpp3Dom)
129           {
130             parseAndAddReportReferenceIfRelevant(references, (Xpp3Dom) object);
131           }
132         }
133       }
134     }
135     Collections.sort(references);
136     return references;
137   }
138 
139   /**
140    * Parses the information form the DOM fragment.
141    *
142    * @param references the references to add to.
143    * @param dom the DOM fragment to extract reference information.
144    */
145   @SuppressWarnings("unchecked")
146   private void parseAndAddReportReferenceIfRelevant(
147       final List<ReportReference> references, final Xpp3Dom dom)
148   {
149     final String giConf = dom.getName();
150     if ("configuration".equals(giConf))
151     {
152       final ReportReference ref = createReportReference(dom);
153       if (ref != null && version.compareTo(ref.getVersionRepresentative()) > 0)
154       {
155         references.add(ref);
156       }
157     }
158   }
159 
160   /**
161    * Creates a report reference from the given configuration.
162    *
163    * @param dom the configuration to read the report reference information from.
164    * @return the report reference or <code>null</code> if the information is not
165    *         sufficient or invalid.
166    */
167   private ReportReference createReportReference(final Xpp3Dom dom)
168   {
169     try
170     {
171       return createReportReferenceInstance(dom);
172     }
173     catch (final IllegalArgumentException e)
174     {
175       return null;
176     }
177     catch (final InvalidVersionSpecificationException e)
178     {
179       return null;
180     }
181   }
182 
183   /**
184    * Creates a report reference from the given configuration.
185    *
186    * @param dom the configuration to read the report reference information from.
187    * @return the report reference or <code>null</code> if the information is not
188    *         sufficient or invalid.
189    * @throws InvalidVersionSpecificationException if the version information
190    *           read cannot be parsed.
191    * @throws IllegalArgumentException if the version representative cannot be
192    *           determined from the version information.
193    */
194   private ReportReference createReportReferenceInstance(final Xpp3Dom dom)
195     throws InvalidVersionSpecificationException, IllegalArgumentException
196   {
197     String outputName = null;
198     String title = null;
199     String versionRangeSpec = null;
200     for (Xpp3Dom child : dom.getChildren())
201     {
202       final String name = child.getName();
203       if ("outputName".equals(name))
204       {
205         outputName = child.getValue();
206         if (isNotReportOfSameType(outputName))
207         {
208           return null;
209         }
210       }
211       else if ("title".equals(name))
212       {
213         title = child.getValue();
214       }
215       else if ("versionRange".equals(name))
216       {
217         versionRangeSpec = child.getValue();
218       }
219     }
220 
221     return createReportReference(outputName, title, versionRangeSpec);
222   }
223 
224   /**
225    * Checks if the report is of the same type.
226    *
227    * @param outputName the report's output name.
228    * @return <code>true</code> if the report's output name starts with the
229    *         <code>id</code> but is not equal to it, <code>false</code>
230    *         otherwise.
231    */
232   private boolean isNotReportOfSameType(final String outputName)
233   {
234     return !outputName.startsWith(id) || outputName.equals(id);
235   }
236 
237   /**
238    * Creates the report reference for the given information.
239    *
240    * @param outputName the <code>outputName</code> from the POM.
241    * @param title the <code>title</code> from the POM.
242    * @param versionRangeSpec the <code>versionRange</code> from the POM.
243    * @return the report reference or <code>null</code> if none can be
244    *         constructed.
245    * @throws InvalidVersionSpecificationException if the version information
246    *           read cannot be parsed.
247    * @throws IllegalArgumentException if the version representative cannot be
248    *           determined from the version information.
249    */
250   private ReportReference createReportReference(final String outputName,
251       final String title, final String versionRangeSpec)
252     throws InvalidVersionSpecificationException, IllegalArgumentException
253   {
254     if (versionRangeSpec == null)
255     {
256       return null;
257     }
258 
259     final VersionRange range =
260         VersionRange.createFromVersionSpec(versionRangeSpec);
261     final ArtifactVersion representative =
262         Utils.findVersionRepresentative(range);
263     final ReportReference ref =
264         new ReportReference(title, outputName, representative);
265     return ref;
266   }
267 
268   /**
269    * Checks if the report plugin is an issues plugin.
270    *
271    * @param plugin the report plugin to check.
272    * @return <code>true</code> if the plugin is an issues plugin,
273    *         <code>false</code> otherwise.
274    */
275   private boolean isIssueReportPlugin(final ReportPlugin plugin)
276   {
277     return "maven-issues-plugin".equals(plugin.getArtifactId())
278            && "de.smartics.maven.plugin".equals(plugin.getGroupId());
279   }
280 
281   // --- object basics --------------------------------------------------------
282 
283 }