blob: 1e328511f66cb14a943c042bee3eae1d6533cd9f [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.controller;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.emf.emfstore.client.common.UnknownEMFStoreWorkloadCommand;
import org.eclipse.emf.emfstore.client.model.WorkspaceManager;
import org.eclipse.emf.emfstore.client.model.connectionmanager.ServerCall;
import org.eclipse.emf.emfstore.client.model.controller.callbacks.UpdateCallback;
import org.eclipse.emf.emfstore.client.model.exceptions.ChangeConflictException;
import org.eclipse.emf.emfstore.client.model.impl.ProjectSpaceBase;
import org.eclipse.emf.emfstore.client.model.observers.UpdateObserver;
import org.eclipse.emf.emfstore.server.conflictDetection.ConflictBucketCandidate;
import org.eclipse.emf.emfstore.server.conflictDetection.ConflictDetector;
import org.eclipse.emf.emfstore.server.exceptions.EmfStoreException;
import org.eclipse.emf.emfstore.server.model.versioning.ChangePackage;
import org.eclipse.emf.emfstore.server.model.versioning.PrimaryVersionSpec;
import org.eclipse.emf.emfstore.server.model.versioning.VersionSpec;
import org.eclipse.emf.emfstore.server.model.versioning.Versions;
/**
* Controller class for updating a project space.
*
* @author ovonwesen
* @author emueller
*/
public class UpdateController extends ServerCall<PrimaryVersionSpec> {
private VersionSpec version;
private UpdateCallback callback;
/**
* Constructor.
*
* @param projectSpace
* the project space to be updated
* @param version
* the target version
* @param callback
* an optional update callback instance
* @param progress
* a progress monitor that is used to indicate the progress of the update
*/
public UpdateController(ProjectSpaceBase projectSpace, VersionSpec version, UpdateCallback callback,
IProgressMonitor progress) {
super(projectSpace);
// SANITY CHECKS
if (version == null) {
version = Versions.createHEAD(projectSpace.getBaseVersion());
}
if (callback == null) {
callback = UpdateCallback.NOCALLBACK;
}
this.version = version;
this.callback = callback;
setProgressMonitor(progress);
}
/**
*
* {@inheritDoc}
*
* @see org.eclipse.emf.emfstore.client.model.connectionmanager.ServerCall#run()
*/
@Override
protected PrimaryVersionSpec run() throws EmfStoreException {
return doUpdate(version);
}
private PrimaryVersionSpec doUpdate(VersionSpec version) throws EmfStoreException {
getProgressMonitor().beginTask("Updating Project...", 100);
getProgressMonitor().worked(1);
getProgressMonitor().subTask("Resolving new version");
final PrimaryVersionSpec resolvedVersion = getProjectSpace().resolveVersionSpec(version);
if (resolvedVersion.compareTo(getProjectSpace().getBaseVersion()) == 0) {
return resolvedVersion;
}
getProgressMonitor().worked(5);
if (getProgressMonitor().isCanceled()) {
return getProjectSpace().getBaseVersion();
}
getProgressMonitor().subTask("Fetching changes from server");
List<ChangePackage> changes = new UnknownEMFStoreWorkloadCommand<List<ChangePackage>>(getProgressMonitor()) {
@Override
public List<ChangePackage> run(IProgressMonitor monitor) throws EmfStoreException {
return getConnectionManager().getChanges(getSessionId(), getProjectSpace().getProjectId(),
getProjectSpace().getBaseVersion(), resolvedVersion);
}
}.execute();
ChangePackage localchanges = getProjectSpace().getLocalChangePackage(false);
getProgressMonitor().worked(65);
if (getProgressMonitor().isCanceled()) {
return getProjectSpace().getBaseVersion();
}
getProgressMonitor().subTask("Checking for conflicts");
ConflictDetector conflictDetector = new ConflictDetector();
boolean potentialConflictsDetected = false;
if (getProjectSpace().getOperations().size() > 0) {
Set<ConflictBucketCandidate> conflictBucketCandidates = conflictDetector.calculateConflictCandidateBuckets(
Collections.singletonList(localchanges), changes);
potentialConflictsDetected = conflictDetector.containsConflictingBuckets(conflictBucketCandidates);
if (potentialConflictsDetected) {
getProgressMonitor().subTask("Conflicts detected, calculating conflicts");
ChangeConflictException conflictException = new ChangeConflictException(getProjectSpace(),
localchanges, changes, conflictBucketCandidates);
if (callback.conflictOccurred(conflictException, getProgressMonitor())) {
return getProjectSpace().getBaseVersion();
}
throw conflictException;
}
}
getProgressMonitor().worked(15);
// TODO ASYNC review this cancel
if (getProgressMonitor().isCanceled() || !callback.inspectChanges(getProjectSpace(), changes)) {
return getProjectSpace().getBaseVersion();
}
WorkspaceManager.getObserverBus().notify(UpdateObserver.class).inspectChanges(getProjectSpace(), changes);
getProgressMonitor().subTask("Applying changes");
getProjectSpace().applyChanges(resolvedVersion, changes, localchanges);
WorkspaceManager.getObserverBus().notify(UpdateObserver.class).updateCompleted(getProjectSpace());
return getProjectSpace().getBaseVersion();
}
}