blob: 223155cfc051941ea89cf51ea6ee0ac1d228b89d [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 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.example.merging;
import java.util.List;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.emf.emfstore.bowling.BowlingFactory;
import org.eclipse.emf.emfstore.bowling.League;
import org.eclipse.emf.emfstore.bowling.Player;
import org.eclipse.emf.emfstore.client.ESLocalProject;
import org.eclipse.emf.emfstore.client.ESServer;
import org.eclipse.emf.emfstore.client.ESWorkspace;
import org.eclipse.emf.emfstore.client.ESWorkspaceProvider;
import org.eclipse.emf.emfstore.client.callbacks.ESUpdateCallback;
import org.eclipse.emf.emfstore.client.exceptions.ESServerStartFailedException;
import org.eclipse.emf.emfstore.common.ESSystemOutProgressMonitor;
import org.eclipse.emf.emfstore.common.model.ESModelElementIdToEObjectMapping;
import org.eclipse.emf.emfstore.server.ESConflict;
import org.eclipse.emf.emfstore.server.ESConflictSet;
import org.eclipse.emf.emfstore.server.exceptions.ESException;
import org.eclipse.emf.emfstore.server.exceptions.ESUpdateRequiredException;
import org.eclipse.emf.emfstore.server.model.ESChangePackage;
import org.eclipse.emf.emfstore.server.model.versionspec.ESVersionSpec;
import org.eclipse.equinox.app.IApplication;
import org.eclipse.equinox.app.IApplicationContext;
/**
* An application that runs the demo.<br>
* Run a client that shows the merging feature of the EMFstore
* Please note: this is the programmatic way of merging
* EMFStore also provides a default UI for merging
* If there is a problem with the connection to the server
* e.g. a network, a specific ESException will be thrown
*/
public class Application implements IApplication {
/**
* {@inheritDoc}
*/
public Object start(IApplicationContext context) {
try {
// Create a client representation for a local server and start a local server.
final ESServer localServer = ESServer.FACTORY.createAndStartLocalServer();
// Reuse the client from the hello world example. It will clean up all local and remote projects and create
// one project with some content on the server and two checked-out copies of the project on the client.
org.eclipse.emf.emfstore.example.helloworld.Application.runClient(localServer);
// We run our own client code to demonstrate merging now.
runClient(localServer);
} catch (final ESServerStartFailedException e) {
System.out.println("Server start failed!"); //$NON-NLS-1$
e.printStackTrace();
} catch (final ESException e) {
// If there is a problem with the connection to the server
// e.g. a network, a specific EMFStoreException will be thrown
System.out.println("Connection to Server failed!"); //$NON-NLS-1$
e.printStackTrace();
}
return IApplication.EXIT_OK;
}
/**
* Simulates a client.
*
* @param server
* the server the client will interact with
* @throws ESException in case any error occurs
*/
public static void runClient(ESServer server) throws ESException {
System.out.println("Client starting..."); //$NON-NLS-1$
final ESWorkspace workspace = ESWorkspaceProvider.INSTANCE.getWorkspace();
final ESLocalProject demoProject = workspace.getLocalProjects().get(0);
final League league = (League) demoProject.getModelElements().get(0);
final ESLocalProject demoProjectCopy = workspace.getLocalProjects().get(1);
final League leagueCopy = (League) demoProjectCopy.getModelElements().get(0);
// Change the name of the league in project 1,add a new player and commit the change
league.setName("Euro-League"); //$NON-NLS-1$
final Player newPlayer = BowlingFactory.eINSTANCE.createPlayer();
newPlayer.setName("Eugene"); //$NON-NLS-1$
league.getPlayers().add(newPlayer);
demoProject.commit(new ESSystemOutProgressMonitor());
// Changing the name again value without calling update() on the copy first will cause a conflict on commit.
// We also add one change which is non-conflicting, setting the name of the first player.
leagueCopy.setName("EU-League"); //$NON-NLS-1$
leagueCopy.getPlayers().get(0).setName("Johannes"); //$NON-NLS-1$
try {
demoProjectCopy.commit(new ESSystemOutProgressMonitor());
} catch (final ESUpdateRequiredException e) {
// The commit failed since the other demoProject was committed first and therefore demoProjectCopy needs an
// update
System.out.println("\nCommit of demoProjectCopy failed."); //$NON-NLS-1$
// We run update in demoProjectCopy with an UpdateCallback to handle conflicts
System.out.println("\nUpdate of demoProjectCopy with conflict resolver..."); //$NON-NLS-1$
demoProjectCopy.update(ESVersionSpec.FACTORY.createHEAD(), new ESUpdateCallback() {
public void noChangesOnServer() {
// do nothing if there are no changes on the server (in this example we know
// there are changes anyway)
}
public boolean inspectChanges(ESLocalProject project, List<ESChangePackage> changes,
ESModelElementIdToEObjectMapping idToEObjectMapping) {
// allow update to proceed, here we could also add some UI
return true;
}
public boolean conflictOccurred(ESConflictSet changeConflictSet, IProgressMonitor monitor) {
// One or more conflicts have occured, they are delivered in a change conflict set
// We know there is only one conflict so we grab it
final ESConflict conflict = changeConflictSet.getConflicts().iterator().next();
// We resolve the conflict by accepting all of the conflicting local operations and rejecting all of
// the remote
// operations. This means that we revert the league name change of demoProject and accept the league
// name change of demoProjectCopy. The player name change in demoProject is accepted also since it
// was not conflicting with any other change.
conflict.resolveConflict(conflict.getLocalOperations(), conflict.getRemoteOperations());
// Finally we claim to have resolved all conflicts so update will try to proceed.
return true;
}
}, new ESSystemOutProgressMonitor());
// commit merge result in project 2
System.out.println("\nCommit of merge result of demoProjectCopy"); //$NON-NLS-1$
demoProjectCopy.commit(new ESSystemOutProgressMonitor());
// After having merged the two projects update local project 1
System.out.println("\nUpdate of demoProject"); //$NON-NLS-1$
demoProject.update(new NullProgressMonitor());
// Finally we print the league and player names of both projects
System.out.println("\nLeague name in demoProject is now: " + league.getName()); //$NON-NLS-1$
System.out.println("\nLeague name in demoProjectCopy is now: " + leagueCopy.getName()); //$NON-NLS-1$
System.out.println("\nPlayer name in demoProject is now: " + league.getPlayers().get(0).getName()); //$NON-NLS-1$
System.out.println("\nPlayer name in demoProjectCopy is now: " + leagueCopy.getPlayers().get(0).getName()); //$NON-NLS-1$
}
}
/**
*
* {@inheritDoc}
*
* @see org.eclipse.equinox.app.IApplication#stop()
*/
public void stop() {
// do nothing
}
}