View Javadoc

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