001: package com.jeantessier.dependencyfinder.cli;
002:
003: import java.io.*;
004: import java.util.*;
005:
006: import com.jeantessier.commandline.*;
007: import com.jeantessier.commandline.Printer;
008: import com.jeantessier.commandline.TextPrinter;
009: import com.jeantessier.dependencyfinder.*;
010: import com.jeantessier.dependency.*;
011: import org.apache.log4j.*;
012:
013: public abstract class Command {
014: public static final String DEFAULT_LOGFILE = "System.out";
015: public static final String DEFAULT_INCLUDES = "//";
016:
017: private String name;
018: private CommandLine commandLine;
019: private CommandLineUsage commandLineUsage;
020:
021: private Date startTime;
022: private VerboseListener verboseListener;
023: protected PrintWriter out;
024:
025: public Command(String name) throws CommandLineException {
026: this .name = name;
027: }
028:
029: public String getName() {
030: return name;
031: }
032:
033: private void resetCommandLine() {
034: commandLine = new CommandLine(getParameterStrategy());
035: populateCommandLineSwitches();
036: }
037:
038: protected ParameterStrategy getParameterStrategy() {
039: return new CollectingParameterStrategy();
040: }
041:
042: protected CommandLine getCommandLine() {
043: if (commandLine == null) {
044: resetCommandLine();
045: }
046:
047: return commandLine;
048: }
049:
050: public CommandLineUsage getCommandLineUsage() {
051: if (commandLineUsage == null) {
052: commandLineUsage = new CommandLineUsage(getName());
053: getCommandLine().accept(commandLineUsage);
054: }
055:
056: return commandLineUsage;
057: }
058:
059: protected VerboseListener getVerboseListener() {
060: return verboseListener;
061: }
062:
063: public void run(String[] args) throws Exception {
064: if (validateCommandLine(args, System.err)) {
065: process();
066: } else {
067: System.exit(1);
068: }
069: }
070:
071: protected void populateCommandLineSwitches() {
072: getCommandLine().addToggleSwitch("echo");
073: getCommandLine().addToggleSwitch("help");
074: getCommandLine().addSingleValueSwitch("out");
075: getCommandLine().addToggleSwitch("time");
076: getCommandLine().addOptionalValueSwitch("verbose",
077: DEFAULT_LOGFILE);
078: getCommandLine().addToggleSwitch("version");
079: }
080:
081: protected void populateCommandLineSwitchesForXMLOutput(
082: String defaultEncoding, String defaultDTDPrefix) {
083: getCommandLine().addSingleValueSwitch("encoding",
084: defaultEncoding);
085: getCommandLine().addSingleValueSwitch("dtd-prefix",
086: defaultDTDPrefix);
087: getCommandLine().addSingleValueSwitch("indent-text");
088: }
089:
090: protected Collection<CommandLineException> parseCommandLine(
091: String[] args) {
092: resetCommandLine();
093: return getCommandLine().parse(args);
094: }
095:
096: protected boolean validateCommandLine(String[] args, PrintStream out) {
097: boolean result = true;
098:
099: Collection<CommandLineException> exceptions = parseCommandLine(args);
100:
101: if (getCommandLine().getToggleSwitch("version")) {
102: showVersion(out);
103: result = false;
104: }
105:
106: if (getCommandLine().getToggleSwitch("help")) {
107: showError(out);
108: result = false;
109: }
110:
111: if (getCommandLine().getToggleSwitch("echo")) {
112: echo(out);
113: result = false;
114: }
115:
116: if (result) {
117: for (CommandLineException exception : exceptions) {
118: result = false;
119: Logger.getLogger(getClass()).error(exception);
120: }
121: }
122:
123: return result;
124: }
125:
126: protected Collection<CommandLineException> validateCommandLineForScoping() {
127: Collection<CommandLineException> exceptions = new ArrayList<CommandLineException>();
128:
129: if (hasScopeRegularExpressionSwitches()
130: && hasScopeListSwitches()) {
131: exceptions
132: .add(new CommandLineException(
133: "You can use switches for regular expressions or lists for scope, but not at the same time"));
134: }
135:
136: return exceptions;
137: }
138:
139: protected Collection<CommandLineException> validateCommandLineForFiltering() {
140: Collection<CommandLineException> exceptions = new ArrayList<CommandLineException>();
141:
142: if (hasFilterRegularExpressionSwitches()
143: && hasFilterListSwitches()) {
144: exceptions
145: .add(new CommandLineException(
146: "You can use switches for regular expressions or lists for filter, but not at the same time"));
147: }
148:
149: return exceptions;
150: }
151:
152: private void process() throws Exception {
153: startProcessing();
154: doProcessing();
155: stopProcessing();
156: }
157:
158: private void startProcessing() throws IOException {
159: startVerboseListener();
160: startTimer();
161: startOutput();
162: }
163:
164: protected abstract void doProcessing() throws Exception;
165:
166: private void stopProcessing() {
167: stopTimer();
168: stopOutput();
169: stopVerboseListener();
170: }
171:
172: private void startVerboseListener() throws IOException {
173: verboseListener = new VerboseListener();
174: if (commandLine.isPresent("verbose")) {
175: if (DEFAULT_LOGFILE.equals(commandLine
176: .getOptionalSwitch("verbose"))) {
177: verboseListener.setWriter(new OutputStreamWriter(
178: System.out));
179: } else {
180: verboseListener.setWriter(new FileWriter(commandLine
181: .getOptionalSwitch("verbose")));
182: }
183: }
184: }
185:
186: private void stopVerboseListener() {
187: verboseListener.close();
188: }
189:
190: private void startTimer() {
191: startTime = new Date();
192: }
193:
194: private void stopTimer() {
195: if (commandLine.getToggleSwitch("time")) {
196: Date end = new Date();
197: System.err
198: .println(getClass().getName()
199: + ": "
200: + ((end.getTime() - (double) startTime
201: .getTime()) / 1000) + " secs.");
202: }
203: }
204:
205: private void startOutput() throws IOException {
206: if (getCommandLine().isPresent("out")) {
207: out = new PrintWriter(new FileWriter(getCommandLine()
208: .getSingleSwitch("out")));
209: } else {
210: out = new PrintWriter(new OutputStreamWriter(System.out));
211: }
212: }
213:
214: private void stopOutput() {
215: out.close();
216: }
217:
218: protected void echo() {
219: echo(System.err);
220: }
221:
222: protected void echo(PrintStream out) {
223: Printer printer = new TextPrinter(getClass().getSimpleName());
224: getCommandLine().accept(printer);
225: out.println(printer);
226: }
227:
228: protected void showError() {
229: showError(System.err);
230: }
231:
232: protected void showError(PrintStream out) {
233: out.println(getCommandLineUsage());
234: showSpecificUsage(out);
235: }
236:
237: protected void showError(String msg) {
238: showError(System.err, msg);
239: }
240:
241: protected void showError(PrintStream out, String msg) {
242: out.println(msg);
243: showError(out);
244: }
245:
246: protected abstract void showSpecificUsage(PrintStream out);
247:
248: protected void showVersion() {
249: showVersion(System.err);
250: }
251:
252: protected void showVersion(PrintStream out) {
253: Version version = new Version();
254:
255: out.print(version.getImplementationTitle());
256: out.print(" ");
257: out.print(version.getImplementationVersion());
258: out.print(" (c) ");
259: out.print(version.getCopyrightDate());
260: out.print(" ");
261: out.print(version.getCopyrightHolder());
262: out.println();
263:
264: out.print(version.getImplementationURL());
265: out.println();
266:
267: out.print("Compiled on ");
268: out.print(version.getImplementationDate());
269: out.println();
270: }
271:
272: protected void populateCommandLineSwitchesForScoping() {
273: populateRegularExpressionCommandLineSwitches("scope", true,
274: DEFAULT_INCLUDES);
275: populateListCommandLineSwitches("scope");
276: }
277:
278: protected void populateCommandLineSwitchesForFiltering() {
279: populateRegularExpressionCommandLineSwitches("filter", true,
280: DEFAULT_INCLUDES);
281: populateListCommandLineSwitches("filter");
282: }
283:
284: protected void populateCommandLineSwitchesForStartCondition() {
285: populateRegularExpressionCommandLineSwitches("start", false,
286: DEFAULT_INCLUDES);
287: populateListCommandLineSwitches("start");
288: }
289:
290: protected void populateCommandLineSwitchesForStopCondition() {
291: populateRegularExpressionCommandLineSwitches("stop", false,
292: null);
293: populateListCommandLineSwitches("stop");
294: }
295:
296: protected void populateRegularExpressionCommandLineSwitches(
297: String name, boolean addToggles, String defaultIncludes) {
298: if (defaultIncludes != null) {
299: getCommandLine().addMultipleValuesSwitch(
300: name + "-includes", defaultIncludes);
301: } else {
302: getCommandLine()
303: .addMultipleValuesSwitch(name + "-includes");
304: }
305: getCommandLine().addMultipleValuesSwitch(name + "-excludes");
306: getCommandLine().addMultipleValuesSwitch(
307: "package-" + name + "-includes");
308: getCommandLine().addMultipleValuesSwitch(
309: "package-" + name + "-excludes");
310: getCommandLine().addMultipleValuesSwitch(
311: "class-" + name + "-includes");
312: getCommandLine().addMultipleValuesSwitch(
313: "class-" + name + "-excludes");
314: getCommandLine().addMultipleValuesSwitch(
315: "feature-" + name + "-includes");
316: getCommandLine().addMultipleValuesSwitch(
317: "feature-" + name + "-excludes");
318:
319: if (addToggles) {
320: getCommandLine().addToggleSwitch("package-" + name);
321: getCommandLine().addToggleSwitch("class-" + name);
322: getCommandLine().addToggleSwitch("feature-" + name);
323: }
324: }
325:
326: protected void populateListCommandLineSwitches(String name) {
327: getCommandLine().addMultipleValuesSwitch(
328: name + "-includes-list");
329: getCommandLine().addMultipleValuesSwitch(
330: name + "-excludes-list");
331: }
332:
333: protected SelectionCriteria getScopeCriteria() {
334: return getSelectionCriteria("scope",
335: new ComprehensiveSelectionCriteria());
336: }
337:
338: protected SelectionCriteria getFilterCriteria() {
339: return getSelectionCriteria("filter",
340: new ComprehensiveSelectionCriteria());
341: }
342:
343: protected SelectionCriteria getStartCriteria() {
344: return getSelectionCriteria("start",
345: new ComprehensiveSelectionCriteria());
346: }
347:
348: protected SelectionCriteria getStopCriteria() {
349: return getSelectionCriteria("stop", new NullSelectionCriteria());
350: }
351:
352: protected SelectionCriteria getSelectionCriteria(String name,
353: SelectionCriteria defaultSelectionCriteria) {
354: SelectionCriteria result = defaultSelectionCriteria;
355:
356: if (hasRegularExpressionSwitches(name)) {
357: RegularExpressionSelectionCriteria regularExpressionFilterCriteria = new RegularExpressionSelectionCriteria();
358:
359: if (getCommandLine().isPresent("package-" + name)
360: || getCommandLine().isPresent("class-" + name)
361: || getCommandLine().isPresent("feature-" + name)) {
362: regularExpressionFilterCriteria
363: .setMatchingPackages(getCommandLine()
364: .getToggleSwitch("package-" + name));
365: regularExpressionFilterCriteria
366: .setMatchingClasses(getCommandLine()
367: .getToggleSwitch("class-" + name));
368: regularExpressionFilterCriteria
369: .setMatchingFeatures(getCommandLine()
370: .getToggleSwitch("feature-" + name));
371: }
372:
373: if (getCommandLine().isPresent(name + "-includes")
374: || (!getCommandLine().isPresent(
375: "package-" + name + "-includes")
376: && !getCommandLine().isPresent(
377: "class-" + name + "-includes") && !getCommandLine()
378: .isPresent("feature-" + name + "-includes"))) {
379: // Only use the default if nothing else has been specified.
380: regularExpressionFilterCriteria
381: .setGlobalIncludes(getCommandLine()
382: .getMultipleSwitch(name + "-includes"));
383: }
384: regularExpressionFilterCriteria
385: .setGlobalExcludes(getCommandLine()
386: .getMultipleSwitch(name + "-excludes"));
387: regularExpressionFilterCriteria
388: .setPackageIncludes(getCommandLine()
389: .getMultipleSwitch(
390: "package-" + name + "-includes"));
391: regularExpressionFilterCriteria
392: .setPackageExcludes(getCommandLine()
393: .getMultipleSwitch(
394: "package-" + name + "-excludes"));
395: regularExpressionFilterCriteria
396: .setClassIncludes(getCommandLine()
397: .getMultipleSwitch(
398: "class-" + name + "-includes"));
399: regularExpressionFilterCriteria
400: .setClassExcludes(getCommandLine()
401: .getMultipleSwitch(
402: "class-" + name + "-excludes"));
403: regularExpressionFilterCriteria
404: .setFeatureIncludes(getCommandLine()
405: .getMultipleSwitch(
406: "feature-" + name + "-includes"));
407: regularExpressionFilterCriteria
408: .setFeatureExcludes(getCommandLine()
409: .getMultipleSwitch(
410: "feature-" + name + "-excludes"));
411:
412: result = regularExpressionFilterCriteria;
413: } else if (hasListSwitches(name)) {
414: result = createCollectionSelectionCriteria(getCommandLine()
415: .getMultipleSwitch(name + "-includes-list"),
416: getCommandLine().getMultipleSwitch(
417: name + "-excludes-list"));
418: }
419:
420: return result;
421: }
422:
423: protected boolean hasScopeRegularExpressionSwitches() {
424: return hasRegularExpressionSwitches("scope");
425: }
426:
427: protected boolean hasFilterRegularExpressionSwitches() {
428: return hasRegularExpressionSwitches("filter");
429: }
430:
431: protected boolean hasRegularExpressionSwitches(String name) {
432: Collection<String> switches = getCommandLine()
433: .getPresentSwitches();
434:
435: return switches.contains(name + "-includes")
436: || switches.contains(name + "-excludes")
437: || switches.contains("package-" + name)
438: || switches.contains("package-" + name + "-includes")
439: || switches.contains("package-" + name + "-excludes")
440: || switches.contains("class-" + name)
441: || switches.contains("class-" + name + "-includes")
442: || switches.contains("class-" + name + "-excludes")
443: || switches.contains("feature-" + name)
444: || switches.contains("feature-" + name + "-includes")
445: || switches.contains("feature-" + name + "-excludes");
446: }
447:
448: protected boolean hasScopeListSwitches() {
449: return hasListSwitches("scope");
450: }
451:
452: protected boolean hasFilterListSwitches() {
453: return hasListSwitches("filter");
454: }
455:
456: protected boolean hasListSwitches(String name) {
457: Collection<String> switches = getCommandLine()
458: .getPresentSwitches();
459:
460: return switches.contains(name + "-includes-list")
461: || switches.contains(name + "-excludes-list");
462: }
463:
464: protected CollectionSelectionCriteria createCollectionSelectionCriteria(
465: Collection<String> includes, Collection<String> excludes) {
466: return new CollectionSelectionCriteria(
467: loadCollection(includes), loadCollection(excludes));
468: }
469:
470: private Collection<String> loadCollection(
471: Collection<String> filenames) {
472: Collection<String> result = null;
473:
474: if (!filenames.isEmpty()) {
475: result = new HashSet<String>();
476:
477: for (String filename : filenames) {
478: BufferedReader reader = null;
479: try {
480: reader = new BufferedReader(
481: new FileReader(filename));
482:
483: String line;
484: while ((line = reader.readLine()) != null) {
485: result.add(line);
486: }
487: } catch (IOException ex) {
488: Logger.getLogger(getClass()).error(
489: "Couldn't read file " + filename, ex);
490: } finally {
491: try {
492: if (reader != null) {
493: reader.close();
494: }
495: } catch (IOException ex) {
496: Logger.getLogger(getClass()).error(
497: "Couldn't close file " + filename, ex);
498: }
499: }
500: }
501: }
502:
503: return result;
504: }
505: }
|