blob: 80e80ac5e7de34197c77f97a107184b5ebc1b4a8 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.netbeans.modules.projectimport.eclipse.core;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Logger;
import org.netbeans.modules.projectimport.eclipse.core.spi.LaunchConfiguration;
import org.openide.util.Utilities;
import org.openide.xml.XMLUtil;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
/**
* Parses given workspace and fills up it with found data.
*
* @author mkrauskopf
*/
final class WorkspaceParser {
/** Logger for this class. */
private static final Logger logger = Logger.getLogger(WorkspaceParser.class.getName());
private static final String VM_XML = "org.eclipse.jdt.launching.PREF_VM_XML"; // NOI18N
private static final String IGNORED_CP_ENTRY = "##<cp entry ignore>##"; // NOI18N
private static final String VARIABLE_PREFIX = "org.eclipse.jdt.core.classpathVariable."; // NOI18N
private static final int VARIABLE_PREFIX_LENGTH = VARIABLE_PREFIX.length();
private static final String RESOURCES_VARIABLE_PREFIX = "pathvariable."; // NOI18N
private static final int RESOURCES_VARIABLE_PREFIX_LENGTH = RESOURCES_VARIABLE_PREFIX.length();
private static final String USER_LIBRARY_PREFIX = "org.eclipse.jdt.core.userLibrary."; // NOI18N
private static final int USER_LIBRARY_PREFIX_LENGTH = USER_LIBRARY_PREFIX.length();
private static final String JSF_LIB_NS = "http://www.eclipse.org/webtools/jsf/schema/jsflibraryregistry.xsd"; // NOI18N
private final Workspace workspace;
/** Creates a new instance of WorkspaceParser */
WorkspaceParser(Workspace workspace) {
this.workspace = workspace;
}
/** Returns classpath content from project's .classpath file */
void parse() throws ProjectImporterException {
try {
parseLaunchingPreferences();
parseCorePreferences();
parseResourcesPreferences();
parseWorkspaceProjects();
parseJSFLibraryRegistryV2();
parseLaunchConfigurations();
} catch (IOException e) {
throw new ProjectImporterException(
"Cannot load workspace properties", e); // NOI18N
}
}
private void parseLaunchingPreferences() throws IOException, ProjectImporterException {
if (!workspace.getLaunchingPrefsFile().exists()) {
workspace.setJREContainers(new HashMap<String, String>());
return;
}
for (Map.Entry<String,String> entry : EclipseUtils.loadProperties(workspace.getLaunchingPrefsFile()).entrySet()) {
if (entry.getKey().equals(VM_XML)) {
Map<String,String> vmMap = PreferredVMParser.parse(entry.getValue());
workspace.setJREContainers(vmMap);
}
}
}
private void parseCorePreferences() throws IOException, ProjectImporterException {
for (Map.Entry<String,String> entry : EclipseUtils.loadProperties(workspace.getCorePreferenceFile()).entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
if (key.startsWith(VARIABLE_PREFIX)) {
Workspace.Variable var = new Workspace.Variable(key.substring(VARIABLE_PREFIX_LENGTH), value);
workspace.addVariable(var);
} else if (key.startsWith(USER_LIBRARY_PREFIX) && !value.startsWith(IGNORED_CP_ENTRY)) { // #73542
String libName = key.substring(USER_LIBRARY_PREFIX_LENGTH);
List<String> jars = new ArrayList<String>();
List<String> javadocs = new ArrayList<String>();
List<String> sources = new ArrayList<String>();
UserLibraryParser.getJars(libName, value, jars, javadocs, sources);
workspace.addUserLibrary(libName, jars, javadocs, sources);
} // else we don't use other properties in the meantime
}
}
/*private*/ void parseJSFLibraryRegistryV2() throws IOException {
if (!workspace.getUserJSFLibraries().exists()) {
return;
}
Document xml;
try {
xml = XMLUtil.parse(new InputSource(Utilities.toURI(workspace.getUserJSFLibraries()).toString()), false, true, XMLUtil.defaultErrorHandler(), null);
} catch (SAXException e) {
IOException ioe = (IOException) new IOException(workspace.getUserJSFLibraries() + ": " + e.toString()).initCause(e); // NOI18N
throw ioe;
}
Element root = xml.getDocumentElement();
if (!"JSFLibraryRegistry".equals(root.getLocalName()) || // NOI18N
!JSF_LIB_NS.equals(root.getNamespaceURI())) {
return;
}
for (Element el : XMLUtil.findSubElements(root)) {
String libraryName = el.getAttribute("Name"); // NOI18N
List<String> jars = new ArrayList<String>();
for (Element file : XMLUtil.findSubElements(el)) {
String path = file.getAttribute("SourceLocation"); // NOI18N
if (!"false".equals(file.getAttribute("RelativeToWorkspace"))) { // NOI18N
path = new File(workspace.getDirectory(), path).getPath();
}
jars.add(path);
}
// TODO: in Ganymede Javadoc/sources customization does not seem to be persisted. eclipse defect??
workspace.addUserLibrary(libraryName, jars, null, null);
}
}
private void parseResourcesPreferences() throws IOException, ProjectImporterException {
if (!workspace.getResourcesPreferenceFile().exists()) {
return;
}
for (Map.Entry<String,String> entry : EclipseUtils.loadProperties(workspace.getResourcesPreferenceFile()).entrySet()) {
String key = entry.getKey();
if (key.startsWith(RESOURCES_VARIABLE_PREFIX)) {
Workspace.Variable var = new Workspace.Variable(key.substring(RESOURCES_VARIABLE_PREFIX_LENGTH), entry.getValue());
workspace.addResourcesVariable(var);
}
}
}
private void parseWorkspaceProjects() throws ProjectImporterException {
// directory filter
FileFilter dirFilter = new FileFilter() {
public boolean accept(File file) {
return file.isDirectory();
}
};
Set<File> projectsDirs = new HashSet<File>();
// let's find internal projects
File[] innerDirs = workspace.getDirectory().listFiles(dirFilter);
for (int i = 0; i < innerDirs.length; i++) {
File prjDir = innerDirs[i];
if (EclipseUtils.isRegularProject(prjDir)) {
// we cannot load projects recursively until we have loaded
// information of all projects in the workspace
logger.finest("Found a regular Eclipse Project in: " // NOI18N
+ prjDir.getAbsolutePath());
if (!projectsDirs.contains(prjDir)) {
addLightProject(projectsDirs, prjDir, true);
} else {
logger.finest("Trying to add the same project twice: " // NOI18N
+ prjDir.getAbsolutePath());
}
} // else .metadata or something we don't care about yet
}
// let's try to find external projects
File[] resourceDirs = workspace.getResourceProjectsDir().listFiles(dirFilter);
for (int i = 0; i < resourceDirs.length; i++) {
File resDir = resourceDirs[i];
File location = getLocation(resDir);
if (location != null) {
if (EclipseUtils.isRegularProject(location)) {
logger.finest("Found a regular Eclipse Project in: " // NOI18N
+ location.getAbsolutePath());
if (!projectsDirs.contains(location)) {
addLightProject(projectsDirs, location, false);
} else {
logger.finest("Trying to add the same project twice: " // NOI18N
+ location.getAbsolutePath());
}
} else {
logger.finest(location.getAbsolutePath() + " does not contain regular project"); // NOI18N
}
}
}
// Project instances with base infos are loaded, let's load all the
// information we need (we have to do this here because project's
// classpath needs at least project's names and abs. paths during
// parsing
// Load first all .project files to init any links project may have
// and then .classpath files.
for (EclipseProject project : workspace.getProjects()) {
project.setWorkspace(workspace);
ProjectFactory.getInstance().loadDotProject(project);
}
for (EclipseProject project : workspace.getProjects()) {
ProjectFactory.getInstance().loadDotClassPath(project);
}
for (EclipseProject project : workspace.getProjects()) {
project.replaceContainers();
}
}
private void addLightProject(Set<File> projectsDirs, File prjDir, boolean internal) {
EclipseProject project = EclipseProject.createProject(prjDir);
if (project != null) {
project.setName(prjDir.getName());
project.setInternal(internal);
workspace.addProject(project);
projectsDirs.add(prjDir);
}
}
/** Loads location of external project. */
private static File getLocation(final File prjDir) throws ProjectImporterException {
if (".org.eclipse.jdt.core.external.folders".equals(prjDir.getName())) { //NOI18N
// ignore this. some internal Eclipse stuff
return null;
}
File locationFile = new File(prjDir, ".location"); // NOI18N
if (locationFile.isFile()) {
FileInputStream fis = null;
try {
fis = new FileInputStream(locationFile);
return getLocation(fis);
} catch (IOException e) {
throw new ProjectImporterException("Error during reading " + // NOI18N
".location file", e); // NOI18N
} finally {
if (fis != null) {
try {
fis.close();
} catch (IOException e) {
throw new ProjectImporterException(e);
}
}
}
}
return null;
}
/**
* Loads location of external project. Package-private for unit tests only.
*/
static File getLocation(final InputStream is) throws IOException {
// starts with 17 bytes.
long toSkip = 17;
while(toSkip != 0) {
toSkip -= is.skip(toSkip);
}
// follows byte describing path length
int pathLength = is.read();
// follows path itself
byte[] path = new byte[pathLength];
int read = is.read(path);
assert read == pathLength;
String pathS = new String(path, StandardCharsets.ISO_8859_1);
if (pathS.startsWith("URI//")) { // #89577 // NOI18N
pathS = pathS.substring(pathS.indexOf(':') + 1);
}
if (pathS.length() == 0) {
return null;
}
return new File(pathS);
}
private void parseLaunchConfigurations() throws IOException, ProjectImporterException {
List<LaunchConfiguration> configs = new ArrayList<LaunchConfiguration>();
File[] launches = new File(workspace.getDirectory(), ".metadata/.plugins/org.eclipse.debug.core/.launches").listFiles(new FilenameFilter() { // NOI18N
public boolean accept(File dir, String name) {
return name.endsWith(".launch"); // NOI18N
}
});
if (launches != null) {
for (File launch : launches) {
Document doc;
try {
doc = XMLUtil.parse(new InputSource(Utilities.toURI(launch).toString()), false, false, null, null);
} catch (SAXException x) {
throw new ProjectImporterException("Could not parse " + launch, x);
}
Element launchConfiguration = doc.getDocumentElement();
String type = launchConfiguration.getAttribute("type"); // NOI18N
Map<String,String> attrs = new HashMap<String,String>();
NodeList nl = launchConfiguration.getElementsByTagName("stringAttribute"); // NOI18N
for (int i = 0; i < nl.getLength(); i++) {
Element stringAttribute = (Element) nl.item(i);
attrs.put(stringAttribute.getAttribute("key"), stringAttribute.getAttribute("value")); // NOI18N
}
configs.add(new LaunchConfiguration(launch.getName().replaceFirst("\\.launch$", ""), type, // NOI18N
attrs.get("org.eclipse.jdt.launching.PROJECT_ATTR"), // NOI18N
attrs.get("org.eclipse.jdt.launching.MAIN_TYPE"), // NOI18N
attrs.get("org.eclipse.jdt.launching.PROGRAM_ARGUMENTS"), // NOI18N
attrs.get("org.eclipse.jdt.launching.VM_ARGUMENTS"))); // NOI18N
}
}
workspace.setLaunchConfigurations(configs);
}
}