1 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 37 public class Macker 38 { 39 43 public static void main(String [] args) 44 throws Exception 45 { 46 try 47 { 48 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 varName = args[arg].substring(initialPos, equalPos); 89 String 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 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 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 className) 182 throws ClassNotFoundException 183 { 184 cm.makePrimary( 185 cm.getClassInfo(className)); 186 } 187 188 public void addReachableClasses(Class initialClass, final String primaryPrefix) 189 throws IncompleteClassInfoException 190 { addReachableClasses(initialClass.getName(), primaryPrefix); } 191 192 198 public void addReachableClasses(String initialClassName, final String primaryPrefix) 199 throws IncompleteClassInfoException 200 { 201 Graphs.reachableNodes( 202 cm.getClassInfo(initialClassName), 203 new GraphWalker() 204 { 205 public Collection getEdgesFrom(Object 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 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 name, String value) 247 { vars.put(name, value); } 248 249 public void setVerbose(boolean verbose) 250 { this.verbose = verbose; } 251 252 public void setClassLoader(ClassLoader 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 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 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 ruleSets; 371 private Map vars; 372 private boolean verbose; 373 private File xmlReportFile; 374 private List listeners = new ArrayList(); 375 private int printMaxMessages; 376 private RuleSeverity printThreshold = RuleSeverity.INFO, angerThreshold = RuleSeverity.ERROR; 377 } 378 | Popular Tags |