blob: 49d9cb99b88ade07aa07857a0585b5b775fe73b3 [file] [log] [blame]
/*******************************************************************************
* Copyright 2011 Chair for Applied Software Engineering,
* Technische Universitaet Muenchen.
* All rights reserved. This program and the accompanying materials
* are made available under the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
******************************************************************************/
package org.eclipse.emf.emfstore.client.model.changeTracking.merging;
import static org.eclipse.emf.emfstore.server.model.versioning.operations.util.OperationUtil.isAttribute;
import static org.eclipse.emf.emfstore.server.model.versioning.operations.util.OperationUtil.isComposite;
import static org.eclipse.emf.emfstore.server.model.versioning.operations.util.OperationUtil.isCompositeRef;
import static org.eclipse.emf.emfstore.server.model.versioning.operations.util.OperationUtil.isDelete;
import static org.eclipse.emf.emfstore.server.model.versioning.operations.util.OperationUtil.isDiagramLayout;
import static org.eclipse.emf.emfstore.server.model.versioning.operations.util.OperationUtil.isMultiAtt;
import static org.eclipse.emf.emfstore.server.model.versioning.operations.util.OperationUtil.isMultiAttMove;
import static org.eclipse.emf.emfstore.server.model.versioning.operations.util.OperationUtil.isMultiAttSet;
import static org.eclipse.emf.emfstore.server.model.versioning.operations.util.OperationUtil.isMultiRef;
import static org.eclipse.emf.emfstore.server.model.versioning.operations.util.OperationUtil.isMultiRefSet;
import static org.eclipse.emf.emfstore.server.model.versioning.operations.util.OperationUtil.isSingleRef;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.emfstore.client.model.changeTracking.merging.conflict.Conflict;
import org.eclipse.emf.emfstore.client.model.changeTracking.merging.conflict.conflicts.AttributeConflict;
import org.eclipse.emf.emfstore.client.model.changeTracking.merging.conflict.conflicts.CompositeConflict;
import org.eclipse.emf.emfstore.client.model.changeTracking.merging.conflict.conflicts.DeletionConflict;
import org.eclipse.emf.emfstore.client.model.changeTracking.merging.conflict.conflicts.DiagramLayoutConflict;
import org.eclipse.emf.emfstore.client.model.changeTracking.merging.conflict.conflicts.MultiAttributeConflict;
import org.eclipse.emf.emfstore.client.model.changeTracking.merging.conflict.conflicts.MultiAttributeMoveConflict;
import org.eclipse.emf.emfstore.client.model.changeTracking.merging.conflict.conflicts.MultiAttributeMoveSetConflict;
import org.eclipse.emf.emfstore.client.model.changeTracking.merging.conflict.conflicts.MultiAttributeSetConflict;
import org.eclipse.emf.emfstore.client.model.changeTracking.merging.conflict.conflicts.MultiAttributeSetSetConflict;
import org.eclipse.emf.emfstore.client.model.changeTracking.merging.conflict.conflicts.MultiReferenceConflict;
import org.eclipse.emf.emfstore.client.model.changeTracking.merging.conflict.conflicts.MultiReferenceSetConflict;
import org.eclipse.emf.emfstore.client.model.changeTracking.merging.conflict.conflicts.MultiReferenceSetSetConflict;
import org.eclipse.emf.emfstore.client.model.changeTracking.merging.conflict.conflicts.MultiReferenceSetSingleConflict;
import org.eclipse.emf.emfstore.client.model.changeTracking.merging.conflict.conflicts.MultiReferenceSingleConflict;
import org.eclipse.emf.emfstore.client.model.changeTracking.merging.conflict.conflicts.ReferenceConflict;
import org.eclipse.emf.emfstore.client.model.changeTracking.merging.conflict.conflicts.SingleReferenceConflict;
import org.eclipse.emf.emfstore.client.model.changeTracking.merging.util.DecisionUtil;
import org.eclipse.emf.emfstore.client.model.exceptions.ChangeConflictException;
import org.eclipse.emf.emfstore.common.extensionpoint.ExtensionElement;
import org.eclipse.emf.emfstore.common.extensionpoint.ExtensionPoint;
import org.eclipse.emf.emfstore.common.model.ModelElementId;
import org.eclipse.emf.emfstore.common.model.Project;
import org.eclipse.emf.emfstore.common.model.util.ModelUtil;
import org.eclipse.emf.emfstore.server.conflictDetection.ConflictBucket;
import org.eclipse.emf.emfstore.server.conflictDetection.ConflictBucketCandidate;
import org.eclipse.emf.emfstore.server.conflictDetection.ConflictDetector;
import org.eclipse.emf.emfstore.server.model.versioning.ChangePackage;
import org.eclipse.emf.emfstore.server.model.versioning.LogMessage;
import org.eclipse.emf.emfstore.server.model.versioning.PrimaryVersionSpec;
import org.eclipse.emf.emfstore.server.model.versioning.impl.ChangePackageImpl;
import org.eclipse.emf.emfstore.server.model.versioning.operations.AbstractOperation;
import org.eclipse.emf.emfstore.server.model.versioning.operations.CompositeOperation;
import org.eclipse.emf.emfstore.server.model.versioning.operations.CreateDeleteOperation;
import org.eclipse.emf.emfstore.server.model.versioning.operations.MultiAttributeOperation;
import org.eclipse.emf.emfstore.server.model.versioning.operations.MultiReferenceOperation;
/**
* DecisionManager is the controller for the merge dialog and therefore it's
* main component. It calculates the conflicts from incoming changes and can
* execute resolved conflicts.
*
* @author wesendon
*/
public class DecisionManager {
private final Project project;
private final List<ChangePackage> myChangePackages;
private final List<ChangePackage> theirChangePackages;
private ConflictDetector conflictDetector;
private ArrayList<Conflict> conflicts;
private Set<AbstractOperation> notInvolvedInConflict;
private ArrayList<AbstractOperation> acceptedMine;
private ArrayList<AbstractOperation> rejectedTheirs;
private final PrimaryVersionSpec baseVersion;
private final PrimaryVersionSpec targetVersion;
private List<ConflictHandler> conflictHandler;
private final boolean isBranchMerge;
private ChangeConflictException conflictException;
/**
* Default constructor.
*
* @param project
* the related project
* @param myChangePackages
* my changes
* @param theirChangePackages
* incoming changes
* @param baseVersion
* baseversion
* @param targetVersion
* new target version
* @param isBranchMerge
* allows to specify whether two branches are merged, opposed to
* changes from the same branch. Has an effect on the wording of
* conflictions
* @param conflictException a conflict exception with preliminary results
*/
public DecisionManager(Project project, List<ChangePackage> myChangePackages,
List<ChangePackage> theirChangePackages, PrimaryVersionSpec baseVersion, PrimaryVersionSpec targetVersion,
boolean isBranchMerge, ChangeConflictException conflictException) {
this.project = project;
this.myChangePackages = myChangePackages;
this.theirChangePackages = theirChangePackages;
this.baseVersion = baseVersion;
this.targetVersion = targetVersion;
this.isBranchMerge = isBranchMerge;
this.conflictException = conflictException;
this.conflictHandler = initConflictHandlers();
this.conflictDetector = new ConflictDetector();
init();
}
private List<ConflictHandler> initConflictHandlers() {
ArrayList<ConflictHandler> result = new ArrayList<ConflictHandler>();
for (ExtensionElement element : new ExtensionPoint("org.eclipse.emf.emfstore.client.merge.conflictHandler")
.getExtensionElements()) {
ConflictHandler handler = element.getClass("class", ConflictHandler.class);
if (handler != null) {
result.add(handler);
}
}
return result;
}
private void init() {
// flatten operations
acceptedMine = new ArrayList<AbstractOperation>();
rejectedTheirs = new ArrayList<AbstractOperation>();
conflicts = new ArrayList<Conflict>();
notInvolvedInConflict = new LinkedHashSet<AbstractOperation>();
Set<ConflictBucketCandidate> conflictBucketCandidates;
if (conflictException != null) {
conflictBucketCandidates = conflictException.getConflictBucketCandidates();
} else {
conflictBucketCandidates = new ConflictDetector().calculateConflictCandidateBuckets(myChangePackages,
theirChangePackages);
}
Set<ConflictBucket> conflictBucketsSet = conflictDetector.calculateConflictBucketsFromConflictCandidateBuckets(
conflictBucketCandidates, notInvolvedInConflict);
createConflicts(conflictBucketsSet);
}
/**
* BEGIN FACTORY TODO EXTRACT FACTORY CLASS.
*/
// BEGIN COMPLEX CODE
private void createConflicts(Set<ConflictBucket> ConflictBucket) {
// Create Conflicts from ConflictBucket
for (ConflictBucket conf : ConflictBucket) {
AbstractOperation my = conf.getMyOperation();
AbstractOperation their = conf.getTheirOperation();
// #checkRegistedHandlers adds Conflicts on its own
if (checkRegisteredHandlers(conf)) {
continue;
} else if (isDiagramLayout(my) && isDiagramLayout(their)) {
addConflict(createDiagramLayoutDecision(conf));
continue;
} else if (isAttribute(my) && isAttribute(their)) {
addConflict(createAttributeAttributeDecision(conf));
continue;
} else if (isSingleRef(my) && isSingleRef(their)) {
addConflict(createSingleSingleConflict(conf));
continue;
} else if (isMultiRef(my) && isMultiRef(their)) {
addConflict(createMultiMultiConflict(conf));
continue;
} else if ((isMultiRef(my) && isSingleRef(their)) || (isMultiRef(their) && isSingleRef(my))) {
addConflict(createMultiSingle(conf));
continue;
} else if (isCompositeRef(my) && isCompositeRef(their)) {
addConflict(createReferenceConflict(conf));
continue;
} else if ((isCompositeRef(my) && (isMultiRef(their) || isSingleRef(their)))
|| ((isMultiRef(my) || isSingleRef(my)) && isCompositeRef(their))) {
addConflict(createReferenceCompVSSingleMulti(conf));
continue;
} else if ((isMultiRef(my) && isMultiRefSet(their)) || (isMultiRef(their) && isMultiRefSet(my))) {
addConflict(createMultiRefMultiSet(conf));
continue;
} else if (isMultiRefSet(my) && isMultiRefSet(their)) {
addConflict(createMultiRefSetSet(conf));
continue;
} else if ((isMultiRefSet(my) && isSingleRef(their)) || (isMultiRefSet(their) && isSingleRef(my))) {
addConflict(createMultiSetSingle(conf));
continue;
} else if (isMultiAtt(my) && isMultiAtt(their)) {
addConflict(createMultiAtt(conf));
continue;
} else if ((isMultiAtt(my) && isMultiAttSet(their)) || (isMultiAtt(their) && isMultiAttSet(my))) {
addConflict(createMultiAttSet(conf));
continue;
} else if ((isMultiAtt(my) && isMultiAttMove(their)) || (isMultiAtt(their) && isMultiAttMove(my))) {
addConflict(createMultiAttMove(conf));
continue;
} else if ((isMultiAttSet(my) && isMultiAttMove(their)) || (isMultiAttSet(their) && isMultiAttMove(my))) {
addConflict(createMultiAttMoveSet(conf));
continue;
} else if (isMultiAttSet(my) && isMultiAttSet(their)) {
addConflict(createMultiAttSetSet(conf));
continue;
} else if (isComposite(my) || isComposite(their)) {
addConflict(createCompositeConflict(conf));
continue;
} else if (isDelete(my) || isDelete(their)) {
addConflict(createDeleteOtherConflict(conf));
}
}
}
private boolean checkRegisteredHandlers(ConflictBucket conf) {
for (ConflictHandler handler : this.conflictHandler) {
if (handler.canHandle(conf)) {
addConflict(handler.handle(this, conf));
return true;
}
}
return false;
}
private void addConflict(Conflict conflict) {
if (conflict == null) {
return;
}
conflicts.add(conflict);
}
// END COMPLEX CODE
private Conflict createMultiRefMultiSet(ConflictBucket conf) {
if (isMultiRef(conf.getMyOperation())) {
return new MultiReferenceSetConflict(conf.getMyOperations(), conf.getTheirOperations(),
conf.getMyOperation(), conf.getTheirOperation(), this, true);
} else {
return new MultiReferenceSetConflict(conf.getTheirOperations(), conf.getMyOperations(),
conf.getTheirOperation(), conf.getMyOperation(), this, false);
}
}
private Conflict createMultiSetSingle(ConflictBucket conf) {
if (isMultiRefSet(conf.getMyOperation())) {
return new MultiReferenceSetSingleConflict(conf.getMyOperations(), conf.getTheirOperations(),
conf.getMyOperation(), conf.getTheirOperation(), this, true);
} else {
return new MultiReferenceSetSingleConflict(conf.getTheirOperations(), conf.getMyOperations(),
conf.getTheirOperation(), conf.getMyOperation(), this, false);
}
}
private Conflict createMultiSingle(ConflictBucket conf) {
if (isMultiRef(conf.getMyOperation())) {
return new MultiReferenceSingleConflict(conf.getMyOperations(), conf.getTheirOperations(),
conf.getMyOperation(), conf.getTheirOperation(), this, true);
} else {
return new MultiReferenceSingleConflict(conf.getTheirOperations(), conf.getMyOperations(),
conf.getTheirOperation(), conf.getMyOperation(), this, false);
}
}
private Conflict createMultiRefSetSet(ConflictBucket conf) {
return new MultiReferenceSetSetConflict(conf.getMyOperations(), conf.getTheirOperations(),
conf.getMyOperation(), conf.getTheirOperation(), this);
}
private Conflict createMultiAttSetSet(ConflictBucket conf) {
return new MultiAttributeSetSetConflict(conf.getMyOperations(), conf.getTheirOperations(),
conf.getMyOperation(), conf.getTheirOperation(), this);
}
private Conflict createMultiAtt(ConflictBucket conf) {
if (((MultiAttributeOperation) conf.getMyOperation()).isAdd()) {
return new MultiAttributeConflict(conf.getMyOperations(), conf.getTheirOperations(), conf.getMyOperation(),
conf.getTheirOperation(), this, true);
} else {
return new MultiAttributeConflict(conf.getTheirOperations(), conf.getMyOperations(),
conf.getTheirOperation(), conf.getMyOperation(), this, false);
}
}
private Conflict createMultiAttSet(ConflictBucket conf) {
if (isMultiAtt(conf.getMyOperation())) {
return new MultiAttributeSetConflict(conf.getMyOperations(), conf.getTheirOperations(),
conf.getMyOperation(), conf.getTheirOperation(), this, true);
} else {
return new MultiAttributeSetConflict(conf.getTheirOperations(), conf.getMyOperations(),
conf.getTheirOperation(), conf.getMyOperation(), this, false);
}
}
private Conflict createMultiAttMove(ConflictBucket conf) {
if (isMultiAtt(conf.getMyOperation())) {
return new MultiAttributeMoveConflict(conf.getMyOperations(), conf.getTheirOperations(),
conf.getMyOperation(), conf.getTheirOperation(), this, true);
} else {
return new MultiAttributeMoveConflict(conf.getTheirOperations(), conf.getMyOperations(),
conf.getTheirOperation(), conf.getMyOperation(), this, false);
}
}
private Conflict createMultiAttMoveSet(ConflictBucket conf) {
if (isMultiAttSet(conf.getMyOperation())) {
return new MultiAttributeMoveSetConflict(conf.getMyOperations(), conf.getTheirOperations(),
conf.getMyOperation(), conf.getTheirOperation(), this, true);
} else {
return new MultiAttributeMoveSetConflict(conf.getTheirOperations(), conf.getMyOperations(),
conf.getTheirOperation(), conf.getMyOperation(), this, false);
}
}
private Conflict createReferenceCompVSSingleMulti(ConflictBucket conf) {
if (isCompositeRef(conf.getMyOperation())) {
return createRefFromSub(conf, ((CompositeOperation) conf.getMyOperation()).getSubOperations(),
Arrays.asList(conf.getTheirOperation()));
} else {
return createRefFromSub(conf, Arrays.asList(conf.getMyOperation()),
((CompositeOperation) conf.getTheirOperation()).getSubOperations());
}
}
private Conflict createReferenceConflict(ConflictBucket conf) {
EList<AbstractOperation> myOperations = ((CompositeOperation) conf.getMyOperation()).getSubOperations();
EList<AbstractOperation> theirOperations = ((CompositeOperation) conf.getTheirOperation()).getSubOperations();
return createRefFromSub(conf, myOperations, theirOperations);
}
private Conflict createRefFromSub(ConflictBucket conf, List<AbstractOperation> myOperations,
List<AbstractOperation> theirOperations) {
for (AbstractOperation myOp : myOperations) {
for (AbstractOperation theirOp : theirOperations) {
if (conflictDetector.doConflict(myOp, theirOp)) {
if (isSingleRef(myOp)) {
return new ReferenceConflict(createSingleSingleConflict(myOp, theirOp), conf.getMyOperations(),
conf.getTheirOperations(), conf.getMyOperation(), conf.getTheirOperation());
} else if (isMultiRef(myOp)) {
return new ReferenceConflict(createMultiMultiConflict(myOp, theirOp), conf.getMyOperations(),
conf.getTheirOperations(), conf.getMyOperation(), conf.getTheirOperation());
} else {
return null;
}
}
}
}
return null;
}
private Conflict createAttributeAttributeDecision(ConflictBucket conf) {
return new AttributeConflict(conf.getMyOperations(), conf.getTheirOperations(), conf.getMyOperation(),
conf.getTheirOperation(), this);
}
private Conflict createDiagramLayoutDecision(ConflictBucket conf) {
return new DiagramLayoutConflict(conf.getMyOperations(), conf.getTheirOperations(), conf.getMyOperation(),
conf.getTheirOperation(), this);
}
private Conflict createSingleSingleConflict(ConflictBucket conf) {
return new SingleReferenceConflict(conf.getMyOperations(), conf.getTheirOperations(), conf.getMyOperation(),
conf.getTheirOperation(), this);
}
private Conflict createSingleSingleConflict(AbstractOperation my, AbstractOperation their) {
return new SingleReferenceConflict(set(my), set(their), my, their, this);
}
private <T> Set<T> set(T object) {
Set<T> set = new LinkedHashSet<T>();
set.add(object);
return set;
}
private Conflict createMultiMultiConflict(ConflictBucket conf) {
if (((MultiReferenceOperation) conf.getMyOperation()).isAdd()) {
return new MultiReferenceConflict(conf.getMyOperations(), conf.getTheirOperations(), conf.getMyOperation(),
conf.getTheirOperation(), this, true);
} else {
return new MultiReferenceConflict(conf.getMyOperations(), conf.getTheirOperations(), conf.getMyOperation(),
conf.getTheirOperation(), this, false);
}
}
private Conflict createMultiMultiConflict(AbstractOperation my, AbstractOperation their) {
if (((MultiReferenceOperation) my).isAdd()) {
return new MultiReferenceConflict(set(my), set(their), my, their, this, true);
} else {
return new MultiReferenceConflict(set(their), set(my), their, my, this, false);
}
}
private Conflict createDeleteOtherConflict(ConflictBucket conf) {
if (isDelete(conf.getMyOperation())) {
return new DeletionConflict(conf.getMyOperations(), conf.getTheirOperations(), conf.getMyOperation(),
conf.getTheirOperation(), true, this);
} else {
return new DeletionConflict(conf.getTheirOperations(), conf.getMyOperations(), conf.getTheirOperation(),
conf.getMyOperation(), false, this);
}
}
private Conflict createCompositeConflict(ConflictBucket conf) {
if (isComposite(conf.getMyOperation())) {
return new CompositeConflict(conf.getMyOperations(), conf.getTheirOperations(), conf.getMyOperation(),
conf.getTheirOperation(), this, true);
} else {
return new CompositeConflict(conf.getTheirOperations(), conf.getMyOperations(), conf.getTheirOperation(),
conf.getMyOperation(), this, false);
}
}
/**
* FACTORY END
*/
/**
* Returns the conflicts.
*
* @return list of conflicts.
*/
public ArrayList<Conflict> getConflicts() {
return conflicts;
}
/**
* Checks whether all conflicts are resolved.
*
* @return true if all are resolved
*/
public boolean isResolved() {
boolean isResolved = true;
for (Conflict conflict : conflicts) {
isResolved = isResolved && conflict.isResolved();
}
return isResolved;
}
/**
* Get "my" accepted operations. This list will be empty, if {@link #calcResult()} hasn't been called before.
*
* @return list of operations
*/
public List<AbstractOperation> getAcceptedMine() {
return acceptedMine;
}
/**
* Get "their" accepted operations. This list will be empty, if {@link #calcResult()} hasn't been called before.
*
* @return list of operations
*/
public List<AbstractOperation> getRejectedTheirs() {
return rejectedTheirs;
}
/**
* If all conflicts are resolved this method will generate the resulting
* operations from the conflicts. Then call {@link #getAcceptedMine()} and {@link #getRejectedTheirs()}.
*/
// BEGIN COMPLEX CODE
public void calcResult() {
if (!isResolved()) {
return;
}
Set<AbstractOperation> accceptedMineSet = new LinkedHashSet<AbstractOperation>();
Set<AbstractOperation> rejectedTheirsSet = new LinkedHashSet<AbstractOperation>();
for (Conflict conflict : conflicts) {
accceptedMineSet.addAll(conflict.getAcceptedMine());
rejectedTheirsSet.addAll(conflict.getRejectedTheirs());
}
// collect my accepted operations
for (ChangePackage myChangePackage : myChangePackages) {
for (AbstractOperation myOp : myChangePackage.getOperations()) {
if (notInvolvedInConflict.contains(myOp)) {
acceptedMine.add(myOp);
} else if (accceptedMineSet.contains(myOp)) {
acceptedMine.add(myOp);
}
accceptedMineSet.remove(myOp);
}
}
// add all remaining operations in acceptedMineSet (they have been generated during merge)
acceptedMine.addAll(accceptedMineSet);
for (ChangePackage theirCP : theirChangePackages) {
for (AbstractOperation theirOp : theirCP.getOperations()) {
if (rejectedTheirsSet.contains(theirOp)) {
rejectedTheirs.add(theirOp);
}
}
}
}
// END COMPLEX CODE
/**
* Returns the conflictdetector.
*
* @return conflictdetector
*/
public ConflictDetector getConflictDetector() {
return conflictDetector;
}
/**
* Flat whether branches are merged opposed to versions on the same branch.
*
* @return true, if branches
*/
public boolean isBranchMerge() {
return isBranchMerge;
}
/**
* Get the Name of an model element by modelelement id.
*
* @param modelElementId
* id of element
* @return name as string
*/
public String getModelElementName(ModelElementId modelElementId) {
return getModelElementName(getModelElement(modelElementId));
}
/**
* Get the Name of an model element.
*
* @param modelElement
* element
* @return name as string
*/
public String getModelElementName(EObject modelElement) {
return DecisionUtil.getModelElementName(modelElement);
}
/**
* Returns the modelelement. Therefore the project as well as creation and
* deletion operations are searched.
*
* @param modelElementId
* id of element.
* @return modelelement
*/
// TODO: SLOW!
public EObject getModelElement(ModelElementId modelElementId) {
EObject modelElement = project.getModelElement(modelElementId);
if (modelElement == null) {
for (ChangePackage cp : myChangePackages) {
modelElement = searchForCreatedME(modelElementId, cp.getOperations());
if (modelElement != null) {
break;
}
}
if (modelElement == null) {
for (ChangePackage cp : theirChangePackages) {
modelElement = searchForCreatedME(modelElementId, cp.getOperations());
if (modelElement != null) {
break;
}
}
}
}
return modelElement;
}
private EObject searchForCreatedME(ModelElementId modelElementId, List<AbstractOperation> operations) {
for (AbstractOperation operation : operations) {
EObject result = null;
if (operation instanceof CreateDeleteOperation) {
result = searchCreateAndDelete((CreateDeleteOperation) operation, modelElementId);
} else if (operation instanceof CompositeOperation) {
EList<AbstractOperation> subOperations = ((CompositeOperation) operation).getSubOperations();
result = searchForCreatedME(modelElementId, subOperations);
} else {
continue;
}
if (result != null) {
return result;
}
}
return null;
}
private EObject searchCreateAndDelete(CreateDeleteOperation cdo, ModelElementId modelElementId) {
EObject modelElement = cdo.getModelElement();
if (modelElement == null) {
return null;
}
Set<EObject> containedModelElements = ModelUtil.getAllContainedModelElements(modelElement, false);
containedModelElements.add(modelElement);
for (EObject child : containedModelElements) {
ModelElementId childId = ModelUtil.clone(cdo.getEObjectToIdMap().get(child));
if (childId != null && childId.equals(modelElementId)) {
return child;
}
}
return null;
}
/**
* Returns the name of the author for a operation in list of their
* operations.
*
* @param theirOperation
* operation
* @return name as string or ""
*/
public String getAuthorForOperation(AbstractOperation theirOperation) {
for (ChangePackage cp : theirChangePackages) {
for (AbstractOperation op : cp.getOperations()) {
List<AbstractOperation> tmpList = new ArrayList<AbstractOperation>();
if (op instanceof CompositeOperation) {
tmpList.add(op);
tmpList.addAll(((CompositeOperation) op).getSubOperations());
} else {
tmpList.add(op);
}
for (AbstractOperation ao : tmpList) {
if (ao.equals(theirOperation)) {
LogMessage log = cp.getLogMessage();
if (log == null) {
return "";
}
return (log.getAuthor() == null) ? "" : log.getAuthor();
}
}
}
}
return "";
}
/**
* Return the related project.
*
* @return project
*/
public Project getProject() {
return project;
}
/**
* Returns the baseVersion of the project which is updating.
*
* @return version
*/
public PrimaryVersionSpec getBaseVersion() {
return baseVersion;
}
/**
* Returns the targetVersion of the update which caused merging.
*
* @return version
*/
public PrimaryVersionSpec getTargetVersion() {
return targetVersion;
}
/**
* Gives Access to internal values. Use with care.
*/
// BEGIN COMPLEX CODE
public DecisionManager.Internal Internal = this.new Internal();
// END COMPLEX CODE
/**
* This class allows access to internal values. Use with care.
*
* @author wesendon
*/
public class Internal {
/**
* My CP.
*
* @return list of cp
*/
public List<ChangePackage> getMyChangePackages() {
return myChangePackages;
}
/**
* Their CP.
*
* @return list of cp
*/
public List<ChangePackage> getTheirChangePackages() {
return theirChangePackages;
}
}
private Integer myLeafOperationCount;
/**
* Count my leaf operations.
*
* @return the number of leaf operations
*/
public int countMyLeafOperations() {
if (myLeafOperationCount == null) {
countConflicts();
}
return myLeafOperationCount;
}
private void countConflicts() {
int myCount = 0;
int myLeafCount = 0;
int theirCount = 0;
int theirLeafCount = 0;
for (Conflict conflict : conflicts) {
myCount += conflict.getLeftOperations().size();
myLeafCount += ChangePackageImpl.countLeafOperations(conflict.getMyOperations());
theirCount += conflict.getRightOperations().size();
theirLeafCount += ChangePackageImpl.countLeafOperations(conflict.getTheirOperations());
}
myOperationCount = myCount;
myLeafOperationCount = myLeafCount;
theirOperationCount = theirCount;
theirLeafOperationCount = theirLeafCount;
}
private Integer theirLeafOperationCount;
/**
* Count their leaf operations.
*
* @return the number of leaf operations
*/
public int countTheirLeafOperations() {
if (theirLeafOperationCount == null) {
countConflicts();
}
return theirLeafOperationCount;
}
private Integer myOperationCount;
/**
* Count my leaf operations.
*
* @return the number of leaf operations
*/
public int countMyOperations() {
if (myOperationCount == null) {
countConflicts();
}
return myOperationCount;
}
private Integer theirOperationCount;
/**
* Count their leaf operations.
*
* @return the number of leaf operations
*/
public int countTheirOperations() {
if (theirOperationCount == null) {
countConflicts();
}
return theirOperationCount;
}
}