/*******************************************************************************
* 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.server.conflictDetection;
import java.util.Set;
import org.eclipse.emf.emfstore.common.model.ModelElementId;
import org.eclipse.emf.emfstore.server.model.versioning.operations.AbstractOperation;
import org.eclipse.emf.emfstore.server.model.versioning.operations.AttributeOperation;
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.DiagramLayoutOperation;
import org.eclipse.emf.emfstore.server.model.versioning.operations.FeatureOperation;
import org.eclipse.emf.emfstore.server.model.versioning.operations.MultiReferenceMoveOperation;
import org.eclipse.emf.emfstore.server.model.versioning.operations.MultiReferenceOperation;
import org.eclipse.emf.emfstore.server.model.versioning.operations.ReferenceOperation;
import org.eclipse.emf.emfstore.server.model.versioning.operations.SingleReferenceOperation;
/**
* A conflict detection strategy that will operate on a per attribute and feature level.
*
* @author koegel
*/
public class FineGrainedConflictDetectionStrategy implements ConflictDetectionStrategy {
/**
* {@inheritDoc}
*
* @see org.eclipse.emf.emfstore.server.conflictDetection.ConflictDetectionStrategy#doConflict(org.eclipse.emf.emfstore.server.model.versioning.operations.AbstractOperation,
* org.eclipse.emf.emfstore.server.model.versioning.operations.AbstractOperation)
*/
public boolean doConflict(AbstractOperation operationA, AbstractOperation operationB) {
if (operationA instanceof DiagramLayoutOperation) {
return doConflict((DiagramLayoutOperation) operationA, operationB);
} else if (operationA instanceof AttributeOperation) {
return doConflict((AttributeOperation) operationA, operationB);
} else if (operationA instanceof MultiReferenceMoveOperation) {
return doConflict((MultiReferenceMoveOperation) operationA, operationB);
} else if (operationA instanceof SingleReferenceOperation) {
return doConflict((SingleReferenceOperation) operationA, operationB);
} else if (operationA instanceof MultiReferenceOperation) {
return doConflict((MultiReferenceOperation) operationA, operationB);
} else if (operationA instanceof CreateDeleteOperation) {
return doConflict((CreateDeleteOperation) operationA, operationB);
} else if (operationA instanceof CompositeOperation) {
return doConflict((CompositeOperation) operationA, operationB);
}
throw new IllegalArgumentException("Unkown operation type: " + operationA);
}
private boolean doConflict(MultiReferenceOperation operationA, AbstractOperation operationB) {
if (operationB instanceof AttributeOperation) {
return false;
} else if (operationB instanceof MultiReferenceMoveOperation) {
boolean sameFeature = ((FeatureOperation) operationA).getFeatureName().equals(
((MultiReferenceMoveOperation) operationB).getFeatureName());
boolean sameElement = operationA.getModelElementId().equals(operationB.getModelElementId());
return sameElement && sameFeature;
} else if (operationB instanceof ReferenceOperation) {
// MK split by multireference and singlereference
MultiReferenceOperation multiOperationA = operationA;
ReferenceOperation referenceOperationB = (ReferenceOperation) operationB;
boolean sameFeature = multiOperationA.getFeatureName().equals(referenceOperationB.getFeatureName());
// check if they really overlap
boolean sameElement = multiOperationA.getModelElementId().equals(referenceOperationB.getModelElementId());
if (sameFeature && sameElement) {
Set<ModelElementId> otherInvolvedModelElements = operationA.getOtherInvolvedModelElements();
for (ModelElementId modelElementId : operationA.getReferencedModelElements()) {
if (otherInvolvedModelElements.contains(modelElementId)) {
return true;
}
}
}
if (multiOperationA.getOppositeFeatureName() != null) {
sameFeature = multiOperationA.getOppositeFeatureName().equals(referenceOperationB.getFeatureName());
}
return false;
} else {
return doConflict(operationB, operationA);
}
}
private boolean doConflict(CompositeOperation operationA, AbstractOperation operationB) {
for (AbstractOperation subOperationA : operationA.getSubOperations()) {
if (doConflict(subOperationA, operationB)) {
return true;
}
}
return false;
}
private boolean doConflict(DiagramLayoutOperation operationA, AbstractOperation operationB) {
if (operationB instanceof DiagramLayoutOperation) {
return operationA.getModelElementId().equals(operationA.getModelElementId());
}
return false;
}
/**
* {@inheritDoc}
*
* @see org.eclipse.emf.emfstore.server.conflictDetection.ConflictDetectionStrategy#isRequired(org.eclipse.emf.emfstore.server.model.versioning.operations.AbstractOperation,
* org.eclipse.emf.emfstore.server.model.versioning.operations.AbstractOperation)
*/
public boolean isRequired(AbstractOperation requiredOperation, AbstractOperation operation) {
if (requiredOperation instanceof CreateDeleteOperation) {
return isRequired((CreateDeleteOperation) requiredOperation, operation);
} else if (requiredOperation instanceof MultiReferenceOperation
&& operation instanceof MultiReferenceMoveOperation) {
return isRequired((MultiReferenceOperation) requiredOperation, (MultiReferenceMoveOperation) operation);
} else if (requiredOperation instanceof MultiReferenceOperation && operation instanceof MultiReferenceOperation) {
return isRequired((MultiReferenceOperation) requiredOperation, (MultiReferenceOperation) operation);
} else if (requiredOperation instanceof CompositeOperation) {
for (AbstractOperation abstractOperation : ((CompositeOperation) requiredOperation).getSubOperations()) {
if (isRequired(abstractOperation, operation)) {
return true;
}
}
return false;
} else if (operation instanceof CompositeOperation) {
for (AbstractOperation abstractOperation : ((CompositeOperation) operation).getSubOperations()) {
if (isRequired(requiredOperation, abstractOperation)) {
return true;
}
}
return false;
}
return false;
}
private boolean isRequired(MultiReferenceOperation requiredMultiReferenceOperation,
MultiReferenceOperation multiReferenceOperation) {
boolean sameElement = requiredMultiReferenceOperation.getModelElementId().equals(
multiReferenceOperation.getModelElementId());
boolean sameFeature = requiredMultiReferenceOperation.getFeatureName().equals(
multiReferenceOperation.getFeatureName());
if (sameElement && sameFeature && requiredMultiReferenceOperation.isAdd() && !multiReferenceOperation.isAdd()) {
for (ModelElementId modelElementId : multiReferenceOperation.getReferencedModelElements()) {
if (requiredMultiReferenceOperation.getReferencedModelElements().contains(modelElementId)) {
return true;
}
}
}
return false;
}
private boolean isRequired(MultiReferenceOperation requiredMultiReferenceOperation,
MultiReferenceMoveOperation moveOperation) {
boolean sameElement = requiredMultiReferenceOperation.getModelElementId().equals(
moveOperation.getModelElementId());
boolean sameFeature = requiredMultiReferenceOperation.getFeatureName().equals(moveOperation.getFeatureName());
if (sameElement && sameFeature) {
for (ModelElementId modelElementId : requiredMultiReferenceOperation.getReferencedModelElements()) {
if (modelElementId.equals(moveOperation.getReferencedModelElementId())) {
return true;
}
}
}
return false;
}
private boolean isRequired(CreateDeleteOperation requiredOperation, AbstractOperation operation) {
if (!requiredOperation.isDelete()) {
if (operation instanceof FeatureOperation) {
if (operation.getModelElementId().equals(requiredOperation.getModelElementId())) {
return true;
}
if (operation instanceof ReferenceOperation) {
return ((ReferenceOperation) operation).getOtherInvolvedModelElements().contains(
requiredOperation.getModelElementId());
}
if (operation instanceof MultiReferenceMoveOperation) {
return ((MultiReferenceMoveOperation) operation).getReferencedModelElementId().equals(
requiredOperation);
}
return false;
} else if (operation instanceof CompositeOperation) {
for (AbstractOperation abstractOperation : ((CompositeOperation) operation).getSubOperations()) {
if (isRequired(requiredOperation, abstractOperation)) {
return true;
}
}
return false;
} else if (operation instanceof CreateDeleteOperation) {
return (((CreateDeleteOperation) operation).isDelete());
}
}
return false;
}
private boolean doConflict(CreateDeleteOperation operationA, AbstractOperation operationB) {
if (operationB instanceof CompositeOperation) {
return doConflict(operationB, operationA);
}
if (operationB instanceof ReferenceOperation) {
for (ModelElementId modelElementId : ((ReferenceOperation) operationB).getOtherInvolvedModelElements()) {
if (operationA.getModelElementId().equals(modelElementId)) {
return true;
}
}
}
return operationA.getModelElementId().equals(operationB.getModelElementId());
}
private boolean doConflict(AttributeOperation operationA, AbstractOperation operationB) {
if (!operationA.getModelElementId().equals(operationB.getModelElementId())) {
return false;
}
if (operationB instanceof FeatureOperation) {
FeatureOperation featureOperationB = (FeatureOperation) operationB;
return featureOperationB.getFeatureName().equals(operationA.getFeatureName());
}
return doConflict(operationB, operationA);
}
private boolean doConflict(MultiReferenceMoveOperation operationA, AbstractOperation operationB) {
if (operationB instanceof MultiReferenceMoveOperation) {
boolean sameElement = operationA.getModelElementId().equals(operationB.getModelElementId());
boolean sameFeature = operationA.getFeatureName().equals(
((MultiReferenceMoveOperation) operationB).getFeatureName());
return sameElement && sameFeature;
} else if (operationB instanceof AttributeOperation) {
return false;
}
return doConflict(operationB, operationA);
}
private boolean doConflict(SingleReferenceOperation operationA, AbstractOperation operationB) {
if (operationB instanceof SingleReferenceOperation) {
ReferenceOperation singleOperationB = (SingleReferenceOperation) operationB;
boolean sameFeature = operationA.getFeatureName().equals(singleOperationB.getFeatureName());
if (operationA.getOppositeFeatureName() != null) {
sameFeature = sameFeature
|| operationA.getOppositeFeatureName().equals(singleOperationB.getFeatureName());
}
boolean sameElement = operationA.getModelElementId().equals(operationB.getModelElementId());
return sameFeature && sameElement;
} else if (operationB instanceof AttributeOperation) {
return false;
} else if (operationB instanceof MultiReferenceMoveOperation) {
return false;
}
return doConflict(operationB, operationA);
}
}