| /******************************************************************************* |
| * Copyright (c) 2012, 2013 The University of York, Willink Transformations 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 |
| * |
| * Contributors: |
| * Horacio Hoyos - initial API and implementation |
| ******************************************************************************/ |
| package org.eclipse.qvtd.pivot.qvtimperative.evaluation; |
| |
| import java.io.IOException; |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| |
| import org.eclipse.emf.common.util.BasicEList; |
| import org.eclipse.emf.common.util.EList; |
| import org.eclipse.emf.common.util.TreeIterator; |
| import org.eclipse.emf.common.util.URI; |
| import org.eclipse.emf.ecore.EClass; |
| import org.eclipse.emf.ecore.EObject; |
| import org.eclipse.emf.ecore.EPackage; |
| import org.eclipse.emf.ecore.resource.Resource; |
| import org.eclipse.emf.ecore.xmi.XMLResource; |
| import org.eclipse.jdt.annotation.NonNull; |
| import org.eclipse.jdt.annotation.Nullable; |
| import org.eclipse.ocl.examples.domain.elements.DomainType; |
| import org.eclipse.ocl.examples.domain.evaluation.DomainModelManager; |
| import org.eclipse.ocl.examples.domain.utilities.DomainUtil; |
| import org.eclipse.ocl.examples.pivot.ParserException; |
| import org.eclipse.ocl.examples.pivot.PivotPackage; |
| import org.eclipse.ocl.examples.pivot.Type; |
| import org.eclipse.ocl.examples.pivot.manager.MetaModelManager; |
| import org.eclipse.qvtd.pivot.qvtbase.TypedModel; |
| |
| /** |
| * QVTc Domain Manager is the class responsible for managing the QVTc virtual |
| * machine meta-models and models. |
| * A QVTc Domain Manager object encapsulates the domain information need to |
| * modify the domains's models. |
| */ |
| public class QVTiModelManager implements DomainModelManager |
| { |
| protected final @NonNull MetaModelManager metaModelManager; |
| // TODO how to manage aliases? |
| /** Map a typed model to its resource (model). */ |
| private @NonNull Map<TypedModel, Resource> modelResourceMap = new HashMap<TypedModel, Resource>(); |
| |
| private @NonNull Map<TypedModel, EList<EObject>> modelElementsMap = new HashMap<TypedModel, EList<EObject>>(); |
| |
| /** |
| * The types upon which execution of the transformation may invoke allInstances(). |
| */ |
| private @NonNull Set<Type> allInstancesTypes; |
| |
| /** |
| * Array of caches for the unnavigable opposite of each used navigable middle to outer property. |
| * The array index is allocated by the QVTiTransformationAanaysis; it identifies the middle2outerProperty |
| * of interest. Each cache is from outerObject to middleObject. |
| */ |
| private @NonNull Map<?, ?> middleOpposites[]; |
| |
| /** |
| * Instantiates a new QVTc Domain Manager. Responsible for creating new |
| * instances of the middle model and the middle model EFactory. |
| */ |
| public QVTiModelManager(@NonNull QVTiTransformationAnalysis transformationAnalysis) { |
| this.metaModelManager = transformationAnalysis.getMetaModelManager(); |
| this.allInstancesTypes = transformationAnalysis.getAllInstancesTypes(); |
| int cacheIndexes = transformationAnalysis.getCacheIndexes(); |
| this.middleOpposites = new Map<?, ?>[cacheIndexes]; |
| for (int i = 0; i < cacheIndexes; i++) { |
| this.middleOpposites[i] = new HashMap<Object, Object>(); |
| } |
| } |
| |
| /** |
| * Adds the model to the list of models managed by this domain manager. The |
| * domain manager supports only one root resource per typed model, this means that |
| * if a model was already binded to the TypedModel it will be replaced. |
| * |
| * @param typedModel the type model associated to the model |
| * @param model the resource |
| */ |
| // TODO support multiple model instances by alias |
| public void addModel(@NonNull TypedModel typedModel, @NonNull Resource model) { |
| modelResourceMap.put(typedModel, model); |
| } |
| |
| /** |
| * Adds the model element to the resource of the given TypeModel |
| * |
| * @param tm the TypeModel |
| * @param element the element |
| */ |
| public void addModelElement(@NonNull TypedModel model, @NonNull Object element) { |
| |
| EList<EObject> elements = null; |
| if (modelElementsMap.containsKey(model)) { |
| elements = modelElementsMap.get(model); |
| } else { |
| elements = new BasicEList<EObject>(modelResourceMap.get(model).getContents()); |
| } |
| elements.add((EObject) element); |
| modelElementsMap.put(model, elements); |
| } |
| |
| /** |
| * Dispose. |
| */ |
| public void dispose() { |
| modelElementsMap.clear(); |
| modelResourceMap.clear(); |
| allInstancesTypes.clear(); |
| for (Map<?, ?> middleOpposite : middleOpposites) { |
| middleOpposite.clear(); |
| } |
| } |
| |
| public @NonNull Set<EObject> get(@NonNull DomainType type) { |
| throw new UnsupportedOperationException(); |
| } |
| |
| /** |
| * Gets the model (resource) for a given TypedModel. |
| * |
| * @param typedModel the typed model |
| * @return the resource |
| */ |
| public Resource getModel(@NonNull TypedModel typedModel) { |
| return modelResourceMap.get(typedModel); |
| } |
| |
| /** |
| * Gets the resources for all the models. |
| * |
| * @return a collection of all the resources |
| */ |
| public Collection<Resource> getAllModelResources() { |
| return modelResourceMap.values(); |
| } |
| |
| /** |
| * Gets the all the instances of the specified Type in the given TypeModel |
| * |
| * @param tm the TypeModel (can be null if it is the middle model) |
| * @param type the type of the elements that are retrieved |
| * @return the instances |
| */ |
| public List<Object> getElementsByType(@Nullable TypedModel model, @NonNull Type type) { |
| |
| List<Object> elements = new ArrayList<Object>(); |
| // Is the TypedModel the middle or output, hence we have elements in the elementsMap |
| if (modelElementsMap.containsKey(model)) { |
| for (EObject root : modelElementsMap.get(model)) { |
| if (root != null) { |
| //if (root.eClass().getName().equals(type.getName())) { |
| if (isInstance(type, root)) { |
| elements.add(root); |
| } |
| for (TreeIterator<EObject> contents = root.eAllContents(); contents |
| .hasNext();) { |
| EObject element = contents.next(); |
| if ((element != null) && isInstance(type, element)) { |
| // if (((EClass) type.getETarget()).getName().equals(element.eClass().getName())) { |
| elements.add(element); |
| } |
| } |
| } |
| } |
| } |
| else { |
| for (TreeIterator<EObject> contents = modelResourceMap.get(model).getAllContents(); contents.hasNext();) { |
| EObject element = contents.next(); |
| //System.out.println(type.getETarget()); |
| //System.out.println(((EClassifier) type.getETarget()).getName()); |
| //System.out.println(object.eClass().getName()); |
| if ((element != null) && isInstance(type, element)) { |
| // if (((EClass) type.getETarget()).getName().equals(element.eClass().getName())) { |
| elements.add(element); |
| } |
| } |
| } |
| return elements; |
| } |
| |
| /** |
| * Retrieve the unnavigable opposite of the cacheIndex of outerObject. |
| */ |
| public Object getMiddleOpposite(@NonNull Integer cacheIndex, @NonNull Object outerObject) { |
| return middleOpposites[cacheIndex].get(outerObject); |
| } |
| |
| /** |
| * Implemented by subclasses to determine whether the specified element |
| * is an instance of the specified class, according to the metamodel |
| * semantics implemented by the environment that created this extent map. |
| * |
| * @param type the type |
| * @param element a potential run-time (M0) instance of that class |
| * @return <code>true</code> if this element is an instance of the given |
| * class; <code>false</code> otherwise |
| */ |
| protected boolean isInstance(@NonNull DomainType requiredType, @NonNull EObject eObject) { |
| EClass eClass = eObject.eClass(); |
| EPackage ePackage = eClass.getEPackage(); |
| Type objectType = null; |
| if (ePackage == PivotPackage.eINSTANCE) { |
| String name = DomainUtil.nonNullEMF(eClass.getName()); |
| objectType = metaModelManager.getPivotType(name); |
| } |
| else { |
| try { |
| objectType = metaModelManager.getPivotOf(Type.class, eClass); |
| } catch (ParserException e) { |
| // FIXME if (!generatedErrorMessage) { |
| // generatedErrorMessage = true; |
| // logger.error("Failed to load an '" + eClass.getName() + "'", e); |
| // } |
| } |
| } |
| return (objectType != null) && objectType.conformsTo(metaModelManager, requiredType); |
| } |
| |
| public List<EObject> getTypeModelEObjectList(TypedModel model) { |
| |
| if (modelElementsMap.containsKey(model)) { |
| return modelElementsMap.get(model); |
| } else { |
| return new ArrayList<EObject>(); |
| } |
| |
| } |
| |
| /** |
| * Saves all the models managed by the domain manager. |
| */ |
| public void saveModels() { |
| for (Map.Entry<TypedModel, Resource> entry : modelResourceMap.entrySet()) { |
| Resource model = entry.getValue(); |
| TypedModel key = entry.getKey(); |
| if (modelElementsMap.containsKey(key)) { // Only save modified models |
| // Move elements without container to the resource contents |
| for (EObject e : modelElementsMap.get(key)) { |
| if (e.eContainer() == null) { |
| model.getContents().add(e); |
| } |
| } |
| } |
| } |
| for (Map.Entry<TypedModel, Resource> entry : modelResourceMap.entrySet()) { |
| Resource model = entry.getValue(); |
| TypedModel key = entry.getKey(); |
| if (modelElementsMap.containsKey(key)) { // Only save modified models |
| try{ |
| Map<Object, Object> options = new HashMap<Object, Object>(); |
| options.put(XMLResource.OPTION_SCHEMA_LOCATION, Boolean.TRUE); |
| model.save(options); |
| } catch (IOException e) { |
| e.printStackTrace(); |
| } |
| } |
| } |
| } |
| |
| public void saveMiddleModel(@NonNull URI uri) { |
| /* Resource r = metaModelManager.getExternalResourceSet().createResource(uri); |
| for (EObject e : modelElementsMap.get(MIDDLE_MODEL)) { |
| if (e.eContainer() == null) { |
| r.getContents().add(e); |
| } |
| } |
| try{ |
| Map<Object, Object> options = new HashMap<Object, Object>(); |
| options.put(XMLResource.OPTION_SCHEMA_LOCATION, Boolean.TRUE); |
| r.save(options); |
| } catch (IOException e) { |
| e.printStackTrace(); |
| } */ |
| } |
| |
| /** |
| * Register middleObject as the unnavigable opposite of the cacheIndex of outerObject. |
| */ |
| @SuppressWarnings("unchecked") |
| public void setMiddleOpposite(@NonNull Integer cacheIndex, @NonNull Object middleObject, Object outerObject) { |
| ((Map<Object, Object>)middleOpposites[cacheIndex]).put(outerObject, middleObject); |
| } |
| } |