blob: 08707b112188bb3f963bd3e8c41d869c7d01e3ae [file] [log] [blame]
/*******************************************************************************
* 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;
}
}