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