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-2006 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:
042: package org.netbeans.modules.projectimport.eclipse;
043:
044: import java.io.File;
045: import java.util.ArrayList;
046: import java.util.Collection;
047: import java.util.Collections;
048: import java.util.HashMap;
049: import java.util.HashSet;
050: import java.util.Iterator;
051: import java.util.Map;
052: import java.util.Set;
053: import java.util.logging.Logger;
054: import org.netbeans.modules.projectimport.LoggerFactory;
055: import org.openide.filesystems.FileUtil;
056:
057: /**
058: * Represents Eclipse project structure.
059: *
060: * @author mkrauskopf
061: */
062: public final class EclipseProject implements Comparable {
063:
064: /** Logger for this class. */
065: private static final Logger logger = LoggerFactory.getDefault()
066: .createLogger(EclipseProject.class);
067:
068: static final String PROJECT_FILE = ".project"; // NOI18N
069: static final String CLASSPATH_FILE = ".classpath"; // NOI18N
070:
071: private Workspace workspace;
072:
073: private String name;
074: private boolean internal = true;
075: private boolean javaNature;
076: private ClassPath cp;
077: private Set links;
078: private Set otherNatures;
079:
080: private final File projectDir;
081: private final File cpFile;
082: private final File prjFile;
083: private String jdkDirectory;
084:
085: /**
086: * Returns <code>EclipseProject</code> instance representing Eclipse project
087: * found in the given <code>projectDir</code>. If a project is not found in
088: * the specified directory, <code>null</code> is returned.
089: *
090: * @return either a <code>EclipseProject</code> instance or null if a given
091: * <code>projectDir</code> doesn't contain valid Eclipse project.
092: */
093: static EclipseProject createProject(File projectDir) {
094: if (!EclipseUtils.isRegularProject(projectDir)) {
095: logger.fine(projectDir
096: + " doesn't contain regular Eclipse project."); // NOI18N
097: return null;
098: }
099: return new EclipseProject(projectDir);
100: }
101:
102: /** Sets up a project directory. */
103: private EclipseProject(File projectDir) {
104: this .projectDir = projectDir;
105: this .cpFile = new File(projectDir, CLASSPATH_FILE);
106: this .prjFile = new File(projectDir, PROJECT_FILE);
107: }
108:
109: void setWorkspace(Workspace workspace) {
110: this .workspace = workspace;
111: }
112:
113: public Workspace getWorkspace() {
114: return workspace;
115: }
116:
117: void setClassPath(ClassPath cp) {
118: this .cp = cp;
119: }
120:
121: ClassPath getClassPath() {
122: return cp;
123: }
124:
125: /**
126: * Returns project's name.
127: */
128: public String getName() {
129: return name;
130: }
131:
132: void setName(String name) {
133: this .name = name;
134: }
135:
136: void setInternal(boolean internal) {
137: this .internal = internal;
138: }
139:
140: public boolean isInternal() {
141: return internal;
142: }
143:
144: public File getDirectory() {
145: return projectDir;
146: }
147:
148: /**
149: * Returns metadata file containing information about this projects. I.e.
150: * normally <em>.project</em> file withing the project's directory. See
151: * {@link #PROJECT_FILE}.
152: */
153: File getProjectFile() {
154: return prjFile;
155: }
156:
157: /**
158: * Returns metadata file containing information about this projects. I.e.
159: * normally <em>.classpath</em> file withing the project's directory. See
160: * {@link #CLASSPATH_FILE}.
161: */
162: File getClassPathFile() {
163: return cpFile;
164: }
165:
166: public boolean hasJavaNature() {
167: return javaNature;
168: }
169:
170: void setJavaNature(boolean javaNature) {
171: this .javaNature = javaNature;
172: }
173:
174: public Set getOtherNatures() {
175: return otherNatures;
176: }
177:
178: void addOtherNature(String nature) {
179: if (otherNatures == null) {
180: otherNatures = new HashSet();
181: }
182: logger.fine("Project " + getName() + " has another nature: " + // NOI18N
183: nature);
184: otherNatures.add(nature);
185: }
186:
187: /**
188: * Returns JDK directory for platform this project uses. Can be null in a
189: * case when a JDK was set for an eclipse project in Eclipse then the
190: * directory with JDK was deleted from filesystem and then a project is
191: * imported to NetBeans.
192: *
193: * @return JDK directory for the project
194: */
195: public String getJDKDirectory() {
196: if (jdkDirectory == null && workspace != null) {
197: logger.finest("Getting JDK directory for project "
198: + this .getName()); // NOI18N
199: jdkDirectory = workspace.getJDKDirectory(cp
200: .getJREContainer());
201: logger.finest("Resolved JDK directory: " + jdkDirectory); // NOI18N
202: // jdkDirectory = workspace.getJDKDirectory(projectDir.getName());
203: }
204: return jdkDirectory;
205: }
206:
207: /** Convenient delegate to <code>ClassPath</code> */
208: public Collection getSourceRoots() {
209: return cp.getSourceRoots();
210: }
211:
212: /**
213: * Returns map of file-label entries representing Eclipse project's source
214: * roots.
215: */
216: public Map/*<File, String>*/getAllSourceRoots() {
217: Map rootsLabels = new HashMap();
218:
219: // internal sources
220: Collection srcRoots = cp.getSourceRoots();
221: for (Iterator it = srcRoots.iterator(); it.hasNext();) {
222: ClassPathEntry cpe = (ClassPathEntry) it.next();
223: File file = FileUtil.normalizeFile(new File(cpe
224: .getAbsolutePath()));
225: rootsLabels.put(file, cpe.getRawPath());
226: }
227: // external sources
228: Collection extSrcRoots = cp.getExternalSourceRoots();
229: for (Iterator it = extSrcRoots.iterator(); it.hasNext();) {
230: ClassPathEntry cpe = (ClassPathEntry) it.next();
231: rootsLabels.put(FileUtil.normalizeFile(new File(cpe
232: .getAbsolutePath())), cpe.getRawPath());
233: }
234:
235: return rootsLabels;
236: }
237:
238: /**
239: * Returns all libraries on the project classpath.
240: */
241: public Collection/*<File>*/getAllLibrariesFiles() {
242: Collection files = new ArrayList();
243: // internal libraries
244: for (Iterator it = cp.getLibraries().iterator(); it.hasNext();) {
245: files.add(FileUtil.normalizeFile(new File(
246: ((ClassPathEntry) it.next()).getAbsolutePath())));
247:
248: }
249: // external libraries
250: for (Iterator it = cp.getExternalLibraries().iterator(); it
251: .hasNext();) {
252: files.add(FileUtil.normalizeFile(new File(
253: ((ClassPathEntry) it.next()).getAbsolutePath())));
254: }
255: // jars in user libraries
256: for (Iterator it = getUserLibrariesJars().iterator(); it
257: .hasNext();) {
258: files.add(FileUtil.normalizeFile(new File((String) it
259: .next())));
260: }
261: // variables
262: for (Iterator it = cp.getVariables().iterator(); it.hasNext();) {
263: ClassPathEntry entry = (ClassPathEntry) it.next();
264: // in case a variable wasn't resolved
265: if (entry.getAbsolutePath() != null) {
266: files.add(FileUtil.normalizeFile(new File(entry
267: .getAbsolutePath())));
268: }
269: }
270: return files;
271: }
272:
273: /** Convenient delegate to <code>ClassPath</code> */
274: public Collection getExternalSourceRoots() {
275: return cp.getExternalSourceRoots();
276: }
277:
278: /** Convenient delegate to <code>ClassPath</code> */
279: public Collection getLibraries() {
280: return cp.getLibraries();
281: }
282:
283: /** Convenient delegate to <code>ClassPath</code> */
284: public Collection getExternalLibraries() {
285: return cp.getExternalLibraries();
286: }
287:
288: public Collection getUserLibrariesJars() {
289: Collection userLibrariesJars = new HashSet();
290: if (workspace != null) {
291: for (Iterator it = cp.getUserLibraries().iterator(); it
292: .hasNext();) {
293: userLibrariesJars.addAll(workspace
294: .getJarsForUserLibrary((String) it.next()));
295: }
296: }
297: return userLibrariesJars;
298: }
299:
300: /** Convenient delegate to <code>ClassPath</code> */
301: public Collection getProjectsEntries() {
302: return cp.getProjects();
303: }
304:
305: private Set projectsWeDependOn;
306:
307: /**
308: * Returns collection of <code>EclipseProject</code> this project requires.
309: */
310: public Set getProjects() {
311: if (workspace != null && projectsWeDependOn == null) {
312: projectsWeDependOn = new HashSet();
313: for (Iterator it = cp.getProjects().iterator(); it
314: .hasNext();) {
315: ClassPathEntry cp = (ClassPathEntry) it.next();
316: EclipseProject prj = workspace.getProjectByRawPath(cp
317: .getRawPath());
318: if (prj != null) {
319: projectsWeDependOn.add(prj);
320: }
321: }
322: }
323: return projectsWeDependOn == null ? Collections.EMPTY_SET
324: : projectsWeDependOn;
325: }
326:
327: /** Convenient delegate to <code>ClassPath</code> */
328: public Collection getVariables() {
329: return cp.getVariables();
330: }
331:
332: void addLink(ClassPath.Link link) {
333: if (links == null) {
334: links = new HashSet();
335: }
336: links.add(link);
337: }
338:
339: /**
340: * Inteligently sets absolute path for a given entry with recongnizing of
341: * links, projects, variables, relative and absolute entries.
342: * If it is not possible (e.g. workspace Varible is not found) sets abs.
343: * path to null.
344: */
345: void setAbsolutePathForEntry(ClassPathEntry entry) {
346: // set abs. path default (null)
347: entry.setAbsolutePath(null);
348:
349: // try to resolve entry as a CONTAINER
350: if (entry.getType() == ClassPathEntry.TYPE_CONTAINER) {
351: // we don't support CONTAINERs so we don't care about them here
352: // (we support JRE/JDK containers but those are solved elsewhere)
353: return;
354: }
355:
356: // try to resolve entry as a VARIABLE
357: if (entry.getType() == ClassPathEntry.TYPE_VARIABLE) {
358: String rawPath = entry.getRawPath();
359: int slashIndex = rawPath.indexOf('/');
360: if (slashIndex != -1) {
361: Workspace.Variable parent = getVariable(rawPath
362: .substring(0, slashIndex));
363: if (parent != null) {
364: entry.setAbsolutePath(parent.getLocation()
365: + rawPath.substring(slashIndex));
366: }
367: } else {
368: Workspace.Variable var = getVariable(entry);
369: if (var != null) {
370: entry.setAbsolutePath(var.getLocation());
371: }
372: }
373: return;
374: }
375:
376: // try to resolve entry as a PROJECT
377: if (entry.getType() == ClassPathEntry.TYPE_PROJECT) {
378: if (workspace != null) {
379: entry.setAbsolutePath(workspace
380: .getProjectAbsolutePath(entry.getRawPath()
381: .substring(1)));
382: }
383: // else {
384: // ErrorManager.getDefault().log(ErrorManager.WARNING, "workspace == null");
385: // }
386: return;
387: }
388:
389: // try to resolve entry as a LINK
390: ClassPath.Link link = getLink(entry.getRawPath());
391: if (link != null) {
392: logger.finest("Found link for entry \"" + entry + "\": "
393: + link); // NOI18N
394: if (FileUtil.normalizeFile(new File(link.getLocation()))
395: .exists()) {
396: // change type from source to source link
397: entry.setType(ClassPathEntry.TYPE_LINK);
398: entry.setAbsolutePath(link.getLocation());
399: } else {
400: logger
401: .info("Not able to resolve absolute path for classpath"
402: + // NOI18N
403: " entry \""
404: + entry.getRawPath()
405: + "\". This classpath"
406: + // NOI18N
407: " entry is external source which points to PATH VARIABLE"
408: + // NOI18N
409: " which points to final destination. This feature will be"
410: + // NOI18N
411: " supported in future version of Importer."); // NOI18N
412: entry.setType(ClassPathEntry.TYPE_UNKNOWN);
413: }
414: return;
415: }
416:
417: // not VARIABLE, not PROJECT, not LINK -> either source root or library
418: if (entry.isRawPathRelative()) {
419: // internal src or lib
420: entry.setAbsolutePath(projectDir.getAbsolutePath()
421: + File.separator + entry.getRawPath());
422: } else {
423: // external src or lib
424: entry.setAbsolutePath(entry.getRawPath());
425: }
426: }
427:
428: /**
429: * Find variable for the given variable rawPath. Note that this method
430: * returns <code>null</code> if workspace wasn't set for the project.
431: */
432: private Workspace.Variable getVariable(String rawPath) {
433: if (workspace == null) {
434: // workspace wasn't set for this project
435: logger.fine("Workspace wasn't set for the project \""
436: + getName() + "\""); // NOI18N
437: return null;
438: }
439: Set variables = workspace.getVariables();
440: if (variables != null) {
441: for (Iterator it = workspace.getVariables().iterator(); it
442: .hasNext();) {
443: Workspace.Variable variable = (Workspace.Variable) it
444: .next();
445: if (variable.getName().equals(rawPath)) {
446: return variable;
447: }
448: }
449: }
450: logger.info("Cannot resolve variable for raw path: " + rawPath); // NOI18N
451: return null;
452: }
453:
454: /**
455: * Recongises if a given entry represents variable. If yes returns variable
456: * it represents otherwise null. Note that this method returns null if
457: * workspace wasn't set for this project.
458: */
459: private Workspace.Variable getVariable(ClassPathEntry entry) {
460: return getVariable(entry.getRawPath());
461: }
462:
463: /**
464: * Recongises if a given entry represents link. If yes returns link it
465: * represents otherwise null.
466: */
467: private ClassPath.Link getLink(String linkName) {
468: if (links != null) {
469: for (Iterator it = links.iterator(); it.hasNext();) {
470: ClassPath.Link link = (ClassPath.Link) it.next();
471: if (link.getName().equals(linkName)) {
472: return link;
473: }
474: }
475: }
476: return null;
477: }
478:
479: public String toString() {
480: return "EclipseProject[" + getName() + ", " + getDirectory()
481: + "]"; // NOI18N
482: }
483:
484: /* name is enough for now */
485: public boolean equals(Object obj) {
486: if (this == obj)
487: return true;
488: if (!(obj instanceof EclipseProject))
489: return false;
490: final EclipseProject ePrj = (EclipseProject) obj;
491: if (!name.equals(ePrj.name))
492: return false;
493: return true;
494: }
495:
496: /* name is enough for now */
497: public int hashCode() {
498: int result = 17;
499: result = 37 * result + System.identityHashCode(name);
500: return result;
501: }
502:
503: /**
504: * Compares projects based on theirs <code>name</code>s. Projects which has
505: * null-name will be last.
506: */
507: public int compareTo(Object o) {
508: String name1 = getName();
509: String name2 = null;
510: if (o instanceof EclipseProject) {
511: name2 = ((EclipseProject) o).getName();
512: }
513: if (name2 == null) {
514: return (name1 == null ? 0 : -1);
515: }
516: return (name1 == null ? 1 : name1.compareToIgnoreCase(name2));
517: }
518: }
|