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.bugzilla;
17  
18  import java.util.Comparator;
19  import java.util.List;
20  
21  import org.apache.commons.logging.Log;
22  import org.apache.commons.logging.LogFactory;
23  import org.apache.maven.artifact.versioning.ArtifactVersion;
24  import org.eclipse.mylyn.internal.bugzilla.core.BugzillaAttribute;
25  import org.eclipse.mylyn.tasks.core.data.TaskAttribute;
26  import org.eclipse.mylyn.tasks.core.data.TaskData;
27  
28  import de.smartics.maven.issues.RendererConfig;
29  
30  /**
31   * Selects the issues to their categories.
32   *
33   * @author <a href="mailto:robert.reiner@smartics.de">Robert Reiner</a>
34   * @version $Revision:591 $
35   */
36  public class VersionedSectioner implements Sectioner<Versions>
37  {
38    // ********************************* Fields *********************************
39  
40    // --- constants ------------------------------------------------------------
41  
42    /**
43     * Reference to the logger for this class.
44     */
45    private static final Log LOG = LogFactory.getLog(VersionedSectioner.class);
46  
47    // --- members --------------------------------------------------------------
48  
49    /**
50     * The configuration to control the processing of the sections.
51     */
52    private final RendererConfig config;
53  
54    /**
55     * The issues to be appointed to the different sections.
56     */
57    private final List<TaskData> issues;
58  
59    /**
60     * The map stores the bugs in the order read from the issue management system
61     * in different sections within different target versions.
62     */
63    private final Versions versions;
64  
65    // ****************************** Initializer *******************************
66  
67    // ****************************** Constructors ******************************
68  
69    /**
70     * Convenience constructor using inverse sort order for versions.
71     *
72     * @param config the configuration to control the processing of the sections.
73     * @param issues the issues to be appointed to the different sections.
74     */
75    public VersionedSectioner(final RendererConfig config,
76        final List<TaskData> issues)
77    {
78      this.config = config;
79      this.issues = issues;
80      this.versions = new Versions(config.getSections());
81    }
82  
83    /**
84     * Default constructor.
85     *
86     * @param config the configuration to control the processing of the sections.
87     * @param issues the issues to be appointed to the different sections.
88     * @param versionComparator the comparator to use to sort version numbers. A
89     *          value of <code>null</code> implies that natural sort order is to
90     *          be used.
91     */
92    public VersionedSectioner(final RendererConfig config,
93        final List<TaskData> issues,
94        final Comparator<ArtifactVersion> versionComparator)
95    {
96      this.config = config;
97      this.issues = issues;
98      this.versions = new Versions(config.getSections(), versionComparator);
99    }
100 
101   // ****************************** Inner Classes *****************************
102 
103   // ********************************* Methods ********************************
104 
105   // --- init -----------------------------------------------------------------
106 
107   // --- get&set --------------------------------------------------------------
108 
109   // --- business -------------------------------------------------------------
110 
111   /**
112    * Distributes the issues to the configured sections within their versions.
113    * Issues not defining the property referenced by
114    * {@link RendererConfig#getSectionType()} are skipped as well as issues that
115    * provide a value for that property that is not part of
116    * {@link RendererConfig#getSections()}. If the issue has no version attribute
117    * (target milestone), the issue is also skipped.
118    *
119    * @impl Skipped issues are logged at debug level.
120    * @return the map of versions.
121    */
122   public Versions run()
123   {
124     final String sectionAttributeKey = config.getSectionType();
125     final BugzillaAttribute versionAttribute =
126         BugzillaAttribute.TARGET_MILESTONE;
127     for (TaskData issue : issues)
128     {
129       final TaskAttribute root = issue.getRoot();
130       final ArtifactVersion version = getVersion(root, versionAttribute);
131       if (version != null)
132       {
133         final TaskAttribute attribute = root.getAttribute(sectionAttributeKey);
134         if (attribute != null)
135         {
136           final String section = attribute.getValue();
137           final boolean added = versions.add(version, section, issue);
138           if (!added && LOG.isDebugEnabled())
139           {
140             LOG.debug("Issue #" + issue.getTaskId() + " defines attribute '"
141                       + sectionAttributeKey + "' as '" + section
142                       + "' which is not mapped to a column. Skipped.");
143           }
144         }
145         else
146         {
147           logSkipping(sectionAttributeKey, issue);
148         }
149       }
150       else
151       {
152         logSkipping(versionAttribute.getKey(), issue);
153       }
154     }
155     return versions;
156   }
157 
158   /**
159    * Simple helper to log that the given issue was skipped due to a missing
160    * attribute of this issue.
161    * <p>
162    * Logging is run on debug level.
163    * </p>
164    *
165    * @param attributeKey the key of the attribute that was not set and therefore
166    *          the issue was skipped.
167    * @param issue the skipped issue.
168    */
169   private static void logSkipping(final String attributeKey,
170       final TaskData issue)
171   {
172     if (LOG.isDebugEnabled())
173     {
174       LOG.debug("Issue #" + issue.getTaskId() + " does not define attribute '"
175                 + attributeKey + "'. Skipped.");
176     }
177   }
178 
179   /**
180    * Returns the value for the version referenced by the
181    * <code>versionAttribute</code>. The value of this attribute is required to
182    * be a version information. Bugzilla supports the version and target
183    * milestone as version values.
184    *
185    * @param rootAttribute the reference to the issues root attribute.
186    * @param versionAttributeDescriptor the key to the attribute to fetch within
187    *          the root attribute.
188    * @return the version instance created upon the version attribute's value or
189    *         <code>null</code> if that information was not present or not valid.
190    */
191   private ArtifactVersion getVersion(final TaskAttribute rootAttribute,
192       final BugzillaAttribute versionAttributeDescriptor)
193   {
194     final TaskAttribute attribute =
195         rootAttribute.getAttribute(versionAttributeDescriptor.getKey());
196     if (attribute != null)
197     {
198       final String versionString = attribute.getValue();
199       if (versionString != null && !"---".equals(versionString))
200       {
201         final ArtifactVersion version =
202             config.getVersionFactoryInstance().createVersion(versionString);
203         return version;
204       }
205     }
206     return null;
207   }
208 
209   // --- object basics --------------------------------------------------------
210 
211 }