package org.objectstyle.wolips.eomodeler.factories; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.net.URL; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathExpression; import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathFactory; import org.objectstyle.woenvironment.env.WOEnvironment; import org.objectstyle.woenvironment.plist.PropertyListParserException; import org.objectstyle.woenvironment.plist.SimpleParserDataStructureFactory; import org.objectstyle.woenvironment.plist.WOLPropertyListSerialization; import org.objectstyle.wolips.baseforplugins.util.StringUtils; import org.objectstyle.wolips.baseforplugins.util.URLUtils; import org.objectstyle.wolips.eomodeler.core.model.AbstractManifestEOModelGroupFactory; import org.objectstyle.wolips.eomodeler.core.model.ManifestSearchFolder; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; public class EclipseProjectEOModelGroupFactory extends AbstractManifestEOModelGroupFactory { @Override public List<ManifestSearchFolder> getSearchFolders(File selectedModelFolder) throws IOException { // System.out.println( // "EclipseProjectEOModelGroupFactory.getSearchFolders: Looking for Eclipse projects ..." // ); List<ManifestSearchFolder> searchFolders = null; List<File> eclipseProjectFolders = new LinkedList<File>(); try { findEclipseProjectFolders(selectedModelFolder, eclipseProjectFolders); } catch (PropertyListParserException e) { e.printStackTrace(); throw new IOException("Failed to parse '.EntityModeler.plist'. " + StringUtils.getErrorMessage(e)); } if (!eclipseProjectFolders.isEmpty()) { searchFolders = new LinkedList<ManifestSearchFolder>(); for (File eclipseProjectFolder : eclipseProjectFolders) { // System.out.println( // "EclipseProjectEOModelGroupFactory.getSearchFolders: Project = " // + eclipseProjectFolder); Set<File> visitedProjectFolders = new HashSet<File>(); try { processEclipseProject(eclipseProjectFolder, searchFolders, visitedProjectFolders, new WOEnvironment()); } catch (Exception e) { e.printStackTrace(); } } } // System.out.println( // "EclipseProjectEOModelGroupFactory.getSearchFolders: " + // searchFolders); return searchFolders; } protected File getWorkspaceFolder(File projectFolder) { File workspaceFolder; String workspaceFolderPath = System.getProperty("workspaceFolder"); if (workspaceFolderPath != null) { workspaceFolder = new File(workspaceFolderPath); } else { workspaceFolder = null; File searchingFolder = projectFolder; while (searchingFolder != null && workspaceFolder == null) { File tempFolder = new File(searchingFolder, ".metadata"); if (tempFolder.exists() && tempFolder.isDirectory()) { workspaceFolder = searchingFolder; } else { searchingFolder = searchingFolder.getParentFile(); } } } if (workspaceFolder == null) { workspaceFolder = projectFolder.getParentFile(); } return workspaceFolder; } protected File getProjectFolder(File workspaceFolder, String projectName) { File projectFolder = null; File projectLocationFile = new File(workspaceFolder, ".metadata/.plugins/org.eclipse.core.resources/.projects/" + projectName + "/.location"); if (projectLocationFile.exists()) { // MS: This is pretty crazy, but the .location file is a binary file (of "unknown" layout) that contains // a URL that is the location of the project folder. We're going to load that binary file and look for // something that looks like a file: URL ... Crazy but works :) try { FileInputStream fis = new FileInputStream(projectLocationFile); try { ByteArrayOutputStream baos = new ByteArrayOutputStream(); byte[] buffer = new byte[2048]; while (fis.available() > 0) { int bytesRead = fis.read(buffer); baos.write(buffer, 0, bytesRead); } String locationContents = baos.toString(); int fileIndex = locationContents.indexOf("file:"); if (fileIndex != -1) { int zeroIndex = locationContents.indexOf(0, fileIndex); String projectPath = locationContents.substring(fileIndex, zeroIndex); projectFolder = URLUtils.cheatAndTurnIntoFile(new URL(projectPath)); } } finally { fis.close(); } } catch (Throwable t) { t.printStackTrace(); } } if (projectFolder == null) { projectFolder = new File(workspaceFolder, projectName); } return projectFolder; } protected void processEclipseProject(File eclipseProjectFolder, List<ManifestSearchFolder> searchFolders, Set<File> visitedProjects, WOEnvironment env) throws IOException, XPathExpressionException, SAXException, ParserConfigurationException { if (eclipseProjectFolder == null || !eclipseProjectFolder.exists() || visitedProjects.contains(eclipseProjectFolder)) { return; } // System.out.println( // "EclipseProjectEOModelGroupFactory.processEclipseProject: Project folder '" // + eclipseProjectFolder + "' ..."); String[] buildFolderNames = new String[] { "build", "dist" }; for (String buildFolderName : buildFolderNames) { File buildFolder = new File(eclipseProjectFolder, buildFolderName); if (buildFolder.exists()) { File buildResourcesFolder; File frameworkResourcesFolder = new File(buildFolder, eclipseProjectFolder.getName() + ".framework" + File.separator + "Resources"); if (frameworkResourcesFolder.exists()) { buildResourcesFolder = frameworkResourcesFolder; } else { File woaResourcesFolder = new File(buildFolder, eclipseProjectFolder.getName() + ".woa" + File.separator + "Contents" + File.separator + "Resources"); if (woaResourcesFolder.exists()) { buildResourcesFolder = woaResourcesFolder; } else { buildResourcesFolder = buildFolder; } } // We're cheating some here and forcing project build resources // folders to the front of the line ... searchFolders.add(0, new ManifestSearchFolder(buildResourcesFolder)); break; } } visitedProjects.add(eclipseProjectFolder); File workspaceFolder = null; File eclipseClasspathFile = new File(eclipseProjectFolder, ".classpath"); if (eclipseClasspathFile.exists()) { XPathExpression eclipseClasspathEntryExpression = XPathFactory.newInstance().newXPath().compile("//classpath/classpathentry"); Document eclipseClasspathDocument = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(eclipseClasspathFile); NodeList eclipseClasspathEntryNodes = (NodeList) eclipseClasspathEntryExpression.evaluate(eclipseClasspathDocument, XPathConstants.NODESET); for (int eclipseClasspathEntryNum = 0; eclipseClasspathEntryNum < eclipseClasspathEntryNodes.getLength(); eclipseClasspathEntryNum++) { Element eclipseClasspathEntryElement = (Element) eclipseClasspathEntryNodes.item(eclipseClasspathEntryNum); String kind = eclipseClasspathEntryElement.getAttribute("kind"); String path = eclipseClasspathEntryElement.getAttribute("path"); if ("src".equals(kind) && path != null && path.startsWith("/")) { if (workspaceFolder == null) { workspaceFolder = getWorkspaceFolder(eclipseProjectFolder); } File referencedProjectFolder = getProjectFolder(workspaceFolder, path).getCanonicalFile(); //new File(eclipseProjectFolder.getParentFile(), path).getCanonicalFile(); processEclipseProject(referencedProjectFolder, searchFolders, visitedProjects, env); } else if ("con".equals(kind) && path != null && path.startsWith("org.objectstyle.wolips.ContainerInitializer/")) { String[] strs = path.split("/"); List<String> frameworkNames = new LinkedList<String>(); for (int i = 3; i < strs.length; i += 11) { frameworkNames.add(strs[i]); } loadFrameworks(frameworkNames.toArray(new String[frameworkNames.size()]), searchFolders, visitedProjects, env); } else if ("con".equals(kind) && path != null && path.startsWith("org.objectstyle.wolips.WO_CLASSPATH/")) { String[] frameworkNames = path.split("/"); loadFrameworks(frameworkNames, searchFolders, visitedProjects, env); } else if ("con".equals(kind) && path != null && path.startsWith("WOFramework/")) { String frameworkName = path.substring(path.indexOf("/") + 1); if (workspaceFolder == null) { workspaceFolder = getWorkspaceFolder(eclipseProjectFolder); } File referencedProjectFolder = getProjectFolder(workspaceFolder, frameworkName).getCanonicalFile(); if (referencedProjectFolder.exists()) { processEclipseProject(referencedProjectFolder, searchFolders, visitedProjects, env); } else { loadFrameworks(new String[] { frameworkName }, searchFolders, visitedProjects, env); } } } } } protected void loadFrameworks(String[] frameworkNames, List<ManifestSearchFolder> searchFolders, Set<File> visitedProjects, WOEnvironment env) throws IOException { File userFrameworksFolder = new File(env.getWOVariables().userFrameworkPath()); File localFrameworksFolder = new File(env.getWOVariables().localFrameworkPath()); File systemFrameworksFolder = new File(env.getWOVariables().systemFrameworkPath()); for (int frameworkNum = 1; frameworkNum < frameworkNames.length; frameworkNum++) { String frameworkFolderName = frameworkNames[frameworkNum] + ".framework"; File matchingFrameworkFolder = null; File userFrameworkFolder = new File(userFrameworksFolder, frameworkFolderName); if (userFrameworkFolder.exists()) { matchingFrameworkFolder = userFrameworkFolder.getCanonicalFile(); } else { File localFrameworkFolder = new File(localFrameworksFolder, frameworkFolderName); if (localFrameworkFolder.exists()) { matchingFrameworkFolder = localFrameworkFolder.getCanonicalFile(); } else { File systemFrameworkFolder = new File(systemFrameworksFolder, frameworkFolderName); if (systemFrameworkFolder.exists()) { matchingFrameworkFolder = systemFrameworkFolder.getCanonicalFile(); } } } if (matchingFrameworkFolder != null && !visitedProjects.contains(matchingFrameworkFolder)) { // System.out.println( // "EclipseProjectEOModelGroupFactory.processEclipseProject: framework = " // + matchingFrameworkFolder); ManifestSearchFolder searchFolder = new ManifestSearchFolder(new File(matchingFrameworkFolder, "Resources")); if (!searchFolders.contains(searchFolder)) { searchFolders.add(searchFolder); } visitedProjects.add(matchingFrameworkFolder); } } } @SuppressWarnings("unchecked") protected void findEclipseProjectFolders(File folder, List<File> eclipseProjectFolders) throws IOException, PropertyListParserException { if (folder != null) { boolean foundProjectFolders = false; if (folder.isDirectory()) { // System.out.println( // "EclipseProjectEOModelGroupFactory.findEclipseProjectFolders: Looking for '" // + folder + "' ..."); File projectLocator = new File(folder, ".EntityModeler.plist"); if (projectLocator.exists()) { // System.out.println( // "EclipseProjectEOModelGroupFactory.findEclipseProjectFolders: Found project locator '" // + projectLocator + "' ..."); Map<String, Object> projectProperties = (Map<String, Object>) WOLPropertyListSerialization.propertyListWithContentsOfFile(projectLocator.getCanonicalPath(), new SimpleParserDataStructureFactory()); Map<String, List<String>> dependencies = (Map<String, List<String>>) projectProperties.get("Dependencies"); if (dependencies != null) { List<String> projectFilePaths = dependencies.get("Eclipse"); if (projectFilePaths != null) { for (String projectFilePath : projectFilePaths) { File projectFolder = new File(projectFilePath); if (!projectFolder.exists()) { projectFolder = new File(folder, projectFilePath); } if (projectFolder.exists()) { projectFolder = projectFolder.getCanonicalFile(); if (isEclipseProjectFolder(projectFolder)) { // System.out.println( // "EclipseProjectEOModelGroupFactory.findEclipseProjectFolders: Found project '" // + projectFolder + "'"); eclipseProjectFolders.add(projectFolder); foundProjectFolders = true; } } } } } } else if (isEclipseProjectFolder(folder)) { // System.out.println( // "EclipseProjectEOModelGroupFactory.findEclipseProjectFolders: Found project '" // + folder + "'"); File eclipseProjectFolder = folder.getCanonicalFile(); eclipseProjectFolders.add(eclipseProjectFolder); foundProjectFolders = true; } } if (!foundProjectFolders) { File parentFolder = folder.getParentFile(); findEclipseProjectFolders(parentFolder, eclipseProjectFolders); } } } public boolean isEclipseProjectFolder(File folder) { return new File(folder, ".project").exists() && new File(folder, ".classpath").exists(); } }