| /******************************************************************************* |
| * 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.merger; |
| |
| import java.util.Collection; |
| import java.util.Iterator; |
| import java.util.Map; |
| 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; |
| |
| /** |
| * Low level model merge. Merges the two modelspaces: Elements with same fqn and |
| * type (relation or entity) are treated as same elements |
| * |
| * Modify on 2007/10/29: - correct multiplicity and other metaproperty transfers |
| * |
| * @author Andras Schmidt, Istvan Rath |
| */ |
| public class Merger { |
| |
| IModelManager leftManager; |
| |
| IModelManager rightManager; |
| |
| Collection<IRelation> newlyCreatedRelations = new TreeSet<IRelation>(); |
| |
| /** |
| * Maps fully qualified names of left model to the new fully qualified name |
| * in right model. Only those modelelements are mapped, which had its name |
| * changed. With the use of this map we can find the equivalent element of |
| * all left side elements in the merged right side. |
| */ |
| Map<String, String> mapFqn = new TreeMap<String, String>(); |
| |
| /** |
| * Merges the two models. Merged model will be in rightModel. All conflicts |
| * will be resolved in a way, that the one in rightModel will be used. |
| * |
| * @param leftModel |
| * @param rightModel |
| * @throws VPMMergeException |
| */ |
| public void merge(IModelSpace leftModel, IModelSpace rightModel) |
| throws VPMMergeException { |
| try { |
| // Create entities new in newmodel
|
| leftManager = leftModel.getModelManager(); |
| rightManager = rightModel.getModelManager(); |
| IEntity leftRoot = leftManager.getRoot(); |
| IEntity rightRoot = rightManager.getRoot(); |
| // browse the element hierarchy in both models in the same order. |
| // When an element does not exist in
|
| // new model (right) but exists in left model, then create it. When |
| // element exists just map it.
|
| mergeElementsInBaranch(leftRoot, rightRoot); |
| // New relations are creatred with default target set. Set the |
| // target to the equivalent of left side
|
| // model target
|
| setNewRelationsTarget(); |
| // Merge the type hierarchy
|
| mergeTypes(); |
| } catch (VPMCoreException e) { |
| // TODO Auto-generated catch block
|
| e.printStackTrace(); |
| VPMMergeException toThrow = new VPMMergeException( |
| "Core threw while merging (internal error):" |
| + e.getMessage()); |
| toThrow.initCause(e); |
| throw toThrow; |
| } catch (RuntimeException e) { |
| e.printStackTrace(); |
| VPMMergeException toThrow = new VPMMergeException( |
| "Runtime exception while merging (internal error)"); |
| toThrow.initCause(e); |
| throw toThrow; |
| } finally { |
| leftManager = null; |
| rightManager = null; |
| } |
| } |
| |
| /** |
| * After creating or mapping all elements from left to right side create all |
| * new type relationships. Iterates through all elements in left side, finds |
| * its right side equivalent and sets all non existing type relations. |
| * |
| * @throws VPMCoreException |
| */ |
| private void mergeTypes() throws VPMCoreException { |
| for (int i = 0; i < 2; ++i) { |
| Iterator<? extends IModelElement> it; |
| if (i == 0) { |
| it = leftManager.getEntities().iterator(); |
| } else { |
| it = leftManager.getRelations().iterator(); |
| } |
| while (it.hasNext()) { |
| IModelElement left = it.next(); |
| IModelElement right = leftModelElement2RightModelElement(left); |
| if (right != null) |
| mergeTypes(left, right); |
| } |
| } |
| } |
| |
| /** |
| * After creating or mapping all elements from left to right side create all |
| * new type relationships |
| * |
| * @param left |
| * the modelelement in left side (origin of right side element) |
| * @param right |
| * the modelement in right side whose types must be set |
| * @throws VPMCoreException |
| */ |
| private void mergeTypes(IModelElement left, IModelElement right) |
| throws VPMCoreException { |
| for (Iterator<IModelElement> it = left.getTypes().iterator(); it.hasNext();) { |
| IModelElement leftType = it.next(); |
| IModelElement rightType = leftModelElement2RightModelElement(leftType); |
| if (!right.isInstanceOf(rightType)) { |
| rightManager.newInstanceOfMachine(rightType, right); |
| } |
| } |
| for (Iterator<IModelElement> it = left.getSupertypes().iterator(); it.hasNext();) { |
| IModelElement leftType = it.next(); |
| IModelElement rightType = leftModelElement2RightModelElement(leftType); |
| if (!right.isInstanceOf(rightType)) { |
| rightManager.newSupertypeOfMachine(rightType, right); |
| } |
| } |
| } |
| |
| /** |
| * New relations (not existant in right side model) to side are set after |
| * creating or mapping all elements in left side model to right side model. |
| * |
| * @throws VPMCoreException |
| */ |
| private void setNewRelationsTarget() throws VPMCoreException { |
| for (IRelation rel : newlyCreatedRelations) { |
| IRelation rightRel = (IRelation) leftModelElement2RightModelElement(rel); |
| IModelElement tg = rel.getTo(); |
| IModelElement rightTg = leftModelElement2RightModelElement(tg); |
| rightManager.setRelationTo(rightRel, rightTg); |
| } |
| } |
| |
| /** |
| * Find the element in right side model, whose origin is lMe in left side |
| * model. |
| * |
| * @param lMe |
| * @return |
| */ |
| private IModelElement leftModelElement2RightModelElement(IModelElement lMe) { |
| String fqn = lMe.getFullyQualifiedName(); |
| String mapName = mapFqn.get(fqn); |
| if (mapName == null) { |
| mapName = fqn; |
| } |
| IModelElement ret = rightManager.getElementByName(mapName); |
| return ret; |
| } |
| |
| /** |
| * Merge all elements in namespace of leftEntity with elements in namespace |
| * of rightEntity |
| * |
| * @param leftEntity |
| * @param rightEntity |
| * @throws VPMCoreException |
| */ |
| private void mergeElementsInBaranch(IModelElement leftEntity, |
| IModelElement rightEntity) throws VPMCoreException { |
| Iterator<IModelElement> it = leftEntity.getElementsInNamespace().iterator(); |
| while (it.hasNext()) { |
| IModelElement leftMe = it.next(); |
| IModelElement rightMe = rightEntity |
| .getElementInNamespaceByName(leftMe.getName()); |
| if (rightMe != null && getType(rightMe) == getType(leftMe)) { |
| // They are the same go on with children
|
| mergeElementsInBaranch(leftMe, rightMe); |
| } else { |
| // There is no such entity in left side, go on and create it
|
| createElementsInBranch(leftMe, rightEntity); |
| // IEntity |
| // right=rightManager.newEntity(left.getName(),left.getValue |
| // (),rightEntity);
|
| } |
| } |
| } |
| |
| /** |
| * We are in namespace rightEntity and we have to create leftContent in this |
| * element with all its children. |
| * |
| * @param leftEntity |
| * @param rightEntity |
| * @throws VPMCoreException |
| */ |
| private void createElementsInBranch(IModelElement leftContent, |
| IModelElement rightEntity) throws VPMCoreException { |
| IModelElement right = null; |
| if (getType(leftContent) == ENT) { |
| right = rightManager.newEntity(leftContent.getName(), |
| ((IEntity) leftContent).getValue(), (IEntity) rightEntity); |
| } else { |
| right = rightManager.newRelation(leftContent.getName(), |
| rightEntity, rightEntity); |
| |
| // fix by Istvan
|
| // set various properties
|
| rightManager.setRelationMultiplicity((IRelation) right, |
| ((IRelation) leftContent).getMultiplicity()); |
| rightManager.setRelationIsAggregation((IRelation) right, |
| ((IRelation) leftContent).getIsAggregation()); |
| // TODO set inverse -- required a second pass probably
|
| |
| newlyCreatedRelations.add((IRelation) leftContent); |
| } |
| rightManager.setViewInfo(right, leftContent.getViewInfo()); |
| |
| // fix by Istvan
|
| rightManager.setIsFinalType(right, leftContent.getIsFinalType()); |
| |
| if (!right.getFullyQualifiedName().equals( |
| leftContent.getFullyQualifiedName())) { |
| mapFqn.put(leftContent.getFullyQualifiedName(), right |
| .getFullyQualifiedName()); |
| } |
| for (Iterator<IModelElement> it = leftContent.getElementsInNamespace().iterator(); it |
| .hasNext();) { |
| IModelElement left = it.next(); |
| createElementsInBranch(left, right); |
| } |
| } |
| |
| private static final int ENT = 0; |
| |
| private static final int REL = 1; |
| |
| private int getType(IModelElement me) { |
| if (me instanceof IEntity) |
| return ENT; |
| if (me instanceof IRelation) |
| return REL; |
| return -1; |
| } |
| } |