| /** |
| * 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; |
| } |
| } |