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;
17  
18  import java.io.BufferedInputStream;
19  import java.io.File;
20  import java.io.FileInputStream;
21  import java.io.IOException;
22  import java.io.InputStream;
23  import java.util.ArrayList;
24  import java.util.List;
25  import java.util.ResourceBundle;
26  
27  import org.apache.commons.io.IOUtils;
28  import org.apache.commons.lang.StringUtils;
29  import org.apache.commons.lang.builder.ToStringBuilder;
30  import org.apache.commons.logging.Log;
31  import org.apache.commons.logging.LogFactory;
32  import org.apache.maven.artifact.versioning.ArtifactVersion;
33  import org.eclipse.mylyn.internal.bugzilla.core.BugzillaAttribute;
34  
35  import de.smartics.maven.issues.notes.NotesReader;
36  import de.smartics.maven.issues.util.ReportReference;
37  
38  /**
39   * Configuration to control the rendering process.
40   *
41   * @author <a href="mailto:robert.reiner@smartics.de">Robert Reiner</a>
42   * @version $Revision:591 $
43   */
44  public final class RendererConfig // NOPMD Config has a lot of properties.
45  {
46    // ********************************* Fields *********************************
47  
48    // --- constants ------------------------------------------------------------
49  
50    // --- members --------------------------------------------------------------
51  
52    /**
53     * The message bundle for labels.
54     */
55    private final ResourceBundle bundle;
56  
57    /**
58     * Sets the component(s) that you want to limit your report to include.
59     * Multiple components can be separated by commas. If this is set to empty -
60     * that means all components.
61     */
62    private final String component;
63  
64    /**
65     * The type (probably but not necessarily a user type) that specifies the
66     * information in the issue that is used to group the issues in sections.
67     * <p>
68     * For example a user type <code>ct_type</code> may be defined to specify the
69     * type of an issue. Valid types could be <code>Bug</code>,
70     * <code>New Feature</code>, <code>Improvement</code>, and <code>Task</code>.
71     * </p>
72     */
73    private final String sectionType;
74  
75    /**
76     * The order of the values specified for the {@link #getSectionType() section
77     * type}. Only values specified in this list will be rendered at all.
78     * <p>
79     * Regarding the example given for {@link #getSectionType()}, this list could
80     * define <code>New Feature</code>, <code>Bug</code>, <code>Improvement</code>
81     * . This would render issues tagged as new features in the first, issues
82     * tagged as bugs in the second and issues tagged as improvements in the last
83     * section. Issues tagged as tasks will not be rendered.
84     */
85    private final List<String> sections;
86  
87    /**
88     * The name of the query to execute. If the query name is specified none of
89     * the other query properties is taken into account.
90     */
91    private final String queryName;
92  
93    /**
94     * Lists the columns to be rendered. Each element of this list is a property
95     * of an issue. The identifiers given here must match the ones defined in the
96     * referenced issue management system. E.g. for Bugzilla these are defined in
97     * <code>org.eclipse.mylyn.internal.bugzilla.core.BugzillaAttribute</code>.
98     */
99    private final List<String> columns;
100 
101   /**
102    * Lists the column width to be used to set to the columns. If the value is
103    * <code>0</code> (zero) no width will be set explicitly for that column.
104    */
105   private final List<String> columnWidths;
106 
107   /**
108    * Specifies the index (zero bases) of the column at which the
109    * {@link #getComponent() component information} is to rendered. This option
110    * is only taken into account if the {@link #getComponent() component
111    * property} does not specify exactly one component. Please note that this
112    * cannot be used in named queries.
113    * <p>
114    * This is a handy option for running the report on a multi project. Sub
115    * projects specify exactly one component while the parent project specifies
116    * none. The result with setting an index of e.g. <code>1</code> is that in
117    * each sub project the component is not mentioned while it is on the parent
118    * project (listing all issues of all projects) it is rendered at the second
119    * column.
120    * </p>
121    */
122   private final int includeComponentAtIndex;
123 
124   /**
125    * Specifies the column width for the {@link #getIncludeComponentAtIndex()
126    * includeComponentAtIndex} property. If that property is not set, this
127    * property value is ignored.
128    */
129   private final int includeComponentAtIndexColumnWidth;
130 
131   /**
132    * The value of the flag that indicates whether or not eMail addresses should
133    * be rendered. Rendering eMail addresses may be useful for intranet sites.
134    * Due to spamming it might not be wise to render an eMail address on an
135    * internet server.
136    * <p>
137    * A value of <code>true</code> indicates that the eMail address should be
138    * rendered (e.g. as a mailto anchor in HTML for an assignee name),
139    * <code>false</code> if no eMail address information should be written.
140    * </p>
141    */
142   private final boolean renderEmailAdresses;
143 
144   /**
145    * A range defining the versions of issues to be rendered.
146    */
147   private final ArtifactVersionRange versionRange;
148 
149   /**
150    * On the same page all of the given version type are rendered. For instance
151    * if this value refers to the major version, all versions having the same
152    * major version are rendered. A value of micro implies that only the current
153    * version is to be rendered.
154    */
155   private final VersionType includeOnSamePageAllOfVersion;
156 
157   /**
158    * The current version of the project. This information is used to determine
159    * which issues are targeted prior or later than the current version.
160    */
161   private final ArtifactVersion currentReleaseVersion;
162 
163   /**
164    * The factory to create comparable version instances. This factory is used to
165    * sort issues by their version information.
166    */
167   private final VersionFactory versionFactory;
168 
169   /**
170    * The title to be set in the configuration to be used instead of the one
171    * found in the localized files. This property is used to specify the title
172    * from the configuration and is useful if the user wants to select a specific
173    * set of information retrieved by a specific query and now wants to set a
174    * specific title.
175    * <p>
176    * This value may be <code>null</code> in which case the renderer retrieves a
177    * default value (probably assuming that a release notes report is rendered).
178    * </p>
179    */
180   private final String title;
181 
182   /**
183    * The description to be set in the configuration to be used instead of the
184    * one found in the localized files. This property is used to specify the
185    * description from the configuration and is useful if the user wants to
186    * select a specific set of information retrieved by a specific query and now
187    * wants to set a specific description.
188    * <p>
189    * This value may be <code>null</code> in which case the renderer retrieves a
190    * default value (probably assuming that a release notes report is rendered).
191    * </p>
192    */
193   private final String description;
194 
195   /**
196    * The description file is a <a
197    * href="http://maven.apache.org/doxia/references/xdoc-format.html">XDoc</a>
198    * file to be included as-is into the generated report. It is rendered between
199    * the main header and the report table where the description is normally
200    * written. The description is left out if a description file is given.
201    */
202   private final File descriptionFile;
203 
204   /**
205    * The description to be set in the configuration if no issue matches the
206    * query to be used instead of the one found in the localized files. This
207    * property is used to specify the description from the configuration and is
208    * useful if the user wants to select a specific set of information retrieved
209    * by a specific query and now wants to set a specific description.
210    * <p>
211    * This value may be omitted in which case the renderer retrieves a default
212    * value (probably assuming that a release notes report is rendered).
213    * </p>
214    */
215   private final String noResultsDescription;
216 
217   /**
218    * The text to be added as a footer as raw text.
219    */
220   private final String footerText;
221 
222   /**
223    * The references to former reports.
224    */
225   private final List<ReportReference> reportReferences;
226 
227   // ****************************** Initializer *******************************
228 
229   // ****************************** Constructors ******************************
230 
231   /**
232    * Default constructor.
233    *
234    * @param builder the builder with the information to set.
235    */
236   private RendererConfig(final Builder builder)
237   {
238     this.bundle = builder.bundle;
239     this.component = builder.component;
240     this.sectionType = builder.sectionType;
241     this.sections = builder.sections;
242     this.queryName = builder.queryName;
243     this.columns = builder.columns;
244     this.columnWidths = builder.columnWidths;
245     this.includeOnSamePageAllOfVersion = builder.includeOnSamePageAllOfVersion;
246     this.includeComponentAtIndex = builder.includeComponentAtIndex;
247     this.includeComponentAtIndexColumnWidth =
248         builder.includeComponentAtIndexColumnWidth;
249     this.renderEmailAdresses = builder.renderEmailAdresses;
250     this.versionRange = builder.versionRange;
251     this.currentReleaseVersion = builder.currentReleaseVersion;
252     this.versionFactory = builder.versionFactory;
253     this.title = builder.title;
254     this.description = builder.description;
255     this.noResultsDescription = builder.noResultsDescription;
256     this.footerText = builder.footerText;
257     this.descriptionFile = builder.descriptionFile;
258     this.reportReferences = builder.reportReferences;
259   }
260 
261   // ****************************** Inner Classes *****************************
262 
263   /**
264    * Builder to create instances of type {@link RendererConfig}.
265    */
266   public static final class Builder // NOPMD Builder has a lot of properties.
267   {
268     // ******************************** Fields ********************************
269 
270     /**
271      * Reference to the logger for this class.
272      */
273     private final Log log = LogFactory.getLog(RendererConfig.class);
274 
275     /**
276      * The message bundle for labels.
277      */
278     private ResourceBundle bundle;
279 
280     /**
281      * Sets the component(s) that you want to limit your report to include.
282      * Multiple components can be separated by commas. If this is set to empty -
283      * that means all components.
284      */
285     private String component;
286 
287     /**
288      * The type (probably but not necessarily a user type) that specifies the
289      * information in the issue that is used to group the issues in sections.
290      * <p>
291      * For example a user type <code>ct_type</code> may be defined to specify
292      * the type of an issue. Valid types could be <code>Bug</code>,
293      * <code>New Feature</code>, <code>Improvement</code>, and <code>Task</code>
294      * .
295      * </p>
296      */
297     private String sectionType;
298 
299     /**
300      * The order of the values specified for the {@link #getSectionType()
301      * section type}. Only values specified in this list will be rendered at
302      * all.
303      * <p>
304      * Regarding the example given for {@link #getSectionType()}, this list
305      * could define <code>New Feature</code>, <code>Bug</code>,
306      * <code>Improvement</code> . This would render issues tagged as new
307      * features in the first, issues tagged as bugs in the second and issues
308      * tagged as improvements in the last section. Issues tagged as tasks will
309      * not be rendered.
310      * </p>
311      */
312     private List<String> sections;
313 
314     /**
315      * The name of the query to execute. If the query name is specified none of
316      * the other query properties is taken into account.
317      */
318     private String queryName;
319 
320     /**
321      * Lists the columns to be rendered. Each element of this list is a property
322      * of an issue. The identifiers given here must match the ones defined in
323      * the referenced issue management system. E.g. for Bugzilla these are
324      * defined in
325      * <code>org.eclipse.mylyn.internal.bugzilla.core.BugzillaAttributey</code>.
326      */
327     private List<String> columns;
328 
329     /**
330      * Lists the column width to be used to set to the columns. If the value is
331      * <code>0</code> (zero) no width will be set explicitly for that column.
332      */
333     private List<String> columnWidths;
334 
335     /**
336      * Specifies the index (zero bases) of the column at which the
337      * {@link #getComponent() component information} is to rendered. This option
338      * is only taken into account if the {@link #getComponent() component
339      * property} does not specify exactly one component. Please note that this
340      * cannot be used in named queries.
341      * <p>
342      * This is a handy option for running the report on a multi project. Sub
343      * projects specify exactly one component while the parent project specifies
344      * none. The result with setting an index of e.g. <code>1</code> is that in
345      * each sub project the component is not mentioned while it is on the parent
346      * project (listing all issues of all projects) it is rendered at the second
347      * column.
348      * </p>
349      */
350     private int includeComponentAtIndex;
351 
352     /**
353      * Specifies the column width for the {@link #getIncludeComponentAtIndex()
354      * includeComponentAtIndex} property. If that property is not set, this
355      * property value is ignored.
356      */
357     private int includeComponentAtIndexColumnWidth;
358 
359     /**
360      * The value of the flag that indicates whether or not eMail addresses
361      * should be rendered. Rendering eMail addresses may be useful for intranet
362      * sites. Due to spamming it might not be wise to render an eMail address on
363      * an internet server.
364      * <p>
365      * A value of <code>true</code> indicates that the eMail address should be
366      * rendered (e.g. as a mailto anchor in HTML for an assignee name),
367      * <code>false</code> if no eMail address information should be written.
368      * </p>
369      */
370     private boolean renderEmailAdresses;
371 
372     /**
373      * On the same page all of the given version type are rendered. For instance
374      * if this value refers to the major version, all versions having the same
375      * major version are rendered. A value of micro implies that only the
376      * current version is to be rendered.
377      * <p>
378      * Defaults to {@link VersionType#MAJOR}.
379      * </p>
380      */
381     private VersionType includeOnSamePageAllOfVersion = VersionType.MAJOR;
382 
383     /**
384      * A range defining the versions of issues to be rendered.
385      */
386     private ArtifactVersionRange versionRange;
387 
388     /**
389      * The current version of the project. This information is used to determine
390      * which issues are targeted prior or later than the current version.
391      */
392     private ArtifactVersion currentReleaseVersion;
393 
394     /**
395      * The factory to create comparable version instances. This factory is used
396      * to sort issues by their version information.
397      */
398     private VersionFactory versionFactory;
399 
400     /**
401      * The title to be set in the configuration to be used instead of the one
402      * found in the localized files. This property is used to specify the title
403      * from the configuration and is useful if the user wants to select a
404      * specific set of information retrieved by a specific query and now wants
405      * to set a specific title.
406      * <p>
407      * This value may be <code>null</code> in which case the renderer retrieves
408      * a default value (probably assuming that a release notes report is
409      * rendered).
410      */
411     private String title;
412 
413     /**
414      * The description to be set in the configuration to be used instead of the
415      * one found in the localized files. This property is used to specify the
416      * description from the configuration and is useful if the user wants to
417      * select a specific set of information retrieved by a specific query and
418      * now wants to set a specific description.
419      * <p>
420      * This value may be <code>null</code> in which case the renderer retrieves
421      * a default value (probably assuming that a release notes report is
422      * rendered).
423      * </p>
424      */
425     private String description;
426 
427     /**
428      * The description file is a <a
429      * href="http://maven.apache.org/doxia/references/xdoc-format.html">XDoc</a>
430      * file to be included as-is into the generated report. It is rendered
431      * between the main header and the report table where the description is
432      * normally written. The description is left out if a description file is
433      * given.
434      */
435     private File descriptionFile;
436 
437     /**
438      * The description to be set in the configuration if no issue matches the
439      * query to be used instead of the one found in the localized files. This
440      * property is used to specify the description from the configuration and is
441      * useful if the user wants to select a specific set of information
442      * retrieved by a specific query and now wants to set a specific
443      * description.
444      * <p>
445      * This value may be omitted in which case the renderer retrieves a default
446      * value (probably assuming that a release notes report is rendered).
447      * </p>
448      */
449     private String noResultsDescription;
450 
451     /**
452      * The text to be added as a footer as raw text.
453      */
454     private String footerText;
455 
456     /**
457      * The references to former reports.
458      */
459     private List<ReportReference> reportReferences;
460 
461     // --- constants ----------------------------------------------------------
462 
463     // --- members ------------------------------------------------------------
464 
465     // ***************************** Initializer ******************************
466 
467     // ***************************** Constructors *****************************
468 
469     // ***************************** Inner Classes ****************************
470 
471     // ******************************** Methods *******************************
472 
473     // --- init ---------------------------------------------------------------
474 
475     // --- get&set ------------------------------------------------------------
476 
477     /**
478      * Sets the message bundle for labels.
479      *
480      * @param bundle the message bundle for labels.
481      */
482     public void setBundle(final ResourceBundle bundle)
483     {
484       this.bundle = bundle;
485     }
486 
487     /**
488      * Sets the value for component.
489      * <p>
490      * Sets the component(s) that you want to limit your report to include.
491      * Multiple components can be separated by commas. If this is set to empty -
492      * that means all components.
493      * </p>
494      *
495      * @param component the value for component.
496      */
497     public void setComponent(final String component)
498     {
499       this.component = component;
500     }
501 
502     /**
503      * Sets the type (probably but not necessarily a user type) that specifies
504      * the information in the issue that is used to group the issues in
505      * sections.
506      * <p>
507      * For example a user type <code>ct_type</code> may be defined to specify
508      * the type of an issue. Valid types could be <code>Bug</code>,
509      * <code>New Feature</code>, <code>Improvement</code>, and <code>Task</code>
510      * .
511      * </p>
512      *
513      * @param sectionType the type (probably but not necessarily a user type)
514      *          that specifies the information in the issue that is used to
515      *          group the issues in sections.
516      */
517     public void setSectionType(final String sectionType)
518     {
519       this.sectionType = sectionType;
520     }
521 
522     /**
523      * Sets the order of the values specified for the <code>sectionType</code>.
524      * Only values specified in this list will be rendered at all.
525      * <p>
526      * Regarding the example given for <code>sectionType</code>, this list could
527      * define <code>New Feature</code>, <code>Bug</code>,
528      * <code>Improvement</code>. This would render issues tagged as new features
529      * in the first, issues tagged as bugs in the second and issues tagged as
530      * improvements in the last section. Issues tagged as tasks will not be
531      * rendered.
532      *
533      * @param sections the order of the values specified for the
534      *          <code>sectionType</code>.
535      */
536     public void setSections(final List<String> sections)
537     {
538       this.sections = new ArrayList<String>(sections);
539     }
540 
541     /**
542      * Sets the name of the query to execute. If the query name is specified
543      * none of the other query properties is taken into account.
544      *
545      * @param queryName the name of the query to execute.
546      */
547     public void setQueryName(final String queryName)
548     {
549       this.queryName = queryName;
550     }
551 
552     /**
553      * Sets the value for columns.
554      * <p>
555      * Lists the columns to be rendered. Each element of this list is a property
556      * of an issue. The identifiers given here must match the ones defined in
557      * the referenced issue management system. E.g. for Bugzilla these are
558      * defined in
559      * <code>org.eclipse.mylyn.internal.bugzilla.core.BugzillaAttribute</code>.
560      * </p>
561      *
562      * @param columns the value for columns.
563      */
564     public void setColumns(final List<String> columns)
565     {
566       this.columns = new ArrayList<String>(columns);
567     }
568 
569     /**
570      * Sets the value for columnWidths.
571      * <p>
572      * Lists the column width to be used to set to the columns. If the value is
573      * <code>0</code> (zero) no width will be set explicitly for that column.
574      * </p>
575      *
576      * @param columnWidths the value for columnWidths.
577      */
578     public void setColumnWidths(final List<String> columnWidths)
579     {
580       this.columnWidths = columnWidths;
581     }
582 
583     /**
584      * Sets the value for includeComponentAtIndex.
585      * <p>
586      * Specifies the index (zero bases) of the column at which the
587      * {@link #getComponent() component information} is to rendered. This option
588      * is only taken into account if the {@link #getComponent() component
589      * property} does not specify exactly one component. Please note that this
590      * cannot be used in named queries.
591      * </p>
592      * <p>
593      * This is a handy option for running the report on a multi project. Sub
594      * projects specify exactly one component while the parent project specifies
595      * none. The result with setting an index of e.g. <code>1</code> is that in
596      * each sub project the component is not mentioned while it is on the parent
597      * project (listing all issues of all projects) it is rendered at the second
598      * column.
599      * </p>
600      *
601      * @param includeComponentAtIndex the value for includeComponentAtIndex.
602      */
603     public void setIncludeComponentAtIndex(final int includeComponentAtIndex)
604     {
605       this.includeComponentAtIndex = includeComponentAtIndex;
606     }
607 
608     /**
609      * Sets the value for includeComponentAtIndexColumnWidth.
610      * <p>
611      * Specifies the column width for the {@link #getIncludeComponentAtIndex()
612      * includeComponentAtIndex} property. If that property is not set, this
613      * property value is ignored.
614      * </p>
615      *
616      * @param includeComponentAtIndexColumnWidth the value for
617      *          includeComponentAtIndexColumnWidth.
618      */
619     public void setIncludeComponentAtIndexColumnWidth(
620         final int includeComponentAtIndexColumnWidth)
621     {
622       this.includeComponentAtIndexColumnWidth =
623           includeComponentAtIndexColumnWidth;
624     }
625 
626     /**
627      * Sets the value of the flag that indicates whether or not eMail addresses
628      * should be rendered. Rendering eMail addresses may be useful for intranet
629      * sites. Due to spamming it might not be wise to render an eMail address on
630      * an internet server.
631      * <p>
632      * A value of <code>true</code> indicates that the eMail address should be
633      * rendered (e.g. as a mailto anchor in HTML for an assignee name),
634      * <code>false</code> if no eMail address information should be written.
635      * </p>
636      *
637      * @param renderEmailAdresses the value of the flag that indicates whether
638      *          or not eMail addresses should be rendered.
639      */
640     public void setRenderEmailAdresses(final boolean renderEmailAdresses)
641     {
642       this.renderEmailAdresses = renderEmailAdresses;
643     }
644 
645     /**
646      * Sets the value for includeOnSamePageAll.
647      * <p>
648      * On the same page all of the given version type are rendered. For instance
649      * if this value refers to the major version, all versions having the same
650      * major version are rendered. A value of micro implies that only the
651      * current version is to be rendered.
652      * <p>
653      * Defaults to {@link VersionType#MAJOR}.
654      * </p>
655      *
656      * @param includeOnSamePageAll the value for includeOnSamePageAll.
657      */
658     public void setIncludeOnSamePageAllOfVersion(
659         final VersionType includeOnSamePageAll)
660     {
661       this.includeOnSamePageAllOfVersion = includeOnSamePageAll;
662     }
663 
664     /**
665      * Sets the range defining the versions of issues to be rendered.
666      *
667      * @param versionRange the range defining the versions of issues to be rendered.
668      */
669     public void setVersionRange(final ArtifactVersionRange versionRange)
670     {
671       this.versionRange = versionRange;
672     }
673 
674     /**
675      * Sets the current version of the project. This information is used to
676      * determine which issues are targeted prior or later than the current
677      * version.
678      *
679      * @param currentReleaseVersion the current version of the project.
680      */
681     public void setCurrentReleaseVersion(
682         final ArtifactVersion currentReleaseVersion)
683     {
684       this.currentReleaseVersion = currentReleaseVersion;
685     }
686 
687     /**
688      * Sets the factory to create comparable version instances. This factory is
689      * used to sort issues by their version information.
690      *
691      * @param versionFactory the factory to create comparable version instances.
692      */
693     public void setVersionFactory(final VersionFactory versionFactory)
694     {
695       this.versionFactory = versionFactory;
696     }
697 
698     /**
699      * Sets the title to be set in the configuration to be used instead of the
700      * one found in the localized files. This property is used to specify the
701      * title from the configuration and is useful if the user wants to select a
702      * specific set of information retrieved by a specific query and now wants
703      * to set a specific title.
704      * <p>
705      * This value may be <code>null</code> in which case the renderer retrieves
706      * a default value (probably assuming that a release notes report is
707      * rendered).
708      *
709      * @param title the title to be set in the configuration to be used instead
710      *          of the one found in the localized files.
711      */
712     public void setTitle(final String title)
713     {
714       this.title = title;
715     }
716 
717     /**
718      * Sets the description to be set in the configuration to be used instead of
719      * the one found in the localized files. This property is used to specify
720      * the description from the configuration and is useful if the user wants to
721      * select a specific set of information retrieved by a specific query and
722      * now wants to set a specific description.
723      * <p>
724      * This value may be <code>null</code> in which case the renderer retrieves
725      * a default value (probably assuming that a release notes report is
726      * rendered).
727      * </p>
728      *
729      * @param description the description to be set in the configuration to be
730      *          used instead of the one found in the localized files.
731      */
732     public void setDescription(final String description)
733     {
734       this.description = description;
735     }
736 
737     /**
738      * Sets the description file is a <a
739      * href="http://maven.apache.org/doxia/references/xdoc-format.html"
740      * >XDoc</a> file to be included as-is into the generated report. It is
741      * rendered between the main header and the report table where the
742      * description is normally written. The description is left out if a
743      * description file is given.
744      *
745      * @param descriptionFile the description file is a <a
746      *          href="http://maven.apache.org/doxia/references/xdoc-format.html"
747      *          >XDoc</a> file to include in the report.
748      */
749     public void setDescriptionFile(final File descriptionFile)
750     {
751       this.descriptionFile = descriptionFile;
752     }
753 
754     /**
755      * Sets the description to be set in the configuration if no issue matches
756      * the query to be used instead of the one found in the localized files.
757      * This property is used to specify the description from the configuration
758      * and is useful if the user wants to select a specific set of information
759      * retrieved by a specific query and now wants to set a specific
760      * description.
761      * <p>
762      * This value may be omitted in which case the renderer retrieves a default
763      * value (probably assuming that a release notes report is rendered).
764      * </p>
765      *
766      * @param noResultsDescription the description to be set in the
767      *          configuration if no issue matches the query to be used instead
768      *          of the one found in the localized files.
769      */
770     public void setNoResultsDescription(final String noResultsDescription)
771     {
772       this.noResultsDescription = noResultsDescription;
773     }
774 
775     /**
776      * Sets the text to be added as a footer as raw text.
777      *
778      * @param footerText the text to be added as a footer as raw text.
779      */
780     public void setFooterText(final String footerText)
781     {
782       this.footerText = footerText;
783     }
784 
785     // --- business -----------------------------------------------------------
786 
787     /**
788      * Validates the information passed to the builder and creates in instance
789      * of type {@link RendererConfig}.
790      *
791      * @return the created instance.
792      * @throws IllegalArgumentException if the information passed to the builder
793      *           is invalid to create the instance.
794      */
795     public RendererConfig build() throws IllegalArgumentException
796     {
797       final StringBuilder buffer = new StringBuilder();
798 
799       if (bundle == null)
800       {
801         buffer.append("No resource bundle specified, but required.");
802       }
803       if (currentReleaseVersion == null)
804       {
805         buffer.append("No current release version specified, but required.");
806       }
807       if (versionFactory == null)
808       {
809         buffer.append("No version factory specified, but required.");
810       }
811 
812       checkSections(buffer);
813       checkColumns(buffer);
814 
815       addIncludeComponentAtIndex();
816 
817       if (buffer.length() > 0)
818       {
819         throw new IllegalArgumentException(buffer.toString());
820       }
821       return new RendererConfig(this); // NOPMD
822     }
823 
824     /**
825      * Adds the {@link #setIncludeComponentAtIndex includeComponentAtIndex}
826      * feature. The feature is only added if it is not a named query, the
827      * columns do not yet contain the component information and the property is
828      * correctly set. If the property is not correctly set (out of column's
829      * range), a warning is issued at warn level but else silently ignored.
830      */
831     private void addIncludeComponentAtIndex()
832     {
833       final String componentKey = BugzillaAttribute.COMPONENT.getKey();
834 
835       if (includeComponentAtIndex >= 0 && StringUtils.isEmpty(queryName)
836           && !columns.contains(componentKey) && !isOnlyOneComponentSpecified())
837       {
838         if (includeComponentAtIndex < columns.size())
839         {
840           columns.add(includeComponentAtIndex, componentKey);
841           columnWidths.add(includeComponentAtIndex,
842               String.valueOf(includeComponentAtIndexColumnWidth));
843         }
844         else
845         {
846           if (log.isWarnEnabled())
847           {
848             log.warn("The index specified for 'includeComponentAtIndex' is out of range. It should be between 0 and "
849                      + (columns.size() - 1)
850                      + " but is set to "
851                      + includeComponentAtIndex + "'. The index is ignored.");
852           }
853         }
854       }
855     }
856 
857     /**
858      * Checks if one and only one component is specified.
859      *
860      * @return <code>true</code> if only one component is specified,
861      *         <code>false</code> if no or more than one component is specified.
862      */
863     private boolean isOnlyOneComponentSpecified()
864     {
865       return StringUtils.isNotBlank(component) && component.indexOf(',') == -1;
866     }
867 
868     /**
869      * Checks the sections information.
870      *
871      * @param buffer the buffer to append violation messages.
872      */
873     private void checkSections(final StringBuilder buffer)
874     {
875       if (StringUtils.isBlank(sectionType))
876       {
877         buffer.append("No section type given that selects the"
878                       + " information of an issue to render sections.");
879       }
880       if (sections == null || sections.isEmpty())
881       {
882         buffer.append("No sections provided to specify which issue types"
883                       + " should be rendered to individual sections.");
884       }
885     }
886 
887     /**
888      * Checks the columns information.
889      *
890      * @param buffer the buffer to append violation messages.
891      */
892     private void checkColumns(final StringBuilder buffer)
893     {
894       if (isNullOrEmpty(columns))
895       {
896         buffer.append("No columns provided to specify which issue information"
897                       + " should be rendered in the report tables.");
898       }
899       if (isNullOrEmpty(columnWidths))
900       {
901         columnWidths = new ArrayList<String>(columns.size());
902         for (int i = columns.size(); i > 0; i--)
903         {
904           columnWidths.add("0");
905         }
906       }
907       if (notOfEqualSize(columns, columnWidths))
908       {
909         buffer.append("The length of columns (" + columns.size()
910                       + ") and columnWidths (" + columnWidths.size()
911                       + ") differs.");
912       }
913     }
914 
915     /**
916      * Checks if both lists are of equal size.
917      *
918      * @param list1 the first list.
919      * @param list2 the second list.
920      * @return <code>true</code> if they are not of equal size, false otherwise.
921      */
922     private static boolean notOfEqualSize(final List<?> list1,
923         final List<?> list2)
924     {
925       return list1 != null && list2 != null && list1.size() != list2.size();
926     }
927 
928     /**
929      * Checks if the given list is <code>null</code> or empty.
930      *
931      * @param list the list to check.
932      * @return true of the list is <code>null</code> or empty,
933      *         <code>false</code> otherwise.
934      */
935     private boolean isNullOrEmpty(final List<?> list)
936     {
937       return list == null || list.isEmpty();
938     }
939 
940     /**
941      * Sets the references to former reports.
942      *
943      * @param reportReferences the references to former reports.
944      */
945     public void setReportReferences(final List<ReportReference> reportReferences)
946     {
947       this.reportReferences = reportReferences;
948     }
949 
950     // --- object basics ------------------------------------------------------
951   }
952 
953   // ********************************* Methods ********************************
954 
955   // --- init -----------------------------------------------------------------
956 
957   // --- get&set --------------------------------------------------------------
958 
959   /**
960    * Returns the message bundle for labels.
961    *
962    * @return the message bundle for labels.
963    */
964   public ResourceBundle getBundle()
965   {
966     return bundle;
967   }
968 
969   /**
970    * Returns the value for component.
971    * <p>
972    * Sets the component(s) that you want to limit your report to include.
973    * Multiple components can be separated by commas. If this is set to empty -
974    * that means all components.
975    *
976    * @return the value for component.
977    */
978   public String getComponent()
979   {
980     return component;
981   }
982 
983   /**
984    * Returns the type (probably but not necessarily a user type) that specifies
985    * the information in the issue that is used to group the issues in sections.
986    * <p>
987    * For example a user type <code>ct_type</code> may be defined to specify the
988    * type of an issue. Valid types could be <code>Bug</code>,
989    * <code>New Feature</code>, <code>Improvement</code>, and <code>Task</code> .
990    * </p>
991    *
992    * @return the type (probably but not necessarily a user type) that specifies
993    *         the information in the issue that is used to group the issues in
994    *         sections.
995    */
996   public String getSectionType()
997   {
998     return sectionType;
999   }
1000 
1001   /**
1002    * Returns the order of the values specified for the {@link #getSectionType()
1003    * section type}. Only values specified in this list will be rendered at all.
1004    * <p>
1005    * Regarding the example given for {@link #getSectionType()}, this list could
1006    * define <code>New Feature</code>, <code>Bug</code>, <code>Improvement</code>
1007    * . This would render issues tagged as new features in the first, issues
1008    * tagged as bugs in the second and issues tagged as improvements in the last
1009    * section. Issues tagged as tasks will not be rendered.
1010    * </p>
1011    *
1012    * @return the order of the values specified for the {@link #getSectionType()
1013    *         section type}.
1014    */
1015   public List<String> getSections()
1016   {
1017     return sections;
1018   }
1019 
1020   /**
1021    * Returns the name of the query to execute. If the query name is specified
1022    * none of the other query properties is taken into account.
1023    *
1024    * @return the name of the query to execute.
1025    */
1026   public String getQueryName()
1027   {
1028     return queryName;
1029   }
1030 
1031   /**
1032    * Returns the value for columns.
1033    * <p>
1034    * Lists the columns to be rendered. Each element of this list is a property
1035    * of an issue. The identifiers given here must match the ones defined in the
1036    * referenced issue management system. E.g. for Bugzilla these are defined in
1037    * <code>org.eclipse.mylyn.internal.bugzilla.core.BugzillaAttribute</code>.
1038    * </p>
1039    *
1040    * @return the value for columns.
1041    */
1042   public List<String> getColumns()
1043   {
1044     return columns;
1045   }
1046 
1047   /**
1048    * Returns the value for columnWidths.
1049    * <p>
1050    * Lists the column width to be used to set to the columns. If the value is
1051    * <code>0</code> (zero) no width will be set explicitly for that column.
1052    * </p>
1053    *
1054    * @return the value for columnWidths.
1055    */
1056   public List<String> getColumnWidths()
1057   {
1058     return columnWidths;
1059   }
1060 
1061   /**
1062    * Returns the value for includeComponentAtIndex.
1063    * <p>
1064    * Specifies the index (zero bases) of the column at which the
1065    * {@link #getComponent() component information} is to rendered. This option
1066    * is only taken into account if the {@link #getComponent() component
1067    * property} does not specify exactly one component. Please note that this
1068    * cannot be used in named queries.
1069    * </p>
1070    * <p>
1071    * This is a handy option for running the report on a multi project. Sub
1072    * projects specify exactly one component while the parent project specifies
1073    * none. The result with setting an index of e.g. <code>1</code> is that in
1074    * each sub project the component is not mentioned while it is on the parent
1075    * project (listing all issues of all projects) it is rendered at the second
1076    * column.
1077    * </p>
1078    *
1079    * @return the value for includeComponentAtIndex.
1080    */
1081   public int getIncludeComponentAtIndex()
1082   {
1083     return includeComponentAtIndex;
1084   }
1085 
1086   /**
1087    * Returns the value for includeComponentAtIndexColumnWidth.
1088    * <p>
1089    * Specifies the column width for the {@link #getIncludeComponentAtIndex()
1090    * includeComponentAtIndex} property. If that property is not set, this
1091    * property value is ignored.
1092    *
1093    * @return the value for includeComponentAtIndexColumnWidth.
1094    */
1095   public int getIncludeComponentAtIndexColumnWidth()
1096   {
1097     return includeComponentAtIndexColumnWidth;
1098   }
1099 
1100   /**
1101    * Returns the value of the flag that indicates whether or not eMail addresses
1102    * should be rendered. Rendering eMail addresses may be useful for intranet
1103    * sites. Due to spamming it might not be wise to render an eMail address on
1104    * an internet server.
1105    * <p>
1106    * A value of <code>true</code> indicates that the eMail address should be
1107    * rendered (e.g. as a mailto anchor in HTML for an assignee name),
1108    * <code>false</code> if no eMail address information should be written.
1109    * </p>
1110    *
1111    * @return the value of the flag that indicates whether or not eMail addresses
1112    *         should be rendered.
1113    */
1114   public boolean isRenderEmailAdresses()
1115   {
1116     return renderEmailAdresses;
1117   }
1118 
1119   /**
1120    * Returns the value for includeOnSamePageAll.
1121    * <p>
1122    * On the same page all of the given version type are rendered. For instance
1123    * if this value refers to the major version, all versions having the same
1124    * major version are rendered. A value of micro implies that only the current
1125    * version is to be rendered.
1126    * <p>
1127    * Defaults to {@link VersionType#MAJOR}.
1128    * </p>
1129    *
1130    * @return the value for includeOnSamePageAll.
1131    */
1132   public VersionType getIncludeOnSamePageAllOfVersion()
1133   {
1134     return includeOnSamePageAllOfVersion;
1135   }
1136 
1137   /**
1138    * Returns a range defining the versions of issues to be rendered.
1139    *
1140    * @return a range defining the versions of issues to be rendered.
1141    */
1142   public ArtifactVersionRange getVersionRange()
1143   {
1144     return versionRange;
1145   }
1146 
1147   /**
1148    * Returns the current version of the project. This information is used to
1149    * determine which issues are targeted prior or later than the current
1150    * version.
1151    *
1152    * @return the current version of the project.
1153    */
1154   public ArtifactVersion getCurrentReleaseVersion()
1155   {
1156     return currentReleaseVersion;
1157   }
1158 
1159   /**
1160    * Returns the factory to create comparable version instances. This factory is
1161    * used to sort issues by their version information.
1162    *
1163    * @return the factory to create comparable version instances.
1164    */
1165   public VersionFactory getVersionFactoryInstance()
1166   {
1167     return versionFactory;
1168   }
1169 
1170   /**
1171    * Returns the title to be set in the configuration to be used instead of the
1172    * one found in the localized files. This property is used to specify the
1173    * title from the configuration and is useful if the user wants to select a
1174    * specific set of information retrieved by a specific query and now wants to
1175    * set a specific title.
1176    * <p>
1177    * This value may be <code>null</code> in which case the renderer retrieves a
1178    * default value (probably assuming that a release notes report is rendered).
1179    *
1180    * @return the title to be set in the configuration to be used instead of the
1181    *         one found in the localized files.
1182    */
1183   public String getTitle()
1184   {
1185     return title;
1186   }
1187 
1188   /**
1189    * Returns the description to be set in the configuration to be used instead
1190    * of the one found in the localized files. This property is used to specify
1191    * the description from the configuration and is useful if the user wants to
1192    * select a specific set of information retrieved by a specific query and now
1193    * wants to set a specific description.
1194    * <p>
1195    * This value may be <code>null</code> in which case the renderer retrieves a
1196    * default value (probably assuming that a release notes report is rendered).
1197    * </p>
1198    *
1199    * @return the description to be set in the configuration to be used instead
1200    *         of the one found in the localized files.
1201    */
1202   public String getDescription()
1203   {
1204     return description;
1205   }
1206 
1207   /**
1208    * Returns the description file is a <a
1209    * href="http://maven.apache.org/doxia/references/xdoc-format.html">XDoc</a>
1210    * file to be included as-is into the generated report. It is rendered between
1211    * the main header and the report table where the description is normally
1212    * written. The description is left out if a description file is given.
1213    *
1214    * @return the description file is a <a
1215    *         href="http://maven.apache.org/doxia/references/xdoc-format.html"
1216    *         >XDoc</a> file to include in the report.
1217    */
1218   public File getDescriptionFile()
1219   {
1220     return descriptionFile;
1221   }
1222 
1223   /**
1224    * Returns the description to be set in the configuration if no issue matches
1225    * the query to be used instead of the one found in the localized files. This
1226    * property is used to specify the description from the configuration and is
1227    * useful if the user wants to select a specific set of information retrieved
1228    * by a specific query and now wants to set a specific description.
1229    * <p>
1230    * This value may be omitted in which case the renderer retrieves a default
1231    * value (probably assuming that a release notes report is rendered).
1232    * </p>
1233    *
1234    * @return the description to be set in the configuration if no issue matches
1235    *         the query to be used instead of the one found in the localized
1236    *         files.
1237    */
1238   public String getNoResultsDescription()
1239   {
1240     return noResultsDescription;
1241   }
1242 
1243   /**
1244    * Returns the text to be added as a footer as raw text.
1245    *
1246    * @return the text to be added as a footer as raw text.
1247    */
1248   public String getFooterText()
1249   {
1250     return footerText;
1251   }
1252 
1253   /**
1254    * Returns the references to former reports.
1255    *
1256    * @return the references to former reports.
1257    */
1258   public List<ReportReference> getReportReferences()
1259   {
1260     return reportReferences;
1261   }
1262 
1263   // --- business -------------------------------------------------------------
1264 
1265   /**
1266    * Reads the body content from the {@link #getDescriptionFile() description
1267    * file}.
1268    *
1269    * @return the content of the body element (without the body tags). If no
1270    *         description file is given, the empty string is returned.
1271    * @throws IOException if the file cannot be parsed to extract the body
1272    *           element content.
1273    */
1274   public String getDescriptionFileBodyContent() throws IOException
1275   {
1276     final File file = getDescriptionFile();
1277 
1278     if (file != null)
1279     {
1280       final NotesReader reader = new NotesReader();
1281       InputStream in = null;
1282       try
1283       {
1284         in = new BufferedInputStream(new FileInputStream(file));
1285         final String content = reader.read(in);
1286         return content;
1287       }
1288       finally
1289       {
1290         IOUtils.closeQuietly(in);
1291       }
1292     }
1293     return StringUtils.EMPTY;
1294   }
1295 
1296   // --- object basics --------------------------------------------------------
1297 
1298   /**
1299    * {@inheritDoc}
1300    *
1301    * @see java.lang.Object#toString()
1302    */
1303   @Override
1304   public String toString()
1305   {
1306     return ToStringBuilder.reflectionToString(this);
1307   }
1308 }