1 19 20 package org.netbeans.modules.java.j2seplatform.platformdefinition; 21 22 import java.beans.PropertyChangeListener ; 23 import java.beans.PropertyChangeSupport ; 24 import java.io.*; 25 import java.lang.ref.Reference ; 26 import java.lang.ref.WeakReference ; 27 import java.net.URL ; 28 import java.util.ArrayList ; 29 import java.util.List ; 30 import java.util.Map ; 31 import java.util.Set ; 32 import java.util.Iterator ; 33 import java.util.HashSet ; 34 import java.util.StringTokenizer ; 35 import java.util.WeakHashMap ; 36 import java.util.Collections ; 37 import org.netbeans.api.java.classpath.ClassPath; 38 import org.netbeans.api.java.classpath.GlobalPathRegistry; 39 import org.netbeans.api.java.classpath.GlobalPathRegistryListener; 40 import org.netbeans.api.java.queries.SourceForBinaryQuery; 41 import org.netbeans.api.java.platform.JavaPlatform; 42 import org.netbeans.api.java.platform.JavaPlatformManager; 43 import org.netbeans.spi.java.classpath.ClassPathProvider; 44 import org.netbeans.spi.java.classpath.ClassPathImplementation; 45 import org.netbeans.spi.java.classpath.ClassPathFactory; 46 import org.netbeans.spi.java.classpath.support.ClassPathSupport; 47 import org.netbeans.modules.classfile.ClassFile; 48 import org.netbeans.modules.classfile.ClassName; 49 import org.openide.ErrorManager; 50 import org.openide.filesystems.FileObject; 51 import org.openide.filesystems.FileStateInvalidException; 52 import org.openide.filesystems.URLMapper; 53 54 58 public class DefaultClassPathProvider implements ClassPathProvider { 59 60 61 private static final String PACKAGE = "package"; 63 private static final String JAVA_EXT = "java"; 65 private static final String CLASS_EXT = "class"; 67 private static final int TYPE_JAVA = 1; 68 69 private static final int TYPE_CLASS = 2; 70 71 private Map sourceRootsCache = new WeakHashMap (); 72 private Map sourceClasPathsCache = new WeakHashMap (); 73 private Reference compiledClassPath; 74 75 76 public DefaultClassPathProvider() { 77 } 78 79 public synchronized ClassPath findClassPath(FileObject file, String type) { 80 if (!file.isValid ()) { 81 return null; 82 } 83 if (file.isVirtual()) { 85 return null; 87 } 88 try { 97 URL externalURL = URLMapper.findURL(file, URLMapper.EXTERNAL); 98 if ( externalURL == null || !externalURL.equals(file.getURL())) { 99 return null; 100 } 101 } catch (FileStateInvalidException fsi) { 102 return null; 103 } 104 if (JAVA_EXT.equalsIgnoreCase(file.getExt()) || file.isFolder()) { if (ClassPath.BOOT.equals (type)) { 106 JavaPlatform defaultPlatform = JavaPlatformManager.getDefault().getDefaultPlatform(); 107 if (defaultPlatform != null) { 108 return defaultPlatform.getBootstrapLibraries(); 109 } 110 } 111 else if (ClassPath.COMPILE.equals(type)) { 112 synchronized (this) { 113 ClassPath cp = null; 114 if (this.compiledClassPath == null || (cp = (ClassPath)this.compiledClassPath.get()) == null) { 115 cp = ClassPathFactory.createClassPath(new CompileClassPathImpl ()); 116 this.compiledClassPath = new WeakReference (cp); 117 } 118 return cp; 119 } 120 } 121 else if (ClassPath.SOURCE.equals(type)) { 122 synchronized (this) { 123 ClassPath cp = null; 124 if (file.isFolder()) { 125 Reference ref = (Reference ) this.sourceClasPathsCache.get (file); 126 if (ref == null || (cp = (ClassPath)ref.get()) == null ) { 127 cp = ClassPathSupport.createClassPath(new FileObject[] {file}); 128 this.sourceClasPathsCache.put (file, new WeakReference (cp)); 129 } 130 } 131 else { 132 Reference ref = (Reference ) this.sourceRootsCache.get (file); 133 FileObject sourceRoot = null; 134 if (ref == null || (sourceRoot = (FileObject)ref.get()) == null ) { 135 sourceRoot = getRootForFile (file, TYPE_JAVA); 136 if (sourceRoot == null) { 137 return null; 138 } 139 this.sourceRootsCache.put (file, new WeakReference (sourceRoot)); 140 } 141 if (!sourceRoot.isValid()) { 142 this.sourceClasPathsCache.remove(sourceRoot); 143 } 144 else { 145 ref = (Reference ) this.sourceClasPathsCache.get(sourceRoot); 146 if (ref == null || (cp = (ClassPath)ref.get()) == null ) { 147 cp = ClassPathSupport.createClassPath(new FileObject[] {sourceRoot}); 148 this.sourceClasPathsCache.put (sourceRoot, new WeakReference (cp)); 149 } 150 } 151 } 152 return cp; 153 } 154 } 155 } 156 else if (CLASS_EXT.equals(file.getExt())) { 157 if (ClassPath.BOOT.equals (type)) { 158 JavaPlatform defaultPlatform = JavaPlatformManager.getDefault().getDefaultPlatform(); 159 if (defaultPlatform != null) { 160 return defaultPlatform.getBootstrapLibraries(); 161 } 162 } 163 else if (ClassPath.EXECUTE.equals(type)) { 164 ClassPath cp = null; 165 Reference ref = (Reference ) this.sourceRootsCache.get (file); 166 FileObject execRoot = null; 167 if (ref == null || (execRoot = (FileObject)ref.get()) == null ) { 168 execRoot = getRootForFile (file, TYPE_CLASS); 169 if (execRoot == null) { 170 return null; 171 } 172 this.sourceRootsCache.put (file, new WeakReference (execRoot)); 173 } 174 if (!execRoot.isValid()) { 175 this.sourceClasPathsCache.remove (execRoot); 176 } 177 else { 178 ref = (Reference ) this.sourceClasPathsCache.get(execRoot); 179 if (ref == null || (cp = (ClassPath)ref.get()) == null ) { 180 cp = ClassPathSupport.createClassPath(new FileObject[] {execRoot}); 181 this.sourceClasPathsCache.put (execRoot, new WeakReference (cp)); 182 } 183 return cp; 184 } 185 } 186 } 187 return null; 188 } 189 190 private static FileObject getRootForFile (final FileObject fo, int type) { 191 String pkg; 192 if (type == TYPE_JAVA) { 193 pkg = findJavaPackage (fo); 194 } 195 else { 196 pkg = findClassPackage (fo); 197 } 198 FileObject packageRoot = null; 199 if (pkg == null) { 200 packageRoot = fo.getParent(); 201 } 202 else { 203 List elements = new ArrayList (); 204 for (StringTokenizer tk = new StringTokenizer (pkg,"."); tk.hasMoreTokens();) { 205 elements.add(tk.nextElement()); 206 } 207 FileObject tmp = fo; 208 for (int i=elements.size()-1; i>=0; i--) { 209 String name = (String )elements.get(i); 210 tmp = tmp.getParent(); 211 if (tmp == null || !tmp.getName().equals(name)) { 212 tmp = fo; 213 break; 214 } 215 } 216 packageRoot = tmp.getParent(); 217 } 218 return packageRoot; 219 } 220 221 222 227 private static final String findClassPackage (FileObject file) { 228 try { 229 InputStream in = file.getInputStream(); 230 try { 231 ClassFile cf = new ClassFile(in,false); 232 ClassName cn = cf.getName(); 233 return cn.getPackage(); 234 } finally { 235 in.close (); 236 } 237 } catch (FileNotFoundException fnf) { 238 } catch (IOException e) { 241 ErrorManager.getDefault().notify(e); 242 } 243 return null; 244 } 245 246 251 private static String findJavaPackage(FileObject file) { 252 String pkg = ""; boolean packageKnown = false; 254 255 BufferedReader rd = null; 257 258 try { 259 int pckgPos; 261 rd = new BufferedReader(new SourceReader(file.getInputStream())); 262 263 rd.mark(2); 265 char[] cbuf = new char[2]; 266 rd.read(cbuf, 0, 2); 267 268 if (cbuf[0] == 255 && cbuf[1] == 254) { 269 rd.close(); 270 rd = new BufferedReader(new SourceReader(file.getInputStream(), "Unicode")); } else { 272 rd.reset(); 273 } 274 275 while (!packageKnown) { 276 String line = rd.readLine(); 277 if (line == null) { 278 packageKnown = true; return pkg; 281 } 282 283 pckgPos = line.indexOf(PACKAGE); 284 if (pckgPos == -1) { 285 continue; 286 } 287 StringTokenizer tok = new StringTokenizer (line, " \t;"); boolean gotPackage = false; 289 while (tok.hasMoreTokens()) { 290 String theTok = tok.nextToken (); 291 if (gotPackage) { 292 StringTokenizer ptok = new StringTokenizer (theTok, "."); boolean ok = ptok.hasMoreTokens(); 295 while (ptok.hasMoreTokens()) { 296 String component = ptok.nextToken(); 297 if (component.length() == 0) { 298 ok = false; 299 break; 300 } 301 if (!Character.isJavaIdentifierStart(component.charAt(0))) { 302 ok = false; 303 break; 304 } 305 for (int pos = 1; pos < component.length(); pos++) { 306 if (!Character.isJavaIdentifierPart(component.charAt(pos))) { 307 ok = false; 308 break; 309 } 310 } 311 } 312 if (ok) { 313 pkg = theTok; 314 packageKnown = true; 315 return pkg; 317 } else { 318 gotPackage = false; 320 continue; 321 } 322 } else if (theTok.equals (PACKAGE)) { 323 gotPackage = true; 324 } else if (theTok.equals ("{")) { packageKnown = true; return pkg; 330 } 331 } 332 } 333 } catch (FileNotFoundException fnf) { 334 } 337 catch (IOException e1) { 338 ErrorManager.getDefault().notify(e1); 339 } finally { 340 try { 341 if (rd != null) { 342 rd.close(); 343 } 344 } catch (IOException e2) { 345 ErrorManager.getDefault().notify(e2); 346 } 347 } 348 349 return null; 350 } 351 352 356 public static class SourceReader extends InputStreamReader { 357 private int preRead = -1; 358 private boolean inString = false; 359 private boolean backslashLast = false; 360 private boolean separatorLast = false; 361 static private final char separators[] = {'.'}; static private final char whitespaces[] = {' ', '\t', '\r', '\n'}; 363 364 public SourceReader(InputStream in) { 365 super(in); 366 } 367 368 public SourceReader(InputStream in, String encoding) throws UnsupportedEncodingException { 369 super(in, encoding); 370 } 371 372 373 public int read(char[] data, int pos, int len) throws IOException { 374 int numRead = 0; 375 int c; 376 char[] onechar = new char[1]; 377 378 while (numRead < len) { 379 if (preRead != -1) { 380 c = preRead; 381 preRead = -1; 382 } else { 383 c = super.read(onechar, 0, 1); 384 if (c == -1) { return (numRead > 0) ? numRead : -1; 386 } 387 c = onechar[0]; 388 } 389 390 if (c == '/' && !inString) { preRead = super.read(onechar, 0, 1); 392 if (preRead == 1) { 393 preRead = onechar[0]; 394 } 395 if (preRead != '*' && preRead != '/') { data[pos++] = (char) c; 397 numRead++; 398 if (preRead == -1) { return numRead; 400 } 401 } else { if (preRead == '*') { preRead = -1; 404 do { 405 c = moveToChar('*'); 406 if (c == 0) { 407 c = super.read(onechar, 0, 1); 408 if (c == 1) { 409 c = onechar[0]; 410 } 411 if (c == '*') { 412 preRead = c; 413 } 414 } 415 } while (c != '/' && c != -1); 416 } else { preRead = -1; 418 c = moveToChar('\n'); 419 if (c == 0) { 420 preRead = '\n'; 421 } 422 } 423 if (c == -1) { return -1; 425 } 426 } 427 } else { if (!inString) { if (isWhitespace(c)) { while (true) { 431 preRead = super.read(onechar, 0, 1); 432 if (preRead == -1) { return (numRead > 0) ? numRead : -1; 434 } 435 preRead = onechar[0]; 436 437 if (isSeparator(preRead)) { 438 c = preRead; 439 preRead = -1; 440 break; 441 } else if (!isWhitespace(preRead)) { 442 if (separatorLast) { 443 c = preRead; 444 preRead = -1; 445 } 446 break; 447 } 448 } 449 } 450 451 if (c == '\"' || c == '\'') { 452 inString = true; 453 separatorLast = false; 454 } else { 455 separatorLast = isSeparator(c); 456 } 457 } else { if (c == '\"' || c == '\'') { 459 if (!backslashLast) { 460 inString = false; 461 } else { 462 backslashLast = false; 463 } 464 } else { 465 backslashLast = (c == '\\'); 466 } 467 } 468 469 data[pos++] = (char) c; 470 numRead++; 471 } 472 } 473 return numRead; 474 } 475 476 private int moveToChar(int c) throws IOException { 477 int cc; 478 char[] onechar = new char[1]; 479 480 if (preRead != -1) { 481 cc = preRead; 482 preRead = -1; 483 } else { 484 cc = super.read(onechar, 0, 1); 485 if (cc == 1) { 486 cc = onechar[0]; 487 } 488 } 489 490 while (cc != -1 && cc != c) { 491 cc = super.read(onechar, 0, 1); 492 if (cc == 1) { 493 cc = onechar[0]; 494 } 495 } 496 497 return (cc == -1) ? -1 : 0; 498 } 499 500 static private boolean isSeparator(int c) { 501 for (int i=0; i < separators.length; i++) { 502 if (c == separators[i]) { 503 return true; 504 } 505 } 506 return false; 507 } 508 509 static private boolean isWhitespace(int c) { 510 for (int i=0; i < whitespaces.length; i++) { 511 if (c == whitespaces[i]) { 512 return true; 513 } 514 } 515 return false; 516 } 517 } 519 private static class CompileClassPathImpl implements ClassPathImplementation, GlobalPathRegistryListener { 520 521 private List cachedCompiledClassPath; 522 private PropertyChangeSupport support; 523 524 public CompileClassPathImpl () { 525 this.support = new PropertyChangeSupport (this); 526 } 527 528 public synchronized List getResources () { 529 if (this.cachedCompiledClassPath == null) { 530 GlobalPathRegistry regs = GlobalPathRegistry.getDefault(); 531 regs.addGlobalPathRegistryListener(this); 532 Set roots = new HashSet (); 533 Set paths = regs.getPaths (ClassPath.COMPILE); 535 for (Iterator it = paths.iterator(); it.hasNext();) { 536 ClassPath cp = (ClassPath) it.next(); 537 for (Iterator eit = cp.entries().iterator(); eit.hasNext();) { 538 ClassPath.Entry entry = (ClassPath.Entry) eit.next(); 539 roots.add (entry.getURL()); 540 } 541 } 542 Set sources = regs.getPaths(ClassPath.SOURCE); 544 Set sroots = new HashSet (); 545 for (Iterator it = sources.iterator(); it.hasNext();) { 546 ClassPath cp = (ClassPath) it.next(); 547 for (Iterator eit = cp.entries().iterator(); eit.hasNext();) { 548 ClassPath.Entry entry = (ClassPath.Entry) eit.next(); 549 sroots.add (entry.getURL()); 550 } 551 } 552 Set exec = regs.getPaths(ClassPath.EXECUTE); 553 for (Iterator it = exec.iterator(); it.hasNext();) { 554 ClassPath cp = (ClassPath) it.next (); 555 for (Iterator eit = cp.entries().iterator(); eit.hasNext();) { 556 ClassPath.Entry entry = (ClassPath.Entry) eit.next (); 557 FileObject[] fos = SourceForBinaryQuery.findSourceRoots(entry.getURL()).getRoots(); 558 for (int i=0; i< fos.length; i++) { 559 try { 560 if (sroots.contains(fos[i].getURL())) { 561 roots.add (entry.getURL()); 562 } 563 } catch (FileStateInvalidException e) { 564 ErrorManager.getDefault().notify(e); 565 } 566 } 567 } 568 } 569 List l = new ArrayList (); 570 for (Iterator it = roots.iterator(); it.hasNext();) { 571 l.add (ClassPathSupport.createResource((URL )it.next())); 572 } 573 this.cachedCompiledClassPath = Collections.unmodifiableList(l); 574 } 575 return this.cachedCompiledClassPath; 576 } 577 578 public void addPropertyChangeListener (PropertyChangeListener l) { 579 this.support.addPropertyChangeListener (l); 580 } 581 582 public void removePropertyChangeListener (PropertyChangeListener l) { 583 this.support.removePropertyChangeListener (l); 584 } 585 586 public void pathsAdded(org.netbeans.api.java.classpath.GlobalPathRegistryEvent event) { 587 synchronized (this) { 588 if (ClassPath.COMPILE.equals(event.getId()) || ClassPath.SOURCE.equals(event.getId())) { 589 GlobalPathRegistry.getDefault().removeGlobalPathRegistryListener(this); 590 this.cachedCompiledClassPath = null; 591 } 592 } 593 this.support.firePropertyChange(PROP_RESOURCES,null,null); 594 } 595 596 public void pathsRemoved(org.netbeans.api.java.classpath.GlobalPathRegistryEvent event) { 597 synchronized (this) { 598 if (ClassPath.COMPILE.equals(event.getId()) || ClassPath.SOURCE.equals(event.getId())) { 599 GlobalPathRegistry.getDefault().removeGlobalPathRegistryListener(this); 600 this.cachedCompiledClassPath = null; 601 } 602 } 603 this.support.firePropertyChange(PROP_RESOURCES,null,null); 604 } 605 606 } 607 608 } 609 | Popular Tags |