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.tools.ant.*;
041: import org.apache.tools.ant.types.*;
042: import org.apache.log4j.*;
043: import org.xml.sax.*;
044:
045: import com.jeantessier.dependency.*;
046:
047: public class DependencyCycles extends GraphTask {
048: private String startIncludes = "//";
049: private String startExcludes = "";
050: private String packageStartIncludes = "";
051: private String packageStartExcludes = "";
052: private String classStartIncludes = "";
053: private String classStartExcludes = "";
054: private String featureStartIncludes = "";
055: private String featureStartExcludes = "";
056:
057: private Path startIncludesList;
058: private Path startExcludesList;
059:
060: private String maximumCycleLenth = "";
061:
062: private boolean xml = false;
063: private String encoding = XMLPrinter.DEFAULT_ENCODING;
064: private String dtdPrefix = XMLPrinter.DEFAULT_DTD_PREFIX;
065: private String indentText;
066:
067: public String getStartincludes() {
068: return startIncludes;
069: }
070:
071: public void setStartincludes(String startIncludes) {
072: this .startIncludes = startIncludes;
073: }
074:
075: public String getStartexcludes() {
076: return startExcludes;
077: }
078:
079: public void setStartexcludes(String startExcludes) {
080: this .startExcludes = startExcludes;
081: }
082:
083: public String getPackagestartincludes() {
084: return packageStartIncludes;
085: }
086:
087: public void setPackagestartincludes(String packageStartIncludes) {
088: this .packageStartIncludes = packageStartIncludes;
089: }
090:
091: public String getPackagestartexcludes() {
092: return packageStartExcludes;
093: }
094:
095: public void setPackagestartexcludes(String packageStartExcludes) {
096: this .packageStartExcludes = packageStartExcludes;
097: }
098:
099: public String getClassstartincludes() {
100: return classStartIncludes;
101: }
102:
103: public void setClassstartincludes(String classStartIncludes) {
104: this .classStartIncludes = classStartIncludes;
105: }
106:
107: public String getClassstartexcludes() {
108: return classStartExcludes;
109: }
110:
111: public void setClassstartexcludes(String classStartExcludes) {
112: this .classStartExcludes = classStartExcludes;
113: }
114:
115: public String getFeaturestartincludes() {
116: return featureStartIncludes;
117: }
118:
119: public void setFeaturestartincludes(String featureStartIncludes) {
120: this .featureStartIncludes = featureStartIncludes;
121: }
122:
123: public String getFeaturestartexcludes() {
124: return featureStartExcludes;
125: }
126:
127: public void setFeaturestartexcludes(String featureStartExcludes) {
128: this .featureStartExcludes = featureStartExcludes;
129: }
130:
131: public Path createStartincludeslist() {
132: if (startIncludesList == null) {
133: startIncludesList = new Path(getProject());
134: }
135:
136: return startIncludesList;
137: }
138:
139: public Path getStartincludeslist() {
140: return startIncludesList;
141: }
142:
143: public Path createStartexcludeslist() {
144: if (startExcludesList == null) {
145: startExcludesList = new Path(getProject());
146: }
147:
148: return startExcludesList;
149: }
150:
151: public Path getStartexcludeslist() {
152: return startExcludesList;
153: }
154:
155: public String getMaximumcyclelength() {
156: return maximumCycleLenth;
157: }
158:
159: public void setMaximumcyclelength(String maximumCycleLenth) {
160: this .maximumCycleLenth = maximumCycleLenth;
161: }
162:
163: public boolean getXml() {
164: return xml;
165: }
166:
167: public void setXml(boolean xml) {
168: this .xml = xml;
169: }
170:
171: public String getEncoding() {
172: return encoding;
173: }
174:
175: public void setEncoding(String encoding) {
176: this .encoding = encoding;
177: }
178:
179: public String getDtdprefix() {
180: return dtdPrefix;
181: }
182:
183: public void setDtdprefix(String dtdPrefix) {
184: this .dtdPrefix = dtdPrefix;
185: }
186:
187: public String getIndenttext() {
188: return indentText;
189: }
190:
191: public void setIntenttext(String indentText) {
192: this .indentText = indentText;
193: }
194:
195: protected void validateParameters() throws BuildException {
196: super .validateParameters();
197:
198: if (hasStartRegularExpressionSwitches()
199: && hasStartListSwitches()) {
200: throw new BuildException(
201: "Cannot have start attributes for regular expressions and lists at the same time!");
202: }
203: }
204:
205: public void execute() throws BuildException {
206: // first off, make sure that we've got what we need
207: validateParameters();
208:
209: VerboseListener verboseListener = new VerboseListener(this );
210:
211: try {
212: NodeFactory factory = new NodeFactory();
213:
214: for (String filename : getSrc().list()) {
215: log("Reading graph from " + filename);
216:
217: if (filename.endsWith(".xml")) {
218: NodeLoader loader = new NodeLoader(factory,
219: getValidate());
220: loader.addDependencyListener(verboseListener);
221: loader.load(filename);
222: }
223: }
224:
225: CycleDetector detector = new CycleDetector(
226: getStartCriteria());
227:
228: if (getMaximumcyclelength() != null) {
229: detector.setMaximumCycleLength(Integer
230: .parseInt(getMaximumcyclelength()));
231: }
232:
233: detector.traverseNodes(factory.getPackages().values());
234:
235: log("Saving dependency cycles to "
236: + getDestfile().getAbsolutePath());
237:
238: PrintWriter out = new PrintWriter(new FileWriter(
239: getDestfile()));
240:
241: CyclePrinter printer;
242: if (getXml()) {
243: printer = new XMLCyclePrinter(out, getEncoding(),
244: getDtdprefix());
245: } else {
246: printer = new TextCyclePrinter(out);
247: }
248:
249: if (getIndenttext() != null) {
250: printer.setIndentText(getIndenttext());
251: }
252:
253: printer.visitCycles(detector.getCycles());
254:
255: out.close();
256: } catch (SAXException ex) {
257: throw new BuildException(ex);
258: } catch (ParserConfigurationException ex) {
259: throw new BuildException(ex);
260: } catch (IOException ex) {
261: throw new BuildException(ex);
262: }
263: }
264:
265: protected SelectionCriteria getStartCriteria()
266: throws BuildException {
267: SelectionCriteria result = new ComprehensiveSelectionCriteria();
268:
269: if (hasStartRegularExpressionSwitches()) {
270: result = createRegularExpressionStartCriteria();
271: } else if (hasStartListSwitches()) {
272: result = createCollectionSelectionCriteria(
273: getStartincludeslist(), getStartexcludeslist());
274: }
275:
276: return result;
277: }
278:
279: protected RegularExpressionSelectionCriteria createRegularExpressionStartCriteria()
280: throws BuildException {
281: RegularExpressionSelectionCriteria result = new RegularExpressionSelectionCriteria();
282:
283: result.setGlobalIncludes(getStartincludes());
284: result.setGlobalExcludes(getStartexcludes());
285: result.setPackageIncludes(getPackagestartincludes());
286: result.setPackageExcludes(getPackagestartexcludes());
287: result.setClassIncludes(getClassstartincludes());
288: result.setClassExcludes(getClassstartexcludes());
289: result.setFeatureIncludes(getFeaturestartincludes());
290: result.setFeatureExcludes(getFeaturestartexcludes());
291:
292: return result;
293: }
294:
295: private CollectionSelectionCriteria createCollectionSelectionCriteria(
296: Path includes, Path excludes) {
297: return new CollectionSelectionCriteria(
298: loadCollection(includes), loadCollection(excludes));
299: }
300:
301: private boolean hasStartRegularExpressionSwitches() {
302: return !getStartincludes().equals("//")
303: || !getStartexcludes().equals("")
304: || !getPackagestartincludes().equals("")
305: || !getPackagestartexcludes().equals("")
306: || !getClassstartincludes().equals("")
307: || !getClassstartexcludes().equals("")
308: || !getFeaturestartincludes().equals("")
309: || !getFeaturestartexcludes().equals("");
310: }
311:
312: private boolean hasStartListSwitches() {
313: return getStartincludeslist() != null
314: || getStartexcludeslist() != null;
315: }
316:
317: private Collection<String> loadCollection(Path path) {
318: Collection<String> result = null;
319:
320: if (path != null) {
321: result = new HashSet<String>();
322:
323: for (String filename : path.list()) {
324: BufferedReader reader = null;
325: String line;
326:
327: try {
328: reader = new BufferedReader(
329: new FileReader(filename));
330: while ((line = reader.readLine()) != null) {
331: result.add(line);
332: }
333: } catch (IOException ex) {
334: Logger.getLogger(getClass()).error(
335: "Couldn't read file " + filename, ex);
336: } finally {
337: try {
338: if (reader != null) {
339: reader.close();
340: }
341: } catch (IOException ex) {
342: Logger.getLogger(getClass()).error(
343: "Couldn't close file " + filename, ex);
344: }
345: }
346: }
347: }
348:
349: return result;
350: }
351: }
|