blob: 69b9a206a43222f708c2e6c541eac057892d707e [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:
* Maximilian Koegel - initial API and implementation
******************************************************************************/
package org.eclipse.emf.emfstore.internal.server.conflictDetection;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import org.eclipse.emf.emfstore.internal.common.model.ModelElementIdToEObjectMapping;
import org.eclipse.emf.emfstore.internal.common.model.Project;
import org.eclipse.emf.emfstore.internal.server.model.versioning.ChangePackage;
import org.eclipse.emf.emfstore.internal.server.model.versioning.operations.AbstractOperation;
/**
* Detects conflicts between operation.
*
* @author koegel
*/
public class ConflictDetector {
/**
* Constructor.
*/
public ConflictDetector() {
}
/**
* Calculates a {@link ChangeConflictSet} based on opposing {@link ChangePackage}s.
*
* @param myChangePackages
* a list of {@link ChangePackage}s
* @param theirChangePackages
* a other list of {@link ChangePackage}s
* @param project
* the project for which calculate conflicts
* @return a {@link ChangeConflictSet}
*/
public ChangeConflictSet calculateConflicts(List<ChangePackage> myChangePackages,
List<ChangePackage> theirChangePackages, Project project) {
final ModelElementIdToEObjectMappingImpl idToEObjectMappingImpl = new ModelElementIdToEObjectMappingImpl(
project,
myChangePackages);
idToEObjectMappingImpl.put(theirChangePackages);
return calculateConflicts(myChangePackages, theirChangePackages, idToEObjectMappingImpl);
}
/**
* Calculates a {@link ChangeConflictSet} based on opposing {@link ChangePackage}s.
*
* @param myChangePackages
* a list of {@link ChangePackage}s
* @param theirChangePackages
* a other list of {@link ChangePackage}s
* @param idToEObjectMapping
* a mapping that is used to resolve model elements while calculating conflicts
* @return a {@link ChangeConflictSet}
*/
public ChangeConflictSet calculateConflicts(List<ChangePackage> myChangePackages,
List<ChangePackage> theirChangePackages, ModelElementIdToEObjectMapping idToEObjectMapping) {
final Set<ConflictBucketCandidate> conflictCandidateBuckets = calculateConflictCandidateBuckets(
myChangePackages,
theirChangePackages, idToEObjectMapping);
final Set<AbstractOperation> notInvolvedInConflict = new LinkedHashSet<AbstractOperation>();
final Set<ConflictBucket> conflictBuckets = calculateConflictBucketsFromConflictCandidateBuckets(
conflictCandidateBuckets, notInvolvedInConflict);
return new ChangeConflictSet(conflictBuckets, notInvolvedInConflict, idToEObjectMapping, myChangePackages,
theirChangePackages);
}
/**
* Calculate a set of conflict candidate buckets from a list of my and their change packages.
*
* @param myChangePackages their operations in a list of change packages
* @param theirChangePackages their operations in a list of change packages
* @return a set of buckets with potentially conflicting operations
*/
private Set<ConflictBucketCandidate> calculateConflictCandidateBuckets(List<ChangePackage> myChangePackages,
List<ChangePackage> theirChangePackages, ModelElementIdToEObjectMapping idToEObjectMapping) {
final List<AbstractOperation> myOperations = flattenChangepackages(myChangePackages);
final List<AbstractOperation> theirOperations = flattenChangepackages(theirChangePackages);
return calculateConflictCandidateBuckets(idToEObjectMapping, myOperations, theirOperations);
}
private Set<ConflictBucketCandidate> calculateConflictCandidateBuckets(
ModelElementIdToEObjectMapping idToEObjectMapping,
List<AbstractOperation> myOperations, List<AbstractOperation> theirOperations) {
final ReservationToConflictBucketCandidateMap conflictMap = new ReservationToConflictBucketCandidateMap();
int counter = 0;
for (final AbstractOperation myOperation : myOperations) {
conflictMap.scanOperationReservations(myOperation, counter, idToEObjectMapping, true);
counter++;
}
for (final AbstractOperation theirOperation : theirOperations) {
conflictMap.scanOperationReservations(theirOperation, counter, idToEObjectMapping, false);
counter++;
}
return conflictMap.getConflictBucketCandidates();
}
private List<AbstractOperation> flattenChangepackages(List<ChangePackage> cps) {
final List<AbstractOperation> operations = new ArrayList<AbstractOperation>();
for (final ChangePackage cp : cps) {
operations.addAll(cp.getOperations());
}
return operations;
}
/**
* Calculate a set of conflict buckets from an existing set of conflict candidate buckets. the resulting set may be
* empty.
*
* @param conflictBucketsCandidateSet a set of conflict candidate buckets
* @param notInvolvedInConflict all my operations that are not involved in a conflict are collected in this
* transient parameter set
* @return a set of conflict buckets
*/
private Set<ConflictBucket> calculateConflictBucketsFromConflictCandidateBuckets(
Set<ConflictBucketCandidate> conflictBucketsCandidateSet, Set<AbstractOperation> notInvolvedInConflict) {
final Set<ConflictBucket> conflictBucketsSet = new LinkedHashSet<ConflictBucket>();
for (final ConflictBucketCandidate conflictBucketCandidate : conflictBucketsCandidateSet) {
final Set<ConflictBucket> buckets = conflictBucketCandidate.calculateConflictBuckets(this,
notInvolvedInConflict);
for (final ConflictBucket bucket : buckets) {
conflictBucketsSet.add(bucket);
}
}
return conflictBucketsSet;
}
}