blob: 954db31d15712f483839cbadd60eedd75f06d19b [file] [log] [blame]
/**
* Copyright (c) 2011-2012 Eclipse contributors 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
*/
package org.eclipse.emf.ecore.xcore.resource;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
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.common.util.EList;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EcorePackage;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.xcore.XDataType;
import org.eclipse.emf.ecore.xcore.XModelElement;
import org.eclipse.emf.ecore.xcore.XNamedElement;
import org.eclipse.emf.ecore.xcore.XOperation;
import org.eclipse.emf.ecore.xcore.XPackage;
import org.eclipse.emf.ecore.xcore.XStructuralFeature;
import org.eclipse.emf.ecore.xcore.XcorePackage;
import org.eclipse.emf.ecore.xcore.mappings.ToXcoreMapping;
import org.eclipse.emf.ecore.xcore.mappings.XDataTypeMapping;
import org.eclipse.emf.ecore.xcore.mappings.XFeatureMapping;
import org.eclipse.emf.ecore.xcore.mappings.XcoreMapper;
import org.eclipse.emf.ecore.xcore.util.XcoreEcoreBuilder;
import org.eclipse.emf.ecore.xcore.util.XcoreGenModelBuilder;
import org.eclipse.emf.ecore.xcore.util.XcoreGenModelInitializer;
import org.eclipse.emf.ecore.xcore.util.XcoreJvmInferrer;
import org.eclipse.xtext.common.types.JvmIdentifiableElement;
import org.eclipse.xtext.common.types.TypesPackage;
import org.eclipse.xtext.parser.antlr.IReferableElementsUnloader;
import org.eclipse.xtext.resource.DerivedStateAwareResource;
import org.eclipse.xtext.resource.IDerivedStateComputer;
import org.eclipse.xtext.util.OnChangeEvictingCache;
import org.eclipse.xtext.util.concurrent.IUnitOfWork;
import org.eclipse.xtext.xbase.XBlockExpression;
import org.eclipse.xtext.xbase.XExpression;
import org.eclipse.xtext.xbase.jvmmodel.IJvmModelAssociations;
import org.eclipse.xtext.xbase.jvmmodel.ILogicalContainerProvider;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
@Singleton
public class XcoreModelAssociator implements IJvmModelAssociations, ILogicalContainerProvider, IDerivedStateComputer
{
@Inject
private OnChangeEvictingCache cache;
@Inject
protected XcoreJvmInferrer jvmInferrer;
@Inject
protected XcoreGenModelBuilder genModelBuilder;
@Inject
private Provider<XcoreEcoreBuilder> xcoreEcoreBuilderProvider;
@Inject
protected XcoreMapper mapper;
@Inject
private IReferableElementsUnloader unloader;
@Inject
protected XcoreGenModelInitializer genModelInitializer;
public void installDerivedState(DerivedStateAwareResource resource, boolean preLinkingPhase)
{
if (resource.getParseResult() != null && resource.getParseResult().getRootASTElement() instanceof XPackage)
{
XPackage model = (XPackage)resource.getParseResult().getRootASTElement();
final XcoreEcoreBuilder xcoreEcoreBuilder = xcoreEcoreBuilderProvider.get();
EPackage ePackage = xcoreEcoreBuilder.getEPackage(model);
resource.getContents().add(ePackage);
final GenModel genModel = genModelBuilder.getGenModel(model);
genModel.setCanGenerate(true);
Collection<? extends Runnable> runnables = genModelInitializer.initialize(genModel, true);
resource.getContents().addAll(jvmInferrer.inferElements(genModel));
if (!preLinkingPhase)
{
cache.execWithoutCacheClear(resource, new IUnitOfWork.Void<Resource>()
{
@Override
public void process(Resource state) throws Exception
{
xcoreEcoreBuilder.link();
}
});
genModelBuilder.initializeUsedGenPackages(genModel);
for (Runnable runnable : runnables)
{
runnable.run();
}
// If the model has edit support, it's important to determine if we have a dependencies on Ecore's generated item providers...
//
if (genModel.hasEditSupport())
{
for (GenPackage genPackage : genModel.getUsedGenPackages())
{
// If we find a GenPackage for Ecore itself...
//
if (EcorePackage.eNS_URI.equals(genPackage.getNSURI()))
{
boolean needsEcoreEditSupport = false;
EPackage ecorePackage = genPackage.getEcorePackage();
// Consider all the class of the package...
LOOP:
for (EClassifier eClassifier : ePackage.getEClassifiers())
{
if (eClassifier instanceof EClass)
{
EClass eClass = (EClass)eClassifier;
// If one of the super types is from the Ecore package and isn't EObject, we need Ecore edit support.
//
for (EClass eSuperType : eClass.getEAllSuperTypes())
{
if (eSuperType.getEPackage() == ecorePackage && !"EObject".equals(eSuperType.getName()))
{
needsEcoreEditSupport = true;
break LOOP;
}
}
// If one of the reference types is from the Ecore package and isn't EObject, we need Ecore edit support.
//
for (EReference eReference : eClass.getEAllReferences())
{
EClass eReferenceType = eReference.getEReferenceType();
if (eReferenceType != null && eReferenceType.getEPackage() == ecorePackage && !"EObject".equals(eReferenceType.getName()))
{
needsEcoreEditSupport = true;
break LOOP;
}
}
}
}
// Modify the Ecore package's GenPackage's model to indicate whether Ecore provides edit support.
// Do this without producing notifications to avoid Ecore Tools transactional editing domain complaining that there is a model modification without a write transaction.
//
GenModel ecoreGenModel = genPackage.getGenModel();
ecoreGenModel.eSetDeliver(false);
ecoreGenModel.setEditDirectory(needsEcoreEditSupport ? "/org.eclipse.emf.edit.ecore/src" : "");
ecoreGenModel.eSetDeliver(true);
break;
}
}
}
cache.execWithoutCacheClear(resource, new IUnitOfWork.Void<Resource>()
{
@Override
public void process(Resource state) throws Exception
{
jvmInferrer.inferDeepStructure(genModel);
}
});
}
resource.getCache().clear(resource);
}
}
public void discardDerivedState(DerivedStateAwareResource resource)
{
EList<EObject> contents = resource.getContents();
int size = contents.size();
if (size > 1)
{
List<EObject> toBeRemoved = Lists.newArrayList();
for (Iterator<EObject> i = contents.iterator(); i.hasNext();)
{
EObject eObject = i.next();
if (eObject instanceof XPackage)
{
mapper.unsetMapping((XPackage)eObject);
}
else
{
unloader.unloadRoot(eObject);
toBeRemoved.add(eObject);
}
}
contents.removeAll(toBeRemoved);
}
}
public XExpression getAssociatedExpression(JvmIdentifiableElement element)
{
ToXcoreMapping mapping = mapper.getToXcoreMapping(element);
XNamedElement xcoreElement = mapping.getXcoreElement();
if (xcoreElement instanceof XOperation)
{
XOperation xOperation = (XOperation)xcoreElement;
if (element == mapper.getMapping(xOperation).getJvmOperation())
{
return xOperation.getBody();
}
}
else if (xcoreElement instanceof XDataType)
{
XDataType xDataType = (XDataType)xcoreElement;
XDataTypeMapping typeMapping = mapper.getMapping(xDataType);
if (element == typeMapping.getConverter())
{
return xDataType.getConvertBody();
}
else if (element == typeMapping.getCreator())
{
return xDataType.getCreateBody();
}
}
else if (xcoreElement instanceof XStructuralFeature)
{
XStructuralFeature feature = (XStructuralFeature)xcoreElement;
XFeatureMapping featureMapping = mapper.getMapping(feature);
if (element == featureMapping.getGetter())
{
return feature.getGetBody();
}
else if (element == featureMapping.getSetter())
{
return feature.getSetBody();
}
else if (element == featureMapping.getIsSetter())
{
return feature.getIsSetBody();
}
else if (element == featureMapping.getUnsetter())
{
return feature.getUnsetBody();
}
}
return null;
}
public Set<EObject> getJvmElements(EObject eObject)
{
final Set<EObject> result = Sets.newLinkedHashSet();
if (eObject instanceof XNamedElement)
{
GenBase genBase = mapper.getGen((XNamedElement)eObject);
if (genBase != null)
{
result.addAll(XcoreJvmInferrer.getInferredElements(genBase));
}
}
else if (eObject instanceof GenBase)
{
result.addAll(XcoreJvmInferrer.getInferredElements((GenBase)eObject));
}
else if (eObject.eClass().getEPackage() == TypesPackage.eINSTANCE)
{
result.add(eObject);
}
return result;
}
public Set<EObject> getSourceElements(EObject eObject)
{
EObject xcoreElement = mapper.getXcoreElement(eObject);
return xcoreElement == null || xcoreElement == eObject ? Collections.<EObject>emptySet() : Collections.singleton(eObject);
}
public EObject getPrimarySourceElement(EObject eObject)
{
EObject xcoreElement = mapper.getXcoreElement(eObject);
return xcoreElement;
}
public JvmIdentifiableElement getLogicalContainer(XExpression xExpression)
{
if (xExpression instanceof XBlockExpression)
{
EObject eContainer = xExpression.eContainer();
EReference eContainmentFeature = xExpression.eContainmentFeature();
if (eContainmentFeature == XcorePackage.Literals.XOPERATION__BODY)
{
return mapper.getMapping((XOperation)eContainer).getJvmOperation();
}
else if (eContainmentFeature == XcorePackage.Literals.XDATA_TYPE__CREATE_BODY)
{
return mapper.getMapping((XDataType)eContainer).getCreator();
}
else if (eContainmentFeature == XcorePackage.Literals.XDATA_TYPE__CONVERT_BODY)
{
return mapper.getMapping((XDataType)eContainer).getConverter();
}
else if (eContainmentFeature == XcorePackage.Literals.XSTRUCTURAL_FEATURE__GET_BODY)
{
return mapper.getMapping((XStructuralFeature)eContainer).getGetter();
}
else if (eContainmentFeature == XcorePackage.Literals.XSTRUCTURAL_FEATURE__SET_BODY)
{
return mapper.getMapping((XStructuralFeature)eContainer).getSetter();
}
else if (eContainmentFeature == XcorePackage.Literals.XSTRUCTURAL_FEATURE__IS_SET_BODY)
{
return mapper.getMapping((XStructuralFeature)eContainer).getIsSetter();
}
else if (eContainmentFeature == XcorePackage.Literals.XSTRUCTURAL_FEATURE__UNSET_BODY)
{
return mapper.getMapping((XStructuralFeature)eContainer).getUnsetter();
}
else
{
return null;
}
}
return null;
}
public JvmIdentifiableElement getNearestLogicalContainer(EObject eObject)
{
for (EObject eContainer = eObject; eContainer != null; eContainer = eContainer.eContainer())
{
if (eContainer instanceof XExpression && eContainer.eContainer() instanceof XModelElement)
{
return getLogicalContainer((XExpression)eContainer);
}
}
return null;
}
public EObject getPrimaryJvmElement(EObject sourceElement)
{
return Iterables.getFirst(getJvmElements(sourceElement), null);
}
public boolean isPrimaryJvmElement(EObject jvmElement)
{
return getPrimaryJvmElement(getPrimarySourceElement(jvmElement)) == jvmElement;
}
}