blob: e45f2a3e1dd61cd0818ab5e07fd2f38d52cd6dbc [file] [log] [blame]
/**
* 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());
}
}
}