1 25 package classycle; 26 27 import java.io.FileWriter ; 28 import java.io.IOException ; 29 import java.io.PrintWriter ; 30 import java.text.DateFormat ; 31 import java.text.SimpleDateFormat ; 32 import java.util.ArrayList ; 33 import java.util.Date ; 34 import java.util.HashSet ; 35 import java.util.List ; 36 import java.util.Map ; 37 38 import classycle.graph.AtomicVertex; 39 import classycle.graph.StrongComponent; 40 import classycle.graph.StrongComponentAnalyser; 41 import classycle.renderer.AtomicVertexRenderer; 42 import classycle.renderer.PlainStrongComponentRenderer; 43 import classycle.renderer.StrongComponentRenderer; 44 import classycle.renderer.TemplateBasedClassRenderer; 45 import classycle.renderer.XMLClassRenderer; 46 import classycle.renderer.XMLStrongComponentRenderer; 47 import classycle.util.StringPattern; 48 import classycle.util.Text; 49 import classycle.util.TrueStringPattern; 50 51 57 public class Analyser 58 { 59 private static final String VERSION = "1.3"; 60 private static final DateFormat DATE_FORMAT 61 = new SimpleDateFormat ("yyyy-MM-dd"); 62 private static final String CSV_TEMPLATE 63 = "{0},{1},{3},{2},{4},{5},{6},{7}\n"; 64 65 private final String [] _classFiles; 66 private final StringPattern _pattern; 67 private final StringPattern _reflectionPattern; 68 private final boolean _mergeInnerClasses; 69 private StrongComponentAnalyser _classAnalyser; 70 private StrongComponentAnalyser _packageAnalyser; 71 72 76 public Analyser(String [] classFiles) 77 { 78 this(classFiles, new TrueStringPattern(), null, false); 79 } 80 81 95 public Analyser(String [] classFiles, StringPattern pattern, 96 StringPattern reflectionPattern, boolean mergeInnerClasses) 97 { 98 _classFiles = classFiles; 99 _pattern = pattern; 100 _reflectionPattern = reflectionPattern; 101 _mergeInnerClasses = mergeInnerClasses; 102 } 103 104 109 public long createClassGraph() throws IOException 110 { 111 long time = System.currentTimeMillis(); 112 AtomicVertex[] classGraph = Parser.readClassFiles(_classFiles, _pattern, 113 _reflectionPattern, 114 _mergeInnerClasses); 115 _classAnalyser = new StrongComponentAnalyser(classGraph); 116 return System.currentTimeMillis() - time; 117 } 118 119 123 public AtomicVertex[] getClassGraph() 124 { 125 if (_classAnalyser == null) 126 { 127 try 128 { 129 createClassGraph(); 130 } catch (IOException e) 131 { 132 throw new RuntimeException (e.toString()); 133 } 134 } 135 return _classAnalyser.getGraph(); 136 } 137 138 141 public int getNumberOfExternalClasses() 142 { 143 AtomicVertex[] graph = getClassGraph(); 144 HashSet usedClasses = new HashSet (); 145 int result = 0; 146 for (int i = 0; i < graph.length; i++) 147 { 148 AtomicVertex vertex = graph[i]; 149 for (int j = 0, n = vertex.getNumberOfOutgoingArcs(); j < n; j++) 150 { 151 ClassAttributes attributes = 152 (ClassAttributes) vertex.getHeadVertex(j).getAttributes(); 153 if (attributes.getType() == ClassAttributes.UNKNOWN) 154 { 155 if (!usedClasses.contains(attributes.getName())) 156 { 157 result++; 158 usedClasses.add(attributes.getName()); 159 } 160 } 161 } 162 } 163 return result; 164 } 165 166 172 public long condenseClassGraph() 173 { 174 checkClassGraph("condenseClassGraph()"); 175 long time = System.currentTimeMillis(); 176 _classAnalyser.getCondensedGraph(); 177 return System.currentTimeMillis() - time; 178 } 179 180 186 public StrongComponent[] getCondensedClassGraph() 187 { 188 checkClassGraph("getCondenseClassGraph()"); 189 return _classAnalyser.getCondensedGraph(); 190 } 191 192 200 public long calculateClassLayerMap() 201 { 202 checkClassGraph("calculateClassLayerMap()"); 203 long time = System.currentTimeMillis(); 204 _classAnalyser.getLayerMap(); 205 return System.currentTimeMillis() - time; 206 } 207 208 215 public Map getClassLayerMap() 216 { 217 checkClassGraph("getClassLayerMap()"); 218 return _classAnalyser.getLayerMap(); 219 } 220 221 227 public long createPackageGraph() 228 { 229 checkClassGraph("createPackageGraph()"); 230 long time = System.currentTimeMillis(); 231 PackageProcessor processor = new PackageProcessor(); 232 processor.deepSearchFirst(_classAnalyser.getGraph()); 233 _packageAnalyser = new StrongComponentAnalyser(processor.getGraph()); 234 return System.currentTimeMillis() - time; 235 } 236 237 252 public void printCSV(PrintWriter writer) 253 { 254 AtomicVertex[] graph = getClassGraph(); 255 Map map = getClassLayerMap(); 256 writer.println("class name,type,inner class,size,used by," 257 + "uses internal classes,uses external classes,layer index"); 258 render(graph, null, map, new TemplateBasedClassRenderer(CSV_TEMPLATE), writer); 259 writer.close(); 260 } 261 262 267 public void printRaw(PrintWriter writer) 268 { 269 AtomicVertex[] graph = getClassGraph(); 270 for (int i = 0; i < graph.length; i++) 271 { 272 AtomicVertex vertex = graph[i]; 273 writer.println(vertex.getAttributes()); 274 for (int j = 0, n = vertex.getNumberOfOutgoingArcs(); j < n; j++) 275 { 276 writer.println(" " + vertex.getHeadVertex(j).getAttributes()); 277 } 278 } 279 writer.close(); 280 } 281 282 292 public void printComponents(PrintWriter writer, int minSize) 293 { 294 checkClassGraph("printComponents()"); 295 StrongComponent[] components = getCondensedClassGraph(); 296 StrongComponentRenderer renderer = new PlainStrongComponentRenderer(); 297 for (int i = 0; i < components.length; i++) 298 { 299 StrongComponent component = components[i]; 300 if (component.getNumberOfVertices() >= minSize) 301 { 302 writer.println(renderer.render(component)); 303 } 304 } 305 writer.close(); 306 } 307 308 private void checkClassGraph(String method) 309 { 310 if (_classAnalyser == null) 311 { 312 throw new IllegalStateException ( 313 method + " should be invoked after createClassGraph()."); 314 } 315 } 316 317 322 public AtomicVertex[] getPackageGraph() 323 { 324 if (_packageAnalyser == null) 325 { 326 createPackageGraph(); 327 } 328 return _packageAnalyser.getGraph(); 329 } 330 331 337 public long condensePackageGraph() 338 { 339 checkPackageGraph("condensePackageGraph()"); 340 long time = System.currentTimeMillis(); 341 _packageAnalyser.getCondensedGraph(); 342 return System.currentTimeMillis() - time; 343 } 344 345 352 public StrongComponent[] getCondensedPackageGraph() 353 { 354 checkPackageGraph("getCondensedPackageGraph()"); 355 return _packageAnalyser.getCondensedGraph(); 356 } 357 358 366 public long calculatePackageLayerMap() 367 { 368 checkPackageGraph("calculatePackageLayerMap()"); 369 long time = System.currentTimeMillis(); 370 _packageAnalyser.getLayerMap(); 371 return System.currentTimeMillis() - time; 372 } 373 374 381 public Map getPackageLayerMap() 382 { 383 checkPackageGraph("getPackageLayerMap()"); 384 return _packageAnalyser.getLayerMap(); 385 } 386 387 393 public void readAndAnalyse(boolean packagesOnly) throws IOException 394 { 395 System.out.println("============== Classycle V" + VERSION 396 + " =============="); 397 System.out.println("=========== by Franz-Josef Elmer ==========="); 398 System.out.print("read class files and create class graph ... "); 399 long duration = createClassGraph(); 400 System.out.println("done after " + duration + " ms: " 401 + getClassGraph().length + " classes analysed."); 402 403 if (!packagesOnly) 404 { 405 System.out.print("condense class graph ... "); 407 duration = condenseClassGraph(); 408 System.out.println("done after " + duration + " ms: " 409 + getCondensedClassGraph().length 410 + " strong components found."); 411 412 System.out.print("calculate class layer indices ... "); 414 duration = calculateClassLayerMap(); 415 System.out.println("done after " + duration + " ms."); 416 } 417 System.out.print("create package graph ... "); 418 duration = createPackageGraph(); 419 System.out.println("done after " + duration + " ms: " 420 + getPackageGraph().length + " packages."); 421 System.out.print("condense package graph ... "); 423 duration = condensePackageGraph(); 424 System.out.println("done after " + duration + " ms: " 425 + getCondensedPackageGraph().length 426 + " strong components found."); 427 System.out.print("calculate package layer indices ... "); 429 duration = calculatePackageLayerMap(); 430 System.out.println("done after " + duration + " ms."); 431 } 432 433 441 public void printXML(String title, boolean packagesOnly, PrintWriter writer) 442 { 443 checkPackageGraph("printXML()"); 444 writer.println("<?xml version='1.0' encoding='UTF-8'?>"); 445 writer.println("<?xml-stylesheet type='text/xsl' " 446 + "href='reportXMLtoHTML.xsl'?>"); 447 writer.print("<classycle title='"); 448 writer.print(Text.excapeForXML(title)); 449 writer.print("' date='"); 450 writer.print(DATE_FORMAT.format(new Date ())); 451 writer.println("'>"); 452 if (!packagesOnly) 453 { 454 StrongComponent[] components = getCondensedClassGraph(); 455 writer.println(" <cycles>"); 456 StrongComponentRenderer sRenderer 457 = new XMLStrongComponentRenderer(2); 458 for (int i = 0; i < components.length; i++) 459 { 460 writer.print(sRenderer.render(components[i])); 461 } 462 writer.println(" </cycles>"); 463 writer.println(" <classes numberOfExternalClasses=\"" 464 + getNumberOfExternalClasses() + "\">"); 465 AtomicVertex[] graph = getClassGraph(); 466 Map layerMap = getClassLayerMap(); 467 render(graph, components, layerMap, new XMLClassRenderer(), writer); 468 writer.println(" </classes>"); 469 } 470 StrongComponent[] components = getCondensedPackageGraph(); 471 writer.println(" <packageCycles>"); 472 StrongComponentRenderer sRenderer 473 = new XMLPackageStrongComponentRenderer(2); 474 for (int i = 0; i < components.length; i++) 475 { 476 writer.print(sRenderer.render(components[i])); 477 } 478 writer.println(" </packageCycles>"); 479 writer.println(" <packages>"); 480 AtomicVertex[] graph = getPackageGraph(); 481 Map layerMap = getPackageLayerMap(); 482 render(graph, components, layerMap, new XMLPackageRenderer(), writer); 483 writer.println(" </packages>"); 484 485 writer.println("</classycle>"); 486 writer.close(); 487 } 488 489 private void render(AtomicVertex[] graph, StrongComponent[] cycles, 490 Map layerMap, AtomicVertexRenderer renderer, PrintWriter writer) 491 { 492 List list = getTrueCycles(cycles); 493 for (int i = 0; i < graph.length; i++) 494 { 495 AtomicVertex vertex = graph[i]; 496 Integer layerIndex = (Integer ) layerMap.get(vertex); 497 writer.print(renderer.render(vertex, 498 getCycleFor(vertex, list), 499 layerIndex == null ? -1 : layerIndex.intValue())); 500 } 501 } 502 503 private List getTrueCycles(StrongComponent[] cycles) 504 { 505 List list = new ArrayList (); 506 if (cycles != null) 507 { 508 for (int i = 0; i < cycles.length; i++) 509 { 510 if (cycles[i].getNumberOfVertices() > 1) 511 { 512 list.add(cycles[i]); 513 } 514 } 515 } 516 return list; 517 } 518 519 private StrongComponent getCycleFor(AtomicVertex vertex, List cycles) 520 { 521 for (int i = 0, n = cycles.size(); i < n; i++) 522 { 523 StrongComponent cycle = (StrongComponent) cycles.get(i); 524 for (int j = 0, m = cycle.getNumberOfVertices(); j < m; j++) 525 { 526 if (cycle.getVertex(j) == vertex) 527 { 528 return cycle; 529 } 530 } 531 } 532 return null; 533 } 534 535 private void checkPackageGraph(String method) 536 { 537 if (_packageAnalyser == null) 538 { 539 throw new IllegalStateException ( 540 method + " should be invoked after createPackageGraph()."); 541 } 542 } 543 544 550 public static void main(String [] args) throws Exception { 551 AnalyserCommandLine commandLine = new AnalyserCommandLine(args); 552 if (!commandLine.isValid()) { 553 System.out.println("Usage: java -jar classycle.jar " 554 + commandLine.getUsage()); 555 System.exit(0); 556 } 557 558 Analyser analyser = new Analyser(commandLine.getClassFiles(), 559 commandLine.getPattern(), 560 commandLine.getReflectionPattern(), 561 commandLine.isMergeInnerClasses()); 562 analyser.readAndAnalyse(commandLine.isPackagesOnly()); 563 564 if (commandLine.getXmlFile() != null) 566 { 567 analyser.printXML(commandLine.getTitle(), commandLine.isPackagesOnly(), 568 new PrintWriter (new FileWriter (commandLine.getXmlFile()))); 569 } 570 if (commandLine.getCsvFile() != null) 571 { 572 analyser.printCSV( 573 new PrintWriter (new FileWriter (commandLine.getCsvFile()))); 574 } 575 if (commandLine.isRaw()) 576 { 577 analyser.printRaw(new PrintWriter (System.out)); 578 } 579 if (commandLine.isCycles() || commandLine.isStrong()) 580 { 581 analyser.printComponents(new PrintWriter (System.out), 582 commandLine.isCycles() ? 2 : 1); 583 } 584 } 585 } | Popular Tags |