001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041: package org.netbeans.napi.gsfret.source;
042:
043: import java.beans.PropertyChangeEvent;
044: import java.beans.PropertyChangeListener;
045: import java.io.File;
046: import java.net.URL;
047: import java.util.ArrayList;
048: import java.util.List;
049: import javax.swing.event.ChangeEvent;
050: import javax.swing.event.ChangeListener;
051: import javax.swing.event.EventListenerList;
052: import org.netbeans.modules.gsfpath.api.classpath.ClassPath;
053: import org.netbeans.modules.gsfpath.api.platform.JavaPlatformManager;
054: import org.netbeans.modules.gsf.Language;
055: import org.netbeans.modules.gsf.LanguageRegistry;
056: import org.netbeans.modules.gsfret.source.CacheClassPath;
057: import org.netbeans.modules.gsfret.source.usages.ClasspathInfoAccessor;
058: import org.netbeans.modules.gsfpath.spi.classpath.support.ClassPathSupport;
059: import org.openide.ErrorManager;
060: import org.openide.filesystems.FileObject;
061: import org.openide.filesystems.FileUtil;
062: import org.openide.util.WeakListeners;
063:
064: /**
065: * This file is originally from Retouche, the Java Support
066: * infrastructure in NetBeans. I have modified the file as little
067: * as possible to make merging Retouche fixes back as simple as
068: * possible.
069: *
070: * Class which contains info about classpath
071: *
072: * @author Tomas Zezula, Petr Hrebejk
073: */
074: public final class ClasspathInfo {
075:
076: private static final ClassPath EMPTY_PATH = ClassPathSupport
077: .createClassPath(new URL[0]);
078:
079: static {
080: ClasspathInfoAccessor.INSTANCE = new ClasspathInfoAccessorImpl();
081: try {
082: Class.forName(ClassIndex.class.getName(), true,
083: CompilationInfo.class.getClassLoader());
084: } catch (ClassNotFoundException ex) {
085: ErrorManager.getDefault().notify(ex);
086: }
087: }
088:
089: // private final CachingArchiveProvider archiveProvider;
090: private final ClassPath srcClassPath;
091: private final ClassPath bootClassPath;
092: private final ClassPath compileClassPath;
093: private final ClassPath cachedBootClassPath;
094: private final ClassPath cachedCompileClassPath;
095: private ClassPath outputClassPath;
096:
097: private final ClassPathListener cpListener;
098: private final boolean backgroundCompilation;
099: private final boolean ignoreExcludes;
100: private final Object/*JavaFileFilterImplementation*/filter;
101: //private JavaFileManager fileManager;
102: private EventListenerList listenerList = null;
103: private List<ClassIndex> usagesQuery;
104:
105: /** Creates a new instance of ClasspathInfo (private use the factory methods) */
106: private ClasspathInfo(
107: /*CachingArchiveProvider archiveProvider,*/ClassPath bootCp,
108: ClassPath compileCp, ClassPath srcCp,
109: Object/*JavaFileFilterImplementation*/filter,
110: boolean backgroundCompilation, boolean ignoreExcludes) {
111: assert /*archiveProvider != null &&*/bootCp != null
112: && compileCp != null;
113: this .cpListener = new ClassPathListener();
114: //this.archiveProvider = archiveProvider;
115: this .bootClassPath = bootCp;
116: this .compileClassPath = compileCp;
117: this .cachedBootClassPath = CacheClassPath
118: .forBootPath(this .bootClassPath);
119: this .cachedCompileClassPath = CacheClassPath
120: .forClassPath(this .compileClassPath);
121: this .cachedBootClassPath
122: .addPropertyChangeListener(WeakListeners
123: .propertyChange(this .cpListener,
124: this .cachedBootClassPath));
125: this .cachedCompileClassPath
126: .addPropertyChangeListener(WeakListeners
127: .propertyChange(this .cpListener,
128: this .cachedCompileClassPath));
129: if (srcCp != null) {
130: this .srcClassPath = srcCp;
131: this .outputClassPath = CacheClassPath
132: .forSourcePath(this .srcClassPath);
133: this .srcClassPath
134: .addPropertyChangeListener(WeakListeners
135: .propertyChange(this .cpListener,
136: this .srcClassPath));
137: } else {
138: this .srcClassPath = ClassPathSupport
139: .createClassPath(new URL[0]);
140: this .outputClassPath = ClassPathSupport
141: .createClassPath(new URL[0]);
142: }
143: this .backgroundCompilation = backgroundCompilation;
144: this .ignoreExcludes = ignoreExcludes;
145: this .filter = filter;
146: }
147:
148: @Override
149: public String toString() {
150: return "ClasspathInfo boot:[" + cachedBootClassPath
151: + "],compile:[" + cachedCompileClassPath + "],src:["
152: + srcClassPath + "]"; //NOI18N
153: }
154:
155: // Factory methods ---------------------------------------------------------
156:
157: /** Creates new interface to the compiler
158: * @param file for which the CompilerInterface should be created
159: * @return ClasspathInfo or null if the file does not exist on the
160: * local file system or it has no classpath associated
161: */
162: public static ClasspathInfo create(final File file) {
163: if (file == null) {
164: throw new IllegalArgumentException(
165: "Cannot pass null as parameter of ClasspathInfo.create(java.io.File)"); //NOI18N
166: }
167: final FileObject fo = FileUtil.toFileObject(file);
168: if (fo == null) {
169: return null;
170: } else {
171: return create(fo);
172: }
173: }
174:
175: private static ClasspathInfo create(FileObject fo,
176: Object/*JavaFileFilterImplementation*/filter,
177: boolean backgroundCompilation, boolean ignoreExcludes) {
178: ClassPath bootPath = ClassPath.getClassPath(fo, ClassPath.BOOT);
179: if (bootPath == null) {
180: //javac requires at least java.lang
181: bootPath = JavaPlatformManager.getDefault()
182: .getDefaultPlatform().getBootstrapLibraries();
183: }
184: ClassPath compilePath = ClassPath.getClassPath(fo,
185: ClassPath.COMPILE);
186: if (compilePath == null) {
187: compilePath = EMPTY_PATH;
188: }
189: ClassPath srcPath = ClassPath
190: .getClassPath(fo, ClassPath.SOURCE);
191: if (srcPath == null) {
192: srcPath = EMPTY_PATH;
193: }
194: return create(bootPath, compilePath, srcPath, filter,
195: backgroundCompilation, ignoreExcludes);
196: }
197:
198: /** Creates new interface to the compiler
199: * @param fo for which the CompilerInterface should be created
200: */
201: public static ClasspathInfo create(FileObject fo) {
202: return create(fo, null, false, false);
203: }
204:
205: private static ClasspathInfo create(ClassPath bootPath,
206: ClassPath classPath, ClassPath sourcePath,
207: Object/*JavaFileFilterImplementation*/filter,
208: boolean backgroundCompilation, boolean ignoreExcludes) {
209: return new ClasspathInfo(
210: /*CachingArchiveProvider.getDefault(),*/bootPath,
211: classPath, sourcePath, filter, backgroundCompilation,
212: ignoreExcludes);
213: }
214:
215: public static ClasspathInfo create(ClassPath bootPath,
216: ClassPath classPath, ClassPath sourcePath) {
217: return new ClasspathInfo(
218: /*CachingArchiveProvider.getDefault(),*/bootPath,
219: classPath, sourcePath, null, false, false);
220: }
221:
222: // Public methods ----------------------------------------------------------
223:
224: /** Registers ChangeListener which will be notified about the changes in the classpath.
225: * @param listener The listener to register.
226: */
227: public synchronized void addChangeListener(ChangeListener listener) {
228: if (listenerList == null) {
229: listenerList = new EventListenerList();
230: }
231: listenerList.add(ChangeListener.class, listener);
232: }
233:
234: /**Removes ChangeListener from the list of listeners.
235: * @param listener The listener to remove.
236: */
237: public synchronized void removeChangeListener(
238: ChangeListener listener) {
239: listenerList.remove(ChangeListener.class, listener);
240: }
241:
242: public ClassPath getClassPath(PathKind pathKind) {
243: switch (pathKind) {
244: case BOOT:
245: return this .bootClassPath;
246: case COMPILE:
247: return this .compileClassPath;
248: case SOURCE:
249: return this .srcClassPath;
250: default:
251: assert false : "Unknown path type"; //NOI18N
252: return null;
253: }
254: }
255:
256: ClassPath getCachedClassPath(PathKind pathKind) {
257: switch (pathKind) {
258: case BOOT:
259: return this .cachedBootClassPath;
260: case COMPILE:
261: return this .cachedCompileClassPath;
262: case SOURCE:
263: return this .srcClassPath;
264: case OUTPUT:
265: return this .outputClassPath;
266: default:
267: assert false : "Unknown path type"; //NOI18N
268: return null;
269: }
270: }
271:
272: public synchronized ClassIndex getClassIndex(String mimeType) {
273: if (usagesQuery == null) {
274: usagesQuery = new ArrayList<ClassIndex>(8);
275: } else {
276: for (int i = 0; i < usagesQuery.size(); i++) {
277: ClassIndex ci = usagesQuery.get(i);
278: if (ci.getLanguage().getMimeType().equals(mimeType)) {
279: return ci;
280: }
281: }
282: }
283:
284: Language language = LanguageRegistry.getInstance()
285: .getLanguageByMimeType(mimeType);
286: assert language != null : mimeType;
287:
288: ClassIndex ci = new ClassIndex(language, this .bootClassPath,
289: this .compileClassPath, this .srcClassPath);
290:
291: usagesQuery.add(ci);
292:
293: return ci;
294: }
295:
296: // Package private methods -------------------------------------------------
297: //
298: // synchronized JavaFileManager getFileManager() {
299: // if (this.fileManager == null) {
300: // boolean hasSources = this.srcClassPath != null;
301: // this.fileManager = new ProxyFileManager (
302: // new CachingFileManager (this.archiveProvider, this.bootClassPath, true),
303: // new CachingFileManager (this.archiveProvider, this.compileClassPath, false),
304: // hasSources ? (backgroundCompilation ? new CachingFileManager (this.archiveProvider, this.srcClassPath, filter, false)
305: // : new SourceFileManager (this.srcClassPath.getRoots())) : null,
306: // hasSources ? new OutputFileManager (this.archiveProvider, this.outputClassPath, this.srcClassPath) : null
307: // );
308: // }
309: // return this.fileManager;
310: // }
311:
312: // Private methods ---------------------------------------------------------
313:
314: private void fireChangeListenerStateChanged() {
315: ChangeEvent e = null;
316: if (listenerList == null)
317: return;
318: Object[] listeners = listenerList.getListenerList();
319: for (int i = listeners.length - 2; i >= 0; i -= 2) {
320: if (listeners[i] == ChangeListener.class) {
321: if (e == null)
322: e = new ChangeEvent(this );
323: ((ChangeListener) listeners[i + 1]).stateChanged(e);
324: }
325: }
326: }
327:
328: // Innerclasses ------------------------------------------------------------
329:
330: public static enum PathKind {
331: BOOT, COMPILE, SOURCE, OUTPUT,
332:
333: }
334:
335: private class ClassPathListener implements PropertyChangeListener {
336:
337: public void propertyChange(PropertyChangeEvent event) {
338: if (ClassPath.PROP_ROOTS.equals(event.getPropertyName())) {
339: synchronized (this ) {
340: // Kill FileManager
341: //fileManager = null;
342: }
343: fireChangeListenerStateChanged();
344: }
345: }
346: }
347:
348: private static class ClasspathInfoAccessorImpl extends
349: ClasspathInfoAccessor {
350:
351: // @Override
352: // public JavaFileManager getFileManager(ClasspathInfo cpInfo) {
353: // return cpInfo.getFileManager();
354: // }
355:
356: public ClassPath getCachedClassPath(final ClasspathInfo cpInfo,
357: final PathKind kind) {
358: return cpInfo.getCachedClassPath(kind);
359: }
360:
361: @Override
362: public ClasspathInfo create(ClassPath bootPath,
363: ClassPath classPath, ClassPath sourcePath,
364: Object/*JavaFileFilterImplementation*/filter,
365: boolean backgroundCompilation, boolean ignoreExcludes) {
366: return ClasspathInfo.create(bootPath, classPath,
367: sourcePath, filter, backgroundCompilation,
368: ignoreExcludes);
369: }
370:
371: @Override
372: public ClasspathInfo create(FileObject fo,
373: Object/*JavaFileFilterImplementation*/filter,
374: boolean backgroundCompilation, boolean ignoreExcludes) {
375: return ClasspathInfo.create(fo, filter,
376: backgroundCompilation, ignoreExcludes);
377: }
378: }
379: }
|