blob: 6466a1884ebb7cae90b480bd6559d53160ee21d9 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2017, 2018 Willink Transformations and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v20.html
*
* Contributors:
* E.D.Willink - initial API and implementation
*******************************************************************************/
package org.eclipse.qvtd.cs2as.build.mwe;
import java.io.IOException;
import java.text.MessageFormat;
import java.util.List;
import org.eclipse.emf.codegen.ecore.genmodel.GenModel;
import org.eclipse.emf.codegen.ecore.genmodel.GenPackage;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EcoreFactory;
import org.eclipse.emf.ecore.EcorePackage;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.mwe.core.WorkflowContext;
import org.eclipse.emf.mwe.core.issues.Issues;
import org.eclipse.emf.mwe.core.lib.AbstractWorkflowComponent2;
import org.eclipse.emf.mwe.core.monitor.ProgressMonitor;
import org.eclipse.emf.mwe2.runtime.Mandatory;
public class CSTracePropertyInjector extends AbstractWorkflowComponent2 {
public static class ASTraceInfo {
private String genModelURI;
private String traceClassName;
@Mandatory
public void setTargetGenModel(String genModelURI) {
this.genModelURI = genModelURI;
}
@Mandatory
public void setTargetTypeName(String className) {
this.traceClassName = className;
}
}
public static class CSTraceInfo {
private String baseGenModelURI;
private String targetGenModelURI;
private String traceClassName = "CSTrace";
private String tracePropName = "ast";
@Mandatory
public void setTargetGenModel(String genModelURI) {
this.targetGenModelURI = genModelURI;
}
public void setBaseGenModel(String genModelURI) {
this.baseGenModelURI = genModelURI;
}
public void setTracePropertyName(String tracePropName) {
this.tracePropName = tracePropName;
}
public void setTraceClassName(String traceClassName) {
this.traceClassName = traceClassName;
}
}
private ResourceSet rSet;
private CSTraceInfo csTraceInfo;
private ASTraceInfo asTraceType;
@Override
public void preInvoke() {
super.preInvoke();
if (csTraceInfo.baseGenModelURI == null) {
csTraceInfo.baseGenModelURI = csTraceInfo.targetGenModelURI;
}
}
@Override
protected void invokeInternal(WorkflowContext ctx, ProgressMonitor monitor, Issues issues) {
try {
EClass traceClass = getCSTraceClass(csTraceInfo.baseGenModelURI);
Resource targetResource = rSet.getResource(URI.createURI(csTraceInfo.targetGenModelURI), true);
GenModel targetGenModel = (GenModel) targetResource.getContents().get(0);
GenPackage targetGenPackage = targetGenModel.getGenPackages().get(0); // FIXME what if we have many ?
EPackage targetEPackage = targetGenPackage.getEcorePackage();
boolean targetChanged = false;
for (EClassifier eClassifier : targetEPackage.getEClassifiers()) {
if (eClassifier instanceof EClass) {
EClass eClass = (EClass) eClassifier;
if (eClass.getESuperTypes().size() == 0
&& eClass != traceClass) {
eClass.getESuperTypes().add(traceClass);
targetChanged = true;
}
}
}
if (targetChanged) {
targetEPackage.eResource().save(null);
targetGenModel.reconcile();
targetResource.save(null);
}
} catch(IOException e) {
issues.addError(e.getMessage());
}
}
private EClass getCSTraceClass(String genModelURI) throws IOException {
Resource resource = rSet.getResource(URI.createURI(genModelURI), true);
GenModel genModel = (GenModel) resource.getContents().get(0);
GenPackage baseGenPackage = genModel.getGenPackages().get(0); // FIXME what if we have many ?
EPackage ePackage = baseGenPackage.getEcorePackage();
String traceClassName = csTraceInfo.traceClassName;
String tracePropName = csTraceInfo.tracePropName;
for (EClassifier eClassifier : ePackage.getEClassifiers()) {
if (eClassifier instanceof EClass) {
EClass eClass = (EClass) eClassifier;
if (traceClassName.equals(eClass.getName())) {
for (EReference eRef : eClass.getEReferences()) {
if (tracePropName.equals(eRef.getName())) {
return eClass;
}
}
}
}
}
// If not found we create it
// FIXME solve the situation of having an already "traceClassName" class with no ast property
EClass traceClass = EcoreFactory.eINSTANCE.createEClass();
traceClass.setName(traceClassName);
traceClass.setAbstract(true);
EReference traceProp = EcoreFactory.eINSTANCE.createEReference();
traceProp.setName(tracePropName);
traceProp.setTransient(true);
if (asTraceType == null) {
traceProp.setEType(EcorePackage.Literals.EOBJECT);
} else {
Resource asResource = rSet.getResource(URI.createURI(asTraceType.genModelURI), true);
GenModel asGenModel = (GenModel) asResource.getContents().get(0);
GenPackage asGenPackage = asGenModel.getGenPackages().get(0); // FIXME what if we have many ?
EPackage asEPackage = asGenPackage.getEcorePackage();
traceProp.setEType(getASTraceClass(asEPackage));
List<GenPackage> usedGenPackages = genModel.getUsedGenPackages();
if (!usedGenPackages.contains(asGenPackage)) {
usedGenPackages.add(asGenPackage);
}
}
traceClass.getEStructuralFeatures().add(traceProp);
ePackage.getEClassifiers().add(traceClass);
ePackage.eResource().save(null);
genModel.reconcile();
resource.save(null);
return traceClass;
}
private EClass getASTraceClass(EPackage ePackage, boolean isNestedPackage) {
for (EClassifier eClassifier : ePackage.getEClassifiers()) {
if (eClassifier instanceof EClass) {
EClass eClass = (EClass) eClassifier;
if (asTraceType.traceClassName.equals(eClass.getName())) {
return eClass;
}
}
}
for (EPackage nestedPackage : ePackage.getESubpackages()) {
EClass asTraceClass = getASTraceClass(nestedPackage, true);
if (asTraceClass != null) {
return asTraceClass;
}
}
if (isNestedPackage) {
return null;
} else {
throw new IllegalStateException(MessageFormat.format("AS class with name {0} not found in the EPackage of {1}", asTraceType.traceClassName,asTraceType.genModelURI));
}
}
private EClass getASTraceClass(EPackage ePackage) {
return getASTraceClass(ePackage, false);
}
@Mandatory
public void setResourceSet(ResourceSet rSet) {
this.rSet = rSet;
}
@Mandatory
public void setCSTraceInfo(CSTraceInfo csTraceInfo) {
this.csTraceInfo = csTraceInfo;
}
public void setASTraceType(ASTraceInfo asTraceInfo) {
this.asTraceType = asTraceInfo;
}
}