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 }