/** * Copyright (c) 2006-2010 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM - Initial API and implementation */ package org.eclipse.emf.codegen.ecore.genmodel.generator; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.List; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IWorkspace; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.Path; import org.eclipse.emf.codegen.ecore.CodeGenEcorePlugin; import org.eclipse.emf.codegen.ecore.Generator; import org.eclipse.emf.codegen.ecore.generator.AbstractGeneratorAdapter; import org.eclipse.emf.codegen.ecore.generator.GeneratorAdapterFactory; import org.eclipse.emf.codegen.ecore.genmodel.GenBase; import org.eclipse.emf.codegen.ecore.genmodel.GenModel; import org.eclipse.emf.codegen.ecore.genmodel.GenPackage; import org.eclipse.emf.codegen.ecore.genmodel.GenRuntimePlatform; import org.eclipse.emf.codegen.jet.JETEmitter; import org.eclipse.emf.codegen.jet.JETException; import org.eclipse.emf.common.EMFPlugin; import org.eclipse.emf.common.util.Diagnostic; import org.eclipse.emf.common.util.Monitor; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.common.util.UniqueEList; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.emf.ecore.resource.ResourceSet; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.JavaCore; /** * A base generator adapter implementation for GenModel elements. * * This base defines four project types for code generation and provides implementations of * {@link #canGenerate(Object, Object)}, {@link #getGenerateChildren(Object, Object)}, and * {@link #doGenerate(Object, Object, Monitor)} that dispatch to project-type-specific methods, which * can be overridden in subclasses. * * @since 2.2.0 */ public class GenBaseGeneratorAdapter extends AbstractGeneratorAdapter { /** * The project type constant representing a model project. * This is the string "org.eclipse.emf.codegen.ecore.genmodel.generator.ModelProject". */ public static final String MODEL_PROJECT_TYPE = "org.eclipse.emf.codegen.ecore.genmodel.generator.ModelProject"; /** * The project type constant representing an edit project. * This is the string "org.eclipse.emf.codegen.ecore.genmodel.generator.EditProject". */ public static final String EDIT_PROJECT_TYPE = "org.eclipse.emf.codegen.ecore.genmodel.generator.EditProject"; /** * The project type constant representing an editor project. * This is the string "org.eclipse.emf.codegen.ecore.genmodel.generator.EditorProject". */ public static final String EDITOR_PROJECT_TYPE = "org.eclipse.emf.codegen.ecore.genmodel.generator.EditorProject"; /** * The project type constant representing a tests project. * This is the string "org.eclipse.emf.codegen.ecore.genmodel.generator.TestsProject". */ public static final String TESTS_PROJECT_TYPE = "org.eclipse.emf.codegen.ecore.genmodel.generator.TestsProject"; public GenBaseGeneratorAdapter() { super(); } public GenBaseGeneratorAdapter(GeneratorAdapterFactory generatorAdapterFactory) { super(generatorAdapterFactory); } /** * Based on the given project type, dispatches to one of {@link #canGenerateModel(Object)}, * {@link #canGenerateEdit(Object)}, {@link #canGenerateEditor(Object)}, or {@link #canGenerateTests(Object)}. */ @Override public boolean canGenerate(Object object, Object projectType) { if (MODEL_PROJECT_TYPE.equals(projectType)) { return canGenerateModel(object); } else if (EDIT_PROJECT_TYPE.equals(projectType)) { return canGenerateEdit(object); } else if (EDITOR_PROJECT_TYPE.equals(projectType)) { return canGenerateEditor(object); } else if (TESTS_PROJECT_TYPE.equals(projectType)) { return canGenerateTests(object); } return false; } /** * Delegates to the GenModel element's {@link GenBase#canGenerate() canGenerate()} method. */ public boolean canGenerateModel(Object object) { return ((GenBase)object).canGenerate(); } /** * Delegates to the GenModel element's {@link GenBase#canGenerateEdit() canGenerateEdit()} method. */ public boolean canGenerateEdit(Object object) { return ((GenBase)object).canGenerateEdit(); } /** * Delegates to the GenModel element's {@link GenBase#canGenerateEditor() canGenerateEditor()} method. */ public boolean canGenerateEditor(Object object) { return ((GenBase)object).canGenerateEditor(); } /** * Delegates to the GenModel element's {@link GenBase#canGenerateTests() canGenerateTests()} method. */ public boolean canGenerateTests(Object object) { return ((GenBase)object).canGenerateTests(); } /** * Based on the given project type, dispatches to one of {@link #getGenerateModelChildren(Object)}, * {@link #getGenerateEditChildren(Object)}, {@link #getGenerateEditorChildren(Object)}, or * {@link #getGenerateTestsChildren(Object)}. */ @Override public Collection<?> getGenerateChildren(Object object, Object projectType) { if (MODEL_PROJECT_TYPE.equals(projectType)) { return getGenerateModelChildren(object); } else if (EDIT_PROJECT_TYPE.equals(projectType)) { return getGenerateEditChildren(object); } else if (EDITOR_PROJECT_TYPE.equals(projectType)) { return getGenerateEditorChildren(object); } else if (TESTS_PROJECT_TYPE.equals(projectType)) { return getGenerateTestsChildren(object); } return Collections.EMPTY_LIST; } protected Collection<?> getGenerateModelChildren(Object object) { return Collections.EMPTY_LIST; } protected Collection<?> getGenerateEditChildren(Object object) { return Collections.EMPTY_LIST; } protected Collection<?> getGenerateEditorChildren(Object object) { return Collections.EMPTY_LIST; } protected Collection<?> getGenerateTestsChildren(Object object) { return Collections.EMPTY_LIST; } /** * Returns the container of the given object if it is a GenModel element, and null otherwise. */ protected Object getParent(Object object) { Object result = ((GenBase)object).eContainer(); return result instanceof GenBase ? result : null; } /** * Based on the given project type, dispatches to one of {@link #generateModel(Object, Monitor)}, * {@link #generateEdit(Object, Monitor)}, {@link #generateEditor(Object, Monitor)}, or * {@link #generateTests(Object, Monitor)}. */ @Override public Diagnostic doGenerate(Object object, Object projectType, Monitor monitor) { if (MODEL_PROJECT_TYPE.equals(projectType)) { return generateModel(object, monitor); } else if (EDIT_PROJECT_TYPE.equals(projectType)) { return generateEdit(object, monitor); } else if (EDITOR_PROJECT_TYPE.equals(projectType)) { return generateEditor(object, monitor); } else if (TESTS_PROJECT_TYPE.equals(projectType)) { return generateTests(object, monitor); } throw new IllegalArgumentException("Invalid projectType: " + projectType.toString()); } protected Diagnostic generateModel(Object object, Monitor monitor) { return Diagnostic.OK_INSTANCE; } protected Diagnostic generateEdit(Object object, Monitor monitor) { return Diagnostic.OK_INSTANCE; } protected Diagnostic generateEditor(Object object, Monitor monitor) { return Diagnostic.OK_INSTANCE; } protected Diagnostic generateTests(Object object, Monitor monitor) { return Diagnostic.OK_INSTANCE; } /** * Returns the user-specified portion of the dynamic template path from the GenModel. * @since org.eclipse.emf.codegen.ecore 2.2.2 */ @Override protected List<String> getUserTemplatePath() { String templateLocation = ((GenBase)generatingObject).getGenModel().getTemplateDirectory(); if (templateLocation != null && templateLocation.length() != 0) { if (templateLocation.indexOf(':') == -1) { templateLocation = URI.createPlatformResourceURI(templateLocation, true).toString(); } return Collections.singletonList(templateLocation); } return Collections.emptyList(); } /** * Adds the default EMF template location to the base portion of the dynamic template path. Subclasses may * override this to add to the front of the path, and then invoke this implementation. * @since org.eclipse.emf.codegen.ecore 2.2.2 */ @Override protected void addBaseTemplatePathEntries(List<String> templatePath) { templatePath.add(CodeGenEcorePlugin.INSTANCE.getBaseURL().toString() + "templates"); super.addBaseTemplatePathEntries(templatePath); } /** * Adds the plug-ins required for GenModel/Ecore-based templates to the <code>JETEmitter</code>'s classpath. */ @Override protected void addClasspathEntries(JETEmitter jetEmitter) throws JETException { jetEmitter.addVariable("EMF_CODEGEN", "org.eclipse.emf.codegen"); jetEmitter.addVariable("EMF_CODEGEN_ECORE", "org.eclipse.emf.codegen.ecore"); jetEmitter.addVariable("EMF_COMMON", "org.eclipse.emf.common"); jetEmitter.addVariable("EMF_ECORE", "org.eclipse.emf.ecore"); super.addClasspathEntries(jetEmitter); } /** * Creates the import manager and stores it on the <code>GenModel</code>, for use its in computing names. */ @Override protected void createImportManager(String packageName, String className) { super.createImportManager(packageName, className); updateImportManager(); } /** * Clears the import manager and removes it from the <code>GenModel</code>. */ @Override protected void clearImportManager() { super.clearImportManager(); updateImportManager(); } private void updateImportManager() { if (generatingObject != null) { ((GenBase)generatingObject).getGenModel().setImportManager(importManager); } } @Override protected void setLineDelimiter(String lineDelimiter) { super.setLineDelimiter(lineDelimiter); if (generatingObject != null) { ((GenBase)generatingObject).getGenModel().setLineDelimiter(lineDelimiter); } } /** * Ensures that a project exists. If not, a properly configured EMF project will be created. Similarly, if the project * does exist and <code>force</code> is true, it will be reconfigured to match the default EMF configuration. */ @Override protected void ensureProjectExists(String workspacePath, Object object, Object projectType, boolean force, Monitor monitor) { try { if (EMFPlugin.IS_ECLIPSE_RUNNING) { EclipseHelper.ensureProjectExists(workspacePath, object, projectType, force, monitor); } } finally { monitor.done(); } } /* * All Eclipse-dependent operations are delegated to this class. This pattern avoids any runtime failure due to * missing dependencies in the stand-alone case. */ private static class EclipseHelper { public static boolean ensureProjectExists(String workspacePath, Object object, Object projectType, boolean force, Monitor monitor) { try { IPath path = new Path(workspacePath); if (path.isAbsolute()) { GenModel genModel = ((GenBase)object).getGenModel(); IWorkspace workspace = ResourcesPlugin.getWorkspace(); IProject project = workspace.getRoot().getProject(path.segment(0)); if (!project.exists() || force) { URI projectLocation = null; List<IProject> referencedProjects = new UniqueEList<IProject>(); if (project.exists()) { referencedProjects.addAll(Arrays.asList(project.getDescription().getReferencedProjects())); projectLocation = getLocationURI(project); } else { Resource genModelResource = genModel.eResource(); URI genModelURI = genModelResource.getURI(); ResourceSet resourceSet = genModelResource.getResourceSet(); if (resourceSet != null) { genModelURI = resourceSet.getURIConverter().normalize(genModelURI); } if (genModelURI.isPlatformResource()) { IProject genModelProject = workspace.getRoot().getProject(URI.decode(genModelURI.segments()[1])); if (genModelProject.exists()) { projectLocation = getLocationURI(genModelProject); } } } IProject modelProject = workspace.getRoot().getProject(genModel.getModelProjectDirectory()); IPath javaSource = new Path(genModel.getModelDirectory()); //DMS factor this into a method? Use a non-static subclass? int style = 0; if (MODEL_PROJECT_TYPE.equals(projectType)) style = Generator.EMF_MODEL_PROJECT_STYLE; if (EDIT_PROJECT_TYPE.equals(projectType)) style = Generator.EMF_EDIT_PROJECT_STYLE; if (EDITOR_PROJECT_TYPE.equals(projectType)) style = Generator.EMF_EDITOR_PROJECT_STYLE; if (TESTS_PROJECT_TYPE.equals(projectType)) style = Generator.EMF_TESTS_PROJECT_STYLE; if (genModel.getRuntimePlatform() == GenRuntimePlatform.GWT) { style |= Generator.EMF_GWT_PROJECT_STYLE; } if ((style & Generator.EMF_TESTS_PROJECT_STYLE) != 0) { IProject testsProject = workspace.getRoot().getProject(genModel.getTestsProjectDirectory()); javaSource = new Path(genModel.getTestsDirectory()); if (!genModel.sameModelTestsProject()) { if (testsProject.exists()) { projectLocation = getLocationURI(testsProject); } referencedProjects.add(modelProject); referencedProjects.addAll(Arrays.asList(modelProject.getDescription().getReferencedProjects())); } } else if ((style & Generator.EMF_MODEL_PROJECT_STYLE) == 0 && genModel.hasEditSupport()) { IProject editProject = workspace.getRoot().getProject(genModel.getEditProjectDirectory()); javaSource = new Path(genModel.getEditDirectory()); if (!genModel.sameModelEditProject()) { if (editProject.exists()) { projectLocation = getLocationURI(editProject); } referencedProjects.add(modelProject); } for (GenPackage genPackage : genModel.getUsedGenPackages()) { GenModel otherGenModel = genPackage.getGenModel(); if (otherGenModel.hasEditSupport()) { IProject otherEditProject = workspace.getRoot().getProject(otherGenModel.getEditProjectDirectory()); if (otherEditProject.exists()) { referencedProjects.add(otherEditProject); referencedProjects.addAll(Arrays.asList(otherEditProject.getDescription().getReferencedProjects())); } } } if ((style & Generator.EMF_EDIT_PROJECT_STYLE) == 0 && genModel.hasEditorSupport()) { javaSource = new Path(genModel.getEditorDirectory()); if (!genModel.sameEditEditorProject()) { referencedProjects.add(editProject); referencedProjects.addAll(Arrays.asList(editProject.getDescription().getReferencedProjects())); } } } // Remove any non-Java dependencies from being added. // for (Iterator<IProject> i = referencedProjects.iterator(); i.hasNext(); ) { IProject referencedProject = i.next(); IJavaProject referencedJavaProject = JavaCore.create(referencedProject); if (!referencedJavaProject.exists()) { i.remove(); } } if (projectLocation != null) { projectLocation = projectLocation.trimSegments(1).appendSegment(javaSource.segment(0)); } if (genModel.hasXMLDependency()) { style |= Generator.EMF_XML_PROJECT_STYLE; } if ((style & Generator.EMF_MODEL_PROJECT_STYLE) == 0 || genModel.hasPluginSupport()) { style |= Generator.EMF_PLUGIN_PROJECT_STYLE; } Generator.createEMFProject (javaSource, projectLocation, referencedProjects, monitor, style, genModel.getEffectiveModelPluginVariables()); } return workspace.getRoot().getProject(path.segment(0)).exists(); } } catch (Exception exception) { //DMS should we let this exception out? CodeGenEcorePlugin.INSTANCE.log(exception); } return false; } protected static URI getLocationURI(IProject project) throws CoreException { java.net.URI locationURI = project.getDescription().getLocationURI(); return locationURI == null ? null : URI.createURI(locationURI.toString()); } } }