1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 package net.sf.statcvs.output;
24
25 import java.awt.Color;
26 import java.io.BufferedReader;
27 import java.io.File;
28 import java.io.FileInputStream;
29 import java.io.FileNotFoundException;
30 import java.io.FileReader;
31 import java.io.IOException;
32 import java.io.InputStream;
33 import java.net.MalformedURLException;
34 import java.net.URL;
35 import java.util.ArrayList;
36 import java.util.Collection;
37 import java.util.List;
38 import java.util.Properties;
39 import java.util.regex.Pattern;
40 import java.util.regex.PatternSyntaxException;
41
42 import net.sf.statcvs.pages.MarkupSyntax;
43 import net.sf.statcvs.util.FilePatternMatcher;
44 import net.sf.statcvs.util.FileUtils;
45 import net.sf.statcvs.util.StringUtils;
46 import net.sf.statcvs.weblinks.bugs.BugTracker;
47 import net.sf.statcvs.weblinks.bugs.Bugzilla;
48 import net.sf.statcvs.weblinks.bugs.Mantis;
49
50 import org.jfree.chart.renderer.category.BarRenderer;
51 import org.jfree.chart.renderer.category.StandardBarPainter;
52 import org.jfree.chart.renderer.xy.StandardXYBarPainter;
53 import org.jfree.chart.renderer.xy.XYBarRenderer;
54
55 /**
56 * Class for storing all command line parameters. The parameters
57 * are set by the {@link net.sf.statcvs.Main#main} method. Interested classes
58 * can read all parameter values from here.
59 *
60 * TODO: Should be moved to more appropriate package and made non-public
61 *
62 * @author jentzsch
63 * @version $Id: ConfigurationOptions.java,v 1.40 2009/08/21 23:06:51 benoitx Exp $
64 */
65 public class ConfigurationOptions {
66
67 private static final String LOGGING_CONFIG_DEFAULT = "logging.properties";
68 private static final String LOGGING_CONFIG_VERBOSE = "logging-verbose.properties";
69 private static final String LOGGING_CONFIG_DEBUG = "logging-debug.properties";
70
71 private static String headerUrl = null;
72 private static String footerUrl = null;
73 private static String logFileName = null;
74 private static String checkedOutDirectory = null;
75 private static String projectName = null;
76 private static String outputDir = "";
77 private static String loggingProperties = LOGGING_CONFIG_DEFAULT;
78 private static String notesFile = null;
79 private static String notes = null;
80
81 private static FilePatternMatcher includePattern = null;
82 private static FilePatternMatcher excludePattern = null;
83
84 private static Collection nonDeveloperLogins = new ArrayList();
85 private static boolean enableTwitterButton = true;
86
87 private static CssHandler cssHandler = new DefaultCssHandler("objectlab-statcvs.css");
88 private static String charSet = "ISO-8859-1";
89 private static WebRepositoryIntegration webRepository = null;
90 private static Pattern symbolicNamesPattern;
91
92 private static BugTracker webBugTracker = BugTracker.NO_BUG_TRACKER;
93 private static String outputFormat = "html";
94 private static Properties properties = new Properties();
95
96 static {
97 XYBarRenderer.setDefaultBarPainter(new StandardXYBarPainter());
98 BarRenderer.setDefaultBarPainter(new StandardBarPainter());
99 }
100
101 public static String getCharSet() {
102 return charSet;
103 }
104
105 public static void setCharSet(final String cs) {
106 charSet = cs;
107 }
108
109 /**
110 * returns the {@link CssHandler}
111 * @return the CssHandler
112 */
113 public static CssHandler getCssHandler() {
114 return cssHandler;
115 }
116
117 /**
118 * Method getProjectName.
119 * @return String name of the project
120 */
121 public static String getProjectName() {
122 return projectName;
123 }
124
125 /**
126 * Method getCheckedOutDirectory.
127 * @return String name of the checked out directory
128 */
129 public static String getCheckedOutDirectory() {
130 return checkedOutDirectory;
131 }
132
133 /**
134 * Method getLogfilename.
135 * @return String name of the logfile to be parsed
136 */
137 public static String getLogFileName() {
138 return logFileName;
139 }
140
141 /**
142 * Returns the outputDir.
143 * @return String output Directory
144 */
145 public static String getOutputDir() {
146 return outputDir;
147 }
148
149 /**
150 * Returns the report notes (from "-notes filename" switch) or <tt>null</tt>
151 * if not specified
152 * @return the report notes
153 */
154 public static String getNotes() {
155 return notes;
156 }
157
158 /**
159 * Returns a {@link WebRepositoryIntegration} object if the user
160 * has specified a URL to one. <tt>null</tt> otherwise.
161 * @return the web repository
162 */
163 public static WebRepositoryIntegration getWebRepository() {
164 return webRepository;
165 }
166
167 /**
168 * Sets the checkedOutDirectory.
169 * @param checkedOutDirectory The checkedOutDirectory to set
170 * @throws ConfigurationException if directory does not exist
171 */
172 public static void setCheckedOutDirectory(final String checkedOutDirectory) throws ConfigurationException {
173 final File directory = new File(checkedOutDirectory);
174 if (!directory.exists() || !directory.isDirectory()) {
175 throw new ConfigurationException("directory does not exist: " + checkedOutDirectory);
176 }
177 ConfigurationOptions.checkedOutDirectory = checkedOutDirectory;
178 }
179
180 /**
181 * Sets the cssFile. Currently, the css file can be any local file or
182 * a HTTP URL. If it is a local file, a copy will be included in the
183 * output directory. If this method is never called, a default CSS file
184 * will be generated in the output directory.
185 *
186 * @param cssFile The cssFile to set
187 * @throws ConfigurationException if the specified CSS file can not be
188 * accessed from local file system or from URL source, or if the specified
189 * CSS file is local and does not exist
190 */
191 public static void setCssFile(final String cssFile) throws ConfigurationException {
192 try {
193 final URL url = new URL(cssFile);
194
195
196
197 cssHandler = new UrlCssHandler(url);
198 } catch (final MalformedURLException isLocalFile) {
199 cssHandler = new LocalFileCssHandler(cssFile);
200 }
201 cssHandler.checkForMissingResources();
202 }
203
204 /**
205 * Sets the logFileName.
206 * @param logFileName The logFileName to set
207 * @throws ConfigurationException if the file does not exist
208 */
209 public static void setLogFileName(final String logFileName) throws ConfigurationException {
210 final File inputFile = new File(logFileName);
211 if (!inputFile.exists()) {
212 throw new ConfigurationException("Specified logfile not found: " + logFileName);
213 }
214 ConfigurationOptions.logFileName = logFileName;
215 }
216
217 /**
218 * Sets the outputDir.
219 * @param outputDir The outputDir to set
220 * @throws ConfigurationException if the output directory cannot be created
221 */
222 public static void setOutputDir(String outputDir) throws ConfigurationException {
223 if (!outputDir.endsWith(FileUtils.getDirSeparator())) {
224 outputDir += FileUtils.getDefaultDirSeparator();
225 }
226 final File outDir = new File(outputDir);
227 if (!outDir.exists() && !outDir.mkdirs()) {
228 throw new ConfigurationException("Can't create output directory: " + outputDir);
229 }
230 ConfigurationOptions.outputDir = outputDir;
231 }
232
233 /**
234 * Sets the name of the notes file. The notes file will be included
235 * on the index page of the output. It must contain a valid
236 * block-level HTML fragment (for example
237 * <tt>"<p>Some notes</p>"</tt>)
238 * @param notesFile a local filename
239 * @throws ConfigurationException if the file is not found or can't be read
240 */
241 public static void setNotesFile(final String notesFile) throws ConfigurationException {
242 final File f = new File(notesFile);
243 if (!f.exists()) {
244 throw new ConfigurationException("Notes file not found: " + notesFile);
245 }
246 if (!f.canRead()) {
247 throw new ConfigurationException("Can't read notes file: " + notesFile);
248 }
249 ConfigurationOptions.notesFile = notesFile;
250 try {
251 notes = readNotesFile();
252 } catch (final IOException e) {
253 throw new ConfigurationException(e.getMessage());
254 }
255 }
256
257 /**
258 * Sets the URL to a <a href="http://viewcvs.sourceforge.net/">ViewCVS</a>
259 * web-based CVS browser. This must be the URL at which the checked-out
260 * module's root can be viewed in ViewCVS.
261 * @param url URL to a ViewCVS repository
262 */
263 public static void setViewCvsURL(final String url) {
264 ConfigurationOptions.webRepository = new ViewCvsIntegration(url);
265 }
266
267 /**
268 * Sets the URL to a
269 * <a href="http://www.freebsd.org/projects/cvsweb.html">cvsweb</a>
270 * web-based CVS browser. This must be the URL at which the checked-out
271 * module's root can be viewed in cvsweb.
272 * @param url URL to a cvsweb repository
273 */
274 public static void setCvswebURL(final String url) {
275 ConfigurationOptions.webRepository = new CvswebIntegration(url);
276 }
277
278 /**
279 * Sets the URL to a <a href="http://www.horde.org/chora/">Chora</a>
280 * web-based CVS browser. This must be the URL at which the checked-out
281 * module's root can be viewed in Chora.
282 * @param url URL to a cvsweb repository
283 */
284 public static void setChoraURL(final String url) {
285 ConfigurationOptions.webRepository = new ChoraIntegration(url);
286 }
287
288 /**
289 * Sets the URL to a <a href="http://www.jcvs.org/jcvsweb/">JCVSWeb</a>
290 * web-based CVS browser. This must be the URL at which the checked-out
291 * module's root can be viewed in JCVSWeb.
292 * @param url URL to a JCVSWeb repository
293 */
294 public static void setJCVSWebURL(final String url) {
295 ConfigurationOptions.webRepository = new JCVSWebIntegration(url);
296 }
297
298 /**
299 * Sets the URL to a <a href="http://www.viewvc.org/">ViewVC</a> web-based CVS/SVN browser.
300 * This must be the URL at which the checked-out module's
301 * root can be viewed in ViewVC.
302 *
303 * @param url
304 * URL to a ViewVC repository
305 */
306 public static void setViewVcURL(final String url) {
307 ConfigurationOptions.webRepository = new ViewVcIntegration(url);
308 }
309
310 /**
311 * Sets the URL to a <a href="http://trac.edgewall.org/wiki/TracBrowser">Trac</a> web-based SVN browser and issue tracking.
312 * This must be the URL at which the checked-out module's
313 * root can be viewed in Trac
314 *
315 * @param url
316 * URL to a Trac website
317 */
318 public static void setViewTracURL(final String url) {
319 ConfigurationOptions.webRepository = new TracIntegration(url);
320 }
321
322 /**
323 * Sets a project title to be used in the reports
324 * @param projectName The project title to be used in the reports
325 */
326 public static void setProjectName(final String projectName) {
327 ConfigurationOptions.projectName = projectName;
328 }
329
330 /**
331 * Gets the name of the logging properties file
332 * @return the name of the logging properties file
333 */
334 public static String getLoggingProperties() {
335 return loggingProperties;
336 }
337
338 /**
339 * Sets the logging level to verbose
340 */
341 public static void setVerboseLogging() {
342 ConfigurationOptions.loggingProperties = LOGGING_CONFIG_VERBOSE;
343 }
344
345 /**
346 * Sets the logging level to debug
347 */
348 public static void setDebugLogging() {
349 ConfigurationOptions.loggingProperties = LOGGING_CONFIG_DEBUG;
350 }
351
352 private static String readNotesFile() throws IOException {
353 BufferedReader r = null;
354 final StringBuffer result = new StringBuffer();
355 try {
356 r = new BufferedReader(new FileReader(notesFile));
357 String line = r.readLine();
358 while (line != null) {
359 result.append(line);
360 line = r.readLine();
361 }
362 } finally {
363 if (r != null) {
364 r.close();
365 }
366 }
367 return result.toString();
368 }
369
370 /**
371 * Sets a file include pattern list. Only files matching one of the
372 * patterns will be included in the analysis.
373 * @param patternList a list of Ant-style wildcard patterns, seperated
374 * by : or ;
375 * @see net.sf.statcvs.util.FilePatternMatcher
376 */
377 public static void setIncludePattern(final String patternList) {
378 includePattern = new FilePatternMatcher(patternList);
379 }
380
381 /**
382 * Sets a file exclude pattern list. Files matching any of the
383 * patterns will be excluded from the analysis.
384 * @param patternList a list of Ant-style wildcard patterns, seperated
385 * by : or ;
386 * @see net.sf.statcvs.util.FilePatternMatcher
387 */
388 public static void setExcludePattern(final String patternList) {
389 excludePattern = new FilePatternMatcher(patternList);
390 }
391
392 /**
393 * @return Returns the excludePattern.
394 */
395 public static FilePatternMatcher getExcludePattern() {
396 return excludePattern;
397 }
398
399 /**
400 * @return Returns the includePattern.
401 */
402 public static FilePatternMatcher getIncludePattern() {
403 return includePattern;
404 }
405
406 public static void setSymbolicNamesPattern(final String symbolicNamesPattern) throws ConfigurationException {
407 try {
408 ConfigurationOptions.symbolicNamesPattern = Pattern.compile(symbolicNamesPattern);
409 } catch (final PatternSyntaxException e) {
410 throw new ConfigurationException("Invalid regular expression for tags: " + e.getLocalizedMessage());
411 }
412 }
413
414 public static Pattern getSymbolicNamesPattern() {
415 return symbolicNamesPattern;
416 }
417
418 public static void setBugzillaUrl(final String bugzillaUrl) {
419 ConfigurationOptions.webBugTracker = new Bugzilla(bugzillaUrl);
420 }
421
422 public static void setMantisUrl(final String mantisUrl) {
423 ConfigurationOptions.webBugTracker = new Mantis(mantisUrl);
424 }
425
426 public static BugTracker getWebBugtracker() {
427 return ConfigurationOptions.webBugTracker;
428 }
429
430 public static void setOutputFormat(final String outputFormat) throws ConfigurationException {
431 if (!"html".equals(outputFormat) && !"xdoc".equals(outputFormat) && !"xml".equals(outputFormat)) {
432 throw new ConfigurationException("Invalid output format, use only 'html', 'xdoc' or 'xml'");
433 }
434 ConfigurationOptions.outputFormat = outputFormat;
435 }
436
437 public static String getOutputFormat() {
438 return outputFormat;
439 }
440
441 public static MarkupSyntax getMarkupSyntax() {
442 if ("xdoc".equals(outputFormat)) {
443 return ReportConfig.XDOC;
444 } else if ("xml".equals(outputFormat)) {
445 return ReportConfig.XML;
446 }
447 return ReportConfig.HTML;
448 }
449
450 public static void setWebRepositoryIntegration(final WebRepositoryIntegration webRepo) {
451 webRepository = webRepo;
452 }
453
454 /**
455 * Allow change between css that are shipped with the tool.
456 * @param cssName statcvs.css or objectlab-statcvs-xdoc.css
457 */
458 public static void setDefaultCssFile(final String cssName) {
459 cssHandler = new DefaultCssHandler(cssName);
460 }
461
462 /**
463 * Excludes a login name from charts and reports that compare
464 * several developers. Useful to reduce the noise from admin
465 * accounts.
466 * @param loginName A login name
467 */
468 public static void addNonDeveloperLogin(final String loginName) {
469 nonDeveloperLogins.add(loginName);
470 }
471
472 /**
473 * Gets login names that should be excluded from charts and
474 * reports that compare several developers.
475 */
476 public static Collection getNonDeveloperLogins() {
477 return nonDeveloperLogins;
478 }
479
480 /**
481 * Set the config file that may contain user details.
482 * @param propertiesFilename
483 */
484 public static void setConfigFile(final String propertiesFilename) throws ConfigurationException {
485 if (propertiesFilename != null) {
486 InputStream is = null;
487 try {
488 is = new FileInputStream(propertiesFilename);
489 properties.load(is);
490 } catch (final FileNotFoundException e) {
491 throw new ConfigurationException("Unable to find the configuration file " + propertiesFilename);
492 } catch (final IOException e) {
493 throw new ConfigurationException("Problem reading the configuration file " + propertiesFilename);
494 } finally {
495 if (is != null) {
496 try {
497 is.close();
498 } catch (final IOException e) {
499 throw new ConfigurationException("Problem closing stream to the configuration file " + propertiesFilename);
500 }
501 }
502 }
503 }
504 }
505
506 /**
507 * The config properties.
508 * @return
509 */
510 public static Properties getConfigProperties() {
511 return properties;
512 }
513
514 /**
515 * Return a String prop.
516 * @param propName
517 * @param defaultValue
518 * @return
519 */
520 public static String getConfigStringProperty(final String propName, final String defaultValue) {
521 if (properties != null) {
522 return properties.getProperty(propName, defaultValue);
523 }
524 return defaultValue;
525 }
526
527 /**
528 * Return a list of String prop.
529 * @param propName
530 * @param defaultValue
531 * @return List (could be empty)
532 */
533 public static List getConfigStringListProperty(final String propName, final String defaultValue) {
534 if (properties != null) {
535 return StringUtils.listify(properties.getProperty(propName, defaultValue), ",");
536 }
537 return StringUtils.listify(defaultValue, ",");
538 }
539
540 public static String getConfigStringProperty(final String propName, final String fallBackPropName, final String defaultValue) {
541 if (properties != null) {
542 final String val = properties.getProperty(propName);
543 if (val != null) {
544 return val;
545 } else {
546 return properties.getProperty(fallBackPropName, defaultValue);
547 }
548 }
549 return defaultValue;
550 }
551
552 /**
553 * Return a Integer prop.
554 * @param propName
555 * @param defaultValue
556 * @return
557 */
558 public static Integer getConfigIntegerProperty(final String propName, final Integer defaultValue) {
559 if (properties != null) {
560 final String val = properties.getProperty(propName);
561 if (val != null) {
562 try {
563 return Integer.valueOf(val);
564 } catch (final NumberFormatException e) {
565 return defaultValue;
566 }
567 }
568 }
569 return defaultValue;
570 }
571
572 /**
573 * Return a Float prop.
574 * @param propName
575 * @param defaultValue
576 * @return
577 */
578 public static Float getConfigIntegerProperty(final String propName, final Float defaultValue) {
579 if (properties != null) {
580 final String val = properties.getProperty(propName);
581 if (val != null) {
582 try {
583 return Float.valueOf(val);
584 } catch (final NumberFormatException e) {
585 return defaultValue;
586 }
587 }
588 }
589 return defaultValue;
590 }
591
592 /**
593 * Return a String prop.
594 * @param propName
595 * @param defaultValue
596 * @return
597 */
598 public static Color getConfigColorProperty(final String propName, final Color defaultValue) {
599 if (properties != null) {
600 String val = properties.getProperty(propName);
601 if (val != null) {
602 if (val.startsWith("#")) {
603 val = val.substring(1);
604 }
605 val = val.toLowerCase();
606 if (val.length() > 6) {
607 return defaultValue;
608 }
609 return new Color(Integer.parseInt(val, 16));
610 }
611 }
612 return defaultValue;
613 }
614
615 /**
616 * Return a Integer prop.
617 * @param propName
618 * @param defaultValue
619 * @return
620 */
621 public static Integer getConfigIntegerProperty(final String propName, final String fallBackPropName, final Integer defaultValue) {
622 if (properties != null) {
623 final String val = properties.getProperty(propName);
624 if (val != null) {
625 try {
626 return Integer.valueOf(val);
627 } catch (final NumberFormatException e) {
628 return defaultValue;
629 }
630 } else {
631 return getConfigIntegerProperty(fallBackPropName, defaultValue);
632 }
633 }
634 return defaultValue;
635 }
636
637 /**
638 * Return a Float prop.
639 * @param propName
640 * @param defaultValue
641 * @return
642 */
643 public static Float getConfigFloatProperty(final String propName, final String fallBackPropName, final Float defaultValue) {
644 if (properties != null) {
645 final String val = properties.getProperty(propName);
646 if (val != null) {
647 try {
648 return Float.valueOf(val);
649 } catch (final NumberFormatException e) {
650 return defaultValue;
651 }
652 } else {
653 return getConfigIntegerProperty(fallBackPropName, defaultValue);
654 }
655 }
656 return defaultValue;
657 }
658
659 /**
660 * Return a Boolean prop.
661 * @param propName
662 * @param defaultValue
663 * @return
664 */
665 public static Boolean getConfigBooleanProperty(final String propName, final String fallBackPropName, final Boolean defaultValue) {
666 if (properties != null) {
667 String val = properties.getProperty(propName);
668 if (val != null) {
669 try {
670 return Boolean.valueOf(val);
671 } catch (final NumberFormatException e) {
672 return defaultValue;
673 }
674 } else {
675 val = properties.getProperty(fallBackPropName);
676 if (val != null) {
677 return Boolean.valueOf(val);
678 }
679 }
680 }
681 return defaultValue;
682 }
683
684 /**
685 * Return a Color prop.
686 * @param propName
687 * @param defaultValue
688 * @return
689 */
690 public static Color getConfigColorProperty(final String propName, final String fallBackPropName, final Color defaultValue) {
691 if (properties != null) {
692 String val = properties.getProperty(propName);
693 if (val != null) {
694 if (val.startsWith("#")) {
695 val = val.substring(1);
696 }
697 val = val.toLowerCase();
698 if (val.length() > 6) {
699 return defaultValue;
700 }
701 return new Color(Integer.parseInt(val, 16));
702 } else {
703 return getConfigColorProperty(fallBackPropName, defaultValue);
704 }
705 }
706 return defaultValue;
707 }
708
709 /**
710 * Enable/disable the Twitter "Tweet This" Buttons.
711 * @param value
712 */
713 public static void setEnableTwitterButton(boolean value) {
714 enableTwitterButton = value;
715 }
716
717 public static boolean isEnableTwitterButton() {
718 return enableTwitterButton;
719 }
720
721 public static String getHeaderUrl() {
722 return headerUrl;
723 }
724
725 public static void setHeaderUrl(String headerUrl) {
726 ConfigurationOptions.headerUrl = headerUrl;
727 }
728
729 public static String getFooterUrl() {
730 return footerUrl;
731 }
732
733 public static void setFooterUrl(String footerUrl) {
734 ConfigurationOptions.footerUrl = footerUrl;
735 }
736 }