blob: ef057eccd04e153c26453748fee356688b33651a [file] [log] [blame]
package org.eclipse.gmf.tooling.tests.xtend.rt;
import java.io.ByteArrayInputStream;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import org.eclipse.core.commands.operations.IUndoableOperation;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.emf.codegen.ecore.Generator;
import org.eclipse.emf.codegen.util.CodeGenUtil.EclipseUtil;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EAttribute;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.EcoreFactory;
import org.eclipse.emf.ecore.EcorePackage;
import org.eclipse.emf.ecore.resource.impl.ResourceImpl;
import org.eclipse.gef.EditPart;
import org.eclipse.gef.commands.Command;
import org.eclipse.gef.commands.CompoundCommand;
import org.eclipse.gmf.codegen.gmfgen.ElementType;
import org.eclipse.gmf.codegen.gmfgen.GenDiagram;
import org.eclipse.gmf.codegen.gmfgen.GenNode;
import org.eclipse.gmf.codegen.gmfgen.GenTopLevelNode;
import org.eclipse.gmf.codegen.gmfgen.MetamodelType;
import org.eclipse.gmf.codegen.gmfgen.SpecializationType;
import org.eclipse.gmf.codegen.util.GMFGeneratorModule;
import org.eclipse.gmf.codegen.xtend.ui.handlers.Xtend2Emitter;
import org.eclipse.gmf.common.UnexpectedBehaviourException;
import org.eclipse.gmf.internal.common.codegen.TextEmitter;
import org.eclipse.gmf.mappings.Constraint;
import org.eclipse.gmf.mappings.FeatureSeqInitializer;
import org.eclipse.gmf.mappings.FeatureValueSpec;
import org.eclipse.gmf.mappings.GMFMapFactory;
import org.eclipse.gmf.mappings.Language;
import org.eclipse.gmf.mappings.NodeMapping;
import org.eclipse.gmf.runtime.common.core.command.ICompositeCommand;
import org.eclipse.gmf.runtime.diagram.ui.commands.ICommandProxy;
import org.eclipse.gmf.runtime.diagram.ui.requests.EditCommandRequestWrapper;
import org.eclipse.gmf.runtime.emf.type.core.requests.SetRequest;
import org.eclipse.gmf.runtime.notation.Diagram;
import org.eclipse.gmf.runtime.notation.Node;
import org.eclipse.gmf.tests.Utils;
import org.eclipse.gmf.tests.rt.EditHelpersTest;
import org.eclipse.gmf.tests.setup.DiaDefSource;
import org.eclipse.gmf.tests.setup.DomainModelSource;
import org.eclipse.gmf.tests.setup.GenProjectSetup;
import org.eclipse.gmf.tests.setup.GeneratedDiagramPlugin;
import org.eclipse.gmf.tests.setup.GeneratorConfiguration;
import org.eclipse.gmf.tests.setup.MapDefSource;
import org.eclipse.gmf.tests.setup.MapSetup;
import org.eclipse.gmf.tests.setup.SessionSetup;
import org.eclipse.gmf.tests.setup.ToolDefSource;
import org.eclipse.gmf.tooling.tests.xtend.setup.RuntimeBasedGeneratorConfigurationXtend;
import org.osgi.framework.BundleException;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Module;
import edithelpers.edithelper;
import edithelpers.manifest;
import edithelpers.plugin;
public class EditHelpersTestXtend extends EditHelpersTest {
private static final String BEFORE_PREFIX = "before";
private static final String AFTER_PREFIX = "after";
private static final String MARKER_COMMAND_LABEL = "MarkerCommand";
private final static Injector injector = Guice.createInjector(new Module[]{new GMFGeneratorModule(null)});;
public EditHelpersTestXtend(String name) {
super(name, new RuntimeBasedGeneratorConfigurationXtend());
}
public void testSingleEditHelperAdviceNode() {
assertTrue(getSetup().getGenModel().getNodeA().getElementType() instanceof MetamodelType);
Command command = getSetNewTopLeveNodeNameCommand(getSetup().getGenModel().getNodeA(), getSetup().getDomainModel().getNodeA().getNameAttr().getName());
Collection<IUndoableOperation> allMarkerCommands = getAllMarkerCommands(command);
Collection<IUndoableOperation> beforeCommands = getBeforeCommands(allMarkerCommands);
Collection<IUndoableOperation> afterCommands = getAfterCommands(allMarkerCommands);
// One before and one after command should be associated with this
// element type
assertTrue(beforeCommands.size() == 1);
assertTrue(getEditHelperVisualID(beforeCommands.iterator().next()) == getSetup().getGenModel().getNodeA().getVisualID());
assertTrue(afterCommands.size() == 1);
assertTrue(getEditHelperVisualID(afterCommands.iterator().next()) == getSetup().getGenModel().getNodeA().getVisualID());
}
public void testTwoEditHelperAdvicesNode() {
assertTrue(getSetup().getGenModel().getNodeB().getElementType() instanceof SpecializationType);
Command command = getSetNewTopLeveNodeNameCommand(getSetup().getGenModel().getNodeB(), getSetup().getDomainModel().getNodeB().getNameAttr().getName());
Collection<IUndoableOperation> allMarkerCommands = getAllMarkerCommands(command);
Collection<IUndoableOperation> beforeCommands = getBeforeCommands(allMarkerCommands);
Collection<IUndoableOperation> afterCommands = getAfterCommands(allMarkerCommands);
// Two before and two after commands should be associated with this
// element type
assertTrue(beforeCommands.size() == 2);
assertTrue(hasCommand(beforeCommands, getSetup().getGenModel().getNodeA().getVisualID()));
assertTrue(hasCommand(beforeCommands, getSetup().getGenModel().getNodeB().getVisualID()));
assertTrue(afterCommands.size() == 2);
assertTrue(hasCommand(afterCommands, getSetup().getGenModel().getNodeA().getVisualID()));
assertTrue(hasCommand(afterCommands, getSetup().getGenModel().getNodeB().getVisualID()));
}
@Override
protected Diagram createDiagramView(EObject domainElement, GeneratedDiagramPlugin genPlugin) {
return RuntimeBasedGeneratorConfigurationXtend.createDiagram(domainElement, genPlugin);
}
private boolean hasCommand(Collection<IUndoableOperation> beforeCommands, int visualID) {
for (IUndoableOperation operation : beforeCommands) {
if (getEditHelperVisualID(operation) == visualID) {
return true;
}
}
return false;
}
private Command getSetNewTopLeveNodeNameCommand(GenNode genNode, String nameAttribute) {
Node node = createNode(genNode, getDiagram());
assertNotNull(node);
EditPart nodeEditPart = getViewerConfiguration().findEditPart(node);
assertNotNull(nodeEditPart);
EObject nodeElement = node.getElement();
SetRequest setReq = new SetRequest(nodeElement, nodeElement.eClass().getEStructuralFeature(nameAttribute), "newName");
Command command = nodeEditPart.getCommand(new EditCommandRequestWrapper(setReq));
assertNotNull(command);
assertTrue(command.canExecute());
return command;
}
private Collection<IUndoableOperation> getAllMarkerCommands(Command command) {
if (command instanceof CompoundCommand) {
Collection<IUndoableOperation> result = new ArrayList<IUndoableOperation>();
for (Object object : ((CompoundCommand) command).getCommands()) {
result.addAll(getAllMarkerCommands((Command) object));
}
return result;
}
if (command instanceof ICommandProxy) {
ICommandProxy commandProxy = (ICommandProxy) command;
return getAllMarkerCommands(commandProxy.getICommand());
}
return Collections.emptyList();
}
private Collection<IUndoableOperation> getAllMarkerCommands(IUndoableOperation operation) {
if (operation instanceof ICompositeCommand) {
ICompositeCommand compositeCommand = (ICompositeCommand) operation;
Collection<IUndoableOperation> result = new ArrayList<IUndoableOperation>();
for (Iterator<?> it = compositeCommand.iterator(); it.hasNext();) {
result.addAll(getAllMarkerCommands((IUndoableOperation) it.next()));
}
return result;
}
if (isMarkerCommand(operation)) {
return Collections.singletonList(operation);
}
return Collections.emptyList();
}
private boolean isMarkerCommand(IUndoableOperation operation) {
String label = operation.getLabel();
return label != null && label.indexOf(MARKER_COMMAND_LABEL) > -1;
}
private Collection<IUndoableOperation> getBeforeCommands(Collection<IUndoableOperation> markerCommands) {
Collection<IUndoableOperation> result = new ArrayList<IUndoableOperation>();
for (IUndoableOperation command : markerCommands) {
if (isBeforeMarkerCommand(command)) {
result.add(command);
}
}
return result;
}
private Collection<IUndoableOperation> getAfterCommands(Collection<IUndoableOperation> markerCommands) {
Collection<IUndoableOperation> result = new ArrayList<IUndoableOperation>();
for (IUndoableOperation command : markerCommands) {
if (isAfterMarkerCommand(command)) {
result.add(command);
}
}
return result;
}
private boolean isBeforeMarkerCommand(IUndoableOperation operation) {
assertTrue("Should be marker operation", isMarkerCommand(operation));
String label = operation.getLabel();
return BEFORE_PREFIX.equals(label.substring(0, label.indexOf(MARKER_COMMAND_LABEL)));
}
private boolean isAfterMarkerCommand(IUndoableOperation operation) {
assertTrue("Should be marker operation", isMarkerCommand(operation));
String label = operation.getLabel();
return AFTER_PREFIX.equals(label.substring(0, label.indexOf(MARKER_COMMAND_LABEL)));
}
private int getEditHelperVisualID(IUndoableOperation operation) {
assertTrue("Should be marker operation", isMarkerCommand(operation));
String label = operation.getLabel();
return Integer.valueOf(label.substring(label.indexOf(MARKER_COMMAND_LABEL) + MARKER_COMMAND_LABEL.length()));
}
public static final class EditHelpersSessionSetup extends SessionSetup {
public EditHelpersSessionSetup() {
super(new RuntimeBasedGeneratorConfigurationXtend());
}
@Override
protected DomainModelSource createDomainModel() {
return new EditHelpersModelSource();
}
@Override
protected GenProjectSetup createGenProject(GeneratorConfiguration generatorConfiguration) throws BundleException {
return new EditHelpersProjectSetup(generatorConfiguration).init(getGenModel());
}
@Override
public MapDefSource createMapModel() {
return new EditHelpersMapSetup().init(getGraphDefModel(), getDomainModel(), getToolDefModel());
}
}
private static final class EditHelpersMapSetup extends MapSetup {
@Override
public MapSetup init(DiaDefSource ddSource, DomainModelSource domainSource, ToolDefSource toolDef) {
super.init(ddSource, domainSource, toolDef);
addConstraint(getNodeA(), "nodeName2.oclIsUndefined()");
addNameInitializer(getNodeA(), domainSource.getNodeA().getNameAttr(), "'name'");
addConstraint(getNodeB(), "nodeName1.oclIsUndefined()");
addNameInitializer(getNodeB(), domainSource.getNodeB().getNameAttr(), "'name'");
return this;
}
private void addConstraint(NodeMapping node, String body) {
node.setDomainSpecialization(GMFMapFactory.eINSTANCE.createConstraint());
node.getDomainSpecialization().setLanguage(Language.OCL_LITERAL);
node.getDomainSpecialization().setBody(body);
}
private void addNameInitializer(NodeMapping node, EStructuralFeature feature, String value) {
FeatureSeqInitializer root = GMFMapFactory.eINSTANCE.createFeatureSeqInitializer();
node.setDomainInitializer(root);
FeatureValueSpec nameSpecification = GMFMapFactory.eINSTANCE.createFeatureValueSpec();
root.getInitializers().add(nameSpecification);
nameSpecification.setFeature(feature);
Constraint valueExpr = GMFMapFactory.eINSTANCE.createConstraint();
nameSpecification.setValue(valueExpr);
valueExpr.setBody(value);
valueExpr.setLanguage(Language.OCL_LITERAL);
}
}
private static final class EditHelpersProjectSetup extends GenProjectSetup {
private String myBundleName;
private EditHelpersProjectSetup(GeneratorConfiguration generatorFactory) {
super(generatorFactory);
}
@Override
protected void generateDiagramPrerequisites(GenDiagram d) throws Exception {
super.generateDiagramPrerequisites(d);
generateEditHelpersProject(d);
}
private void generateEditHelpersProject(GenDiagram d) {
myBundleName = Utils.createUniquePluginID() + ".edithelpers";
IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(myBundleName);
final Path srcPath = new Path('/' + project.getName() + "/src"); //$NON-NLS-1$
final int style = Generator.EMF_PLUGIN_PROJECT_STYLE;
final List<?> pluginVariables = null;
Generator.createEMFProject(srcPath, null, Collections.<IProject> emptyList(), new NullProgressMonitor(), style, pluginVariables);
createManifestMF();
for (GenTopLevelNode node : d.getTopLevelNodes()) {
createEditHelper(node);
}
createPluginXML(d);
projectsToInit.add(myBundleName);
}
public void createManifestMF() {
Xtend2Emitter emiter = new Xtend2Emitter(injector, manifest.class, "main");
doGenerateFile(emiter, new Path("/" + myBundleName + "/META-INF/MANIFEST.MF"), myBundleName);
}
public void createEditHelper(GenTopLevelNode node) {
ElementType elementType = node.getElementType();
if (elementType == null) {
return ;
}
String className;
if (elementType instanceof MetamodelType) {
className = ((MetamodelType) elementType).getEditHelperClassName() + "ExternalAdvice";
} else if (elementType instanceof SpecializationType) {
String adviceClassName = ((SpecializationType) elementType).getEditHelperAdviceClassName();
if (adviceClassName == null || adviceClassName.trim().length() ==0) {
// advice class name is usually empty, as we do not generate anything reasonable inside them,
// hence, need to identify SpecializationType differently
adviceClassName = node.getUniqueIdentifier();
}
className = adviceClassName + "ExternalAdvice";
} else {
return;
}
Xtend2Emitter emiter = new Xtend2Emitter(injector, edithelper.class, "main");
doGenerateFile(emiter, new Path("/" + myBundleName + "/src/" + className + ".java"), elementType);
}
public void createPluginXML(GenDiagram d) {
Xtend2Emitter emiter = new Xtend2Emitter(injector, plugin.class, "main");
doGenerateFile(emiter, new Path("/" + myBundleName + "/plugin.xml"), d);
}
private void doGenerateFile(TextEmitter emitter, IPath filePath, Object... param) {
try {
IPath containerPath = filePath.removeLastSegments(1);
EclipseUtil.findOrCreateContainer(containerPath, false, (IPath) null, new NullProgressMonitor());
String genText = emitter.generate(new NullProgressMonitor(), param);
IFile f = ResourcesPlugin.getWorkspace().getRoot().getFile(filePath);
f.create(new ByteArrayInputStream(genText.getBytes(f.getCharset())), true, new NullProgressMonitor());
} catch (InvocationTargetException ex) {
fail(ex.getMessage());
} catch (UnexpectedBehaviourException ex) {
fail(ex.getMessage());
} catch (CoreException ex) {
fail(ex.getMessage());
} catch (UnsupportedEncodingException ex) {
fail(ex.getMessage());
} catch (InterruptedException ex) {
fail(ex.getMessage());
}
}
}
private static final class EditHelpersModelSource implements DomainModelSource {
private EClass myDiagramElement;
private EPackage myPackage;
private NodeData myNode1;
private LinkData myClassLink;
private NodeData myNode2;
private EReference myRefLink;
{
myPackage = EcoreFactory.eINSTANCE.createEPackage();
myPackage.setName("eh");
myPackage.setNsPrefix("sampleEH");
Calendar c = Calendar.getInstance();
myPackage.setNsURI("uri://eclipse/gmf/tests/sample/eh/" + c.get(Calendar.HOUR_OF_DAY) + '/' + c.get(Calendar.MINUTE) + '/');
myDiagramElement = EcoreFactory.eINSTANCE.createEClass();
myDiagramElement.setName("DiagramElement");
myPackage.getEClassifiers().add(myDiagramElement);
EClass node = EcoreFactory.eINSTANCE.createEClass();
node.setName("Node");
myPackage.getEClassifiers().add(node);
EAttribute node1Name = EcoreFactory.eINSTANCE.createEAttribute();
node1Name.setName("nodeName1");
node1Name.setEType(EcorePackage.eINSTANCE.getEString());
node.getEStructuralFeatures().add(node1Name);
EAttribute node2Name = EcoreFactory.eINSTANCE.createEAttribute();
node2Name.setName("nodeName2");
node2Name.setEType(EcorePackage.eINSTANCE.getEString());
node.getEStructuralFeatures().add(node2Name);
EReference nodeContainment = EcoreFactory.eINSTANCE.createEReference();
nodeContainment.setName("nodeContainment");
nodeContainment.setContainment(true);
nodeContainment.setUpperBound(-1);
nodeContainment.setEType(node);
myDiagramElement.getEStructuralFeatures().add(nodeContainment);
EClass classLink = EcoreFactory.eINSTANCE.createEClass();
classLink.setName("Link");
myPackage.getEClassifiers().add(classLink);
EReference linkContainment = EcoreFactory.eINSTANCE.createEReference();
linkContainment.setName("linkContainment");
linkContainment.setEType(classLink);
linkContainment.setUpperBound(-1);
linkContainment.setContainment(true);
node.getEStructuralFeatures().add(linkContainment);
EReference linkTarget = EcoreFactory.eINSTANCE.createEReference();
linkTarget.setName("target");
linkTarget.setEType(node);
linkTarget.setUpperBound(1);
classLink.getEStructuralFeatures().add(linkTarget);
myRefLink = EcoreFactory.eINSTANCE.createEReference();
myRefLink.setName("refLink");
myRefLink.setEType(node);
myRefLink.setUpperBound(-1);
node.getEStructuralFeatures().add(myRefLink);
new ResourceImpl(URI.createURI("uri://org.eclipse.gmf.eh/tests/DomainModelSetup")).getContents().add(myPackage);
myNode1 = new NodeData(node, node1Name, nodeContainment);
myNode2 = new NodeData(node, node2Name, nodeContainment);
myClassLink = new LinkData(classLink, linkTarget, linkContainment);
}
public EClass getDiagramElement() {
return myDiagramElement;
}
public LinkData getLinkAsClass() {
return myClassLink;
}
public EReference getLinkAsRef() {
return myRefLink;
}
public EPackage getModel() {
return myPackage;
}
public NodeData getNodeA() {
return myNode1;
}
public NodeData getNodeB() {
return myNode2;
}
}
}