package com.hybris.yps.hyeclipse.utils; import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardCopyOption; import java.util.Arrays; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.ListIterator; import java.util.Set; import org.apache.tools.ant.util.StringUtils; import org.eclipse.core.resources.ICommand; import javax.xml.XMLConstants; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.TransformerFactoryConfigurationError; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import org.eclipse.core.resources.IFolder; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IProjectDescription; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.jdt.core.IClasspathEntry; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.JavaModelException; import org.w3c.dom.Attr; import org.w3c.dom.Comment; import org.w3c.dom.Document; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.xml.sax.ErrorHandler; import org.xml.sax.SAXException; import org.xml.sax.SAXParseException; import com.hybris.yps.hyeclipse.Activator; import com.hybris.yps.hyeclipse.ExtensionHolder; public class FixProjectsUtils { private static Activator plugin = Activator.getDefault(); private static final boolean debug = plugin.isDebugging(); public static Set<ExtensionHolder> getAllExtensionsForPlatform(String platformHome) { Set<ExtensionHolder> allExtensions = plugin.getAllExtensionsForPlatform(platformHome); return allExtensions; } public static String getConfigDirectory() { return plugin.getConfigDirectory(); } public static Set<IProject> getProjectsNotInLocalExtensionsFile(String platformHome) { Set<ExtensionHolder> exts = getAllExtensionsForPlatform(platformHome); Set<IProject> allHybrisProjects = getAllHybrisProjects(); Set<IProject> projectsNotInLocalExts = new HashSet<IProject>(); if (debug) Activator.log("Getting Projects not in localextensions.xml"); for (IProject project : allHybrisProjects) { boolean found = false; for (ExtensionHolder ext : exts) { Path projectLocation = Paths.get(project.getLocation().toFile().getAbsolutePath()); Path extLocation = Paths.get(ext.getPath()); try { if (Files.isSameFile(projectLocation, extLocation) || (project.getName().equals("platform") || (project.getName().equals("config")))) { if (debug) Activator.log("Ext in workspace and localextensions.xml: ext [" + ext.getPath() + "] project [" + project.getLocation().toFile().getAbsolutePath() + "]"); found = true; break; } } catch (IOException e) { throw new IllegalStateException(e); } } // if we get here there is no path if (!found) { if (debug) Activator.log("No match in localextensions for project [" + project.getName() + "] path [" + project.getLocation().toFile().getAbsolutePath() + "]"); if (!project.getName().equals("platform") && !project.getName().equals("config")) { projectsNotInLocalExts.add(project); } } } return projectsNotInLocalExts; } public static Set<ExtensionHolder> getExtensionsNotInWorkspace(String platformHome) { Set<ExtensionHolder> exts = getAllExtensionsForPlatform(platformHome); // add platform and config to the list of extensions ExtensionHolder platformHolder = new ExtensionHolder(platformHome,"platform"); exts.add(platformHolder); ExtensionHolder configHolder = new ExtensionHolder(getConfigDirectory(),"config"); exts.add(configHolder); Set<IProject> allHybrisProjects = getAllHybrisProjects(); Set<ExtensionHolder> extensionsNotInWorkspace = new HashSet<ExtensionHolder>(); if (debug) Activator.log("Getting extensions not in workspace"); for (ExtensionHolder ext : exts) { boolean found = false; for (IProject project : allHybrisProjects) { if (debug) Activator.log("ext [" + ext.getPath() + "] project [" + project.getLocation().toFile().getAbsolutePath() + "]"); Path projectLocation = Paths.get(project.getLocation().toFile().getAbsolutePath()); Path extLocation = Paths.get(ext.getPath()); try { if (Files.isSameFile(projectLocation, extLocation)) { if (debug) Activator.log("Match in workspace and localextensions.xml: ext [" + ext.getPath() + "] project [" + project.getLocation().toFile().getAbsolutePath() + "]"); found = true; break; } } catch (IOException e) { throw new IllegalStateException(e); } } // if we get here there is no match if (!found) { if (debug) Activator.log("No match in workspace for extension [" + ext.getName() + "] path [" + ext.getPath() + "]"); extensionsNotInWorkspace.add(ext); } } return extensionsNotInWorkspace; } /** * We don't want to touch any projects that are not hybris extensions so we do some filtering * @return */ public static Set<IProject> getAllHybrisProjects() { final Set<IProject> filteredProjects = new HashSet<IProject>(); final IProject[] projects = ResourcesPlugin.getWorkspace().getRoot().getProjects(); for (IProject project : projects) { if (isAHybrisExtension(project)) { if (debug) Activator.log("hybris project found [" + project.getName() + "]"); filteredProjects.add(project); } } return filteredProjects; } public static Set<IProject> getAllOpenHybrisProjects() { final Set<IProject> filteredProjects = new HashSet<IProject>(); final IProject[] projects = ResourcesPlugin.getWorkspace().getRoot().getProjects(); for (IProject project : projects) { if (isAHybrisExtension(project) && project.isOpen()) { if (debug) Activator.log("hybris project found [" + project.getName() + "]"); filteredProjects.add(project); } } return filteredProjects; } /** * Return true if there is an extensioninfo.xml file in the root of the project directory * @param project * @return */ public static boolean isAHybrisExtension(IProject project) { // handle the 2 special cases if (project.getName().equals("platform") || project.getName().equals("config")) { return true; } else { String extensionInfoPath = project.getLocation().toFile().getAbsolutePath() + "/extensioninfo.xml"; return new File(extensionInfoPath).exists(); } } public static boolean isAPlatformExtension(IProject project) { String path = project.getLocation().toFile().getAbsolutePath(); String binDir = "bin" + File.separator; return (path.indexOf(binDir + "ext-") > 0 || path.indexOf(binDir + "platform") > 0); } public static boolean isATemplateExtension(IProject project) { return project.getLocation().toFile().getAbsolutePath().indexOf("ext-template") > 0; } public static boolean isACustomerExtension(IProject project) { return !isAPlatformExtension(project) && !project.getName().equals("config"); } public static Set<IProject> getAllPlatformProjects() { final Set<IProject> filteredProjects = new HashSet<IProject>(); final IProject[] projects = ResourcesPlugin.getWorkspace().getRoot().getProjects(); for (IProject project : projects) { if (isAHybrisExtension(project) && isAPlatformExtension(project)) { filteredProjects.add(project); } } return filteredProjects; } public static Set<IProject> getAllCustomerProjects() { final Set<IProject> filteredProjects = new HashSet<IProject>(); final IProject[] projects = ResourcesPlugin.getWorkspace().getRoot().getProjects(); for (IProject project : projects) { if (isAHybrisExtension(project) && isACustomerExtension(project)) { filteredProjects.add(project); } } return filteredProjects; } public static void addSourceDirectoriesIfExistingForDir(IProgressMonitor monitor, IProject project, IJavaProject javaProject, String dir) throws JavaModelException { if (project.getFolder(dir).exists()) { if (!isOnClasspath(project.getFolder(dir),javaProject, IClasspathEntry.CPE_SOURCE)) { // check that we don't have the project on the classpath as a source extension if (isOnClasspath(project,javaProject, IClasspathEntry.CPE_SOURCE)) { removeFromClassPath(project, IClasspathEntry.CPE_SOURCE, javaProject, monitor); } addToClassPath(project.getFolder(dir), IClasspathEntry.CPE_SOURCE, javaProject, monitor); } } } /** * Add *all* the *currently existing* sources directories to the project. * They will be pruned later in updateExtensionModules(). */ public static void addSourceDirectoriesIfExisting(IProgressMonitor monitor, IProject project, IJavaProject javaProject) throws JavaModelException { // fix sources directories (if src and gensrc exist in the project then add then) addSourceDirectoriesIfExistingForDir(monitor, project, javaProject, "/src"); addSourceDirectoriesIfExistingForDir(monitor, project, javaProject, "/gensrc"); addSourceDirectoriesIfExistingForDir(monitor, project, javaProject, "/testsrc"); addSourceDirectoriesIfExistingForDir(monitor, project, javaProject, "/web/src"); addSourceDirectoriesIfExistingForDir(monitor, project, javaProject, "/hmc/src"); addSourceDirectoriesIfExistingForDir(monitor, project, javaProject, "/web/testsrc"); addSourceDirectoriesIfExistingForDir(monitor, project, javaProject, "/acceleratoraddon/web/src"); } /** * Using IJavaProject.isOnClasspath() is not accurate * @throws JavaModelException */ private static boolean isOnClasspath(IResource resource, IJavaProject javaProject, int type) throws JavaModelException { for (IClasspathEntry classPath : javaProject.getRawClasspath()) { if (classPath.getEntryKind() == type) { if (resource.getFullPath().equals(classPath.getPath())) { return true; } } } return false; } private static void removeSourceDirectoryIfNotExsistingForDir(IProgressMonitor monitor, IProject project, IJavaProject javaProject, String dir) throws JavaModelException { if (!project.getFolder(dir).exists()) { if (javaProject.isOnClasspath(project.getFolder(dir))) { removeFromClassPath(project.getFolder(dir), IClasspathEntry.CPE_SOURCE, javaProject, monitor); } } } public static void removeSourceDirectoriesIfNotExisting(IProgressMonitor monitor, IProject project, IJavaProject javaProject) throws JavaModelException { // fix sources directories (if src and gensrc exist in the project then add then) removeSourceDirectoryIfNotExsistingForDir(monitor, project, javaProject, "/src"); removeSourceDirectoryIfNotExsistingForDir(monitor, project, javaProject, "/gensrc"); removeSourceDirectoryIfNotExsistingForDir(monitor, project, javaProject, "/testsrc"); removeSourceDirectoryIfNotExsistingForDir(monitor, project, javaProject, "/acceleratoraddon/web/src"); removeSourceDirectoryIfNotExsistingForDir(monitor, project, javaProject, "/acceleratoraddon/web/webroot/WEB-INF/tags"); removeSourceDirectoryIfNotExsistingForDir(monitor, project, javaProject, "/acceleratoraddon/web/webroot/WEB-INF/views"); removeSourceDirectoryIfNotExsistingForDir(monitor, project, javaProject, "/acceleratoraddon/web/webroot/WEB-INF/tld"); } public static void removeFromClassPath(IResource res, int type, IJavaProject javaProject, IProgressMonitor monitor) throws JavaModelException { List<IClasspathEntry> entries = new LinkedList<IClasspathEntry>(Arrays.asList(javaProject.getRawClasspath())); ListIterator<IClasspathEntry> iterator = entries.listIterator(); boolean changed = false; while (iterator.hasNext()) { IClasspathEntry entry = iterator.next(); if (entry.getEntryKind() == IClasspathEntry.CPE_SOURCE) { if (res.getFullPath().equals(entry.getPath())) { changed = true; if (debug) Activator.log("Removing src path [" + res.getFullPath() + "] for project [" + javaProject.getProject().getName() + "]"); iterator.remove(); } } } if (changed) { setClasspath(entries.toArray(new IClasspathEntry[entries.size()]), javaProject, monitor); } } public static void addToClassPath(IResource res, int type, IJavaProject javaProject, IProgressMonitor monitor) throws JavaModelException { Set<IClasspathEntry> entries = new HashSet<IClasspathEntry>(Arrays.asList(javaProject.getRawClasspath())); IClasspathEntry entry = null; switch (type) { case IClasspathEntry.CPE_SOURCE: entry = JavaCore.newSourceEntry(res.getFullPath()); break; case IClasspathEntry.CPE_LIBRARY: entry = JavaCore.newLibraryEntry(res.getFullPath(), null, null, true); break; case IClasspathEntry.CPE_PROJECT: entry = JavaCore.newProjectEntry(res.getFullPath(), true); break; } entries.add(entry); setClasspath(entries.toArray(new IClasspathEntry[entries.size()]), javaProject, monitor); } public static void setClasspath(IClasspathEntry[] classpath, IJavaProject javaProject, IProgressMonitor monitor) throws JavaModelException { // backup .classpath File classPathFileBak = javaProject.getProject().getFile(".classpath.bak").getLocation().toFile(); if (!classPathFileBak.exists()) { File classPathFile = javaProject.getProject().getFile(".classpath").getLocation().toFile(); try { Files.copy(Paths.get(classPathFile.getAbsolutePath()), Paths.get(classPathFileBak.getAbsolutePath()), StandardCopyOption.REPLACE_EXISTING); } catch (IOException e) { // can't back up file but we should continue anyway Activator.log("Failed to backup classfile [" + classPathFile.getAbsolutePath() + "]"); } } javaProject.setRawClasspath(classpath, monitor); } public static void removeBuildersFromProject(IProgressMonitor monitor, IProject project) throws CoreException { final IProjectDescription description = project.getDescription(); // remove hybris builder for (ICommand build : project.getDescription().getBuildSpec()) { if (build.getBuilderName().equals("org.eclipse.jdt.core.javabuilder")) { description.setBuildSpec(new ICommand[] { build }); project.setDescription(description, monitor); break; } } } public static void updateExtensionModules(final ExtensionHolder extension, IProgressMonitor monitor) throws TransformerFactoryConfigurationError { monitor.beginTask("Removing module info", 10); String extensionPath = extension.getPath(); File extInfo = new File(extensionPath, "extensioninfo.xml"); if (extInfo.exists()) { try { IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(extension.getName()); DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance(); docFactory.setValidating(true); docFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); docFactory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); DocumentBuilder docBuilder = docFactory.newDocumentBuilder(); docBuilder.setErrorHandler(new ErrorHandler(){ @Override public void fatalError(SAXParseException exception) throws SAXException {} @Override public void error(SAXParseException exception) throws SAXException {} @Override public void warning(SAXParseException exception) throws SAXException {} }); Document doc = docBuilder.parse(extInfo); boolean updateProject = false; if (!extension.isCoreModule()) { String moduleName = "coremodule"; removeAndAddComment(doc, moduleName); //Remove 'src' directory removeSourceFolder(monitor, project, "src", "src"); //Remove 'gensrc' directory removeSourceFolder(monitor, project, "gensrc", "gensrc"); //Remove 'testsrc' directory removeSourceFolder(monitor, project, "testsrc", "testsrc"); //Remove *-items.xml, *-spring.xml project.getFile("resources/" + extension.getName() + "-spring.xml").delete(true, false, monitor); project.getFile("resources/" + extension.getName() + "-items.xml").delete(true, false, monitor); updateProject = true; } if (!extension.isWebModule()) { String moduleName = "webmodule"; removeAndAddComment(doc, moduleName); //Remove 'web' directory removeSourceFolder(monitor, project, "web", "web/src"); removeSourceFolder(monitor, project, "web", "web/testsrc"); updateProject = true; } if (!extension.isHmcModule()) { String moduleName = "hmcmodule"; removeAndAddComment(doc, moduleName); //Remove 'hmc' directory removeSourceFolder(monitor, project, "hmc", "hmc/src"); updateProject = true; } if (updateProject) { // write the content into xml file TransformerFactory transformerFactory = TransformerFactory.newInstance(); transformerFactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); transformerFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, ""); transformerFactory.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, ""); Transformer transformer = transformerFactory.newTransformer(); DOMSource source = new DOMSource(doc); StreamResult result = new StreamResult(new File(extensionPath, "extensioninfo.xml")); transformer.transform(source, result); monitor.worked(5); //Refresh local project project.refreshLocal(IResource.DEPTH_INFINITE, monitor); } } catch (ParserConfigurationException pce) { Activator.logError("InvocationTargetException", pce); } catch (TransformerException tfe) { Activator.logError("InvocationTargetException", tfe); } catch (IOException ioe) { Activator.logError("InvocationTargetException", ioe); } catch (SAXException sae) { Activator.logError("InvocationTargetException", sae); } catch (CoreException e) { Activator.logError("InvocationTargetException", e); } } monitor.worked(5); monitor.done(); } private static void removeSourceFolder(IProgressMonitor monitor, IProject project, String folderName, String classpathEntry) throws CoreException, JavaModelException { IFolder webFolder = project.getFolder(folderName); if(webFolder != null){ webFolder.delete(true, false, monitor); } //Project is missing required source folder: 'web/src' IJavaProject javaProject = JavaCore.create(project); if (javaProject.isOnClasspath(project.getFolder(classpathEntry))) { FixProjectsUtils.removeFromClassPath(project.getFolder(classpathEntry), IClasspathEntry.CPE_SOURCE, javaProject, monitor); } } private static void removeAndAddComment(Document doc, String moduleName) { Node extensionNode; Node moduleNode; moduleNode = doc.getElementsByTagName(moduleName).item(0); if (moduleNode != null) { extensionNode = moduleNode.getParentNode(); NamedNodeMap attrs = moduleNode.getAttributes(); StringBuilder sb = new StringBuilder("<"); sb.append(moduleName); for (int i = 0 ; i<attrs.getLength() ; i++) { Attr attribute = (Attr)attrs.item(i); sb.append(" " + attribute.getName() + "=\"" + attribute.getValue() + "\""); } sb.append("/>"); appendXmlFragment(extensionNode, sb.toString()); extensionNode.removeChild(moduleNode); } } private static void appendXmlFragment(Node parent, String fragment){ Document doc = parent.getOwnerDocument(); Comment comment = doc.createComment(fragment); parent.appendChild(comment); } public static void setOutputDirectory(IProgressMonitor monitor, IProject project, IJavaProject javaProject) { IPath outputLocation = null, newOutputLocation = null; try { outputLocation = javaProject.getOutputLocation(); // Only change the output location if it is the eclipse default one "bin" if ("bin".equals(outputLocation.lastSegment())) { newOutputLocation = outputLocation.removeLastSegments(1).append("eclipsebin"); javaProject.setOutputLocation(newOutputLocation, monitor); } } catch (JavaModelException e) { System.err.println("project:" + project.getName()); System.err.println("outputLocation:" + outputLocation); System.err.println("newOutputLocation:" + newOutputLocation); Activator.logError("Could not set output directory", e); } } }