KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > java > j2seplatform > platformdefinition > DefaultClassPathProvider


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.netbeans.modules.java.j2seplatform.platformdefinition;
21
22 import java.beans.PropertyChangeListener JavaDoc;
23 import java.beans.PropertyChangeSupport JavaDoc;
24 import java.io.*;
25 import java.lang.ref.Reference JavaDoc;
26 import java.lang.ref.WeakReference JavaDoc;
27 import java.net.URL JavaDoc;
28 import java.util.ArrayList JavaDoc;
29 import java.util.List JavaDoc;
30 import java.util.Map JavaDoc;
31 import java.util.Set JavaDoc;
32 import java.util.Iterator JavaDoc;
33 import java.util.HashSet JavaDoc;
34 import java.util.StringTokenizer JavaDoc;
35 import java.util.WeakHashMap JavaDoc;
36 import java.util.Collections JavaDoc;
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 /**
55  *
56  * @author tom
57  */

58 public class DefaultClassPathProvider implements ClassPathProvider {
59     
60     /** Name of package keyword. */
61     private static final String JavaDoc PACKAGE = "package"; //NOI18N
62
/**Java file extension */
63     private static final String JavaDoc JAVA_EXT = "java"; //NOI18N
64
/**Class file extension*/
65     private static final String JavaDoc CLASS_EXT = "class"; //NOI18N
66

67     private static final int TYPE_JAVA = 1;
68
69     private static final int TYPE_CLASS = 2;
70
71     private /*WeakHash*/Map JavaDoc/*<FileObject,WeakReference<FileObject>>*/ sourceRootsCache = new WeakHashMap JavaDoc ();
72     private /*WeakHash*/Map JavaDoc/*<FileObject,WeakReference<ClassPath>>*/ sourceClasPathsCache = new WeakHashMap JavaDoc();
73     private Reference JavaDoc/*<ClassPath>*/ compiledClassPath;
74     
75     /** Creates a new instance of DefaultClassPathProvider */
76     public DefaultClassPathProvider() {
77     }
78     
79     public synchronized ClassPath findClassPath(FileObject file, String JavaDoc type) {
80         if (!file.isValid ()) {
81             return null;
82         }
83         // #47099 - PVCS: Externally deleted file causes Exception
84
if (file.isVirtual()) {
85             //Can't do more
86
return null;
87         }
88         // #49013 - do not return classpath for files which do
89
// not have EXTERNAL URL, e.g. files from DefaultFS
90
// The modified template has an external URL (file) as well as an internal (nbfs)
91
// the original check externalURL == null does not work, the classpath with nbfs root
92
// is returned. Also it's not possible to create classpath with external URLs
93
// (ClassPathSupport.createClasspath(URLMapper.getURL(root,EXTERNAL))) for these templates
94
// since the the returned classpath WILL NOT work correctly (ClassPath.getClassPath(file,SOURCE).findRoot(file)
95
// returns null).
96
try {
97             URL JavaDoc 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()) { //Workaround: Editor asks for package root
105
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 JavaDoc (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 JavaDoc ref = (Reference JavaDoc) 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 JavaDoc(cp));
129                         }
130                     }
131                     else {
132                         Reference JavaDoc ref = (Reference JavaDoc) 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 JavaDoc(sourceRoot));
140                         }
141                         if (!sourceRoot.isValid()) {
142                             this.sourceClasPathsCache.remove(sourceRoot);
143                         }
144                         else {
145                             ref = (Reference JavaDoc) 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 JavaDoc(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 JavaDoc ref = (Reference JavaDoc) 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 JavaDoc(execRoot));
173                 }
174                 if (!execRoot.isValid()) {
175                     this.sourceClasPathsCache.remove (execRoot);
176                 }
177                 else {
178                     ref = (Reference JavaDoc) 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 JavaDoc(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 JavaDoc 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 JavaDoc elements = new ArrayList JavaDoc ();
204             for (StringTokenizer JavaDoc tk = new StringTokenizer JavaDoc(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 JavaDoc name = (String JavaDoc)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     /**
223      * Find java package in side .class file.
224      *
225      * @return package or null if not found
226      */

227     private static final String JavaDoc 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             //Ignore it
239
// The file was removed after checking it for isValid
240
} catch (IOException e) {
241             ErrorManager.getDefault().notify(e);
242         }
243         return null;
244     }
245
246     /**
247      * Find java package in side .java file.
248      *
249      * @return package or null if not found
250      */

251     private static String JavaDoc findJavaPackage(FileObject file) {
252         String JavaDoc pkg = ""; // NOI18N
253
boolean packageKnown = false;
254         
255         // Try to find the package name and then infer a directory to mount.
256
BufferedReader rd = null;
257
258         try {
259             int pckgPos; // found package position
260

261             rd = new BufferedReader(new SourceReader(file.getInputStream()));
262
263             // Check for unicode byte watermarks.
264
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")); // NOI18N
271
} else {
272                 rd.reset();
273             }
274
275             while (!packageKnown) {
276                 String JavaDoc line = rd.readLine();
277                 if (line == null) {
278                     packageKnown = true; // i.e. valid termination of search, default pkg
279
//break;
280
return pkg;
281                 }
282
283                 pckgPos = line.indexOf(PACKAGE);
284                 if (pckgPos == -1) {
285                     continue;
286                 }
287                 StringTokenizer JavaDoc tok = new StringTokenizer JavaDoc(line, " \t;"); // NOI18N
288
boolean gotPackage = false;
289                 while (tok.hasMoreTokens()) {
290                     String JavaDoc theTok = tok.nextToken ();
291                     if (gotPackage) {
292                         // Hopefully the package name, but first a sanity check...
293
StringTokenizer JavaDoc ptok = new StringTokenizer JavaDoc(theTok, "."); // NOI18N
294
boolean ok = ptok.hasMoreTokens();
295                         while (ptok.hasMoreTokens()) {
296                             String JavaDoc 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                             //break;
316
return pkg;
317                         } else {
318                             // Keep on looking for valid package statement.
319
gotPackage = false;
320                             continue;
321                         }
322                     } else if (theTok.equals (PACKAGE)) {
323                         gotPackage = true;
324                     } else if (theTok.equals ("{")) { // NOI18N
325
// Most likely we can stop if hit opening brace of class def.
326
// Usually people leave spaces around it.
327
packageKnown = true; // valid end of search, default pkg
328
// break;
329
return pkg;
330                     }
331                 }
332             }
333         } catch (FileNotFoundException fnf) {
334             //Ignore it
335
//The file was probably removed after it was checked for isValid
336
}
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     /**
353      * Filtered reader for Java sources - it simply excludes
354      * comments and some useless whitespaces from the original stream.
355      */

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[] = {'.'}; // dot is enough here...
362
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 JavaDoc encoding) throws UnsupportedEncodingException {
369             super(in, encoding);
370         }
371
372         /** Reads chars from input reader and filters them. */
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) { // end of stream reached
385
return (numRead > 0) ? numRead : -1;
386                     }
387                     c = onechar[0];
388                 }
389                 
390                 if (c == '/' && !inString) { // a comment could start here
391
preRead = super.read(onechar, 0, 1);
392                     if (preRead == 1) {
393                         preRead = onechar[0];
394                     }
395                     if (preRead != '*' && preRead != '/') { // it's not a comment
396
data[pos++] = (char) c;
397                         numRead++;
398                         if (preRead == -1) { // end of stream reached
399
return numRead;
400                         }
401                     } else { // we have run into the comment - skip it
402
if (preRead == '*') { // comment started with /*
403
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 { // comment started with //
417
preRead = -1;
418                             c = moveToChar('\n');
419                             if (c == 0) {
420                                 preRead = '\n';
421                             }
422                         }
423                         if (c == -1) { // end of stream reached
424
return -1;
425                         }
426                     }
427                 } else { // normal valid character
428
if (!inString) { // not inside a string " ... "
429
if (isWhitespace(c)) { // reduce some whitespaces
430
while (true) {
431                                 preRead = super.read(onechar, 0, 1);
432                                 if (preRead == -1) { // end of stream reached
433
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 { // we are just in a string
458
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     } // End of class SourceReader.
518

519     private static class CompileClassPathImpl implements ClassPathImplementation, GlobalPathRegistryListener {
520         
521         private List JavaDoc cachedCompiledClassPath;
522         private PropertyChangeSupport JavaDoc support;
523         
524         public CompileClassPathImpl () {
525             this.support = new PropertyChangeSupport JavaDoc (this);
526         }
527         
528         public synchronized List JavaDoc getResources () {
529             if (this.cachedCompiledClassPath == null) {
530                 GlobalPathRegistry regs = GlobalPathRegistry.getDefault();
531                 regs.addGlobalPathRegistryListener(this);
532                 Set JavaDoc roots = new HashSet JavaDoc ();
533                 //Add compile classpath
534
Set JavaDoc paths = regs.getPaths (ClassPath.COMPILE);
535                 for (Iterator JavaDoc it = paths.iterator(); it.hasNext();) {
536                     ClassPath cp = (ClassPath) it.next();
537                     for (Iterator JavaDoc eit = cp.entries().iterator(); eit.hasNext();) {
538                         ClassPath.Entry entry = (ClassPath.Entry) eit.next();
539                         roots.add (entry.getURL());
540                     }
541                 }
542                 //Add entries from Exec CP which has sources on Sources CP and are not on the Compile CP
543
Set JavaDoc sources = regs.getPaths(ClassPath.SOURCE);
544                 Set JavaDoc sroots = new HashSet JavaDoc ();
545                 for (Iterator JavaDoc it = sources.iterator(); it.hasNext();) {
546                     ClassPath cp = (ClassPath) it.next();
547                     for (Iterator JavaDoc eit = cp.entries().iterator(); eit.hasNext();) {
548                         ClassPath.Entry entry = (ClassPath.Entry) eit.next();
549                         sroots.add (entry.getURL());
550                     }
551                 }
552                 Set JavaDoc exec = regs.getPaths(ClassPath.EXECUTE);
553                 for (Iterator JavaDoc it = exec.iterator(); it.hasNext();) {
554                     ClassPath cp = (ClassPath) it.next ();
555                     for (Iterator JavaDoc 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 JavaDoc l = new ArrayList JavaDoc ();
570                 for (Iterator JavaDoc it = roots.iterator(); it.hasNext();) {
571                     l.add (ClassPathSupport.createResource((URL JavaDoc)it.next()));
572                 }
573                 this.cachedCompiledClassPath = Collections.unmodifiableList(l);
574             }
575             return this.cachedCompiledClassPath;
576         }
577         
578         public void addPropertyChangeListener (PropertyChangeListener JavaDoc l) {
579             this.support.addPropertyChangeListener (l);
580         }
581         
582         public void removePropertyChangeListener (PropertyChangeListener JavaDoc 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