| /******************************************************************************* |
| * Copyright (c) 2004-2008 Andras Schmidt, Andras Balogh, Istvan Rath and Daniel Varro |
| * 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: |
| * Andras Schmidt, Andras Balogh, Istvan Rath - initial API and implementation |
| *******************************************************************************/ |
| |
| package org.eclipse.viatra2.copier; |
| |
| import java.util.Collection; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.TreeMap; |
| import java.util.TreeSet; |
| |
| import org.eclipse.viatra2.core.IEntity; |
| import org.eclipse.viatra2.core.IModelElement; |
| import org.eclipse.viatra2.core.IModelManager; |
| import org.eclipse.viatra2.core.IModelSpace; |
| import org.eclipse.viatra2.core.IRelation; |
| import org.eclipse.viatra2.errors.VPMCoreException; |
| |
| /** |
| * |
| * @author Andras Schmidt; modified by Istvan Rath |
| * |
| */ |
| public class ModelCopy { |
| Map<IModelElement, IModelElement> remap; |
| |
| Set<IModelElement> toCopy; |
| |
| TreeMap<IModelElement, IModelElement> src2tg = new TreeMap<IModelElement, IModelElement>(); |
| |
| IModelSpace targetModel; |
| |
| IModelSpace sourceModel; |
| |
| IModelManager tModelManager; |
| |
| /** |
| * Copy elements from one model into another model. Elements to be copied |
| * are given as a set of elements. The new place of the elements to be |
| * copied is given by a map. For example a branch copy has the following |
| * parameters: toCopy: all elements below the root remap: parent of root's |
| * fully qualified name -> new parent of root's fully qualified name |
| * |
| * @param sourceModel |
| * the model to copy elements from |
| * @param targetModel |
| * the model to copy elements to |
| * @param toCopy |
| * elements to be copied |
| * @param remap |
| * fqn mapping from old model's fqn to new model's fqn |
| * @throws VPMCoreException |
| * @throws ModelCopyException |
| */ |
| public static void copyModel(IModelSpace sourceModel, |
| IModelSpace targetModel, Set<IModelElement> toCopy, |
| Map<IModelElement, IModelElement> remap) throws VPMCoreException, |
| ModelCopyException { |
| ModelCopy mc = new ModelCopy(); |
| mc._copyModel(sourceModel, targetModel, toCopy, remap); |
| } |
| |
| /** |
| * Copy a part of a model into another model. |
| * |
| * @param sourceModel |
| * the source model |
| * @param targetModel |
| * the target model |
| * @param root |
| * the root of the model part to be copied |
| * @param destinationContainer |
| * the container of the copied model in the destination model |
| * @param doOutEdges |
| * true: copy edges going out of the copied part of model |
| * @return returns the root modelement of the copied model part |
| * @throws VPMCoreException |
| * @throws ModelCopyException |
| */ |
| public static IModelElement copyModel(IModelSpace sourceModel, |
| IModelSpace targetModel, IModelElement root, |
| IModelElement destinationContainer, boolean doOutEdges) |
| throws VPMCoreException, ModelCopyException { |
| TreeSet<IModelElement> elementsToCopy = new TreeSet<IModelElement>(); |
| addModelElementAndChildren(root, root, elementsToCopy, doOutEdges); |
| TreeMap<IModelElement, IModelElement> remap = new TreeMap<IModelElement, IModelElement>(); |
| remap.put(root.getNamespace(), destinationContainer); |
| ModelCopy mc = new ModelCopy(); |
| mc._copyModel(sourceModel, targetModel, elementsToCopy, remap); |
| IModelElement ret = mc.src2tg.get(root); |
| return ret; |
| } |
| |
| public static IModelElement copyModels(Set<IModelElement> elementsToCopy, |
| IModelSpace sourceModel, IModelSpace targetModel, |
| IModelElement root, IModelElement destinationContainer, |
| boolean doOutEdges) throws VPMCoreException, ModelCopyException { |
| TreeSet<IModelElement> _elementsToCopy = new TreeSet<IModelElement>(); |
| TreeMap<IModelElement, IModelElement> remap = new TreeMap<IModelElement, IModelElement>(); |
| for (IModelElement e : elementsToCopy) { |
| addModelElementAndChildren(e, e, _elementsToCopy, doOutEdges); |
| remap.put(e.getNamespace(), destinationContainer); // FIXME this may |
| // be dangerous!
|
| } |
| remap.put(root.getNamespace(), destinationContainer); |
| ModelCopy mc = new ModelCopy(); |
| mc._copyModel(sourceModel, targetModel, _elementsToCopy, remap); |
| IModelElement ret = mc.src2tg.get(root); |
| return ret; |
| } |
| |
| private static void addModelElementAndChildren(IModelElement root, |
| IModelElement me, TreeSet<IModelElement> elementsToCopy, |
| boolean copyOutEdges) { |
| // if(me.equals(root)||me.isBelowNamespace(root))
|
| elementsToCopy.add(me); |
| for (IModelElement _me : me.getElementsInNamespace()) { |
| if (!copyOutEdges) { |
| if (_me instanceof IRelation) { |
| IRelation rel = (IRelation) _me; |
| IModelElement to = rel.getTo(); |
| if (!(to.equals(root) || to.isBelowNamespace(root))) { |
| continue; |
| } |
| } |
| } |
| addModelElementAndChildren(root, _me, elementsToCopy, copyOutEdges); |
| } |
| if (copyOutEdges) { |
| // TODO do we need to copy the incoming edges as well?
|
| for (IModelElement _me : me.getRelationsTo()) { |
| elementsToCopy.add(_me); |
| } |
| } |
| } |
| |
| private void _copyModel(IModelSpace sourceModel, IModelSpace targetModel, |
| Set<IModelElement> toCopy, Map<IModelElement, IModelElement> remap) |
| throws VPMCoreException, ModelCopyException { |
| this.remap = remap; |
| this.toCopy = toCopy; |
| this.targetModel = targetModel; |
| this.sourceModel = sourceModel; |
| tModelManager = targetModel.getModelManager(); |
| Set<IModelElement> roots = findRoots(toCopy); |
| for (IModelElement root : roots) { |
| createBranch(root); |
| } |
| setTargets(); |
| setTypes(); |
| } |
| |
| private void setTargets() throws VPMCoreException, ModelCopyException { |
| for (IModelElement me : toCopy) { |
| if (!(me instanceof IRelation)) { |
| continue; |
| } |
| IRelation rel = (IRelation) me; |
| IModelElement tg = targetOf(me); |
| if (tg == null) { |
| continue; |
| } |
| if (!(tg instanceof IRelation)) { |
| addError( |
| "copy model internal error: target of a relation is not relaiton", |
| me); |
| continue; |
| } |
| IRelation tgRel = (IRelation) tg; |
| IModelElement to = rel.getTo(); |
| IModelElement tgTo = targetOf(to); |
| if (tgTo == null) { |
| addError("target of relation has no map in target model", rel, |
| to); |
| continue; |
| } |
| tModelManager.setRelationTo(tgRel, tgTo); |
| IRelation inverse = rel.getInverse(); |
| if (inverse != null) { |
| IModelElement tgInverse = targetOf(inverse); |
| if (tgInverse != null && tgInverse instanceof IRelation) { |
| IRelation rTgInverse = (IRelation) tgInverse; |
| tModelManager.setRelationInverse(tgRel, rTgInverse); |
| } else { |
| addError("Inverse of relation is not mapped to a relation", |
| rel, inverse); |
| } |
| } |
| } |
| |
| } |
| |
| private void setTypes() throws VPMCoreException, ModelCopyException { |
| for (IModelElement me : toCopy) { |
| IModelElement tg = targetOf(me); |
| if (tg == null) { |
| continue; |
| } |
| Collection<IModelElement> types = me.getTypes(); |
| for (IModelElement type : types) { |
| IModelElement tgType = targetOf(type); |
| if (tgType != null) { |
| tModelManager.newInstanceOf(tgType, tg); |
| } else { |
| addError( |
| "Element in target model does not exist, when creating type", |
| tg, type); |
| } |
| } |
| types = me.getSupertypes(); |
| for (IModelElement type : types) { |
| IModelElement tgType = targetOf(type); |
| if (tgType != null) { |
| tModelManager.newSupertypeOf(tgType, tg); |
| } else { |
| addError( |
| "Element in target model does not exist, when creating supertype", |
| tg, type); |
| } |
| } |
| } |
| } |
| |
| private void createBranch(IModelElement me) throws VPMCoreException, |
| ModelCopyException { |
| if (!toCopy.contains(me)) |
| return; |
| IModelElement newMe = null; |
| if (me instanceof IEntity) { |
| IEntity ent = (IEntity) me; |
| IEntity par = ent.getParent(); |
| IModelElement newPar = targetOf(par); |
| if (newPar != null && newPar instanceof IEntity) { |
| IEntity eNewPar = (IEntity) newPar; |
| newMe = tModelManager.newEntity(ent.getName(), ent.getValue(), |
| eNewPar); |
| } else { |
| addError( |
| "Parent of copy root entity is not found in target model", |
| ent); |
| } |
| } else { |
| IRelation rel = (IRelation) me; |
| IModelElement par = rel.getFrom(); |
| IModelElement newPar = targetOf(par); |
| if (newPar != null) { |
| newMe = tModelManager.newRelation(rel.getName(), newPar, |
| newPar, rel.getMultiplicity(), rel.getIsAggregation(), |
| null); |
| } else { |
| addError( |
| "Source of copy root relation is not found in target model", |
| rel); |
| } |
| } |
| if (newMe == null) |
| return; |
| addMapping(me, newMe); |
| tModelManager.setViewInfo(newMe, me.getViewInfo()); |
| tModelManager.setIsFinalType(newMe, me.getIsFinalType()); |
| Collection<IModelElement> children = me.getElementsInNamespace(); |
| for (IModelElement child : children) { |
| createBranch(child); |
| } |
| } |
| |
| private void addError(String msg, IModelElement cause, IModelElement cause2) |
| throws ModelCopyException { |
| System.out.println(msg + " " + cause.toString() + " " |
| + cause2.toString()); |
| // TODO
|
| } |
| |
| private void addError(String msg, IModelElement cause) |
| throws ModelCopyException { |
| System.out.println(msg + " " + cause.toString()); |
| // TODO
|
| } |
| |
| private void addMapping(IModelElement source, IModelElement target) { |
| src2tg.put(source, target); |
| } |
| |
| private IModelElement targetOf(IModelElement source) { |
| if (remap.containsKey(source)) { |
| return remap.get(source); |
| } |
| IModelElement tg = src2tg.get(source); |
| if (tg != null) |
| return tg; |
| if (targetModel.equals(sourceModel)) { |
| return source; |
| } |
| tg = targetModel.getModelManager().getElementByName( |
| source.getFullyQualifiedName()); |
| if (tg != null) |
| return tg; |
| return null; |
| } |
| |
| private Set<IModelElement> findRoots(Set<IModelElement> toCopy) { |
| TreeSet<IModelElement> ret = new TreeSet<IModelElement>(); |
| for (IModelElement me : toCopy) { |
| IModelElement namespace = me.getNamespace(); |
| if (namespace == null) |
| ret.add(me); |
| else if (!toCopy.contains(namespace)) { |
| ret.add(me); |
| } |
| } |
| return ret; |
| } |
| } |