001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2008 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-2008 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.modules.ruby.railsprojects.classpath;
042:
043: import java.beans.PropertyChangeEvent;
044: import java.beans.PropertyChangeListener;
045: import java.io.File;
046: import java.util.Map;
047: import java.util.HashMap;
048: import org.netbeans.modules.gsfpath.api.classpath.ClassPath;
049: import org.netbeans.api.project.SourceGroup;
050: import org.netbeans.modules.ruby.railsprojects.SourceRoots;
051: import org.netbeans.modules.ruby.railsprojects.classpath.SourcePathImplementation;
052: import org.netbeans.modules.ruby.spi.project.support.rake.PropertyEvaluator;
053: import org.netbeans.modules.gsfpath.spi.classpath.ClassPathFactory;
054: import org.netbeans.modules.gsfpath.spi.classpath.ClassPathProvider;
055: import org.netbeans.modules.ruby.spi.project.support.rake.RakeProjectHelper;
056: import org.netbeans.modules.gsfpath.spi.classpath.support.ClassPathSupport;
057: import org.openide.filesystems.FileObject;
058: import org.openide.filesystems.FileUtil;
059: import org.openide.util.WeakListeners;
060:
061: /**
062: * Defines the various class paths for a J2SE project.
063: */
064: public final class ClassPathProviderImpl implements ClassPathProvider,
065: PropertyChangeListener {
066:
067: private static final String BUILD_CLASSES_DIR = "build.classes.dir"; // NOI18N
068: private static final String DIST_JAR = "dist.jar"; // NOI18N
069: private static final String BUILD_TEST_CLASSES_DIR = "build.test.classes.dir"; // NOI18N
070:
071: private static final String JAVAC_CLASSPATH = "javac.classpath"; //NOI18N
072: private static final String JAVAC_TEST_CLASSPATH = "javac.test.classpath"; //NOI18N
073: private static final String RUN_CLASSPATH = "run.classpath"; //NOI18N
074: private static final String RUN_TEST_CLASSPATH = "run.test.classpath"; //NOI18N
075:
076: private final RakeProjectHelper helper;
077: private final File projectDirectory;
078: private final PropertyEvaluator evaluator;
079: private final SourceRoots sourceRoots;
080: private final SourceRoots testSourceRoots;
081: private final ClassPath[] cache = new ClassPath[8];
082:
083: private final Map<String, FileObject> dirCache = new HashMap<String, FileObject>();
084:
085: public ClassPathProviderImpl(RakeProjectHelper helper,
086: PropertyEvaluator evaluator, SourceRoots sourceRoots,
087: SourceRoots testSourceRoots) {
088: this .helper = helper;
089: this .projectDirectory = FileUtil.toFile(helper
090: .getProjectDirectory());
091: assert this .projectDirectory != null;
092: this .evaluator = evaluator;
093: this .sourceRoots = sourceRoots;
094: this .testSourceRoots = testSourceRoots;
095: evaluator.addPropertyChangeListener(WeakListeners
096: .propertyChange(this , evaluator));
097: }
098:
099: private synchronized FileObject getDir(String propname) {
100: FileObject fo = this .dirCache.get(propname);
101: if (fo == null || !fo.isValid()) {
102: String prop = evaluator.getProperty(propname);
103: if (prop != null) {
104: fo = helper.resolveFileObject(prop);
105: this .dirCache.put(propname, fo);
106: }
107: }
108: return fo;
109: }
110:
111: private FileObject[] getPrimarySrcPath() {
112: return this .sourceRoots.getRoots();
113: }
114:
115: private FileObject[] getTestSrcDir() {
116: return this .testSourceRoots.getRoots();
117: }
118:
119: private FileObject getBuildClassesDir() {
120: return getDir(BUILD_CLASSES_DIR);
121: }
122:
123: private FileObject getDistJar() {
124: return getDir(DIST_JAR);
125: }
126:
127: private FileObject getBuildTestClassesDir() {
128: return getDir(BUILD_TEST_CLASSES_DIR);
129: }
130:
131: /**
132: * Find what a given file represents.
133: * @param file a file in the project
134: * @return one of: <dl>
135: * <dt>0</dt> <dd>normal source</dd>
136: * <dt>1</dt> <dd>test source</dd>
137: * <dt>2</dt> <dd>built class (unpacked)</dd>
138: * <dt>3</dt> <dd>built test class</dd>
139: * <dt>4</dt> <dd>built class (in dist JAR)</dd>
140: * <dt>-1</dt> <dd>something else</dd>
141: * </dl>
142: */
143: private int getType(FileObject file) {
144: // ALL files in the Rails project are considered sources - we don't have
145: // separate test roots etc.
146: // TODO - check if files are even within the project?
147: return 0;
148: // FileObject[] srcPath = getPrimarySrcPath();
149: // for (int i=0; i < srcPath.length; i++) {
150: // FileObject root = srcPath[i];
151: // if (root.equals(file) || FileUtil.isParentOf(root, file)) {
152: // return 0;
153: // }
154: // }
155: // srcPath = getTestSrcDir();
156: // for (int i=0; i< srcPath.length; i++) {
157: // FileObject root = srcPath[i];
158: // if (root.equals(file) || FileUtil.isParentOf(root, file)) {
159: // return 1;
160: // }
161: // }
162: // FileObject dir = getBuildClassesDir();
163: // if (dir != null && (dir.equals(file) || FileUtil.isParentOf(dir, file))) {
164: // return 2;
165: // }
166: // dir = getDistJar(); // not really a dir at all, of course
167: // if (dir != null && dir.equals(FileUtil.getArchiveFile(file))) {
168: // // XXX check whether this is really the root
169: // return 4;
170: // }
171: // dir = getBuildTestClassesDir();
172: // if (dir != null && (dir.equals(file) || FileUtil.isParentOf(dir,file))) {
173: // return 3;
174: // }
175: // return -1;
176: }
177:
178: // private synchronized ClassPath getCompileTimeClasspath(FileObject file) {
179: // int type = getType(file);
180: // return this.getCompileTimeClasspath(type);
181: // }
182: //
183: // private ClassPath getCompileTimeClasspath(int type) {
184: // if (type < 0 || type > 1) {
185: // // Not a source file.
186: // return null;
187: // }
188: // ClassPath cp = cache[2+type];
189: // if ( cp == null) {
190: // if (type == 0) {
191: // cp = ClassPathFactory.createClassPath(
192: // ProjectClassPathSupport.createPropertyBasedClassPathImplementation(
193: // projectDirectory, evaluator, new String[] {JAVAC_CLASSPATH})); // NOI18N
194: // }
195: // else {
196: // cp = ClassPathFactory.createClassPath(
197: // ProjectClassPathSupport.createPropertyBasedClassPathImplementation(
198: // projectDirectory, evaluator, new String[] {JAVAC_TEST_CLASSPATH})); // NOI18N
199: // }
200: // cache[2+type] = cp;
201: // }
202: // return cp;
203: // }
204: //
205: // private synchronized ClassPath getRunTimeClasspath(FileObject file) {
206: // int type = getType(file);
207: // if (type < 0 || type > 4) {
208: // // Unregistered file, or in a JAR.
209: // // For jar:file:$projdir/dist/*.jar!/**/*.class, it is misleading to use
210: // // run.classpath since that does not actually contain the file!
211: // // (It contains file:$projdir/build/classes/ instead.)
212: // return null;
213: // } else if (type > 1) {
214: // type-=2; //Compiled source transform into source
215: // }
216: // ClassPath cp = cache[4+type];
217: // if ( cp == null) {
218: // if (type == 0) {
219: // cp = ClassPathFactory.createClassPath(
220: // ProjectClassPathSupport.createPropertyBasedClassPathImplementation(
221: // projectDirectory, evaluator, new String[] {RUN_CLASSPATH})); // NOI18N
222: // }
223: // else if (type == 1) {
224: // cp = ClassPathFactory.createClassPath(
225: // ProjectClassPathSupport.createPropertyBasedClassPathImplementation(
226: // projectDirectory, evaluator, new String[] {RUN_TEST_CLASSPATH})); // NOI18N
227: // }
228: // else if (type == 2) {
229: // //Only to make the CompiledDataNode hapy
230: // //Todo: Strictly it should return ${run.classpath} - ${build.classes.dir} + ${dist.jar}
231: // cp = ClassPathFactory.createClassPath(
232: // ProjectClassPathSupport.createPropertyBasedClassPathImplementation(
233: // projectDirectory, evaluator, new String[] {DIST_JAR})); // NOI18N
234: // }
235: // cache[4+type] = cp;
236: // }
237: // return cp;
238: // }
239: //
240: private synchronized ClassPath getSourcepath(FileObject file) {
241: int type = getType(file);
242: return this .getSourcepath(type);
243: }
244:
245: private ClassPath getSourcepath(int type) {
246: if (type < 0 || type > 1) {
247: return null;
248: }
249: ClassPath cp = cache[type];
250: if (cp == null) {
251: switch (type) {
252: case 0:
253: cp = ClassPathFactory
254: .createClassPath(new SourcePathImplementation(
255: this .sourceRoots, helper, evaluator));
256: break;
257: case 1:
258: cp = ClassPathFactory
259: .createClassPath(new SourcePathImplementation(
260: this .testSourceRoots));
261: break;
262: }
263: }
264: cache[type] = cp;
265: return cp;
266: }
267:
268: private synchronized ClassPath getBootClassPath() {
269: ClassPath cp = cache[7];
270: if (cp == null) {
271: cp = ClassPathFactory
272: .createClassPath(new BootClassPathImplementation(
273: projectDirectory, evaluator));
274: cache[7] = cp;
275: }
276: return cp;
277: }
278:
279: public ClassPath findClassPath(FileObject file, String type) {
280: /*if (type.equals(ClassPath.EXECUTE)) {
281: return getRunTimeClasspath(file);
282: } else */if (type.equals(ClassPath.SOURCE)) {
283: return getSourcepath(file);
284: } else if (type.equals(ClassPath.BOOT)) {
285: return getBootClassPath();
286: } else if (type.equals(ClassPath.COMPILE)) {
287: // Bogus
288: return getBootClassPath();
289: } else {
290: return null;
291: }
292: }
293:
294: /**
295: * Returns array of all classpaths of the given type in the project.
296: * The result is used for example for GlobalPathRegistry registrations.
297: */
298: public ClassPath[] getProjectClassPaths(String type) {
299: if (ClassPath.BOOT.equals(type)) {
300: return new ClassPath[] { getBootClassPath() };
301: }
302: // if (ClassPath.COMPILE.equals(type)) {
303: // ClassPath[] l = new ClassPath[2];
304: // l[0] = getCompileTimeClasspath(0);
305: // l[1] = getCompileTimeClasspath(1);
306: // return l;
307: // }
308: if (ClassPath.SOURCE.equals(type)) {
309: ClassPath[] l = new ClassPath[2];
310: l[0] = getSourcepath(0);
311: l[1] = getSourcepath(1);
312: return l;
313: }
314: // assert false;
315: return null;
316: }
317:
318: /**
319: * Returns the given type of the classpath for the project sources
320: * (i.e., excluding tests roots). Valid types are BOOT, SOURCE and COMPILE.
321: */
322: public ClassPath getProjectSourcesClassPath(String type) {
323: if (ClassPath.BOOT.equals(type)) {
324: return getBootClassPath();
325: }
326: if (ClassPath.SOURCE.equals(type)) {
327: return getSourcepath(0);
328: }
329: // if (ClassPath.COMPILE.equals(type)) {
330: // return getCompileTimeClasspath(0);
331: // }
332: // assert false;
333: return null;
334: }
335:
336: public synchronized void propertyChange(PropertyChangeEvent evt) {
337: dirCache.remove(evt.getPropertyName());
338: }
339:
340: public String getPropertyName(SourceGroup sg, String type) {
341: FileObject root = sg.getRootFolder();
342: FileObject[] path = getPrimarySrcPath();
343: for (int i = 0; i < path.length; i++) {
344: if (root.equals(path[i])) {
345: if (ClassPath.COMPILE.equals(type)) {
346: return JAVAC_CLASSPATH;
347: } else if (ClassPath.EXECUTE.equals(type)) {
348: return RUN_CLASSPATH;
349: } else {
350: return null;
351: }
352: }
353: }
354: path = getTestSrcDir();
355: for (int i = 0; i < path.length; i++) {
356: if (root.equals(path[i])) {
357: if (ClassPath.COMPILE.equals(type)) {
358: return JAVAC_TEST_CLASSPATH;
359: } else if (ClassPath.EXECUTE.equals(type)) {
360: return RUN_TEST_CLASSPATH;
361: } else {
362: return null;
363: }
364: }
365: }
366: return null;
367: }
368:
369: }
|