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