blob: f22eb31aa147b647dbe667bb4023627d10029bf9 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2008-2011 Chair for Applied Software Engineering,
* Technische Universitaet Muenchen.
* 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:
******************************************************************************/
package org.eclipse.emf.emfstore.client.ui.dialogs.merge;
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.List;
import java.util.ListIterator;
import java.util.Set;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.edit.ui.provider.AdapterFactoryLabelProvider;
import org.eclipse.emf.emfstore.client.ui.dialogs.merge.conflict.Conflict;
import org.eclipse.emf.emfstore.client.ui.dialogs.merge.conflict.conflicts.AttributeConflict;
import org.eclipse.emf.emfstore.client.ui.dialogs.merge.conflict.conflicts.CompositeConflict;
import org.eclipse.emf.emfstore.client.ui.dialogs.merge.conflict.conflicts.DeletionConflict;
import org.eclipse.emf.emfstore.client.ui.dialogs.merge.conflict.conflicts.DiagramLayoutConflict;
import org.eclipse.emf.emfstore.client.ui.dialogs.merge.conflict.conflicts.MultiAttributeConflict;
import org.eclipse.emf.emfstore.client.ui.dialogs.merge.conflict.conflicts.MultiAttributeMoveConflict;
import org.eclipse.emf.emfstore.client.ui.dialogs.merge.conflict.conflicts.MultiAttributeMoveSetConflict;
import org.eclipse.emf.emfstore.client.ui.dialogs.merge.conflict.conflicts.MultiAttributeSetConflict;
import org.eclipse.emf.emfstore.client.ui.dialogs.merge.conflict.conflicts.MultiAttributeSetSetConflict;
import org.eclipse.emf.emfstore.client.ui.dialogs.merge.conflict.conflicts.MultiReferenceConflict;
import org.eclipse.emf.emfstore.client.ui.dialogs.merge.conflict.conflicts.MultiReferenceSetConflict;
import org.eclipse.emf.emfstore.client.ui.dialogs.merge.conflict.conflicts.MultiReferenceSetSetConflict;
import org.eclipse.emf.emfstore.client.ui.dialogs.merge.conflict.conflicts.MultiReferenceSetSingleConflict;
import org.eclipse.emf.emfstore.client.ui.dialogs.merge.conflict.conflicts.MultiReferenceSingleConflict;
import org.eclipse.emf.emfstore.client.ui.dialogs.merge.conflict.conflicts.ReferenceConflict;
import org.eclipse.emf.emfstore.client.ui.dialogs.merge.conflict.conflicts.SingleReferenceConflict;
import org.eclipse.emf.emfstore.client.ui.dialogs.merge.util.DecisionUtil;
import org.eclipse.emf.emfstore.client.ui.dialogs.merge.util.EventLogger;
import org.eclipse.emf.emfstore.client.ui.views.changes.ChangePackageVisualizationHelper;
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.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.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 ChangePackage myChangePackage;
private final List<ChangePackage> theirChangePackages;
private ConflictDetector conflictDetector;
private ArrayList<Conflict> conflicts;
private ArrayList<AbstractOperation> notInvolvedInConflict;
private ArrayList<AbstractOperation> acceptedMine;
private ArrayList<AbstractOperation> rejectedTheirs;
private final PrimaryVersionSpec baseVersion;
private final PrimaryVersionSpec targetVersion;
private ChangePackageVisualizationHelper visualizationHelper;
private EventLogger eventLogger;
/**
* Default constructor.
*
* @param project the related project
* @param myChangePackage my changes
* @param theirChangePackages incoming changes
* @param baseVersion baseversion
* @param targetVersion new target version
*/
public DecisionManager(Project project, ChangePackage myChangePackage, List<ChangePackage> theirChangePackages,
PrimaryVersionSpec baseVersion, PrimaryVersionSpec targetVersion) {
this.project = project;
this.myChangePackage = myChangePackage;
this.theirChangePackages = theirChangePackages;
this.baseVersion = baseVersion;
this.targetVersion = targetVersion;
conflictDetector = new ConflictDetector();
init();
getEventLogger()
.createMergeEvent(baseVersion, targetVersion, conflicts.size(), myChangePackage.getOperations());
}
private void init() {
// flatten operations
List<AbstractOperation> myOperations = myChangePackage.getOperations();
List<AbstractOperation> theirOperations = new ArrayList<AbstractOperation>();
for (ChangePackage cp : theirChangePackages) {
theirOperations.addAll(cp.getOperations());
}
acceptedMine = new ArrayList<AbstractOperation>();
rejectedTheirs = new ArrayList<AbstractOperation>();
notInvolvedInConflict = new ArrayList<AbstractOperation>();
conflicts = new ArrayList<Conflict>();
ArrayList<Conflicting> conflicting = new ArrayList<Conflicting>();
// Collect all conflicting
ListIterator<AbstractOperation> myIterator = myOperations.listIterator(myOperations.size());
while (myIterator.hasPrevious()) {
AbstractOperation myOperation = myIterator.previous();
boolean involved = false;
ListIterator<AbstractOperation> theirIterator = theirOperations.listIterator(theirOperations.size());
while (theirIterator.hasPrevious()) {
AbstractOperation theirOperation = theirIterator.previous();
if (conflictDetector.doConflict(myOperation, theirOperation)) {
involved = true;
boolean conflictingYet = false;
List<Conflicting> tmpConf = new ArrayList<Conflicting>();
// check against conflicting
for (Conflicting conf : conflicting) {
if (conf.add(myOperation, theirOperation)) {
tmpConf.add(conf);
conflictingYet = true;
}
}
// merge conflicting
if (tmpConf.size() > 1) {
Conflicting main = tmpConf.get(0);
for (int i = 1; i < tmpConf.size(); i++) {
Conflicting conf = tmpConf.get(i);
main.addMyOps(conf.getMyOperations());
main.addTheirOps(conf.getTheirOperations());
conflicting.remove(conf);
}
}
if (!conflictingYet) {
conflicting.add(new Conflicting(myOperation, theirOperation));
}
}
}
if (!involved) {
notInvolvedInConflict.add(myOperation);
}
}
createConflicts(conflicting);
}
/**
* BEGIN FACTORY TODO EXTRACT FACTORY CLASS.
*/
// BEGIN COMPLEX CODE
private void createConflicts(ArrayList<Conflicting> conflicting) {
// Create Conflicts from Conflicting
for (Conflicting conf : conflicting) {
AbstractOperation my = conf.getMyOperation();
AbstractOperation their = conf.getTheirOperation();
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 void addConflict(Conflict conflict) {
if (conflict == null) {
return;
}
conflicts.add(conflict);
}
// END COMPLEX CODE
private Conflict createMultiRefMultiSet(Conflicting conf) {
if (isMultiRef(conf.getMyOperation())) {
return new MultiReferenceSetConflict(conf.getMyOperations(), conf.getTheirOperations(), this, true);
} else {
return new MultiReferenceSetConflict(conf.getTheirOperations(), conf.getMyOperations(), this, false);
}
}
private Conflict createMultiSetSingle(Conflicting conf) {
if (isMultiRefSet(conf.getMyOperation())) {
return new MultiReferenceSetSingleConflict(conf.getMyOperations(), conf.getTheirOperations(), this, true);
} else {
return new MultiReferenceSetSingleConflict(conf.getTheirOperations(), conf.getMyOperations(), this, false);
}
}
private Conflict createMultiSingle(Conflicting conf) {
if (isMultiRef(conf.getMyOperation())) {
return new MultiReferenceSingleConflict(conf.getMyOperations(), conf.getTheirOperations(), this, true);
} else {
return new MultiReferenceSingleConflict(conf.getTheirOperations(), conf.getMyOperations(), this, false);
}
}
private Conflict createMultiRefSetSet(Conflicting conf) {
return new MultiReferenceSetSetConflict(conf.getMyOperations(), conf.getTheirOperations(), this);
}
private Conflict createMultiAttSetSet(Conflicting conf) {
return new MultiAttributeSetSetConflict(conf.getMyOperations(), conf.getTheirOperations(), this);
}
private Conflict createMultiAtt(Conflicting conf) {
if (((MultiAttributeOperation) conf.getMyOperation()).isAdd()) {
return new MultiAttributeConflict(conf.getMyOperations(), conf.getTheirOperations(), this, true);
} else {
return new MultiAttributeConflict(conf.getTheirOperations(), conf.getMyOperations(), this, false);
}
}
private Conflict createMultiAttSet(Conflicting conf) {
if (isMultiAtt(conf.getMyOperation())) {
return new MultiAttributeSetConflict(conf.getMyOperations(), conf.getTheirOperations(), this, true);
} else {
return new MultiAttributeSetConflict(conf.getTheirOperations(), conf.getMyOperations(), this, false);
}
}
private Conflict createMultiAttMove(Conflicting conf) {
if (isMultiAtt(conf.getMyOperation())) {
return new MultiAttributeMoveConflict(conf.getMyOperations(), conf.getTheirOperations(), this, true);
} else {
return new MultiAttributeMoveConflict(conf.getTheirOperations(), conf.getMyOperations(), this, false);
}
}
private Conflict createMultiAttMoveSet(Conflicting conf) {
if (isMultiAttSet(conf.getMyOperation())) {
return new MultiAttributeMoveSetConflict(conf.getMyOperations(), conf.getTheirOperations(), this, true);
} else {
return new MultiAttributeMoveSetConflict(conf.getTheirOperations(), conf.getMyOperations(), this, false);
}
}
private Conflict createReferenceCompVSSingleMulti(Conflicting 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(Conflicting conf) {
EList<AbstractOperation> myOperations = ((CompositeOperation) conf.getMyOperation()).getSubOperations();
EList<AbstractOperation> theirOperations = ((CompositeOperation) conf.getTheirOperation()).getSubOperations();
return createRefFromSub(conf, myOperations, theirOperations);
}
private Conflict createRefFromSub(Conflicting 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());
} else if (isMultiRef(myOp)) {
return new ReferenceConflict(createMultiMultiConflict(myOp, theirOp), conf.getMyOperations(),
conf.getTheirOperations());
} else {
return null;
}
}
}
}
return null;
}
private Conflict createAttributeAttributeDecision(Conflicting conflicting) {
return new AttributeConflict(conflicting.getMyOperations(), conflicting.getTheirOperations(), this);
}
private Conflict createDiagramLayoutDecision(Conflicting conflicting) {
return new DiagramLayoutConflict(conflicting.getMyOperations(), conflicting.getTheirOperations(), this);
}
private Conflict createSingleSingleConflict(Conflicting conflicting) {
return new SingleReferenceConflict(conflicting.getMyOperations(), conflicting.getTheirOperations(), this);
}
private Conflict createSingleSingleConflict(AbstractOperation my, AbstractOperation their) {
return new SingleReferenceConflict(Arrays.asList(my), Arrays.asList(their), this);
}
private Conflict createMultiMultiConflict(Conflicting conf) {
if (((MultiReferenceOperation) conf.getMyOperation()).isAdd()) {
return new MultiReferenceConflict(conf.getMyOperations(), conf.getTheirOperations(), this, true);
} else {
return new MultiReferenceConflict(conf.getMyOperations(), conf.getTheirOperations(), this, false);
}
}
private Conflict createMultiMultiConflict(AbstractOperation my, AbstractOperation their) {
if (((MultiReferenceOperation) my).isAdd()) {
return new MultiReferenceConflict(Arrays.asList(my), Arrays.asList(their), this, true);
} else {
return new MultiReferenceConflict(Arrays.asList(their), Arrays.asList(my), this, false);
}
}
private Conflict createDeleteOtherConflict(Conflicting conf) {
if (isDelete(conf.getMyOperation())) {
return new DeletionConflict(conf.getMyOperations(), conf.getTheirOperations(), true, this);
} else {
return new DeletionConflict(conf.getTheirOperations(), conf.getMyOperations(), false, this);
}
}
private Conflict createCompositeConflict(Conflicting conf) {
if (isComposite(conf.getMyOperation())) {
return new CompositeConflict(conf.getMyOperations(), conf.getTheirOperations(), this, true);
} else {
return new CompositeConflict(conf.getTheirOperations(), conf.getMyOperations(), 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()}.
*/
public void calcResult() {
if (!isResolved()) {
return;
}
// collect my acknowledge operations
for (AbstractOperation myOp : myChangePackage.getOperations()) {
if (notInvolvedInConflict.contains(myOp)) {
acceptedMine.add(myOp);
} else {
for (Conflict conflict : conflicts) {
if (conflict.getAcceptedMine().contains(myOp)) {
acceptedMine.add(myOp);
}
}
}
}
// Collect other accepted, which were generated in the merge process
for (Conflict conflict : conflicts) {
for (AbstractOperation ao : conflict.getAcceptedMine()) {
if (!acceptedMine.contains(ao)) {
acceptedMine.add(ao);
}
}
}
for (ChangePackage theirCP : theirChangePackages) {
for (AbstractOperation theirOp : theirCP.getOperations()) {
for (Conflict conflict : conflicts) {
if (conflict.getRejectedTheirs().contains(theirOp)) {
rejectedTheirs.add(theirOp);
}
}
}
}
}
/**
* Returns the conflictdetector.
*
* @return conflictdetector
*/
public ConflictDetector getConflictDetector() {
return conflictDetector;
}
/**
* 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) {
AdapterFactoryLabelProvider adapterFactory = DecisionUtil.getAdapterFactory();
return adapterFactory.getText(modelElement);
}
/**
* Returns the modelelement. Therefore the project as well as creation and deletion operations are searched.
*
* @param modelElementId id of element.
* @return modelelement
*/
public EObject getModelElement(ModelElementId modelElementId) {
EObject modelElement = project.getModelElement(modelElementId);
if (modelElement == null) {
modelElement = searchForCreatedME(modelElementId, myChangePackage.getOperations());
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 (child != 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 visualizationhelper.
*
* @return visualizationhelper
*/
public ChangePackageVisualizationHelper getChangePackageVisualizationHelper() {
if (visualizationHelper == null) {
ArrayList<ChangePackage> list = new ArrayList<ChangePackage>();
list.add(myChangePackage);
list.addAll(theirChangePackages);
visualizationHelper = new ChangePackageVisualizationHelper(list, project);
}
return visualizationHelper;
}
/**
* Return the Eventlogger.
*
* @return logger
*/
public EventLogger getEventLogger() {
if (eventLogger == null) {
eventLogger = new EventLogger(project);
}
return eventLogger;
}
/**
* 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;
}
/**
* Container for connected, conflicting operations.
*
* @author wesendon
*/
private class Conflicting {
private ArrayList<AbstractOperation> myOps;
private ArrayList<AbstractOperation> theirOps;
public Conflicting(AbstractOperation myOp, AbstractOperation theirOp) {
myOps = new ArrayList<AbstractOperation>();
myOps.add(myOp);
theirOps = new ArrayList<AbstractOperation>();
theirOps.add(theirOp);
}
public AbstractOperation getTheirOperation() {
return theirOps.get(0);
}
public AbstractOperation getMyOperation() {
return myOps.get(0);
}
public List<AbstractOperation> getTheirOperations() {
return theirOps;
}
public List<AbstractOperation> getMyOperations() {
return myOps;
}
public boolean add(AbstractOperation myOp, AbstractOperation theirOp) {
for (AbstractOperation ao : getTheirOperations()) {
if (conflictDetector.doConflict(myOp, ao)) {
addToList(myOp, theirOp);
return true;
}
}
for (AbstractOperation ao : getMyOperations()) {
if (conflictDetector.doConflict(ao, theirOp)) {
addToList(myOp, theirOp);
return true;
}
}
return false;
}
private void addToList(AbstractOperation my, AbstractOperation their) {
addMyOp(my);
addTheirOp(their);
}
private void addMyOp(AbstractOperation my) {
if (!myOps.contains(my)) {
myOps.add(my);
}
}
private void addTheirOp(AbstractOperation their) {
if (!theirOps.contains(their)) {
theirOps.add(their);
}
}
public void addMyOps(List<AbstractOperation> ops) {
for (AbstractOperation ao : ops) {
addMyOp(ao);
}
}
public void addTheirOps(List<AbstractOperation> ops) {
for (AbstractOperation ao : ops) {
addTheirOp(ao);
}
}
}
}