KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > innig > macker > Macker


1 /*______________________________________________________________________________
2  *
3  * Macker http://innig.net/macker/
4  *
5  * Copyright 2002-2003 Paul Cantrell
6  *
7  * This program is free software; you can redistribute it and/or modify it under
8  * the terms of the GNU General Public License version 2, as published by the
9  * Free Software Foundation. See the file LICENSE.html for more information.
10  *
11  * This program is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY, including the implied warranty of MERCHANTABILITY or FITNESS
13  * FOR A PARTICULAR PURPOSE. See the license for more details.
14  *
15  * You should have received a copy of the GNU General Public License along with
16  * this program; if not, write to the Free Software Foundation, Inc. / 59 Temple
17  * Place, Suite 330 / Boston, MA 02111-1307 / USA.
18  *______________________________________________________________________________
19  */

20  
21 package net.innig.macker;
22
23 import net.innig.macker.structure.*;
24 import net.innig.macker.rule.*;
25 import net.innig.macker.event.*;
26
27 import net.innig.collect.*;
28
29 import java.io.*;
30 import java.util.*;
31
32 import org.jdom.input.SAXBuilder;
33
34 /**
35     The main class for the command line interface.
36 */

37 public class Macker
38     {
39     //------------------------------------------------------------------------
40
// Static
41
//------------------------------------------------------------------------
42

43     public static void main(String JavaDoc[] args)
44         throws Exception JavaDoc
45         {
46         try
47             {
48             // Parse args
49

50             Macker macker = new Macker();
51             
52             boolean nextIsRule = false;
53             for(int arg = 0; arg < args.length; arg++)
54                 {
55                 if(args[arg].equals("-h")
56                 || args[arg].equals("-help")
57                 || args[arg].equals("--help"))
58                     {
59                     commandLineUsage();
60                     return;
61                     }
62                 else if(args[arg].equals("-V") || args[arg].equals("--version"))
63                     {
64                     Properties p = new Properties();
65                     p.load(Macker.class.getClassLoader().getResourceAsStream("net/innig/macker/version.properties"));
66                     System.out.println("Macker " + p.get("macker.version.long"));
67                     System.out.println("http://innig.net/macker/");
68                     System.out.println("Licensed under GPL v2.1; see LICENSE.html");
69                     return;
70                     }
71                 else if(args[arg].equals("-v") || args[arg].equals("--verbose"))
72                     macker.setVerbose(true);
73                 else if(args[arg].startsWith("-D") || args[arg].equals("--define"))
74                     {
75                     int initialPos = 0, equalPos;
76                     if(args[arg].length() == 2 || args[arg].equals("--define"))
77                         arg++;
78                     else
79                         initialPos = 2;
80                     
81                     equalPos = args[arg].indexOf('=');
82                     if(equalPos == -1)
83                         {
84                         System.out.println("-D argument doesn't have name=value form: " + args[arg]);
85                         commandLineUsage();
86                         return;
87                         }
88                     String JavaDoc varName = args[arg].substring(initialPos, equalPos);
89                     String JavaDoc value = args[arg].substring(equalPos + 1);
90                     macker.setVariable(varName, value);
91                     }
92                 else if(args[arg].equals("-o") || args[arg].equals("--output"))
93                     macker.setXmlReportFile(new File(args[++arg]));
94                 else if(args[arg].equals("--print-max"))
95                     macker.setPrintMaxMessages(Integer.parseInt(args[++arg]));
96                 else if(args[arg].equals("--print"))
97                     macker.setPrintThreshold(RuleSeverity.fromName(args[++arg]));
98                 else if(args[arg].equals("--anger"))
99                     macker.setAngerThreshold(RuleSeverity.fromName(args[++arg]));
100                 else if(args[arg].equals("-r") || args[arg].equals("--rulesfile"))
101                     nextIsRule = true;
102                 else if(args[arg].endsWith(".xml") || nextIsRule)
103                     {
104                     macker.addRulesFile(new File(args[arg]));
105                     nextIsRule = false;
106                     }
107                 else if(args[arg].endsWith(".class"))
108                     macker.addClass(new File(args[arg]));
109                 else
110                     {
111                     System.out.println();
112                     System.out.println("macker: Unknown file type: " + args[arg]);
113                     System.out.println("(expected .class or .xml)");
114                     commandLineUsage();
115                     return;
116                     }
117                 }
118             
119             macker.check();
120             
121             if(!macker.hasRules() || !macker.hasClasses())
122                 commandLineUsage();
123             }
124         catch(MackerIsMadException mime)
125             {
126             System.out.println(mime.getMessage());
127             System.exit(2);
128             }
129         catch(IncompleteClassInfoException icie)
130             {
131             System.out.println(icie.getMessage());
132             throw icie;
133             }
134         catch(Exception JavaDoc e)
135             {
136             e.printStackTrace(System.out);
137             commandLineUsage();
138             throw e;
139             }
140         }
141     
142     public static void commandLineUsage()
143         {
144         System.out.println("usage: macker [opts]* <rules files> <classes>");
145         System.out.println(" -r, --rulesfile <rules.xml>");
146         System.out.println(" -o, --output <report.xml>");
147         System.out.println(" -D, --define <var>=<value>");
148         System.out.println(" --print <threshold>");
149         System.out.println(" --anger <threshold>");
150         System.out.println(" --print-max <max-messages>");
151         System.out.println(" -v, --verbose");
152         System.out.println(" -V, --version");
153         }
154     
155     //------------------------------------------------------------------------
156
// Instance
157
//------------------------------------------------------------------------
158

159     public Macker()
160         {
161         cm = new ClassManager();
162         ruleSets = new ArrayList();
163         vars = new HashMap();
164         verbose = false;
165         }
166     
167     public void addClass(File classFile)
168         throws IOException, ClassParseException
169         {
170         cm.makePrimary(
171             cm.readClass(classFile));
172         }
173     
174     public void addClass(InputStream classFile)
175         throws IOException, ClassParseException
176         {
177         cm.makePrimary(
178             cm.readClass(classFile));
179         }
180
181     public void addClass(String JavaDoc className)
182         throws ClassNotFoundException JavaDoc
183         {
184         cm.makePrimary(
185             cm.getClassInfo(className));
186         }
187
188     public void addReachableClasses(Class JavaDoc initialClass, final String JavaDoc primaryPrefix)
189         throws IncompleteClassInfoException
190         { addReachableClasses(initialClass.getName(), primaryPrefix); }
191     
192     /**
193      * For determining the primary classes when you don't have a hard-coded class
194      * list, or knowledge of the file system where classes are stored. Determines
195      * the set of primary classes by walking the class reference graph out from
196      * the initial class name, and marking all classes which start with primaryPrefix.
197      */

198     public void addReachableClasses(String JavaDoc initialClassName, final String JavaDoc primaryPrefix)
199         throws IncompleteClassInfoException
200         {
201         Graphs.reachableNodes(
202             cm.getClassInfo(initialClassName),
203             new GraphWalker()
204                 {
205                 public Collection getEdgesFrom(Object JavaDoc node)
206                     {
207                     ClassInfo classInfo = (ClassInfo) node;
208                     cm.makePrimary(classInfo);
209                     return InnigCollections.select(
210                         classInfo.getReferences().keySet(),
211                         new Selector()
212                             {
213                             public boolean select(Object JavaDoc classInfo)
214                                 {
215                                 return ((ClassInfo) classInfo)
216                                     .getFullName()
217                                     .startsWith(primaryPrefix);
218                                 }
219                             });
220                     }
221                 });
222         }
223     
224     public boolean hasClasses()
225         { return !cm.getPrimaryClasses().isEmpty(); }
226         
227     
228     public void addRulesFile(File rulesFile)
229         throws IOException, RulesException
230         { ruleSets.addAll(new RuleSetBuilder().build(rulesFile)); }
231     
232     public void addRulesFile(InputStream rulesFile)
233         throws IOException, RulesException
234         { ruleSets.addAll(new RuleSetBuilder().build(rulesFile)); }
235
236     public void addRuleSet(RuleSet ruleSet)
237         throws IOException, RulesException
238         { ruleSets.add(ruleSet); }
239     
240     public void addListener(MackerEventListener listener)
241         { listeners.add(listener); }
242     
243     public boolean hasRules()
244         { return !ruleSets.isEmpty(); }
245     
246     public void setVariable(String JavaDoc name, String JavaDoc value)
247         { vars.put(name, value); }
248     
249     public void setVerbose(boolean verbose)
250         { this.verbose = verbose; }
251     
252     public void setClassLoader(ClassLoader JavaDoc classLoader)
253         { cm.setClassLoader(classLoader); }
254     
255     public void setPrintMaxMessages(int printMaxMessages)
256         { this.printMaxMessages = printMaxMessages; }
257     
258     public void setPrintThreshold(RuleSeverity printThreshold)
259         { this.printThreshold = printThreshold; }
260     
261     public void setAngerThreshold(RuleSeverity angerThreshold)
262         { this.angerThreshold = angerThreshold; }
263     
264     public void setXmlReportFile(File xmlReportFile)
265         { this.xmlReportFile = xmlReportFile; }
266
267     /**
268      * Performs rule checking with the default printing, throwing, and XML reporting listeners.
269      **/

270     public void check()
271         throws MackerIsMadException, RulesException, ListenerException
272         {
273         if(!hasRules())
274             System.out.println("WARNING: No rules files specified");
275         if(!hasClasses())
276             System.out.println("WARNING: No class files specified");
277
278         if(verbose)
279             {
280             System.out.println(cm.getPrimaryClasses().size() + " primary classes");
281             System.out.println(cm.getAllClasses().size() + " total classes");
282             System.out.println(cm.getReferences().size() + " references");
283             
284             for(Iterator i = cm.getPrimaryClasses().iterator(); i.hasNext(); )
285                 {
286                 ClassInfo classInfo = (ClassInfo) i.next();
287                 System.out.println("Classes used by " + classInfo + ":");
288                 for(Iterator usedIter = classInfo.getReferences().keySet().iterator(); usedIter.hasNext(); )
289                     System.out.println(" " + usedIter.next());
290                 System.out.println();
291                 }
292             }
293
294         PrintingListener printing;
295         if(printThreshold == null)
296             printing = null;
297         else
298             {
299             printing = new PrintingListener(System.out);
300             printing.setThreshold(printThreshold);
301             if(printMaxMessages > 0)
302                 printing.setMaxMessages(printMaxMessages);
303             addListener(printing);
304             }
305
306         ThrowingListener throwing;
307         if(angerThreshold == null)
308             throwing = null;
309         else
310             {
311             throwing = new ThrowingListener(null, angerThreshold);
312             addListener(throwing);
313             }
314
315         XmlReportingListener xmlReporting = null;
316         if(xmlReportFile != null)
317             {
318             xmlReporting = new XmlReportingListener(xmlReportFile);
319             addListener(xmlReporting);
320             }
321         
322         checkRaw();
323         
324         if(printing != null)
325             printing.printSummary();
326         if(xmlReporting != null)
327             {
328             xmlReporting.flush();
329             xmlReporting.close();
330             }
331         if(throwing != null)
332             throwing.timeToGetMad();
333         }
334     
335     /**
336      * Performs rule checking without any default listeners.
337      **/

338     public void checkRaw()
339         throws MackerIsMadException, RulesException, ListenerException
340         {
341         for(Iterator rsIter = ruleSets.iterator(); rsIter.hasNext(); )
342             {
343             RuleSet rs = (RuleSet) rsIter.next();
344             
345             if(verbose)
346                 for(Iterator patIter = rs.getAllPatterns().iterator(); patIter.hasNext(); )
347                     {
348                     final Pattern pat = (Pattern) patIter.next();
349                     final EvaluationContext ctx = new EvaluationContext(cm, rs);
350                     System.out.println("matching " + pat);
351                     for(Iterator i = cm.getPrimaryClasses().iterator(); i.hasNext(); )
352                         {
353                         ClassInfo classInfo = (ClassInfo) i.next();
354                         if(pat.matches(ctx, classInfo))
355                             System.out.println(" " + classInfo);
356                         }
357                     System.out.println();
358                     }
359                     
360             EvaluationContext context = new EvaluationContext(cm, rs);
361             context.setVariables(vars);
362             for(Iterator listenIter = listeners.iterator(); listenIter.hasNext(); )
363                 context.addListener((MackerEventListener) listenIter.next());
364             
365             rs.check(context, cm);
366             }
367         }
368
369     private ClassManager cm;
370     private Collection/*<RuleSet>*/ ruleSets;
371     private Map/*<String,String>*/ vars;
372     private boolean verbose;
373     private File xmlReportFile;
374     private List/*<MackerEventListener>*/ listeners = new ArrayList();
375     private int printMaxMessages;
376     private RuleSeverity printThreshold = RuleSeverity.INFO, angerThreshold = RuleSeverity.ERROR;
377     }
378
Popular Tags