Mercurial > hg > thermostat-tools-eclipse
view com.redhat.thermostat.tools.eclipse.plugin/src/com/redhat/thermostat/tools/eclipse/plugin/wizards/ProjectCreator.java @ 131:b40698bda910
Create a nested project structure
Put the parent pom in parent directory and the submodules in nested
directories. Use explicit paths when creating projects to teach
eclipse about this nested layout.
author | Omair Majid <omajid@redhat.com> |
---|---|
date | Fri, 30 May 2014 16:37:22 -0400 |
parents | df34d0465d83 |
children | 31d0ab4467ad |
line wrap: on
line source
package com.redhat.thermostat.tools.eclipse.plugin.wizards; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Set; import java.util.TreeSet; import org.eclipse.core.commands.ExecutionException; import org.eclipse.core.commands.NotEnabledException; import org.eclipse.core.commands.NotHandledException; import org.eclipse.core.commands.common.NotDefinedException; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IFolder; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IProjectDescription; import org.eclipse.core.resources.IWorkspace; import org.eclipse.core.resources.IWorkspaceRoot; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.Status; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.IPackageFragment; import org.eclipse.jdt.core.JavaCore; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.handlers.IHandlerService; import com.redhat.thermostat.tools.eclipse.plugin.Activator; import com.redhat.thermostat.tools.eclipse.plugin.wizards.PluginXmlCreator.Decisions; /** Creates a Thermostat project using the preferred thermostat defaults, settings, and style */ public class ProjectCreator { private static final String POM_FILE_NAME = "pom.xml"; private static final String POM_HEADER = "" + "<?xml version='1.0' encoding='UTF-8'?>\n" + "<project xsi:schemaLocation='http://maven.apache.org/POM/4.0.0\n" + " http://maven.apache.org/xsd/maven-4.0.0.xsd'\n" + " xmlns='http://maven.apache.org/POM/4.0.0'\n" + " xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'>\n" + "\n" + " <modelVersion>4.0.0</modelVersion>\n" + "\n"; private static final String POM_FOOTER = "" + "</project>\n"; private static final String OSGI_DEPENDENCIES_WITH_VERSION = "" + " <dependency>\n" + " <groupId>org.osgi</groupId>\n" + " <artifactId>org.osgi.core</artifactId>\n" + " <version>4.3.1</version>\n" + " </dependency>\n" + " <dependency>\n" + " <groupId>org.osgi</groupId>\n" + " <artifactId>org.osgi.compendium</artifactId>\n" + " <version>4.3.1</version>\n" + " </dependency>\n"; private static final String OSGI_DEPENDENCIES = "" + " <dependency>\n" + " <groupId>org.osgi</groupId>\n" + " <artifactId>org.osgi.core</artifactId>\n" + " </dependency>\n" + " <dependency>\n" + " <groupId>org.osgi</groupId>\n" + " <artifactId>org.osgi.compendium</artifactId>\n" + " </dependency>\n"; private static final String BUNDLE_PLUGIN_WITH_VERSION = "" + " <plugin>\n" + " <groupId>org.apache.felix</groupId>\n" + " <artifactId>maven-bundle-plugin</artifactId>\n" + " <version>2.3.7</version>\n" + " </plugin>\n"; private static final String BUNDLE_PLUGIN = "" + " <plugin>\n" + " <groupId>org.apache.felix</groupId>\n" + " <artifactId>maven-bundle-plugin</artifactId>\n" + " <extensions>true</extensions>\n" + " </plugin>\n"; private static final String BUNDLE_ACTIVATOR_NAME = "Activator"; private static final String BUNDLE_ACTIVATOR = "" + "package ${package.name};\n" // ${package.name} is replaced with actual package name + "\n" + "import org.osgi.framework.BundleActivator;\n" + "import org.osgi.framework.BundleContext;\n" + "\n" + "public class " + BUNDLE_ACTIVATOR_NAME + " implements BundleActivator {\n" + "\n" + " public void start(BundleContext context) throws Exception {\n" + " // TODO Auto-generated method stub\n" + " }\n" + "\n" + " public void stop(BundleContext context) throws Exception {\n" + " // TODO Auto-generated method stub\n" + " }\n" + "\n" + "}\n"; private IHandlerService serviceHandler; private String packagePrefix; private String groupId; private String artifactId; private String version; private String thermostatVersion; private String parentId; public ProjectCreator(String groupId, String artifactId, String version, String packagePrefix, String thermostatVersion) { this((IHandlerService) PlatformUI.getWorkbench().getService(IHandlerService.class), groupId, artifactId, version, packagePrefix, thermostatVersion); } public ProjectCreator(IHandlerService handler, String groupId, String artifactId, String version, String packagePrefix, String thermostatVersion) { this.serviceHandler = handler; this.groupId = groupId; this.artifactId = artifactId; this.version = version; this.packagePrefix = packagePrefix; this.thermostatVersion = thermostatVersion; this.parentId = artifactId + "-parent"; } public void create() throws CoreException, IOException { List<Project> projects = new ArrayList<>(); Project project; Project parent; project = parent = createParentModuleProject(); projects.add(project); project = createCommonSubproject(parent); projects.add(project); project = createJavaSubproject(parent, "agent"); projects.add(project); project = createJavaSubproject(parent, "client"); projects.add(project); project = createJavaSubproject(parent, "cli"); projects.add(project); project = createDistributionProject(parent); projects.add(project); refreshProjects(projects); } private Project createParentModuleProject() throws CoreException, IOException { String projectName = artifactId; Project project = createMavenProject(null, projectName); String pomContents = "" + POM_HEADER + " <groupId>" + groupId + "</groupId>\n" + " <artifactId>" + parentId + "</artifactId>\n" + " <version>" + version + "</version>\n" + " <packaging>pom</packaging>\n" + "\n" + " <modules>\n" + " <module>" + this.artifactId + "-agent</module>\n" + " <module>" + this.artifactId + "-common</module>\n" + " <module>" + this.artifactId + "-client</module>\n" + " <module>" + this.artifactId + "-cli</module>\n" + " <module>" + this.artifactId + "-distribution</module>\n" + " </modules>\n" + "\n" + " <build>\n" + " <pluginManagement>\n" + " <plugins>\n" + BUNDLE_PLUGIN_WITH_VERSION + " </plugins>\n" + " </pluginManagement>\n" + " </build>\n" + "\n" + " <dependencyManagement>\n" + " <dependencies>\n" + OSGI_DEPENDENCIES_WITH_VERSION + " </dependencies>\n" + " </dependencyManagement>\n" + POM_FOOTER; createPomFile(project, pomContents); return project; } private Project createCommonSubproject(Project parent) throws IOException, CoreException { String suffix = "common"; String artifactId = this.artifactId + "-" + suffix; String packageName = packagePrefix + "." + suffix; Project project = createJavaCodeProject(parent, artifactId, packageName); String pomContents = "" + POM_HEADER + "\n" + createParentSection(groupId, parentId, version) + "\n" + " <artifactId>" + artifactId + "</artifactId>\n" + " <packaging>bundle</packaging>\n" + "\n" + " <build>\n" + " <plugins>\n" + BUNDLE_PLUGIN + " </plugins>\n" + " </build>\n" + "\n" + " <dependencies>\n" + OSGI_DEPENDENCIES + " </dependencies>\n" + POM_FOOTER; createPomFile(project, pomContents); return project; } private Project createJavaSubproject(Project parent, String subproject) throws CoreException, IOException { String artifactId = this.artifactId + "-" + subproject; String subpackage = this.packagePrefix + "." + subproject; Project project = createJavaCodeProject(parent, artifactId, subpackage); String pomContents = "" + POM_HEADER + createParentSection(groupId, parentId, version) + "\n" + " <artifactId>" + artifactId + "</artifactId>\n" + " <packaging>bundle</packaging>\n" + "\n" + " <build>\n" + " <plugins>\n" + BUNDLE_PLUGIN + " </plugins>\n" + " </build>\n" + "\n" + " <dependencies>\n" + " <dependency>\n" + " <groupId>" + groupId + "</groupId>\n" + " <artifactId>" + this.artifactId + "-common</artifactId>\n" + " <version>" + version + "</version>\n" + " </dependency>\n" + OSGI_DEPENDENCIES + " </dependencies>\n" + POM_FOOTER; createPomFile(project, pomContents); return project; } private Project createJavaCodeProject(Project parent, String projectName, String packageName) throws CoreException { Project projects = createJavaAndMavenProject(parent, projectName); IProject project = projects.project; IFolder srcFolder = project.getFolder("src"); srcFolder.create(false, true, null); IFolder srcMainFolder = srcFolder.getFolder("main"); srcMainFolder.create(true, true, null); IFolder srcMainJavaFolder = srcMainFolder.getFolder("java"); srcMainJavaFolder.create(true, true, null); IFolder srcTestFolder = srcFolder.getFolder("test"); srcTestFolder.create(true, true, null); IFolder srcTestJavaFolder = srcTestFolder.getFolder("java"); srcTestJavaFolder.create(true, true, null); createBundleActivator(projects, srcMainJavaFolder, packageName); return projects; } private void createBundleActivator(Project projects, IFolder root, String packageName) throws CoreException { IJavaProject javaProject = projects.javaProject; IPackageFragment pack = javaProject.getPackageFragmentRoot(root) .createPackageFragment(packageName, false, null); String bundleActivatorContents = BUNDLE_ACTIVATOR.replace("${package.name}", pack.getElementName()); pack.createCompilationUnit(BUNDLE_ACTIVATOR_NAME + ".java", bundleActivatorContents, false, null); } private Project createDistributionProject(Project parent) throws CoreException, IOException { String artifactId = this.artifactId + "-distribution"; Project projects = createJavaAndMavenProject(parent, artifactId); String pomContents = "" + POM_HEADER + createParentSection(groupId, parentId, version) + "\n" + " <artifactId>" + artifactId + "</artifactId>\n" + " <packaging>jar</packaging>\n" + "\n" + " <properties>\n" + " <thermostat.plugin>" + this.artifactId + "</thermostat.plugin>\n" + " </properties>\n" + "\n" + " <build>\n" + " <plugins>\n" + " <plugin>\n" + " <artifactId>maven-assembly-plugin</artifactId>\n" + " <dependencies>\n" + " <dependency>\n" + " <groupId>com.redhat.thermostat</groupId>\n" + " <artifactId>thermostat-assembly</artifactId>\n" + " <version>" + thermostatVersion + "</version>\n" + " </dependency>\n" + " </dependencies>\n" + " <configuration>\n" + " <descriptorRefs>\n" + " <descriptorRef>plugin-assembly</descriptorRef>\n" + " </descriptorRefs>\n" + " <appendAssemblyId>false</appendAssemblyId>\n" + " </configuration>\n" + " <executions>\n" + " <execution>\n" + " <id>assemble-plugin</id>\n" + " <phase>package</phase>\n" + " <goals>\n" + " <goal>single</goal>\n" + " </goals>\n" + " </execution>\n" + " </executions>\n" + " </plugin>\n" + " </plugins>\n" + " </build>\n" + "\n" + " <!-- Explicitly list all plug-in artifacts, transitive dependencies\n" + " are not included in assembly. -->\n" + " <dependencies>\n" + " <dependency>\n" + " <groupId>" + groupId + "</groupId>\n" + " <artifactId>" + this.artifactId + "-agent</artifactId>\n" + " <version>${project.version}</version>\n" + " </dependency>\n" + " <dependency>\n" + " <groupId>" + groupId + "</groupId>\n" + " <artifactId>" + this.artifactId + "-common</artifactId>\n" + " <version>${project.version}</version>\n" + " </dependency>\n" + " <dependency>\n" + " <groupId>" + groupId + "</groupId>\n" + " <artifactId>" + this.artifactId + "-client</artifactId>\n" + " <version>${project.version}</version>\n" + " </dependency>\n" + " <dependency>\n" + " <groupId>" + groupId + "</groupId>\n" + " <artifactId>" + this.artifactId + "-cli</artifactId>\n" + " <version>${project.version}</version>\n" + " </dependency>\n" + " </dependencies>\n" + POM_FOOTER; createPomFile(projects, pomContents); IProject project = projects.project; IFolder srcFolder = project.getFolder("src"); srcFolder.create(false, true, null); IFolder srcMainFolder = srcFolder.getFolder("main"); srcMainFolder.create(true, true, null); IFolder srcMainResourcesFolder = srcMainFolder.getFolder("resources"); srcMainResourcesFolder.create(true, true, null); createThermostatPluginXml(project.getName()); return projects; } private void createThermostatPluginXml(String projectName) throws CoreException, IOException { PluginXmlCreator creator = new PluginXmlCreator(ResourcesPlugin.getWorkspace().getRoot()); creator.create(projectName, new NullProgressMonitor(), new Decisions() { @Override public boolean overwriteExistingFile() { return true; } }); } private Project createJavaAndMavenProject(Project parent, String projectName) throws CoreException { Project project = createMavenProject(parent, projectName); addJavaNature(project.project); IJavaProject javaProject = JavaCore.create(project.project); return new Project(project.project, javaProject); } private Project createMavenProject(Project parent, String projectName) throws CoreException { IWorkspace workspace = ResourcesPlugin.getWorkspace(); IWorkspaceRoot root = workspace.getRoot(); IProject project = root.getProject(projectName); if (project.exists()) { project.delete(true, null); } try { if (parent == null) { project.create(null); } else { IProjectDescription description = workspace.newProjectDescription(projectName); description.setLocation(parent.project.getLocation().append(projectName)); project.create(description, null); } project.open(null); } catch (CoreException e) { e.printStackTrace(); } addMavenNature(project); return new Project(project, null); } private void addJavaNature(IProject project) throws CoreException { IProjectDescription description = project.getDescription(); addJavaNature(description); project.setDescription(description, null); } private void addJavaNature(IProjectDescription description) { addNature(description, JavaCore.NATURE_ID); } private void addMavenNature(IProject project) throws CoreException { IProjectDescription description = project.getDescription(); addMavenNature(description); project.setDescription(description, null); } private void addMavenNature(IProjectDescription description) { // provided by m2e // TODO what's the symbolic constant for this? IMavenConstants.NATURE_ID? addNature(description, "org.eclipse.m2e.core.maven2Nature"); } private void addNature(IProjectDescription description, String nature) { String[] existingNatureIds = description.getNatureIds(); Set<String> natures = new TreeSet<>(Arrays.asList(existingNatureIds)); natures.add(nature); String[] newNatureIds = natures.toArray(new String[natures.size()]); description.setNatureIds(newNatureIds); } private void createPomFile(Project projects, String contents) throws IOException, CoreException { IProject project = projects.project; IFile pomFile = project.getFile(POM_FILE_NAME); try (InputStream contentStream = new ByteArrayInputStream(contents.getBytes(StandardCharsets.UTF_8))) { if (pomFile.exists()) { pomFile.setContents(contentStream, true, true, null); } else { pomFile.create(contentStream, true, null); } } } private String createParentSection(String groupId, String parentId, String version) { return "" + " <parent>\n" + " <groupId>" + groupId + "</groupId>\n" + " <artifactId>" + parentId + "</artifactId>\n" + " <version>" + version + "</version>\n" + " </parent>\n"; } private void refreshProjects(List<Project> projects) throws CoreException { // Refresh projects ResourcesPlugin.getWorkspace().getRoot().refreshLocal(IWorkspaceRoot.DEPTH_INFINITE, new NullProgressMonitor()); // Refresh again, just to make sure changes are sane by the time maven sees them ResourcesPlugin.getWorkspace().getRoot().refreshLocal(IWorkspaceRoot.DEPTH_INFINITE, new NullProgressMonitor()); // TODO wait for refresh to complete tellM2eAboutNewProjects(projects); } private void tellM2eAboutNewProjects(List<Project> projects) throws CoreException { try { refreshMavenProjectUsingInternalApi(projects); } catch (UnsupportedOperationException e) { try { refreshMavenProjectUsingUglyButPublicCommandFallback(); } catch (UnsupportedOperationException e2) { Status s = new Status(IStatus.ERROR, Activator.PLUGIN_ID, "Error refreshing maven configuration", e2); throw new CoreException(s); } } } private void refreshMavenProjectUsingInternalApi(List<Project> projects) throws UnsupportedOperationException { List<IProject> actualProjects = new ArrayList<>(); for (Project project : projects) { actualProjects.add(project.project); } IProject[] projectsToUpdate = actualProjects.toArray(new IProject[0]); try { // UpdateMavenProjectJob updateProjectsJob = new UpdateMavenProjectJob(projectsToUpdate); Class<?> klass = Class.forName("org.eclipse.m2e.core.ui.internal.UpdateMavenProjectJob"); Constructor<?> constructor = klass.getConstructor(IProject[].class); Object updateProjectsJob = constructor.newInstance((Object)projectsToUpdate); // updateProjectsJob.schedule(); Method schedule = klass.getMethod("schedule"); schedule.invoke(updateProjectsJob); } catch (ReflectiveOperationException | SecurityException | IllegalArgumentException e) { throw new UnsupportedOperationException("Incompatible m2e version", e); } } /** This interrupts the UI by showing a completely un-needed prompt */ private void refreshMavenProjectUsingUglyButPublicCommandFallback() throws UnsupportedOperationException { final String UPADATE_MAVEN_PROJECT_COMMAND = "org.eclipse.m2e.core.ui.command.updateProject"; try { serviceHandler.executeCommand(UPADATE_MAVEN_PROJECT_COMMAND, null); } catch (ExecutionException | NotDefinedException | NotEnabledException | NotHandledException e) { throw new UnsupportedOperationException("Unable to refresh m2e using " + UPADATE_MAVEN_PROJECT_COMMAND); } } private static class Project { private final IProject project; private final IJavaProject javaProject; public Project(IProject project, IJavaProject javaProject) { this.project = project; this.javaProject = javaProject; } } }