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