package org.eclipse.emf.ecore.xcore.util;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.eclipse.emf.codegen.ecore.genmodel.GenBase;
import org.eclipse.emf.codegen.ecore.genmodel.GenClassifier;
import org.eclipse.emf.codegen.ecore.genmodel.GenFeature;
import org.eclipse.emf.codegen.ecore.genmodel.GenModelPackage;
import org.eclipse.emf.codegen.ecore.genmodel.GenTypeParameter;
import org.eclipse.emf.ecore.EAnnotation;
import org.eclipse.emf.ecore.EAttribute;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.emf.ecore.EDataType;
import org.eclipse.emf.ecore.EEnum;
import org.eclipse.emf.ecore.EEnumLiteral;
import org.eclipse.emf.ecore.EGenericType;
import org.eclipse.emf.ecore.EModelElement;
import org.eclipse.emf.ecore.EOperation;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.EParameter;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.ETypeParameter;
import org.eclipse.emf.ecore.ETypedElement;
import org.eclipse.emf.ecore.EcoreFactory;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.emf.ecore.xcore.XAnnotation;
import org.eclipse.emf.ecore.xcore.XAnnotationDirective;
import org.eclipse.emf.ecore.xcore.XAttribute;
import org.eclipse.emf.ecore.xcore.XClass;
import org.eclipse.emf.ecore.xcore.XClassifier;
import org.eclipse.emf.ecore.xcore.XDataType;
import org.eclipse.emf.ecore.xcore.XEnum;
import org.eclipse.emf.ecore.xcore.XEnumLiteral;
import org.eclipse.emf.ecore.xcore.XGenericType;
import org.eclipse.emf.ecore.xcore.XMember;
import org.eclipse.emf.ecore.xcore.XModelElement;
import org.eclipse.emf.ecore.xcore.XOperation;
import org.eclipse.emf.ecore.xcore.XPackage;
import org.eclipse.emf.ecore.xcore.XParameter;
import org.eclipse.emf.ecore.xcore.XReference;
import org.eclipse.emf.ecore.xcore.XStructuralFeature;
import org.eclipse.emf.ecore.xcore.XTypeParameter;
import org.eclipse.emf.ecore.xcore.XTypedElement;
import org.eclipse.emf.ecore.xcore.XcorePackage;
import org.eclipse.emf.ecore.xcore.interpreter.XcoreConversionDelegate;
import org.eclipse.emf.ecore.xcore.interpreter.XcoreInvocationDelegate;
import org.eclipse.emf.ecore.xcore.interpreter.XcoreSettingDelegate;
import org.eclipse.emf.ecore.xcore.mappings.XcoreMapper;
import org.eclipse.xtext.common.types.JvmTypeReference;
import org.eclipse.xtext.xbase.XBlockExpression;
import com.google.inject.Inject;
import com.google.inject.Provider;
public class XcoreEcoreBuilder
{
@Inject
private XcoreMapper mapper;
@Inject
private Provider<XcoreInvocationDelegate> operationDelegateProvider;
@Inject
private Provider<XcoreSettingDelegate> settingDelegateProvider;
@Inject
private Provider<XcoreConversionDelegate> conversionDelegateProvider;
List<Runnable> runnables = new ArrayList<Runnable>();
public void link()
{
// Hook up local references.
//
List<Runnable> currentRunnables = new ArrayList<Runnable>(runnables);
runnables.clear();
for (Runnable runnable : currentRunnables)
{
runnable.run();
}
for (Runnable runnable : runnables)
{
runnable.run();
}
}
public EPackage getEPackage(XPackage xPackage)
{
EPackage ePackage = EcoreFactory.eINSTANCE.createEPackage();
mapper.getMapping(xPackage).setEPackage(ePackage);
mapper.getToXcoreMapping(ePackage).setXcoreElement(xPackage);
handleAnnotations(xPackage, ePackage);
String name = xPackage.getName();
String basePackage = null;
if (name != null)
{
int index = name.lastIndexOf(".");
if (index == -1)
{
basePackage = null;
ePackage.setName(name);
}
else
{
basePackage = name.substring(0, index);
ePackage.setName(name.substring(index + 1));
}
ePackage.setNsURI(name);
ePackage.setNsPrefix(ePackage.getName());
}
for (XClassifier xClassifier : xPackage.getClassifiers())
{
EClassifier eClassifier = getEClassifier(xClassifier);
ePackage.getEClassifiers().add(eClassifier);
}
for (XAnnotationDirective xAnnotationDirective : xPackage.getAnnotationDirectives())
{
EcoreUtil.setAnnotation(ePackage, XcorePackage.eNS_URI, xAnnotationDirective.getName(), xAnnotationDirective.getSourceURI());
}
if (basePackage != null)
{
EcoreUtil.setAnnotation(ePackage, GenModelPackage.eNS_URI, "basePackage", basePackage);
}
return ePackage;
}
void handleAnnotations(XModelElement xModelElement, EModelElement eModelElement)
{
for (XAnnotation xAnnotation : xModelElement.getAnnotations())
{
EAnnotation eAnnotation = EcoreFactory.eINSTANCE.createEAnnotation();
// map(eAnnotation, xAnnotation);
XAnnotationDirective source = xAnnotation.getSource();
if (source != null)
{
String sourceURI = source.getSourceURI();
eAnnotation.setSource(sourceURI);
}
for (Map.Entry<String, String> detail : xAnnotation.getDetails())
{
eAnnotation.getDetails().put(detail.getKey(), detail.getValue());
}
eModelElement.getEAnnotations().add(eAnnotation);
}
}
EClassifier getEClassifier(final XClassifier xClassifier)
{
final EClassifier eClassifier =
xClassifier instanceof XClass ?
getEClass((XClass)xClassifier) :
xClassifier instanceof XEnum ?
getEEnum((XEnum)xClassifier) :
getEDataType((XDataType)xClassifier);
handleAnnotations(xClassifier, eClassifier);
eClassifier.setName(xClassifier.getName());
runnables.add
(new Runnable()
{
public void run()
{
JvmTypeReference instanceType = xClassifier.getInstanceType();
if (instanceType != null)
{
String instanceTypeName = instanceType.getIdentifier();
eClassifier.setInstanceTypeName(instanceTypeName);
}
}
});
for (XTypeParameter xTypeParameter : xClassifier.getTypeParameters())
{
ETypeParameter eTypeParameter = getETypeParameter(xTypeParameter);
eClassifier.getETypeParameters().add(eTypeParameter);
}
return eClassifier;
}
EClass getEClass(final XClass xClass)
{
final EClass eClass = EcoreFactory.eINSTANCE.createEClass();
mapper.getMapping(xClass).setEClass(eClass);
mapper.getToXcoreMapping(eClass).setXcoreElement(xClass);
if (xClass.isInterface())
{
eClass.setInterface(true);
eClass.setAbstract(true);
}
else if (xClass.isAbstract())
{
eClass.setAbstract(true);
}
for (XGenericType superType : xClass.getSuperTypes())
{
eClass.getEGenericSuperTypes().add(getEGenericType(superType));
}
for (XMember xMember : xClass.getMembers())
{
if (xMember instanceof XOperation)
{
EOperation eOperation = getEOperation((XOperation)xMember);
eClass.getEOperations().add(eOperation);
}
else if (xMember instanceof XReference)
{
EReference eReference = getEReference((XReference)xMember);
eClass.getEStructuralFeatures().add(eReference);
}
else
{
EAttribute eAttribute = getEAttribute((XAttribute)xMember);
eClass.getEStructuralFeatures().add(eAttribute);
}
}
return eClass;
}
EOperation getEOperation(XOperation xOperation)
{
EOperation eOperation = EcoreFactory.eINSTANCE.createEOperation();
mapper.getMapping(xOperation).setEOperation(eOperation);
mapper.getToXcoreMapping(eOperation).setXcoreElement(xOperation);
eOperation.setUnique(false);
handleETypedElement(eOperation, xOperation);
for (XTypeParameter xTypeParameter : xOperation.getTypeParameters())
{
ETypeParameter eTypeParameter = getETypeParameter(xTypeParameter);
eOperation.getETypeParameters().add(eTypeParameter);
}
for (XParameter xParameter : xOperation.getParameters())
{
EParameter eParameter = getEParameter(xParameter);
eOperation.getEParameters().add(eParameter);
}
for (XGenericType exception : xOperation.getExceptions())
{
EGenericType eException = getEGenericType(exception);
eOperation.getEGenericExceptions().add(eException);
}
XBlockExpression body = xOperation.getBody();
if (body != null)
{
final XcoreInvocationDelegate invocationDelegate = operationDelegateProvider.get();
invocationDelegate.initialize(body, eOperation);
((EOperation.Internal)eOperation).setInvocationDelegate(invocationDelegate);
// EAnnotation eAnnotation = EcoreFactory.eINSTANCE.createEAnnotation();
// eAnnotation.setSource(EcorePackage.eNS_URI);
// eAnnotation.getReferences().add(body);
// eOperation.getEAnnotations().add(eAnnotation);
}
return eOperation;
}
EParameter getEParameter(XParameter xParameter)
{
EParameter eParameter = EcoreFactory.eINSTANCE.createEParameter();
// TODO
// map(eParameter, xParameter);
eParameter.setUnique(false);
handleETypedElement(eParameter, xParameter);
return eParameter;
}
ETypeParameter getETypeParameter(XTypeParameter xTypeParameter)
{
ETypeParameter eTypeParameter = EcoreFactory.eINSTANCE.createETypeParameter();
mapper.getToXcoreMapping(eTypeParameter).setXcoreElement(xTypeParameter);
//TODO
// map(eTypeParameter, xTypeParameter);
handleAnnotations(xTypeParameter, eTypeParameter);
eTypeParameter.setName(xTypeParameter.getName());
for (XGenericType xGenericType : xTypeParameter.getBounds())
{
eTypeParameter.getEBounds().add(getEGenericType(xGenericType));
}
return eTypeParameter;
}
void handleETypedElement(ETypedElement eTypedElement, XTypedElement xTypedElement)
{
eTypedElement.setName(xTypedElement.getName());
handleAnnotations(xTypedElement, eTypedElement);
eTypedElement.setEGenericType(getEGenericType(xTypedElement.getType()));
if (xTypedElement.isUnordered())
{
eTypedElement.setOrdered(false);
}
if (xTypedElement.isUnique())
{
eTypedElement.setUnique(true);
}
int[] multiplicity = xTypedElement.getMultiplicity();
if (multiplicity == null)
{
// optional is the default
//
}
else if (multiplicity.length == 0)
{
// []
//
eTypedElement.setUpperBound(EStructuralFeature.UNBOUNDED_MULTIPLICITY);
}
else if (multiplicity.length == 1)
{
if (multiplicity[0] == -3)
{
// [?]
//
}
else if (multiplicity[0] == -2)
{
// [+]
//
eTypedElement.setLowerBound(1);
eTypedElement.setUpperBound(EStructuralFeature.UNBOUNDED_MULTIPLICITY);
}
else if (multiplicity[0] == -1)
{
// [*]
//
eTypedElement.setUpperBound(EStructuralFeature.UNBOUNDED_MULTIPLICITY);
}
else
{
// [n]
//
eTypedElement.setLowerBound(multiplicity[0]);
eTypedElement.setUpperBound(multiplicity[0]);
}
}
else
{
eTypedElement.setLowerBound(multiplicity[0]);
eTypedElement.setUpperBound(multiplicity[1]);
}
}
EGenericType getEGenericType(final XGenericType xGenericType)
{
if (xGenericType == null)
{
return null;
}
else
{
final EGenericType eGenericType = EcoreFactory.eINSTANCE.createEGenericType();
// map(eGenericType, xGenericType);
XGenericType lowerBound = xGenericType.getLowerBound();
if (lowerBound != null)
{
eGenericType.setELowerBound(getEGenericType(lowerBound));
}
XGenericType upperBound = xGenericType.getUpperBound();
if (upperBound != null)
{
eGenericType.setEUpperBound(getEGenericType(upperBound));
}
for (XGenericType typeArgument : xGenericType.getTypeArguments())
{
eGenericType.getETypeArguments().add(getEGenericType(typeArgument));
}
runnables.add
(new Runnable()
{
public void run()
{
GenBase type = xGenericType.getType();
if (type instanceof GenTypeParameter)
{
eGenericType.setETypeParameter(((GenTypeParameter)type).getEcoreTypeParameter());
}
else if (type instanceof GenClassifier)
{
eGenericType.setEClassifier(((GenClassifier)type).getEcoreClassifier());
}
}
});
return eGenericType;
}
}
EReference getEReference(final XReference xReference)
{
final EReference eReference = EcoreFactory.eINSTANCE.createEReference();
mapper.getMapping(xReference).setEStructuralFeature(eReference);
mapper.getToXcoreMapping(eReference).setXcoreElement(xReference);
if (xReference.isContainment())
{
eReference.setContainment(true);
if (!xReference.isResolveProxies())
{
eReference.setResolveProxies(false);
}
}
if (xReference.isLocal())
{
eReference.setResolveProxies(false);
}
handleEStructuralFeature(eReference, xReference);
runnables.add
(new Runnable()
{
public void run()
{
GenFeature opposite = xReference.getOpposite();
if (opposite != null)
{
eReference.setEOpposite((EReference)opposite.getEcoreFeature());
}
for (GenFeature key : xReference.getKeys())
{
EStructuralFeature eAttribute = key.getEcoreFeature();
if (eAttribute instanceof EAttribute)
{
eReference.getEKeys().add((EAttribute)eAttribute);
}
}
}
});
return eReference;
}
EAttribute getEAttribute(final XAttribute xAttribute)
{
final EAttribute eAttribute = EcoreFactory.eINSTANCE.createEAttribute();
mapper.getMapping(xAttribute).setEStructuralFeature(eAttribute);
mapper.getToXcoreMapping(eAttribute).setXcoreElement(xAttribute);
eAttribute.setUnique(false);
if (xAttribute.isID())
{
eAttribute.setID(true);
}
eAttribute.setDefaultValueLiteral(xAttribute.getDefaultValueLiteral());
handleEStructuralFeature(eAttribute, xAttribute);
return eAttribute;
}
void handleEStructuralFeature(EStructuralFeature eStructuralFeature, XStructuralFeature xStructuralFeature)
{
eStructuralFeature.setName(xStructuralFeature.getName());
handleETypedElement(eStructuralFeature, xStructuralFeature);
if (xStructuralFeature.isReadonly())
{
eStructuralFeature.setChangeable(false);
}
if (xStructuralFeature.isTransient())
{
eStructuralFeature.setTransient(true);
}
if (xStructuralFeature.isVolatile())
{
eStructuralFeature.setVolatile(true);
}
if (xStructuralFeature.isUnsettable())
{
eStructuralFeature.setUnsettable(true);
}
if (xStructuralFeature.isDerived())
{
eStructuralFeature.setDerived(true);
}
XBlockExpression getBody = xStructuralFeature.getGetBody();
XBlockExpression setBody = xStructuralFeature.getSetBody();
XBlockExpression isSetBody = xStructuralFeature.getIsSetBody();
XBlockExpression unsetBody = xStructuralFeature.getUnsetBody();
if (getBody != null || setBody != null || isSetBody != null || unsetBody != null)
{
XcoreSettingDelegate settingDelegate = settingDelegateProvider.get();
settingDelegate.initialize(getBody, setBody, isSetBody, unsetBody, eStructuralFeature);
((EStructuralFeature.Internal)eStructuralFeature).setSettingDelegate(settingDelegate);
}
if (getBody != null)
{
eStructuralFeature.setTransient(true);
eStructuralFeature.setVolatile(true);
eStructuralFeature.setDerived(true);
if (setBody == null)
{
eStructuralFeature.setChangeable(false);
}
}
}
EDataType getEDataType(XDataType xDataType)
{
EDataType eDataType = EcoreFactory.eINSTANCE.createEDataType();
mapper.getMapping(xDataType).setEDataType(eDataType);
mapper.getToXcoreMapping(eDataType).setXcoreElement(xDataType);
XcoreConversionDelegate conversionDelegate = conversionDelegateProvider.get();
conversionDelegate.initialize(xDataType.getCreateBody(), xDataType.getConvertBody(), eDataType);
((EDataType.Internal)eDataType).setConversionDelegate(conversionDelegate);
return eDataType;
}
EEnum getEEnum(XEnum xEnum)
{
EEnum eEnum = EcoreFactory.eINSTANCE.createEEnum();
mapper.getMapping(xEnum).setEDataType(eEnum);
mapper.getToXcoreMapping(eEnum).setXcoreElement(xEnum);
for (XEnumLiteral xEnumLiteral : xEnum.getLiterals())
{
eEnum.getELiterals().add(getEEnumLiteral(xEnumLiteral));
}
return eEnum;
}
EEnumLiteral getEEnumLiteral(XEnumLiteral xEnumLiteral)
{
EEnumLiteral eEnumLiteral = EcoreFactory.eINSTANCE.createEEnumLiteral();
mapper.getToXcoreMapping(eEnumLiteral).setXcoreElement(xEnumLiteral);
mapper.getMapping(xEnumLiteral).setEEnumLiteral(eEnumLiteral);
handleAnnotations(xEnumLiteral, eEnumLiteral);
eEnumLiteral.setName(xEnumLiteral.getName());
eEnumLiteral.setLiteral(xEnumLiteral.getLiteral());
eEnumLiteral.setValue(xEnumLiteral.getValue());
return eEnumLiteral;
}
}