1 19 20 package edu.umd.cs.findbugs.classfile.impl; 21 22 import java.io.DataInputStream ; 23 import java.io.File ; 24 import java.io.FileFilter ; 25 import java.io.IOException ; 26 import java.io.InputStream ; 27 import java.util.HashMap ; 28 import java.util.HashSet ; 29 import java.util.Iterator ; 30 import java.util.LinkedList ; 31 import java.util.List ; 32 import java.util.ListIterator ; 33 import java.util.Map ; 34 import java.util.Set ; 35 import java.util.StringTokenizer ; 36 import java.util.jar.Attributes ; 37 import java.util.jar.Manifest ; 38 39 import edu.umd.cs.findbugs.SystemProperties; 40 import edu.umd.cs.findbugs.classfile.CheckedAnalysisException; 41 import edu.umd.cs.findbugs.classfile.ClassDescriptor; 42 import edu.umd.cs.findbugs.classfile.IClassFactory; 43 import edu.umd.cs.findbugs.classfile.IClassPath; 44 import edu.umd.cs.findbugs.classfile.IClassPathBuilder; 45 import edu.umd.cs.findbugs.classfile.IClassPathBuilderProgress; 46 import edu.umd.cs.findbugs.classfile.ICodeBase; 47 import edu.umd.cs.findbugs.classfile.ICodeBaseEntry; 48 import edu.umd.cs.findbugs.classfile.ICodeBaseIterator; 49 import edu.umd.cs.findbugs.classfile.ICodeBaseLocator; 50 import edu.umd.cs.findbugs.classfile.IErrorLogger; 51 import edu.umd.cs.findbugs.classfile.IScannableCodeBase; 52 import edu.umd.cs.findbugs.classfile.InvalidClassFileFormatException; 53 import edu.umd.cs.findbugs.classfile.ResourceNotFoundException; 54 import edu.umd.cs.findbugs.classfile.analysis.ClassInfo; 55 import edu.umd.cs.findbugs.classfile.analysis.ClassNameAndSuperclassInfo; 56 import edu.umd.cs.findbugs.classfile.engine.ClassParser; 57 import edu.umd.cs.findbugs.io.IO; 58 import edu.umd.cs.findbugs.util.Archive; 59 60 65 public class ClassPathBuilder implements IClassPathBuilder { 66 private static final boolean VERBOSE = SystemProperties.getBoolean("findbugs2.builder.verbose"); 67 private static final boolean DEBUG = VERBOSE || SystemProperties.getBoolean("findbugs2.builder.debug"); 68 private static final boolean NO_PARSE_CLASS_NAMES = 69 SystemProperties.getBoolean("findbugs2.builder.noparseclassnames"); 70 71 76 static class WorkListItem { 77 private ICodeBaseLocator codeBaseLocator; 78 private boolean isAppCodeBase; 79 private int howDiscovered; 80 81 public String toString() { 82 return "WorkListItem(" + codeBaseLocator +", " + isAppCodeBase + ", " + howDiscovered +")"; 83 } 84 85 public WorkListItem(ICodeBaseLocator codeBaseLocator, boolean isApplication, int howDiscovered) { 86 this.codeBaseLocator = codeBaseLocator; 87 this.isAppCodeBase = isApplication; 88 this.howDiscovered = howDiscovered; 89 } 90 91 public ICodeBaseLocator getCodeBaseLocator() { 92 return codeBaseLocator; 93 } 94 95 public boolean isAppCodeBase() { 96 return isAppCodeBase; 97 } 98 99 102 public int getHowDiscovered() { 103 return howDiscovered; 104 } 105 } 106 107 110 static class DiscoveredCodeBase { 111 ICodeBase codeBase; 112 LinkedList <ICodeBaseEntry> resourceList; 113 114 public DiscoveredCodeBase(ICodeBase codeBase) { 115 this.codeBase= codeBase; 116 this.resourceList = new LinkedList <ICodeBaseEntry>(); 117 } 118 119 public ICodeBase getCodeBase() { 120 return codeBase; 121 } 122 123 public LinkedList <ICodeBaseEntry> getResourceList() { 124 return resourceList; 125 } 126 127 public void addCodeBaseEntry(ICodeBaseEntry entry) { 128 resourceList.add(entry); 129 } 130 131 public ICodeBaseIterator iterator() throws InterruptedException { 132 if (codeBase instanceof IScannableCodeBase) { 133 return ((IScannableCodeBase) codeBase).iterator(); 134 } else { 135 return new ICodeBaseIterator() { 136 public boolean hasNext() throws InterruptedException { return false; } 137 138 public ICodeBaseEntry next() throws InterruptedException { 139 throw new UnsupportedOperationException (); 140 } 141 }; 142 } 143 } 144 } 145 146 147 private IClassFactory classFactory; 149 private IErrorLogger errorLogger; 150 private LinkedList <WorkListItem> projectWorkList; 151 private LinkedList <DiscoveredCodeBase> discoveredCodeBaseList; 152 private Map <String , DiscoveredCodeBase> discoveredCodeBaseMap; 153 private LinkedList <ClassDescriptor> appClassList; 154 private boolean scanNestedArchives; 155 156 162 ClassPathBuilder(IClassFactory classFactory, IErrorLogger errorLogger) { 163 this.classFactory = classFactory; 164 this.errorLogger = errorLogger; 165 this.projectWorkList = new LinkedList <WorkListItem>(); 166 this.discoveredCodeBaseList = new LinkedList <DiscoveredCodeBase>(); 167 this.discoveredCodeBaseMap = new HashMap <String , DiscoveredCodeBase>(); 168 this.appClassList = new LinkedList <ClassDescriptor>(); 169 } 170 171 174 public void addCodeBase(ICodeBaseLocator locator, boolean isApplication) { 175 addToWorkList(projectWorkList, new WorkListItem(locator, isApplication, ICodeBase.SPECIFIED)); 176 } 177 178 181 public void scanNestedArchives(boolean scanNestedArchives) { 182 this.scanNestedArchives = scanNestedArchives; 183 } 184 185 188 public void build(IClassPath classPath, IClassPathBuilderProgress progress) 189 throws CheckedAnalysisException, IOException , InterruptedException { 190 processWorkList(classPath, projectWorkList, progress); 192 processWorkList(classPath, buildSystemCodebaseList(), progress); 193 194 for (DiscoveredCodeBase discoveredCodeBase : discoveredCodeBaseList) { 196 classPath.addCodeBase(discoveredCodeBase.getCodeBase()); 197 } 198 199 Set <ClassDescriptor> appClassSet = new HashSet <ClassDescriptor>(); 200 201 for (DiscoveredCodeBase discoveredCodeBase : discoveredCodeBaseList) { 204 if (!discoveredCodeBase.getCodeBase().isApplicationCodeBase()) { 205 continue; 206 } 207 208 codeBaseEntryLoop: 209 for (ICodeBaseIterator i = discoveredCodeBase.iterator(); i.hasNext(); ) { 210 ICodeBaseEntry entry = i.next(); 211 if (!ClassDescriptor.isClassResource(entry.getResourceName())) { 212 continue; 213 } 214 215 ClassDescriptor classDescriptor = entry.getClassDescriptor(); 216 if (classDescriptor == null) throw new IllegalStateException (); 217 218 if (appClassSet.contains(classDescriptor)) { 219 continue codeBaseEntryLoop; 221 } 222 appClassSet.add(classDescriptor); 223 appClassList.add(classDescriptor); 224 225 classPath.mapResourceNameToCodeBaseEntry(entry.getResourceName(), entry); 226 } 227 } 228 229 if (DEBUG) { 230 System.out.println("Classpath:"); 231 dumpCodeBaseList(classPath.appCodeBaseIterator(), "Application codebases"); 232 dumpCodeBaseList(classPath.auxCodeBaseIterator(), "Auxiliary codebases"); 233 } 234 } 235 236 private void dumpCodeBaseList(Iterator <? extends ICodeBase> i, String desc) 237 throws InterruptedException { 238 System.out.println(" " + desc + ":"); 239 while (i.hasNext()) { 240 ICodeBase codeBase = i.next(); 241 System.out.println(" " + codeBase.getCodeBaseLocator().toString()); 242 if (codeBase.containsSourceFiles()) { 243 System.out.println(" * contains source files"); 244 } 245 } 246 } 247 248 private LinkedList <WorkListItem> buildSystemCodebaseList() { 249 253 LinkedList <WorkListItem> workList = new LinkedList <WorkListItem>(); 254 255 addWorkListItemsForClasspath(workList, SystemProperties.getProperty("sun.boot.class.path")); 258 String extPath = SystemProperties.getProperty("java.ext.dirs"); 259 if (extPath != null) { 260 StringTokenizer st = new StringTokenizer (extPath, File.pathSeparator); 261 while (st.hasMoreTokens()) { 262 String extDir = st.nextToken(); 263 addWorkListItemsForExtDir(workList, extDir); 264 } 265 } 266 267 return workList; 268 } 269 270 276 private void addWorkListItemsForClasspath(LinkedList <WorkListItem> workList, String path) { 277 if (path == null) { 278 return; 279 } 280 281 StringTokenizer st = new StringTokenizer (path, File.pathSeparator); 282 while (st.hasMoreTokens()) { 283 String entry = st.nextToken(); 284 if (DEBUG) { 285 System.out.println("System classpath entry: " + entry); 286 } 287 addToWorkList(workList, new WorkListItem( 288 classFactory.createFilesystemCodeBaseLocator(entry), false, ICodeBase.IN_SYSTEM_CLASSPATH)); 289 } 290 } 291 292 298 private void addWorkListItemsForExtDir(LinkedList <WorkListItem> workList, String extDir) { 299 File dir = new File (extDir); 300 File [] fileList = dir.listFiles(new FileFilter () { 301 304 public boolean accept(File pathname) { 305 String path = pathname.getParent(); 306 return Archive.isArchiveFileName(path); 307 } 308 }); 309 if (fileList == null) { 310 return; 311 } 312 313 for (File archive : fileList) { 314 addToWorkList(workList, new WorkListItem( 315 classFactory.createFilesystemCodeBaseLocator(archive.getPath()), false, ICodeBase.IN_SYSTEM_CLASSPATH)); 316 } 317 } 318 319 332 private void processWorkList( 333 IClassPath classPath, 334 LinkedList <WorkListItem> workList, IClassPathBuilderProgress progress) 335 throws InterruptedException , IOException , ResourceNotFoundException { 336 while (!workList.isEmpty()) { 339 WorkListItem item = workList.removeFirst(); 340 if (DEBUG) { 341 System.out.println("Working: " + item.getCodeBaseLocator()); 342 } 343 344 DiscoveredCodeBase discoveredCodeBase; 345 346 discoveredCodeBase = discoveredCodeBaseMap.get(item.getCodeBaseLocator().toString()); 348 if (discoveredCodeBase != null) { 349 if (!discoveredCodeBase.getCodeBase().isApplicationCodeBase() && item.isAppCodeBase()) { 353 discoveredCodeBase.getCodeBase().setApplicationCodeBase(true); 354 } 355 356 continue; 357 } 358 359 364 try { 365 discoveredCodeBase = new DiscoveredCodeBase(item.getCodeBaseLocator().openCodeBase()); 367 discoveredCodeBase.getCodeBase().setApplicationCodeBase(item.isAppCodeBase()); 368 discoveredCodeBase.getCodeBase().setHowDiscovered(item.getHowDiscovered()); 369 370 discoveredCodeBaseMap.put(item.getCodeBaseLocator().toString(), discoveredCodeBase); 372 discoveredCodeBaseList.addLast(discoveredCodeBase); 373 374 if (discoveredCodeBase.getCodeBase() instanceof IScannableCodeBase && discoveredCodeBase.codeBase.isApplicationCodeBase()) { 378 scanCodebase(classPath, workList, discoveredCodeBase); 379 } 380 381 scanJarManifestForClassPathEntries(workList, discoveredCodeBase.getCodeBase()); 383 } catch (IOException e) { 384 if (item.isAppCodeBase()) { 385 throw e; 386 } else if (item.getHowDiscovered() == ICodeBase.SPECIFIED) { 387 errorLogger.logError("Cannot open codebase " + item.getCodeBaseLocator(), e); 388 } 389 } catch (ResourceNotFoundException e) { 390 if (item.isAppCodeBase()) { 391 throw e; 392 } else if (item.getHowDiscovered() == ICodeBase.SPECIFIED) { 393 errorLogger.logError("Cannot open codebase " + item.getCodeBaseLocator(), e); 394 } 395 } 396 397 if (item.getHowDiscovered() == ICodeBase.SPECIFIED) { 398 progress.finishArchive(); 399 } 400 } 401 } 402 403 415 private void scanCodebase(IClassPath classPath, LinkedList <WorkListItem> workList, DiscoveredCodeBase discoveredCodeBase) 416 throws InterruptedException { 417 if (DEBUG) { 418 System.out.println("Scanning " + discoveredCodeBase.getCodeBase().getCodeBaseLocator()); 419 } 420 421 IScannableCodeBase codeBase = (IScannableCodeBase) discoveredCodeBase.getCodeBase(); 422 423 ICodeBaseIterator i = codeBase.iterator(); 424 while (i.hasNext()) { 425 ICodeBaseEntry entry = i.next(); 426 if (VERBOSE) { 427 System.out.println("Entry: " + entry.getResourceName()); 428 } 429 430 if (!NO_PARSE_CLASS_NAMES 431 && codeBase.isApplicationCodeBase() 432 && ClassDescriptor.isClassResource(entry.getResourceName())) { 433 parseClassName(entry); 434 } 435 436 discoveredCodeBase.addCodeBaseEntry(entry); 438 439 if (scanNestedArchives && codeBase.isApplicationCodeBase() && Archive.isArchiveFileName(entry.getResourceName())) { 441 if (VERBOSE) { 442 System.out.println("Entry is an archive!"); 443 } 444 ICodeBaseLocator nestedArchiveLocator = 445 classFactory.createNestedArchiveCodeBaseLocator(codeBase, entry.getResourceName()); 446 addToWorkList( 447 workList, 448 new WorkListItem(nestedArchiveLocator, codeBase.isApplicationCodeBase(), ICodeBase.NESTED)); 449 } 450 } 451 } 452 453 460 private void parseClassName(ICodeBaseEntry entry) { 461 DataInputStream in = null; 462 try { 463 in = new DataInputStream (entry.openResource()); 464 ClassParser parser = new ClassParser(in, null, entry); 465 466 ClassNameAndSuperclassInfo classInfo = new ClassNameAndSuperclassInfo(); 467 parser.parse(classInfo); 468 entry.overrideResourceName(classInfo.getClassDescriptor().toResourceName()); 469 } catch (IOException e) { 470 errorLogger.logError("Invalid class resource " + entry.getResourceName() + 471 " in " + entry, e); 472 } catch (InvalidClassFileFormatException e) { 473 errorLogger.logError("Invalid class resource " + entry.getResourceName() + 474 " in " + entry, e); 475 } finally { 476 IO.close(in); 477 } 478 } 479 480 487 private void scanJarManifestForClassPathEntries(LinkedList <WorkListItem> workList, ICodeBase codeBase) 488 throws IOException { 489 try { 490 ICodeBaseEntry manifestEntry = codeBase.lookupResource("META-INF/MANIFEST.MF"); 492 493 InputStream in = null; 495 try { 496 in = manifestEntry.openResource(); 497 Manifest manifest = new Manifest (in); 498 499 Attributes mainAttrs = manifest.getMainAttributes(); 500 String classPath = mainAttrs.getValue("Class-Path"); 501 if (classPath != null) { 502 String [] pathList = classPath.split("\\s+"); 503 504 for (String path : pathList) { 505 ICodeBaseLocator relativeCodeBaseLocator = 509 codeBase.getCodeBaseLocator().createRelativeCodeBaseLocator(path); 510 511 addToWorkList(workList, new WorkListItem(relativeCodeBaseLocator, false, ICodeBase.IN_JAR_MANIFEST)); 514 } 515 } 516 } finally { 517 if (in != null) { 518 IO.close(in); 519 } 520 } 521 } catch (ResourceNotFoundException e) { 522 } 524 525 } 526 527 536 private void addToWorkList(LinkedList <WorkListItem> workList, WorkListItem itemToAdd) { 537 if (DEBUG) { 538 new RuntimeException ("Adding work list item " + itemToAdd).printStackTrace(System.out); 539 } 540 if (!itemToAdd.isAppCodeBase()) { 541 workList.addLast(itemToAdd); 543 return; 544 } 545 546 ListIterator <WorkListItem> i = workList.listIterator(); 550 while (i.hasNext()) { 551 WorkListItem listItem = i.next(); 552 if (!listItem.isAppCodeBase()) { 553 i.previous(); 554 break; 555 } 556 } 557 558 i.add(itemToAdd); 560 } 561 562 565 public List <ClassDescriptor> getAppClassList() { 566 return appClassList; 567 } 568 } 569 | Popular Tags |