001: /*
002: * Copyright (c) 2001-2007, Jean Tessier
003: * All rights reserved.
004: *
005: * Redistribution and use in source and binary forms, with or without
006: * modification, are permitted provided that the following conditions
007: * are met:
008: *
009: * * Redistributions of source code must retain the above copyright
010: * notice, this list of conditions and the following disclaimer.
011: *
012: * * Redistributions in binary form must reproduce the above copyright
013: * notice, this list of conditions and the following disclaimer in the
014: * documentation and/or other materials provided with the distribution.
015: *
016: * * Neither the name of Jean Tessier nor the names of his contributors
017: * may be used to endorse or promote products derived from this software
018: * without specific prior written permission.
019: *
020: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
021: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
022: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
023: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
024: * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
025: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
026: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
027: * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
028: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
029: * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
030: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
031: */
032:
033: package com.jeantessier.dependencyfinder.ant;
034:
035: import java.io.*;
036: import java.util.*;
037:
038: import javax.xml.parsers.*;
039:
040: import org.apache.log4j.*;
041: import org.apache.tools.ant.*;
042: import org.apache.tools.ant.types.*;
043:
044: import org.xml.sax.*;
045:
046: import com.jeantessier.dependency.*;
047:
048: public class DependencyReporter extends GraphTask {
049: private String scopeIncludes = "//";
050: private String scopeExcludes = "";
051: private boolean packageScope = false;
052: private String packageScopeIncludes = "";
053: private String packageScopeExcludes = "";
054: private boolean classScope = false;
055: private String classScopeIncludes = "";
056: private String classScopeExcludes = "";
057: private boolean featureScope = false;
058: private String featureScopeIncludes = "";
059: private String featureScopeExcludes = "";
060: private String filterIncludes = "//";
061: private String filterExcludes = "";
062: private boolean packageFilter = false;
063: private String packageFilterIncludes = "";
064: private String packageFilterExcludes = "";
065: private boolean classFilter = false;
066: private String classFilterIncludes = "";
067: private String classFilterExcludes = "";
068: private boolean featureFilter = false;
069: private String featureFilterIncludes = "";
070: private String featureFilterExcludes = "";
071:
072: private Path scopeIncludesList;
073: private Path scopeExcludesList;
074: private Path filterIncludesList;
075: private Path filterExcludesList;
076:
077: private boolean showInbounds = false;
078: private boolean showOutbounds = false;
079: private boolean showEmptyNodes = false;
080:
081: private boolean minimize = false;
082: private boolean maximize = false;
083: private boolean copyOnly = false;
084: private boolean xml = false;
085: private String encoding = XMLPrinter.DEFAULT_ENCODING;
086: private String dtdPrefix = XMLPrinter.DEFAULT_DTD_PREFIX;
087: private String indentText;
088:
089: public String getScopeincludes() {
090: return scopeIncludes;
091: }
092:
093: public void setScopeincludes(String scopeIncludes) {
094: this .scopeIncludes = scopeIncludes;
095: }
096:
097: public String getScopeexcludes() {
098: return scopeExcludes;
099: }
100:
101: public void setScopeexcludes(String scopeExcludes) {
102: this .scopeExcludes = scopeExcludes;
103: }
104:
105: public boolean getPackagescope() {
106: return packageScope;
107: }
108:
109: public void setPackagescope(boolean packageScope) {
110: this .packageScope = packageScope;
111: }
112:
113: public String getPackagescopeincludes() {
114: return packageScopeIncludes;
115: }
116:
117: public void setPackagescopeincludes(String packageScopeIncludes) {
118: this .packageScopeIncludes = packageScopeIncludes;
119: }
120:
121: public String getPackagescopeexcludes() {
122: return packageScopeExcludes;
123: }
124:
125: public void setPackagescopeexcludes(String packageScopeExcludes) {
126: this .packageScopeExcludes = packageScopeExcludes;
127: }
128:
129: public boolean getClassscope() {
130: return classScope;
131: }
132:
133: public void setClassscope(boolean classScope) {
134: this .classScope = classScope;
135: }
136:
137: public String getClassscopeincludes() {
138: return classScopeIncludes;
139: }
140:
141: public void setClassscopeincludes(String classScopeIncludes) {
142: this .classScopeIncludes = classScopeIncludes;
143: }
144:
145: public String getClassscopeexcludes() {
146: return classScopeExcludes;
147: }
148:
149: public void setClassscopeexcludes(String classScopeExcludes) {
150: this .classScopeExcludes = classScopeExcludes;
151: }
152:
153: public boolean getFeaturescope() {
154: return featureScope;
155: }
156:
157: public void setFeaturescope(boolean featureScope) {
158: this .featureScope = featureScope;
159: }
160:
161: public String getFeaturescopeincludes() {
162: return featureScopeIncludes;
163: }
164:
165: public void setFeaturescopeincludes(String featureScopeIncludes) {
166: this .featureScopeIncludes = featureScopeIncludes;
167: }
168:
169: public String getFeaturescopeexcludes() {
170: return featureScopeExcludes;
171: }
172:
173: public void setFeaturescopeexcludes(String featureScopeExcludes) {
174: this .featureScopeExcludes = featureScopeExcludes;
175: }
176:
177: public String getFilterincludes() {
178: return filterIncludes;
179: }
180:
181: public void setFilterincludes(String filterIncludes) {
182: this .filterIncludes = filterIncludes;
183: }
184:
185: public String getFilterexcludes() {
186: return filterExcludes;
187: }
188:
189: public void setFilterexcludes(String filterExcludes) {
190: this .filterExcludes = filterExcludes;
191: }
192:
193: public boolean getPackagefilter() {
194: return packageFilter;
195: }
196:
197: public void setPackagefilter(boolean packageFilter) {
198: this .packageFilter = packageFilter;
199: }
200:
201: public String getPackagefilterincludes() {
202: return packageFilterIncludes;
203: }
204:
205: public void setPackagefilterincludes(String packageFilterIncludes) {
206: this .packageFilterIncludes = packageFilterIncludes;
207: }
208:
209: public String getPackagefilterexcludes() {
210: return packageFilterExcludes;
211: }
212:
213: public void setPackagefilterexcludes(String packageFilterExcludes) {
214: this .packageFilterExcludes = packageFilterExcludes;
215: }
216:
217: public boolean getClassfilter() {
218: return classFilter;
219: }
220:
221: public void setClassfilter(boolean classFilter) {
222: this .classFilter = classFilter;
223: }
224:
225: public String getClassfilterincludes() {
226: return classFilterIncludes;
227: }
228:
229: public void setClassfilterincludes(String classFilterIncludes) {
230: this .classFilterIncludes = classFilterIncludes;
231: }
232:
233: public String getClassfilterexcludes() {
234: return classFilterExcludes;
235: }
236:
237: public void setClassfilterexcludes(String classFilterExcludes) {
238: this .classFilterExcludes = classFilterExcludes;
239: }
240:
241: public boolean getFeaturefilter() {
242: return featureFilter;
243: }
244:
245: public void setFeaturefilter(boolean featureFilter) {
246: this .featureFilter = featureFilter;
247: }
248:
249: public String getFeaturefilterincludes() {
250: return featureFilterIncludes;
251: }
252:
253: public void setFeaturefilterincludes(String featureFilterIncludes) {
254: this .featureFilterIncludes = featureFilterIncludes;
255: }
256:
257: public String getFeaturefilterexcludes() {
258: return featureFilterExcludes;
259: }
260:
261: public void setFeaturefilterexcludes(String featureFilterExcludes) {
262: this .featureFilterExcludes = featureFilterExcludes;
263: }
264:
265: public void setP2p(boolean value) {
266: setPackagescope(value);
267: setPackagefilter(value);
268: }
269:
270: public void setC2p(boolean value) {
271: setClassscope(value);
272: setPackagefilter(value);
273: }
274:
275: public void setC2c(boolean value) {
276: setClassscope(value);
277: setClassfilter(value);
278: }
279:
280: public void setF2f(boolean value) {
281: setFeaturescope(value);
282: setFeaturefilter(value);
283: }
284:
285: public void setIncludes(String value) {
286: setScopeincludes(value);
287: setFilterincludes(value);
288: }
289:
290: public void setExcludes(String value) {
291: setScopeexcludes(value);
292: setFilterexcludes(value);
293: }
294:
295: public Path createScopeincludeslist() {
296: if (scopeIncludesList == null) {
297: scopeIncludesList = new Path(getProject());
298: }
299:
300: return scopeIncludesList;
301: }
302:
303: public Path getScopeincludeslist() {
304: return scopeIncludesList;
305: }
306:
307: public Path createScopeexcludeslist() {
308: if (scopeExcludesList == null) {
309: scopeExcludesList = new Path(getProject());
310: }
311:
312: return scopeExcludesList;
313: }
314:
315: public Path getScopeexcludeslist() {
316: return scopeExcludesList;
317: }
318:
319: public Path createFilterincludeslist() {
320: if (filterIncludesList == null) {
321: filterIncludesList = new Path(getProject());
322: }
323:
324: return filterIncludesList;
325: }
326:
327: public Path getFilterincludeslist() {
328: return filterIncludesList;
329: }
330:
331: public Path createFilterexcludeslist() {
332: if (filterExcludesList == null) {
333: filterExcludesList = new Path(getProject());
334: }
335:
336: return filterExcludesList;
337: }
338:
339: public Path getFilterexcludeslist() {
340: return filterExcludesList;
341: }
342:
343: public boolean getShowinbounds() {
344: return showInbounds;
345: }
346:
347: public void setShowinbounds(boolean showInbounds) {
348: this .showInbounds = showInbounds;
349: }
350:
351: public boolean getShowoutbounds() {
352: return showOutbounds;
353: }
354:
355: public void setShowoutbounds(boolean showOutbounds) {
356: this .showOutbounds = showOutbounds;
357: }
358:
359: public boolean getShowemptynodes() {
360: return showEmptyNodes;
361: }
362:
363: public void setShowemptynodes(boolean showEmptyNodes) {
364: this .showEmptyNodes = showEmptyNodes;
365: }
366:
367: public void setShowAll(boolean showAll) {
368: setShowinbounds(showAll);
369: setShowoutbounds(showAll);
370: setShowemptynodes(showAll);
371: }
372:
373: public boolean getMinimize() {
374: return minimize;
375: }
376:
377: public void setMinimize(boolean minimize) {
378: this .minimize = minimize;
379: }
380:
381: public boolean getMaximize() {
382: return maximize;
383: }
384:
385: public void setMaximize(boolean maximize) {
386: this .maximize = maximize;
387: }
388:
389: public boolean getCopyOnly() {
390: return copyOnly;
391: }
392:
393: public void setCopyOnly(boolean copyOnly) {
394: this .copyOnly = copyOnly;
395: }
396:
397: public boolean getXml() {
398: return xml;
399: }
400:
401: public void setXml(boolean xml) {
402: this .xml = xml;
403: }
404:
405: public String getEncoding() {
406: return encoding;
407: }
408:
409: public void setEncoding(String encoding) {
410: this .encoding = encoding;
411: }
412:
413: public String getDtdprefix() {
414: return dtdPrefix;
415: }
416:
417: public void setDtdprefix(String dtdPrefix) {
418: this .dtdPrefix = dtdPrefix;
419: }
420:
421: public String getIndenttext() {
422: return indentText;
423: }
424:
425: public void setIntenttext(String indentText) {
426: this .indentText = indentText;
427: }
428:
429: protected void validateParameters() throws BuildException {
430: super .validateParameters();
431:
432: if (hasScopeRegularExpressionSwitches()
433: && hasScopeListSwitches()) {
434: throw new BuildException(
435: "Cannot have scope attributes for regular expressions and lists at the same time!");
436: }
437:
438: if (hasFilterRegularExpressionSwitches()
439: && hasFilterListSwitches()) {
440: throw new BuildException(
441: "Cannot have filter attributes for regular expressions and lists at the same time!");
442: }
443: }
444:
445: public void execute() throws BuildException {
446: // first off, make sure that we've got what we need
447: validateParameters();
448:
449: VerboseListener verboseListener = new VerboseListener(this );
450:
451: try {
452: GraphCopier copier;
453: if (getCopyOnly() || getMaximize()) {
454: copier = new GraphCopier(getStrategy());
455: } else {
456: copier = new GraphSummarizer(getScopeCriteria(),
457: getFilterCriteria());
458: }
459:
460: for (String filename : getSrc().list()) {
461: log("Reading graph from " + filename);
462:
463: Collection<PackageNode> packages = Collections
464: .emptyList();
465:
466: if (filename.endsWith(".xml")) {
467: NodeLoader loader = new NodeLoader(getValidate());
468: loader.addDependencyListener(verboseListener);
469: packages = loader.load(filename).getPackages()
470: .values();
471: }
472:
473: if (getMaximize()) {
474: log("Maximizing ...");
475: new LinkMaximizer().traverseNodes(packages);
476: } else if (getMinimize()) {
477: log("Minimizing ...");
478: new LinkMinimizer().traverseNodes(packages);
479: }
480:
481: copier.traverseNodes(packages);
482: }
483:
484: log("Saving dependency graph to "
485: + getDestfile().getAbsolutePath());
486:
487: PrintWriter out = new PrintWriter(new FileWriter(
488: getDestfile()));
489:
490: Printer printer;
491: if (getXml()) {
492: printer = new XMLPrinter(out, getEncoding(),
493: getDtdprefix());
494: } else {
495: printer = new TextPrinter(out);
496: }
497:
498: if (getIndenttext() != null) {
499: printer.setIndentText(getIndenttext());
500: }
501:
502: if (getShowinbounds() || getShowoutbounds()
503: || getShowemptynodes()) {
504: printer.setShowInbounds(getShowinbounds());
505: printer.setShowOutbounds(getShowoutbounds());
506: printer.setShowEmptyNodes(getShowemptynodes());
507: }
508:
509: printer.traverseNodes(copier.getScopeFactory()
510: .getPackages().values());
511:
512: out.close();
513: } catch (SAXException ex) {
514: throw new BuildException(ex);
515: } catch (ParserConfigurationException ex) {
516: throw new BuildException(ex);
517: } catch (IOException ex) {
518: throw new BuildException(ex);
519: }
520: }
521:
522: protected SelectionCriteria getScopeCriteria()
523: throws BuildException {
524: SelectionCriteria result = new ComprehensiveSelectionCriteria();
525:
526: if (hasScopeRegularExpressionSwitches()) {
527: result = createRegularExpressionScopeCriteria();
528: } else if (hasScopeListSwitches()) {
529: result = createCollectionSelectionCriteria(
530: getScopeincludeslist(), getScopeexcludeslist());
531: }
532:
533: return result;
534: }
535:
536: protected SelectionCriteria getFilterCriteria()
537: throws BuildException {
538: SelectionCriteria result = new ComprehensiveSelectionCriteria();
539:
540: if (hasFilterRegularExpressionSwitches()) {
541: result = createRegularExpressionFilterCriteria();
542: } else if (hasFilterListSwitches()) {
543: result = createCollectionSelectionCriteria(
544: getFilterincludeslist(), getFilterexcludeslist());
545: }
546:
547: return result;
548: }
549:
550: protected RegularExpressionSelectionCriteria createRegularExpressionScopeCriteria()
551: throws BuildException {
552: RegularExpressionSelectionCriteria result = new RegularExpressionSelectionCriteria();
553:
554: if (getPackagescope() || getClassscope() || getFeaturescope()) {
555: result.setMatchingPackages(getPackagescope());
556: result.setMatchingClasses(getClassscope());
557: result.setMatchingFeatures(getFeaturescope());
558: }
559:
560: result.setGlobalIncludes(getScopeincludes());
561: result.setGlobalExcludes(getScopeexcludes());
562: result.setPackageIncludes(getPackagescopeincludes());
563: result.setPackageExcludes(getPackagescopeexcludes());
564: result.setClassIncludes(getClassscopeincludes());
565: result.setClassExcludes(getClassscopeexcludes());
566: result.setFeatureIncludes(getFeaturescopeincludes());
567: result.setFeatureExcludes(getFeaturescopeexcludes());
568:
569: return result;
570: }
571:
572: protected RegularExpressionSelectionCriteria createRegularExpressionFilterCriteria()
573: throws BuildException {
574: RegularExpressionSelectionCriteria result = new RegularExpressionSelectionCriteria();
575:
576: if (getPackagefilter() || getClassfilter()
577: || getFeaturefilter()) {
578: result.setMatchingPackages(getPackagefilter());
579: result.setMatchingClasses(getClassfilter());
580: result.setMatchingFeatures(getFeaturefilter());
581: }
582:
583: result.setGlobalIncludes(getFilterincludes());
584: result.setGlobalExcludes(getFilterexcludes());
585: result.setPackageIncludes(getPackagefilterincludes());
586: result.setPackageExcludes(getPackagefilterexcludes());
587: result.setClassIncludes(getClassfilterincludes());
588: result.setClassExcludes(getClassfilterexcludes());
589: result.setFeatureIncludes(getFeaturefilterincludes());
590: result.setFeatureExcludes(getFeaturefilterexcludes());
591:
592: return result;
593: }
594:
595: private boolean hasScopeRegularExpressionSwitches() {
596: return !getScopeincludes().equals("//")
597: || !getScopeexcludes().equals("") || getPackagescope()
598: || !getPackagescopeincludes().equals("")
599: || !getPackagescopeexcludes().equals("")
600: || getClassscope()
601: || !getClassscopeincludes().equals("")
602: || !getClassscopeexcludes().equals("")
603: || getFeaturescope()
604: || !getFeaturescopeincludes().equals("")
605: || !getFeaturescopeexcludes().equals("");
606: }
607:
608: private boolean hasScopeListSwitches() {
609: return getScopeincludeslist() != null
610: || getScopeexcludeslist() != null;
611: }
612:
613: private boolean hasFilterRegularExpressionSwitches() {
614: return !getFilterincludes().equals("//")
615: || !getFilterexcludes().equals("")
616: || getPackagefilter()
617: || !getPackagefilterincludes().equals("")
618: || !getPackagefilterexcludes().equals("")
619: || getClassfilter()
620: || !getClassfilterincludes().equals("")
621: || !getClassfilterexcludes().equals("")
622: || getFeaturefilter()
623: || !getFeaturefilterincludes().equals("")
624: || !getFeaturefilterexcludes().equals("");
625: }
626:
627: private boolean hasFilterListSwitches() {
628: return getFilterincludeslist() != null
629: || getFilterexcludeslist() != null;
630: }
631:
632: private CollectionSelectionCriteria createCollectionSelectionCriteria(
633: Path includes, Path excludes) {
634: return new CollectionSelectionCriteria(
635: loadCollection(includes), loadCollection(excludes));
636: }
637:
638: private TraversalStrategy getStrategy() throws BuildException {
639: return new SelectiveTraversalStrategy(getScopeCriteria(),
640: getFilterCriteria());
641: }
642:
643: private Collection<String> loadCollection(Path path) {
644: Collection<String> result = null;
645:
646: if (path != null) {
647: result = new HashSet<String>();
648:
649: for (String filename : path.list()) {
650: BufferedReader reader = null;
651: String line;
652:
653: try {
654: reader = new BufferedReader(
655: new FileReader(filename));
656: while ((line = reader.readLine()) != null) {
657: result.add(line);
658: }
659: } catch (IOException ex) {
660: Logger.getLogger(getClass()).error(
661: "Couldn't read file " + filename, ex);
662: } finally {
663: try {
664: if (reader != null) {
665: reader.close();
666: }
667: } catch (IOException ex) {
668: Logger.getLogger(getClass()).error(
669: "Couldn't close file " + filename, ex);
670: }
671: }
672: }
673: }
674:
675: return result;
676: }
677: }
|