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.io.FileFilter;
046: import java.io.FileInputStream;
047: import java.io.IOException;
048: import java.io.InputStream;
049: import java.util.HashSet;
050: import java.util.Iterator;
051: import java.util.Map;
052: import java.util.Properties;
053: import java.util.Set;
054: import java.util.logging.Logger;
055: import org.netbeans.modules.projectimport.LoggerFactory;
056: import org.netbeans.modules.projectimport.ProjectImporterException;
057:
058: /**
059: * Parses given workspace and fills up it with found data.
060: *
061: * @author mkrauskopf
062: */
063: final class WorkspaceParser {
064:
065: /** Logger for this class. */
066: private static final Logger logger = LoggerFactory.getDefault()
067: .createLogger(WorkspaceParser.class);
068:
069: private static final String VM_XML = "org.eclipse.jdt.launching.PREF_VM_XML"; // NOI18N
070: private static final String IGNORED_CP_ENTRY = "##<cp entry ignore>##"; // NOI18N
071:
072: private static final String VARIABLE_PREFIX = "org.eclipse.jdt.core.classpathVariable."; // NOI18N
073: private static final int VARIABLE_PREFIX_LENGTH = VARIABLE_PREFIX
074: .length();
075:
076: private static final String USER_LIBRARY_PREFIX = "org.eclipse.jdt.core.userLibrary."; // NOI18N
077: private static final int USER_LIBRARY_PREFIX_LENGTH = USER_LIBRARY_PREFIX
078: .length();
079:
080: // private static final String CP_CONTAINER_PREFIX =
081: // "org.eclipse.jdt.core.classpathContainer.";
082: // private static final int CP_CONTAINER_PREFIX_LENGTH = CP_CONTAINER_PREFIX.length();
083: // private static final String CP_CONTAINER_SUFFIX =
084: // "|org.eclipse.jdt.launching.JRE_CONTAINER";
085: // private static final int CP_CONTAINER_SUFFIX_LENGTH = CP_CONTAINER_SUFFIX.length();
086:
087: private final Workspace workspace;
088:
089: /** Creates a new instance of WorkspaceParser */
090: WorkspaceParser(Workspace workspace) {
091: this .workspace = workspace;
092: }
093:
094: /** Returns classpath content from project's .classpath file */
095: void parse() throws ProjectImporterException {
096: try {
097: parseLaunchingPreferences();
098: parseCorePreferences();
099: parseWorkspaceProjects();
100: } catch (IOException e) {
101: throw new ProjectImporterException(
102: "Cannot load workspace properties", e); // NOI18N
103: }
104: }
105:
106: private void parseLaunchingPreferences() throws IOException,
107: ProjectImporterException {
108: Properties launchProps = EclipseUtils.loadProperties(workspace
109: .getLaunchingPrefsFile());
110: for (Iterator it = launchProps.entrySet().iterator(); it
111: .hasNext();) {
112: Map.Entry entry = (Map.Entry) it.next();
113: String key = (String) entry.getKey();
114: String value = (String) entry.getValue();
115: if (key.equals(VM_XML)) {
116: Map vmMap = PreferredVMParser.parse(value);
117: workspace.setJREContainers(vmMap);
118: }
119: }
120: }
121:
122: private void parseCorePreferences() throws IOException,
123: ProjectImporterException {
124: Properties coreProps = EclipseUtils.loadProperties(workspace
125: .getCorePreferenceFile());
126: for (Iterator it = coreProps.entrySet().iterator(); it
127: .hasNext();) {
128: Map.Entry entry = (Map.Entry) it.next();
129: String key = (String) entry.getKey();
130: String value = (String) entry.getValue();
131: if (key.startsWith(VARIABLE_PREFIX)) {
132: Workspace.Variable var = new Workspace.Variable();
133: var.setName(key.substring(VARIABLE_PREFIX_LENGTH));
134: var.setLocation(value);
135: workspace.addVariable(var);
136: } else if (key.startsWith(USER_LIBRARY_PREFIX)
137: && !value.startsWith(IGNORED_CP_ENTRY)) { // #73542
138: String libName = key
139: .substring(USER_LIBRARY_PREFIX_LENGTH);
140: workspace.addUserLibrary(libName, UserLibraryParser
141: .getJars(value));
142: } // else we don't use other properties in the meantime
143: }
144: }
145:
146: // private String parseJDKDir(ClassPath cp) {
147: // for (Iterator it = cp.getEntries().iterator(); it.hasNext(); ) {
148: // ClassPathEntry entry = (ClassPathEntry) it.next();
149: // if (entry.getRawPath().endsWith("rt.jar")) {
150: // return entry.getRawPath();
151: // }
152: // }
153: // return null;
154: // }
155:
156: private void parseWorkspaceProjects()
157: throws ProjectImporterException {
158: // directory filter
159: FileFilter dirFilter = new FileFilter() {
160: public boolean accept(File file) {
161: return file.isDirectory();
162: }
163: };
164:
165: Set projectsDirs = new HashSet();
166: // let's find internal projects
167: File[] innerDirs = workspace.getDirectory()
168: .listFiles(dirFilter);
169: for (int i = 0; i < innerDirs.length; i++) {
170: File prjDir = innerDirs[i];
171: if (EclipseUtils.isRegularProject(prjDir)) {
172: // we cannot load projects recursively until we have loaded
173: // information of all projects in the workspace
174: logger.finest("Found a regular Eclipse Project in: " // NOI18N
175: + prjDir.getAbsolutePath());
176: if (!projectsDirs.contains(prjDir.getName())) {
177: addLightProject(projectsDirs, prjDir, true);
178: } else {
179: logger
180: .warning("Trying to add the same project twice: " // NOI18N
181: + prjDir.getAbsolutePath());
182: }
183: } // else .metadata or something we don't care about yet
184: }
185:
186: // let's try to find external projects
187: File[] resourceDirs = workspace.getResourceProjectsDir()
188: .listFiles(dirFilter);
189: for (int i = 0; i < resourceDirs.length; i++) {
190: File resDir = resourceDirs[i];
191: File location = getLocation(resDir);
192: if (location != null) {
193: if (EclipseUtils.isRegularProject(location)) {
194: logger
195: .finest("Found a regular Eclipse Project in: " // NOI18N
196: + location.getAbsolutePath());
197: if (!projectsDirs.contains(location.getName())) {
198: addLightProject(projectsDirs, location, false);
199: } else {
200: logger
201: .warning("Trying to add the same project twice: " // NOI18N
202: + location.getAbsolutePath());
203: }
204: } else {
205: logger.warning(location.getAbsolutePath()
206: + " does not contain regular project"); // NOI18N
207: }
208: }
209: }
210:
211: // Project instances with base infos are loaded, let's load all the
212: // information we need (we have to do this here because project's
213: // classpath needs at least project's names and abs. paths during
214: // parsing
215: for (Iterator it = workspace.getProjects().iterator(); it
216: .hasNext();) {
217: EclipseProject project = (EclipseProject) it.next();
218: project.setWorkspace(workspace);
219: ProjectFactory.getInstance().load(project);
220: }
221: }
222:
223: private void addLightProject(Set projectsDirs, File prjDir,
224: boolean internal) {
225: EclipseProject project = EclipseProject.createProject(prjDir);
226: if (project != null) {
227: project.setName(prjDir.getName());
228: project.setInternal(internal);
229: workspace.addProject(project);
230: projectsDirs.add(prjDir.getName());
231: }
232: }
233:
234: /** Loads location of external project. */
235: private static File getLocation(final File prjDir)
236: throws ProjectImporterException {
237: File locationFile = new File(prjDir, ".location"); // NOI18N
238: if (locationFile.isFile()) {
239: FileInputStream fis = null;
240: try {
241: fis = new FileInputStream(locationFile);
242: return getLocation(fis);
243: } catch (IOException e) {
244: throw new ProjectImporterException(
245: "Error during reading " + // NOI18N
246: ".location file", e); // NOI18N
247: } finally {
248: if (fis != null) {
249: try {
250: fis.close();
251: } catch (IOException e) {
252: throw new ProjectImporterException(e);
253: }
254: }
255: }
256: }
257: return null;
258: }
259:
260: /**
261: * Loads location of external project. Package-private for unit tests only.
262: */
263: static File getLocation(final InputStream is) throws IOException {
264: // starts with 17 bytes.
265: long toSkip = 17;
266: while (toSkip != 0) {
267: toSkip -= is.skip(toSkip);
268: }
269: // follows byte describing path length
270: int pathLength = is.read();
271: // follows path itself
272: byte[] path = new byte[pathLength];
273: int read = is.read(path);
274: assert read == pathLength;
275: String pathS = new String(path, "ISO-8859-1"); // NOI18N
276: if (pathS.startsWith("URI//")) { // #89577 // NOI18N
277: pathS = pathS.substring(pathS.indexOf(':') + 1);
278: }
279: return new File(pathS);
280: }
281:
282: }
|