/******************************************************************************* | |
* 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: | |
* Otto von Wesendonk, Edgar Mueller, Maximilian Koegel - initial API and implementation | |
* Johannes Faltermeier - Pluggable storage, Decoupled Projects | |
******************************************************************************/ | |
package org.eclipse.emf.emfstore.internal.client.model.impl; | |
import java.io.File; | |
import java.io.IOException; | |
import java.text.MessageFormat; | |
import java.util.ArrayList; | |
import java.util.Collection; | |
import java.util.Collections; | |
import java.util.Date; | |
import java.util.LinkedHashMap; | |
import java.util.LinkedHashSet; | |
import java.util.LinkedList; | |
import java.util.List; | |
import java.util.ListIterator; | |
import java.util.Map; | |
import java.util.Set; | |
import java.util.concurrent.Callable; | |
import org.eclipse.core.runtime.IProgressMonitor; | |
import org.eclipse.core.runtime.NullProgressMonitor; | |
import org.eclipse.emf.common.notify.AdapterFactory; | |
import org.eclipse.emf.common.util.EList; | |
import org.eclipse.emf.common.util.URI; | |
import org.eclipse.emf.ecore.EObject; | |
import org.eclipse.emf.ecore.EStructuralFeature.Setting; | |
import org.eclipse.emf.ecore.resource.Resource; | |
import org.eclipse.emf.ecore.resource.ResourceSet; | |
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; | |
import org.eclipse.emf.ecore.util.ECrossReferenceAdapter; | |
import org.eclipse.emf.ecore.util.EcoreUtil.UsageCrossReferencer; | |
import org.eclipse.emf.edit.domain.AdapterFactoryEditingDomain; | |
import org.eclipse.emf.edit.domain.EditingDomain; | |
import org.eclipse.emf.edit.provider.ComposedAdapterFactory; | |
import org.eclipse.emf.edit.provider.ReflectiveItemProviderAdapterFactory; | |
import org.eclipse.emf.emfstore.client.ESUsersession; | |
import org.eclipse.emf.emfstore.client.callbacks.ESCommitCallback; | |
import org.eclipse.emf.emfstore.client.callbacks.ESUpdateCallback; | |
import org.eclipse.emf.emfstore.client.changetracking.ESCommandStack; | |
import org.eclipse.emf.emfstore.client.handler.ESRunnableContext; | |
import org.eclipse.emf.emfstore.client.observer.ESLoginObserver; | |
import org.eclipse.emf.emfstore.client.observer.ESMergeObserver; | |
import org.eclipse.emf.emfstore.client.provider.ESEditingDomainProvider; | |
import org.eclipse.emf.emfstore.client.util.ClientURIUtil; | |
import org.eclipse.emf.emfstore.client.util.RunESCommand; | |
import org.eclipse.emf.emfstore.common.ESResourceSetProvider; | |
import org.eclipse.emf.emfstore.common.extensionpoint.ESExtensionElement; | |
import org.eclipse.emf.emfstore.common.extensionpoint.ESExtensionPoint; | |
import org.eclipse.emf.emfstore.common.extensionpoint.ESPriorityComparator; | |
import org.eclipse.emf.emfstore.internal.client.importexport.impl.ExportChangesController; | |
import org.eclipse.emf.emfstore.internal.client.importexport.impl.ExportProjectController; | |
import org.eclipse.emf.emfstore.internal.client.model.CompositeOperationHandle; | |
import org.eclipse.emf.emfstore.internal.client.model.Configuration; | |
import org.eclipse.emf.emfstore.internal.client.model.ESWorkspaceProviderImpl; | |
import org.eclipse.emf.emfstore.internal.client.model.ProjectSpace; | |
import org.eclipse.emf.emfstore.internal.client.model.Usersession; | |
import org.eclipse.emf.emfstore.internal.client.model.changeTracking.commands.EMFStoreBasicCommandStack; | |
import org.eclipse.emf.emfstore.internal.client.model.changeTracking.merging.ConflictResolver; | |
import org.eclipse.emf.emfstore.internal.client.model.changeTracking.notification.recording.NotificationRecorder; | |
import org.eclipse.emf.emfstore.internal.client.model.connectionmanager.ConnectionManager; | |
import org.eclipse.emf.emfstore.internal.client.model.connectionmanager.ServerCall; | |
import org.eclipse.emf.emfstore.internal.client.model.controller.CommitController; | |
import org.eclipse.emf.emfstore.internal.client.model.controller.ShareController; | |
import org.eclipse.emf.emfstore.internal.client.model.controller.UpdateController; | |
import org.eclipse.emf.emfstore.internal.client.model.exceptions.ChangeConflictException; | |
import org.eclipse.emf.emfstore.internal.client.model.exceptions.IllegalProjectSpaceStateException; | |
import org.eclipse.emf.emfstore.internal.client.model.exceptions.MEUrlResolutionException; | |
import org.eclipse.emf.emfstore.internal.client.model.exceptions.PropertyNotFoundException; | |
import org.eclipse.emf.emfstore.internal.client.model.filetransfer.FileDownloadStatus; | |
import org.eclipse.emf.emfstore.internal.client.model.filetransfer.FileInformation; | |
import org.eclipse.emf.emfstore.internal.client.model.filetransfer.FileTransferManager; | |
import org.eclipse.emf.emfstore.internal.client.model.impl.api.ESLocalProjectImpl; | |
import org.eclipse.emf.emfstore.internal.client.model.util.WorkspaceUtil; | |
import org.eclipse.emf.emfstore.internal.client.observers.DeleteProjectSpaceObserver; | |
import org.eclipse.emf.emfstore.internal.client.properties.PropertyManager; | |
import org.eclipse.emf.emfstore.internal.common.APIUtil; | |
import org.eclipse.emf.emfstore.internal.common.EMFStoreResource; | |
import org.eclipse.emf.emfstore.internal.common.ESDisposable; | |
import org.eclipse.emf.emfstore.internal.common.ExtensionRegistry; | |
import org.eclipse.emf.emfstore.internal.common.model.ModelElementId; | |
import org.eclipse.emf.emfstore.internal.common.model.Project; | |
import org.eclipse.emf.emfstore.internal.common.model.impl.IdentifiableElementImpl; | |
import org.eclipse.emf.emfstore.internal.common.model.impl.ProjectImpl; | |
import org.eclipse.emf.emfstore.internal.common.model.util.ModelUtil; | |
import org.eclipse.emf.emfstore.internal.common.model.util.SerializationException; | |
import org.eclipse.emf.emfstore.internal.server.conflictDetection.ChangeConflictSet; | |
import org.eclipse.emf.emfstore.internal.server.conflictDetection.ConflictBucket; | |
import org.eclipse.emf.emfstore.internal.server.conflictDetection.ConflictDetector; | |
import org.eclipse.emf.emfstore.internal.server.exceptions.FileTransferException; | |
import org.eclipse.emf.emfstore.internal.server.exceptions.InvalidVersionSpecException; | |
import org.eclipse.emf.emfstore.internal.server.model.FileIdentifier; | |
import org.eclipse.emf.emfstore.internal.server.model.ProjectInfo; | |
import org.eclipse.emf.emfstore.internal.server.model.accesscontrol.ACUser; | |
import org.eclipse.emf.emfstore.internal.server.model.accesscontrol.OrgUnitProperty; | |
import org.eclipse.emf.emfstore.internal.server.model.url.ModelElementUrlFragment; | |
import org.eclipse.emf.emfstore.internal.server.model.versioning.BranchInfo; | |
import org.eclipse.emf.emfstore.internal.server.model.versioning.BranchVersionSpec; | |
import org.eclipse.emf.emfstore.internal.server.model.versioning.ChangePackage; | |
import org.eclipse.emf.emfstore.internal.server.model.versioning.LogMessage; | |
import org.eclipse.emf.emfstore.internal.server.model.versioning.PrimaryVersionSpec; | |
import org.eclipse.emf.emfstore.internal.server.model.versioning.TagVersionSpec; | |
import org.eclipse.emf.emfstore.internal.server.model.versioning.VersionSpec; | |
import org.eclipse.emf.emfstore.internal.server.model.versioning.VersioningFactory; | |
import org.eclipse.emf.emfstore.internal.server.model.versioning.Versions; | |
import org.eclipse.emf.emfstore.internal.server.model.versioning.operations.AbstractOperation; | |
import org.eclipse.emf.emfstore.server.exceptions.ESException; | |
import org.eclipse.emf.emfstore.server.model.ESChangePackage; | |
/** | |
* Project space base class that contains custom user methods. | |
* | |
* @author koegel | |
* @author wesendon | |
* @author emueller | |
* @author jfaltermeier | |
* | |
*/ | |
public abstract class ProjectSpaceBase extends IdentifiableElementImpl implements ProjectSpace, ESLoginObserver, | |
ESDisposable { | |
private ESLocalProjectImpl esLocalProjectImpl; | |
private boolean initCompleted; | |
private boolean isTransient; | |
private boolean disposed; | |
private boolean closed; | |
private FileTransferManager fileTransferManager; | |
private OperationManager operationManager; | |
private PropertyManager propertyManager; | |
private final Map<String, OrgUnitProperty> propertyMap; | |
private ResourceSet resourceSet; | |
private ResourceSet contentResourceSet; | |
private EditingDomain contentEditingDomain; | |
private ResourcePersister resourcePersister; | |
private ECrossReferenceAdapter crossReferenceAdapter; | |
private ESRunnableContext runnableContext; | |
/** | |
* Constructor. | |
*/ | |
public ProjectSpaceBase() { | |
propertyMap = new LinkedHashMap<String, OrgUnitProperty>(); | |
initRunnableContext(); | |
} | |
/** | |
* <p> | |
* Provides a context in which a {@link Runnable} is executed. | |
* </p> | |
* <p> | |
* This may be used to provide a context while applying operations on a | |
* {@link org.eclipse.emf.emfstore.client.ESLocalProject}. | |
* </p> | |
* | |
* @param runnableContext | |
* the runnable context to be set | |
*/ | |
public void setRunnableContext(ESRunnableContext runnableContext) { | |
this.runnableContext = runnableContext; | |
} | |
private void initRunnableContext() { | |
runnableContext = ExtensionRegistry.INSTANCE.get( | |
RUNNABLE_CONTEXT_ID, | |
ESRunnableContext.class, | |
new DefaultRunnableContext(), true); | |
} | |
/** | |
* {@inheritDoc} | |
* | |
* @see org.eclipse.emf.emfstore.internal.client.model.ProjectSpace#addFile(java.io.File) | |
*/ | |
public FileIdentifier addFile(File file) throws FileTransferException { | |
return fileTransferManager.addFile(file); | |
} | |
/** | |
* | |
* {@inheritDoc} | |
* | |
* @see org.eclipse.emf.emfstore.internal.client.model.ProjectSpace#addOperations(java.util.List) | |
*/ | |
public void addOperations(List<? extends AbstractOperation> operations) { | |
getOperations().addAll(operations); | |
updateDirtyState(); | |
for (final AbstractOperation op : operations) { | |
operationManager.notifyOperationExecuted(op); | |
} | |
} | |
/** | |
* | |
* {@inheritDoc} | |
* | |
* @see org.eclipse.emf.emfstore.internal.client.model.ProjectSpace#addTag(org.eclipse.emf.emfstore.internal.server.model.versioning.PrimaryVersionSpec, | |
* org.eclipse.emf.emfstore.internal.server.model.versioning.TagVersionSpec) | |
*/ | |
public void addTag(PrimaryVersionSpec versionSpec, TagVersionSpec tag) throws ESException { | |
final ConnectionManager cm = ESWorkspaceProviderImpl.getInstance().getConnectionManager(); | |
cm.addTag(getUsersession().getSessionId(), getProjectId(), versionSpec, tag); | |
} | |
/** | |
* Helper method which applies merged changes on the ProjectSpace. This | |
* method is used by merge mechanisms in update as well as branch merging. | |
* | |
* @param baseSpec | |
* new base version | |
* @param incoming | |
* changes from the current branch | |
* @param myChanges | |
* merged changes | |
* @param progressMonitor | |
* an {@link IProgressMonitor} to inform about the progress of the UpdateCallback in case it is called | |
* @param runChecksumTestOnBaseSpec | |
* whether the checksum check is performed while applying the changes | |
* | |
* @throws ESException in case the checksum comparison failed and the activated IChecksumErrorHandler | |
* also failed | |
*/ | |
public void applyChanges(PrimaryVersionSpec baseSpec, List<ChangePackage> incoming, ChangePackage myChanges, | |
IProgressMonitor progressMonitor, boolean runChecksumTestOnBaseSpec) throws ESException { | |
// revert local changes | |
notifyPreRevertMyChanges(getLocalChangePackage()); | |
revert(); | |
notifyPostRevertMyChanges(); | |
// apply changes from repo. incoming (aka theirs) | |
applyChangePackages(incoming, false); | |
notifyPostApplyTheirChanges(incoming); | |
if (runChecksumTestOnBaseSpec) { | |
runChecksumTests(baseSpec, incoming, progressMonitor); | |
} | |
// reapply local changes | |
applyOperations(myChanges.getOperations(), true); | |
notifyPostApplyMergedChanges(myChanges); | |
setBaseVersion(baseSpec); | |
saveProjectSpaceOnly(); | |
} | |
private void runChecksumTests(PrimaryVersionSpec baseSpec, List<ChangePackage> incoming, | |
IProgressMonitor progressMonitor) | |
throws ESException { | |
progressMonitor.subTask("Computing checksum"); | |
if (!performChecksumCheck(baseSpec, getProject())) { | |
progressMonitor.subTask("Invalid checksum. Activating checksum error handler."); | |
final boolean errorHandled = Configuration.getClientBehavior().getChecksumErrorHandler() | |
.execute(toAPI(), baseSpec.toAPI(), | |
progressMonitor); | |
if (!errorHandled) { | |
// rollback | |
for (int i = incoming.size() - 1; i >= 0; i--) { | |
applyChangePackage(incoming.get(i).reverse(), false); | |
} | |
applyChangePackage(getLocalChangePackage(), true); | |
throw new ESException("Update cancelled by checksum error handler due to invalid checksum."); | |
} | |
} | |
} | |
private void applyChangePackage(ChangePackage changePackage, boolean addOperations) { | |
applyOperations(changePackage.getOperations(), addOperations); | |
} | |
private void applyChangePackages(List<ChangePackage> changePackages, boolean addOperations) { | |
for (final ChangePackage changePackage : changePackages) { | |
applyChangePackage(changePackage, addOperations); | |
} | |
} | |
private boolean performChecksumCheck(PrimaryVersionSpec baseVersion, Project project) { | |
if (Configuration.getClientBehavior().isChecksumCheckActive()) { | |
final long expectedChecksum = baseVersion.getProjectStateChecksum(); | |
try { | |
final long computedChecksum = ModelUtil.computeChecksum(project); | |
return expectedChecksum == computedChecksum; | |
} catch (final SerializationException e) { | |
WorkspaceUtil.logWarning("Could not compute checksum while applying changes.", e); | |
} | |
} | |
return true; | |
} | |
/** | |
* Applies a list of operations to the project. The change tracking will be | |
* stopped meanwhile. | |
* | |
* | |
* @param operations | |
* the list of operations to be applied upon the project space | |
* @param addOperations | |
* whether the operations should be saved in project space | |
* | |
*/ | |
public void applyOperations(List<AbstractOperation> operations, boolean addOperations) { | |
executeRunnable(new ApplyOperationsRunnable(this, operations, addOperations)); | |
} | |
/** | |
* Executes a given {@link Runnable} in the context of this {@link ProjectSpace}.<br> | |
* The {@link Runnable} usually modifies the Project contained in the {@link ProjectSpace}. | |
* | |
* @param runnable | |
* the {@link Runnable} to be executed in the context of this {@link ProjectSpace} | |
*/ | |
public void executeRunnable(Runnable runnable) { | |
getRunnableContext().executeRunnable(runnable); | |
} | |
/** | |
* {@inheritDoc} | |
* | |
* @see org.eclipse.emf.emfstore.internal.client.model.ProjectSpace#beginCompositeOperation() | |
*/ | |
public CompositeOperationHandle beginCompositeOperation() { | |
return operationManager.beginCompositeOperation(); | |
} | |
/** | |
* Removes the elements that are marked as cutted from the project. | |
*/ | |
public void cleanCutElements() { | |
final List<EObject> cutElements = new ArrayList<EObject>(getProject().getCutElements()); | |
for (final EObject cutElement : cutElements) { | |
getProject().deleteModelElement(cutElement); | |
} | |
} | |
/** | |
* | |
* {@inheritDoc} | |
* | |
* @see org.eclipse.emf.emfstore.internal.client.model.ProjectSpace#commit(org.eclipse.core.runtime.IProgressMonitor) | |
*/ | |
public PrimaryVersionSpec commit(IProgressMonitor monitor) throws ESException { | |
return new CommitController(this, null, null, monitor).execute(); | |
} | |
/** | |
* | |
* {@inheritDoc} | |
* | |
* @see org.eclipse.emf.emfstore.internal.client.model.ProjectSpace#commit(java.lang.String, | |
* org.eclipse.emf.emfstore.client.callbacks.ESCommitCallback, org.eclipse.core.runtime.IProgressMonitor) | |
*/ | |
public PrimaryVersionSpec commit(String logMessage, ESCommitCallback callback, IProgressMonitor monitor) | |
throws ESException { | |
return new CommitController(this, logMessage, callback, monitor).execute(); | |
} | |
/** | |
* {@inheritDoc} | |
*/ | |
public PrimaryVersionSpec commitToBranch(BranchVersionSpec branch, String logMessage, | |
ESCommitCallback callback, | |
IProgressMonitor monitor) throws ESException { | |
return new CommitController(this, branch, logMessage, callback, monitor).execute(); | |
} | |
/** | |
* | |
* {@inheritDoc} | |
* | |
* @see org.eclipse.emf.emfstore.internal.client.model.ProjectSpace#exportLocalChanges(java.io.File, | |
* org.eclipse.core.runtime.IProgressMonitor) | |
*/ | |
public void exportLocalChanges(File file, IProgressMonitor progressMonitor) throws IOException { | |
new ExportChangesController(this).execute(file, progressMonitor); | |
} | |
/** | |
* | |
* {@inheritDoc} | |
* | |
* @see org.eclipse.emf.emfstore.internal.client.model.ProjectSpace#exportLocalChanges(java.io.File) | |
*/ | |
public void exportLocalChanges(File file) throws IOException { | |
new ExportChangesController(this).execute(file, new NullProgressMonitor()); | |
} | |
/** | |
* | |
* {@inheritDoc} | |
* | |
* @see org.eclipse.emf.emfstore.internal.client.model.ProjectSpace#exportProject(java.io.File, | |
* org.eclipse.core.runtime.IProgressMonitor) | |
*/ | |
public void exportProject(File file, IProgressMonitor progressMonitor) throws IOException { | |
new ExportProjectController(this).execute(file, progressMonitor); | |
} | |
/** | |
* | |
* {@inheritDoc} | |
* | |
* @see org.eclipse.emf.emfstore.internal.client.model.ProjectSpace#exportProject(java.io.File) | |
*/ | |
public void exportProject(File file) throws IOException { | |
new ExportProjectController(this).execute(file, new NullProgressMonitor()); | |
} | |
/** | |
* | |
* {@inheritDoc} | |
* | |
* @see org.eclipse.emf.emfstore.internal.client.model.ProjectSpace#getChanges(org.eclipse.emf.emfstore.internal.server.model.versioning.VersionSpec, | |
* org.eclipse.emf.emfstore.internal.server.model.versioning.VersionSpec) | |
*/ | |
public List<ChangePackage> getChanges(VersionSpec sourceVersion, VersionSpec targetVersion) | |
throws InvalidVersionSpecException, ESException { | |
// TODO: is this a server call? | |
final ConnectionManager connectionManager = ESWorkspaceProviderImpl.getInstance().getConnectionManager(); | |
final List<ChangePackage> changes = connectionManager.getChanges(getUsersession().getSessionId(), | |
getProjectId(), | |
sourceVersion, targetVersion); | |
return changes; | |
} | |
/** | |
* | |
* {@inheritDoc} | |
* | |
* @see org.eclipse.emf.emfstore.internal.client.model.ProjectSpace#getFile(org.eclipse.emf.emfstore.internal.server.model.FileIdentifier) | |
*/ | |
public FileDownloadStatus getFile(FileIdentifier fileIdentifier) throws FileTransferException { | |
return fileTransferManager.getFile(fileIdentifier, false); | |
} | |
/** | |
* | |
* {@inheritDoc} | |
* | |
* @see org.eclipse.emf.emfstore.internal.client.model.ProjectSpace#getFileInfo(org.eclipse.emf.emfstore.internal.server.model.FileIdentifier) | |
*/ | |
public FileInformation getFileInfo(FileIdentifier fileIdentifier) { | |
return fileTransferManager.getFileInfo(fileIdentifier); | |
} | |
/** | |
* {@inheritDoc} | |
* | |
* @see org.eclipse.emf.emfstore.internal.client.model.ProjectSpace#getLocalChangePackage() | |
*/ | |
public ChangePackage getLocalChangePackage(boolean canonize) { | |
final ChangePackage changePackage = VersioningFactory.eINSTANCE.createChangePackage(); | |
// copy operations from ProjectSpace | |
for (final AbstractOperation abstractOperation : getOperations()) { | |
final AbstractOperation copy = ModelUtil.clone(abstractOperation); | |
changePackage.getOperations().add(copy); | |
} | |
final LogMessage logMessage = VersioningFactory.eINSTANCE.createLogMessage(); | |
if (getUsersession() != null) { | |
logMessage.setAuthor(getUsersession().getUsername()); | |
} | |
else { | |
logMessage.setAuthor("<Unkown>"); | |
} | |
logMessage.setClientDate(new Date()); | |
changePackage.setLogMessage(logMessage); | |
return changePackage; | |
} | |
/** | |
* Get the current notification recorder. | |
* | |
* @return the recorder | |
*/ | |
public NotificationRecorder getNotificationRecorder() { | |
return operationManager.getNotificationRecorder(); | |
} | |
/** | |
* | |
* {@inheritDoc} | |
* | |
* @see org.eclipse.emf.emfstore.internal.client.model.ProjectSpace#getOperationManager() | |
*/ | |
public OperationManager getOperationManager() { | |
return operationManager; | |
} | |
/** | |
* {@inheritDoc} | |
* | |
* @see org.eclipse.emf.emfstore.internal.client.model.ProjectSpace#getOperations() | |
*/ | |
public List<AbstractOperation> getOperations() { | |
ChangePackage localChangePackage = getLocalChangePackage(); | |
if (localChangePackage == null) { | |
setLocalChangePackage(VersioningFactory.eINSTANCE.createChangePackage()); | |
localChangePackage = getLocalChangePackage(); | |
} | |
return localChangePackage.getOperations(); | |
} | |
/** | |
* | |
* {@inheritDoc} | |
* | |
* @see org.eclipse.emf.emfstore.internal.client.model.ProjectSpace#getProjectInfo() | |
*/ | |
public ProjectInfo getProjectInfo() { | |
final ProjectInfo projectInfo = org.eclipse.emf.emfstore.internal.server.model.ModelFactory.eINSTANCE | |
.createProjectInfo(); | |
projectInfo.setProjectId(ModelUtil.clone(getProjectId())); | |
projectInfo.setName(getProjectName()); | |
projectInfo.setDescription(getProjectDescription()); | |
projectInfo.setVersion(ModelUtil.clone(getBaseVersion())); | |
return projectInfo; | |
} | |
/** | |
* {@inheritDoc} | |
* | |
* @see org.eclipse.emf.emfstore.internal.client.model.ProjectSpace#getPropertyManager() | |
*/ | |
public PropertyManager getPropertyManager() { | |
if (propertyManager == null) { | |
propertyManager = new PropertyManager(this); | |
} | |
return propertyManager; | |
} | |
/** | |
* getter for a string argument - see {@link #setProperty(OrgUnitProperty)}. | |
*/ | |
private OrgUnitProperty getProperty(String name) throws PropertyNotFoundException { | |
// sanity checks | |
if (getUsersession() != null && getUsersession().getACUser() != null) { | |
final OrgUnitProperty orgUnitProperty = propertyMap.get(name); | |
if (orgUnitProperty != null) { | |
return orgUnitProperty; | |
} | |
} | |
throw new PropertyNotFoundException(MessageFormat.format( | |
"Property {0} not found.", name)); | |
} | |
/** | |
* {@inheritDoc} | |
* | |
* @see org.eclipse.emf.emfstore.internal.client.model.ProjectSpace#importLocalChanges(java.lang.String) | |
*/ | |
public void importLocalChanges(String fileName) throws IOException { | |
final ResourceSetImpl resourceSet = new ResourceSetImpl(); | |
final Resource resource = resourceSet.getResource(URI.createFileURI(fileName), true); | |
final EList<EObject> directContents = resource.getContents(); | |
// sanity check | |
if (directContents.size() != 1 && !(directContents.get(0) instanceof ChangePackage)) { | |
throw new IOException("File is corrupt, does not contain Changes."); | |
} | |
final ChangePackage changePackage = (ChangePackage) directContents.get(0); | |
if (!initCompleted) { | |
init(); | |
} | |
applyOperations(changePackage.getOperations(), true); | |
} | |
/** | |
* | |
* {@inheritDoc} | |
* | |
* @see org.eclipse.emf.emfstore.internal.client.model.ProjectSpace#init() | |
*/ | |
public void init() { | |
final ResourceSet contentResourceSet = getResourceSetForContents(); | |
if (contentEditingDomain == null) { | |
contentEditingDomain = getEditingDomainForContents(contentResourceSet); | |
} | |
if (getProject().eResource() != null) { | |
contentResourceSet.getResources().add(getProject().eResource()); | |
} else { | |
final Resource resource = contentResourceSet.createResource(ClientURIUtil.createProjectURI(this)); | |
resource.getContents().add(getProject()); | |
} | |
if (getLocalChangePackage() != null) { | |
if (getLocalChangePackage().eResource() != null) { | |
contentResourceSet.getResources().add(getLocalChangePackage().eResource()); | |
} else { | |
final Resource resource = contentResourceSet.createResource(ClientURIUtil.createOperationsURI(this)); | |
resource.getContents().add(getLocalChangePackage()); | |
} | |
} | |
initCrossReferenceAdapter(); | |
final ESCommandStack commandStack = (ESCommandStack) | |
contentEditingDomain.getCommandStack(); | |
fileTransferManager = new FileTransferManager(this); | |
operationManager = new OperationManager(this); | |
initResourcePersister(); | |
commandStack.addCommandStackObserver(operationManager); | |
commandStack.addCommandStackObserver(resourcePersister); | |
// initialization order is important! | |
getProject().addIdEObjectCollectionChangeObserver(operationManager); | |
getProject().addIdEObjectCollectionChangeObserver(resourcePersister); | |
if (getProject() instanceof ProjectImpl) { | |
((ProjectImpl) getProject()).setUndetachable(operationManager); | |
((ProjectImpl) getProject()).setUndetachable(resourcePersister); | |
} | |
initPropertyMap(); | |
startChangeRecording(); | |
cleanCutElements(); | |
initCompleted = true; | |
} | |
/** | |
* Returns the {@link ResourceSet} for the project and the local change package of this project space. If the | |
* resource set was null, it will be created. | |
* | |
* @return the resource set | |
*/ | |
private ResourceSet getResourceSetForContents() { | |
if (contentResourceSet == null) { | |
final ESExtensionPoint extensionPoint = new ESExtensionPoint( | |
"org.eclipse.emf.emfstore.client.resourceSetProvider", //$NON-NLS-1$ | |
true); | |
extensionPoint.setComparator(new ESPriorityComparator("priority", true)); //$NON-NLS-1$ | |
extensionPoint.reload(); | |
final ESResourceSetProvider resourceSetProvider = extensionPoint.getElementWithHighestPriority().getClass( | |
"class", //$NON-NLS-1$ | |
ESResourceSetProvider.class); | |
contentResourceSet = resourceSetProvider.getResourceSet(); | |
} | |
return contentResourceSet; | |
} | |
/** | |
* Returns the {@link EditingDomain} for this project space's project and local change package. | |
* | |
* @param resourceSet the {@link ResourceSet} of the project and local change package | |
* @return | |
*/ | |
private EditingDomain getEditingDomainForContents(ResourceSet resourceSet) { | |
final ESEditingDomainProvider domainProvider = getDomainProvider(); | |
if (domainProvider != null) { | |
return domainProvider.getEditingDomain(resourceSet); | |
} | |
AdapterFactory adapterFactory = new ComposedAdapterFactory( | |
ComposedAdapterFactory.Descriptor.Registry.INSTANCE); | |
adapterFactory = new ComposedAdapterFactory(new AdapterFactory[] { adapterFactory, | |
new ReflectiveItemProviderAdapterFactory() }); | |
final AdapterFactoryEditingDomain domain = new AdapterFactoryEditingDomain(adapterFactory, | |
new EMFStoreBasicCommandStack(), resourceSet); | |
resourceSet.eAdapters().add(new AdapterFactoryEditingDomain.EditingDomainProvider(domain)); | |
return domain; | |
} | |
private ESEditingDomainProvider getDomainProvider() { | |
// TODO EXPT PRIO | |
return new ESExtensionPoint("org.eclipse.emf.emfstore.client.editingDomainProvider") | |
.getClass("class", | |
ESEditingDomainProvider.class); | |
} | |
@SuppressWarnings("unchecked") | |
private void initPropertyMap() { | |
// TODO: deprecated, OrgUnitPropertiy will be removed soon | |
if (getUsersession() != null) { | |
ESWorkspaceProviderImpl.getObserverBus().register(this, ESLoginObserver.class); | |
final ACUser acUser = getUsersession().getACUser(); | |
if (acUser != null) { | |
for (final OrgUnitProperty p : acUser.getProperties()) { | |
if (p.getProject() != null && p.getProject().equals(getProjectId())) { | |
propertyMap.put(p.getName(), p); | |
} | |
} | |
} | |
} | |
} | |
private void initCrossReferenceAdapter() { | |
// default | |
boolean useCrossReferenceAdapter = true; | |
for (final ESExtensionElement element : new ESExtensionPoint( | |
"org.eclipse.emf.emfstore.client.inverseCrossReferenceCache") //$NON-NLS-1$ | |
.getExtensionElements()) { | |
useCrossReferenceAdapter &= element.getBoolean("activated"); //$NON-NLS-1$ | |
} | |
if (useCrossReferenceAdapter) { | |
crossReferenceAdapter = new ECrossReferenceAdapter(); | |
getProject().eAdapters().add(crossReferenceAdapter); | |
} | |
} | |
private void initResourcePersister() { | |
resourcePersister = new ResourcePersister(getProject()); | |
if (!isTransient) { | |
resourcePersister.addResource(eResource()); | |
resourcePersister.addResource(getLocalChangePackage().eResource()); | |
resourcePersister.addResource(getProject().eResource()); | |
resourcePersister.addDirtyStateChangeLister(new ESLocalProjectSaveStateNotifier(toAPI())); | |
ESWorkspaceProviderImpl.getObserverBus().register(resourcePersister); | |
} | |
} | |
/** | |
* Returns the file transfer manager. | |
* | |
* @return the file transfer manager | |
*/ | |
public FileTransferManager getFileTransferManager() { | |
return fileTransferManager; | |
} | |
/** | |
* | |
* {@inheritDoc} | |
* | |
* @see org.eclipse.emf.emfstore.internal.client.model.ProjectSpace#initResources(org.eclipse.emf.ecore.resource.ResourceSet) | |
*/ | |
public void initResources(ResourceSet resourceSet) { | |
this.resourceSet = resourceSet; | |
initCompleted = true; | |
final URI projectSpaceURI = ClientURIUtil.createProjectSpaceURI(this); | |
final URI operationsURI = ClientURIUtil.createOperationsURI(this); | |
final URI projectURI = ClientURIUtil.createProjectURI(this); | |
setResourceCount(0); | |
final List<Resource> resources = new ArrayList<Resource>(); | |
final Resource resource = resourceSet.createResource(projectURI); | |
// if resource splitting fails, we need a reference to the old resource | |
resource.getContents().add(getProject()); | |
resources.add(resource); | |
setResourceCount(getResourceCount() + 1); | |
for (final EObject modelElement : getProject().getAllModelElements()) { | |
((EMFStoreResource) resource).setID(modelElement, getProject().getModelElementId(modelElement).getId()); | |
} | |
final Resource localChangePackageResource = resourceSet.createResource(operationsURI); | |
if (this.getLocalChangePackage() == null) { | |
setLocalChangePackage(VersioningFactory.eINSTANCE.createChangePackage()); | |
} | |
localChangePackageResource.getContents().add(this.getLocalChangePackage()); | |
resources.add(localChangePackageResource); | |
final Resource projectSpaceResource = resourceSet.createResource(projectSpaceURI); | |
projectSpaceResource.getContents().add(this); | |
resources.add(projectSpaceResource); | |
// save all resources that have been created | |
for (final Resource currentResource : resources) { | |
try { | |
ModelUtil.saveResource(currentResource, WorkspaceUtil.getResourceLogger()); | |
} catch (final IOException e) { | |
WorkspaceUtil.logException("Project Space resource init failed!", e); | |
} | |
} | |
init(); | |
} | |
/** | |
* | |
* {@inheritDoc} | |
* | |
* @see org.eclipse.emf.emfstore.internal.client.model.ProjectSpace#delete(org.eclipse.core.runtime.IProgressMonitor) | |
*/ | |
public void delete(IProgressMonitor monitor) throws IOException { | |
ESWorkspaceProviderImpl.getObserverBus().notify(DeleteProjectSpaceObserver.class).projectSpaceDeleted(this); | |
// delete project to notify listeners | |
getProject().delete(); | |
// remove resources from resource set and delete them | |
deleteResource(getProject().eResource()); | |
deleteResource(eResource()); | |
deleteResource(getLocalChangePackage().eResource()); | |
// TODO: remove project space from workspace, this is not the case if delete | |
// is performed via Workspace#deleteProjectSpace | |
ESWorkspaceProviderImpl.getInstance().getInternalWorkspace().getProjectSpaces().remove(this); | |
dispose(); | |
} | |
private void deleteResource(Resource resource) throws IOException { | |
if (resource != null) { | |
resource.delete(null); | |
} | |
} | |
/** | |
* Returns the {@link ECrossReferenceAdapter}, if available. | |
* | |
* @param modelElement | |
* the model element for which to find inverse cross references | |
* | |
* @return the {@link ECrossReferenceAdapter} | |
*/ | |
public Collection<Setting> findInverseCrossReferences(EObject modelElement) { | |
if (crossReferenceAdapter != null) { | |
return crossReferenceAdapter.getInverseReferences(modelElement); | |
} | |
return UsageCrossReferencer.find(modelElement, resourceSet); | |
} | |
/** | |
* | |
* {@inheritDoc} | |
* | |
* @see org.eclipse.emf.emfstore.internal.client.model.ProjectSpace#getResourceSet() | |
*/ | |
public ResourceSet getResourceSet() { | |
return resourceSet; | |
} | |
/** | |
* | |
* {@inheritDoc} | |
* | |
* @see org.eclipse.emf.emfstore.internal.client.model.ProjectSpace#setResourceSet(org.eclipse.emf.ecore.resource.ResourceSet) | |
*/ | |
public void setResourceSet(ResourceSet resourceSet) { | |
this.resourceSet = resourceSet; | |
} | |
/** | |
* | |
* {@inheritDoc} | |
* | |
* @see org.eclipse.emf.emfstore.internal.client.model.ProjectSpace#isTransient() | |
*/ | |
public boolean isTransient() { | |
return isTransient; | |
} | |
/** | |
* | |
* {@inheritDoc} | |
* | |
* @see org.eclipse.emf.emfstore.internal.client.model.ProjectSpace#isUpdated() | |
*/ | |
public boolean isUpdated() throws ESException { | |
final PrimaryVersionSpec headVersion = resolveVersionSpec(Versions.createHEAD(getBaseVersion()), | |
new NullProgressMonitor()); | |
return getBaseVersion().equals(headVersion); | |
} | |
/** | |
* {@inheritDoc} | |
*/ | |
public void loginCompleted(ESUsersession session) { | |
// TODO Implement possibility in observerbus to register only for | |
// certain notifier | |
if (getUsersession() == null || !getUsersession().toAPI().equals(session)) { | |
return; | |
} | |
try { | |
transmitProperties(); | |
// BEGIN SUPRESS CATCH EXCEPTION | |
} catch (final RuntimeException e) { | |
// END SUPRESS CATCH EXCEPTION | |
WorkspaceUtil.logException("Resuming file transfers or transmitting properties failed!", e); | |
} | |
} | |
/** | |
* {@inheritDoc} | |
* | |
* @see org.eclipse.emf.emfstore.internal.client.model.ProjectSpace#makeTransient() | |
*/ | |
public void makeTransient() { | |
if (initCompleted) { | |
throw new IllegalAccessError("Project Space cannot be set to transient after init."); | |
} | |
isTransient = true; | |
} | |
/** | |
* {@inheritDoc} | |
*/ | |
public void mergeBranch(final PrimaryVersionSpec branchSpec, final ConflictResolver conflictResolver, | |
final IProgressMonitor monitor) | |
throws ESException { | |
if (branchSpec == null || conflictResolver == null) { | |
throw new IllegalArgumentException("Arguments must not be null."); | |
} | |
if (Versions.isSameBranch(getBaseVersion(), branchSpec)) { | |
throw new InvalidVersionSpecException("Can't merge branch with itself."); | |
} | |
final PrimaryVersionSpec commonAncestor = new ServerCall<PrimaryVersionSpec>(this) { | |
@Override | |
protected PrimaryVersionSpec run() throws ESException { | |
return resolveVersionSpec(Versions.createANCESTOR(getBaseVersion(), | |
branchSpec), monitor); | |
} | |
}.execute(); | |
final List<ChangePackage> baseChanges = getChanges(commonAncestor, getBaseVersion()); | |
final List<ChangePackage> branchChanges = getChanges(commonAncestor, branchSpec); | |
final ChangeConflictSet conflictSet = new ConflictDetector().calculateConflicts(branchChanges, | |
baseChanges, getProject()); | |
if (conflictResolver.resolveConflicts(getProject(), conflictSet)) { | |
final ChangePackage resolvedConflicts = mergeResolvedConflicts(conflictSet, branchChanges, baseChanges); | |
RunESCommand.WithException.run(ESException.class, new Callable<Void>() { | |
public Void call() throws Exception { | |
applyChanges(getBaseVersion(), baseChanges, resolvedConflicts, monitor, false); | |
setMergedVersion(ModelUtil.clone(branchSpec)); | |
return null; | |
} | |
}, getContentEditingDomain()); | |
} | |
} | |
/** | |
* | |
* {@inheritDoc} | |
* | |
* @see org.eclipse.emf.emfstore.internal.client.model.ProjectSpace#mergeResolvedConflicts(org.eclipse.emf.emfstore.internal.server.conflictDetection.ChangeConflictSet, | |
* java.util.List, java.util.List) | |
*/ | |
public ChangePackage mergeResolvedConflicts(ChangeConflictSet conflictSet, | |
List<ChangePackage> myChangePackages, List<ChangePackage> theirChangePackages) | |
throws ChangeConflictException { | |
final Set<AbstractOperation> accceptedMineSet = new LinkedHashSet<AbstractOperation>(); | |
final Set<AbstractOperation> rejectedTheirsSet = new LinkedHashSet<AbstractOperation>(); | |
for (final ConflictBucket conflict : conflictSet.getConflictBuckets()) { | |
if (!conflict.isResolved()) { | |
throw new ChangeConflictException( | |
"Conflict during update occured and callback failed to resolve all conflicts!", | |
conflictSet); | |
} | |
accceptedMineSet.addAll(conflict.getAcceptedLocalOperations()); | |
rejectedTheirsSet.addAll(conflict.getRejectedRemoteOperations()); | |
} | |
final List<AbstractOperation> acceptedMineList = new LinkedList<AbstractOperation>(); | |
for (final ChangePackage locChangePackage : myChangePackages) { | |
for (final AbstractOperation myOp : locChangePackage.getOperations()) { | |
if (conflictSet.getNotInvolvedInConflict().contains(myOp)) { | |
acceptedMineList.add(myOp); | |
} else if (accceptedMineSet.contains(myOp)) { | |
acceptedMineList.add(myOp); | |
} | |
accceptedMineSet.remove(myOp); | |
} | |
} | |
// add all remaining operations in acceptedMineSet (they have been generated during merge) | |
accceptedMineSet.addAll(accceptedMineSet); | |
final List<AbstractOperation> rejectedTheirsList = new LinkedList<AbstractOperation>(); | |
for (final ChangePackage theirCP : theirChangePackages) { | |
for (final AbstractOperation theirOp : theirCP.getOperations()) { | |
if (rejectedTheirsSet.contains(theirOp)) { | |
rejectedTheirsList.add(theirOp); | |
} | |
} | |
} | |
final List<AbstractOperation> mergeResult = new ArrayList<AbstractOperation>(rejectedTheirsList.size() | |
+ acceptedMineList.size()); | |
for (final AbstractOperation operationToReverse : rejectedTheirsList) { | |
mergeResult.add(0, operationToReverse.reverse()); | |
} | |
mergeResult.addAll(acceptedMineList); | |
final ChangePackage result = VersioningFactory.eINSTANCE.createChangePackage(); | |
result.getOperations().addAll(mergeResult); | |
return result; | |
} | |
/** | |
* | |
* {@inheritDoc} | |
* | |
* @see org.eclipse.emf.emfstore.internal.client.model.ProjectSpace#getBranches() | |
*/ | |
public List<BranchInfo> getBranches() throws ESException { | |
return new ServerCall<List<BranchInfo>>(this) { | |
@Override | |
protected List<BranchInfo> run() throws ESException { | |
final ConnectionManager cm = ESWorkspaceProviderImpl.getInstance().getConnectionManager(); | |
return cm.getBranches(getSessionId(), getProjectId()); | |
} | |
}.execute(); | |
} | |
/** | |
* | |
* {@inheritDoc} | |
* | |
* @see org.eclipse.emf.emfstore.internal.client.model.ProjectSpace#removeTag(org.eclipse.emf.emfstore.internal.server.model.versioning.PrimaryVersionSpec, | |
* org.eclipse.emf.emfstore.internal.server.model.versioning.TagVersionSpec) | |
*/ | |
public void removeTag(PrimaryVersionSpec versionSpec, TagVersionSpec tag) throws ESException { | |
final ConnectionManager cm = ESWorkspaceProviderImpl.getInstance().getConnectionManager(); | |
cm.removeTag(getUsersession().getSessionId(), getProjectId(), versionSpec, tag); | |
} | |
/** | |
* | |
* {@inheritDoc} | |
* | |
* @see org.eclipse.emf.emfstore.internal.client.model.ProjectSpace#resolve(org.eclipse.emf.emfstore.internal.server.model.url.ModelElementUrlFragment) | |
*/ | |
public EObject resolve(ModelElementUrlFragment modelElementUrlFragment) throws MEUrlResolutionException { | |
final ModelElementId modelElementId = modelElementUrlFragment.getModelElementId(); | |
final EObject modelElement = getProject().getModelElement(modelElementId); | |
if (modelElement == null) { | |
throw new MEUrlResolutionException(); | |
} | |
return modelElement; | |
} | |
/** | |
* | |
* {@inheritDoc} | |
* | |
* @see org.eclipse.emf.emfstore.internal.client.model.ProjectSpace#resolveVersionSpec(org.eclipse.emf.emfstore.internal.server.model.versioning.VersionSpec, | |
* org.eclipse.core.runtime.IProgressMonitor) | |
*/ | |
public PrimaryVersionSpec resolveVersionSpec(final VersionSpec versionSpec, IProgressMonitor monitor) | |
throws InvalidVersionSpecException, ESException { | |
return new ServerCall<PrimaryVersionSpec>(this, monitor) { | |
@Override | |
protected PrimaryVersionSpec run() throws ESException { | |
return getConnectionManager().resolveVersionSpec( | |
getSessionId(), | |
getProjectId(), | |
versionSpec); | |
} | |
}.execute(); | |
} | |
/** | |
* | |
* {@inheritDoc} | |
* | |
* @see org.eclipse.emf.emfstore.internal.client.model.ProjectSpace#revert() | |
*/ | |
public void revert() { | |
while (!getOperations().isEmpty()) { | |
undoLastOperation(); | |
} | |
updateDirtyState(); | |
} | |
/** | |
* Saves the project space itself only, no containment children. | |
*/ | |
public void saveProjectSpaceOnly() { | |
saveResource(eResource()); | |
} | |
/** | |
* Saves the project space. | |
*/ | |
public void save() { | |
saveProjectSpaceOnly(); | |
saveChangePackage(); | |
resourcePersister.saveDirtyResources(true); | |
} | |
/** | |
* {@inheritDoc} | |
* | |
* @see org.eclipse.emf.emfstore.internal.client.model.ProjectSpace#hasUnsavedChanges() | |
*/ | |
public boolean hasUnsavedChanges() { | |
if (resourcePersister != null) { | |
return resourcePersister.isDirty(); | |
} | |
// in case the project space has not been initialized yet | |
return false; | |
} | |
private void saveChangePackage() { | |
final ChangePackage localChangePackage = getLocalChangePackage(); | |
if (localChangePackage.eResource() != null) { | |
saveResource(localChangePackage.eResource()); | |
} | |
} | |
/** | |
* Save the given resource that is part of the project space resource set. | |
* | |
* @param resource | |
* the resource | |
*/ | |
public void saveResource(Resource resource) { | |
try { | |
if (resource == null) { | |
if (!isTransient) { | |
WorkspaceUtil.logException("Resources of project space are not properly initialized!", | |
new IllegalProjectSpaceStateException("Resource to save is null")); | |
} | |
return; | |
} | |
ModelUtil.saveResource(resource, WorkspaceUtil.getResourceLogger()); | |
} catch (final IOException e) { | |
WorkspaceUtil.logException("An error in the data was detected during save!" | |
+ " The safest way to deal with this problem is to delete this project and checkout again.", e); | |
} | |
} | |
/** | |
* | |
* {@inheritDoc} | |
* | |
* @see org.eclipse.emf.emfstore.internal.client.model.ProjectSpace#setProperty(org.eclipse.emf.emfstore.internal.server.model.accesscontrol.OrgUnitProperty) | |
*/ | |
public void setProperty(OrgUnitProperty property) { | |
// sanity checks | |
if (getUsersession() != null && getUsersession().getACUser() != null) { | |
try { | |
if (property.getProject() == null) { | |
property.setProject(ModelUtil.clone(getProjectId())); | |
} else if (!property.getProject().equals(getProjectId())) { | |
return; | |
} | |
final OrgUnitProperty prop = getProperty(property.getName()); | |
prop.setValue(property.getValue()); | |
} catch (final PropertyNotFoundException e) { | |
getUsersession().getACUser().getProperties().add(property); | |
propertyMap.put(property.getName(), property); | |
} | |
// the properties that have been altered are retained in a separate | |
// list | |
for (final OrgUnitProperty changedProperty : getUsersession().getChangedProperties()) { | |
if (changedProperty.getName().equals(property.getName()) | |
&& changedProperty.getProject().equals(getProjectId())) { | |
changedProperty.setValue(property.getValue()); | |
ESWorkspaceProviderImpl.getInstance().getWorkspace().toInternalAPI().save(); | |
return; | |
} | |
} | |
getUsersession().getChangedProperties().add(property); | |
ESWorkspaceProviderImpl.getInstance().getWorkspace().toInternalAPI().save(); | |
} | |
} | |
/** | |
* | |
* {@inheritDoc} | |
* | |
* @see org.eclipse.emf.emfstore.internal.client.model.ProjectSpace#shareProject(org.eclipse.core.runtime.IProgressMonitor) | |
*/ | |
public ProjectInfo shareProject(IProgressMonitor monitor) throws ESException { | |
return shareProject(null, monitor); | |
} | |
/** | |
* | |
* {@inheritDoc} | |
* | |
* @see org.eclipse.emf.emfstore.internal.client.model.ProjectSpace#shareProject(org.eclipse.emf.emfstore.internal.client.model.Usersession, | |
* org.eclipse.core.runtime.IProgressMonitor) | |
*/ | |
public ProjectInfo shareProject(Usersession session, IProgressMonitor monitor) throws ESException { | |
return new ShareController(this, session, monitor).execute(); | |
} | |
/** | |
* Starts change recording on this workspace, resumes previous recordings if | |
* there are any. | |
*/ | |
public void startChangeRecording() { | |
operationManager.startChangeRecording(); | |
updateDirtyState(); | |
} | |
/** | |
* Stops current recording of changes and adds recorded changes to this | |
* project spaces changes. | |
*/ | |
public void stopChangeRecording() { | |
if (operationManager != null) { | |
operationManager.stopChangeRecording(); | |
} | |
} | |
/** | |
* | |
* {@inheritDoc} | |
* | |
* @see org.eclipse.emf.emfstore.internal.client.model.ProjectSpace#transmitProperties() | |
*/ | |
public void transmitProperties() { | |
final List<OrgUnitProperty> temp = new ArrayList<OrgUnitProperty>(); | |
for (final OrgUnitProperty changedProperty : getUsersession().getChangedProperties()) { | |
if (changedProperty.getProject() != null && changedProperty.getProject().equals(getProjectId())) { | |
temp.add(changedProperty); | |
} | |
} | |
final ListIterator<OrgUnitProperty> iterator = temp.listIterator(); | |
while (iterator.hasNext()) { | |
try { | |
ESWorkspaceProviderImpl | |
.getInstance() | |
.getConnectionManager() | |
.transmitProperty(getUsersession().getSessionId(), iterator.next(), getUsersession().getACUser(), | |
getProjectId()); | |
iterator.remove(); | |
} catch (final ESException e) { | |
WorkspaceUtil.logException("Transmission of properties failed with exception", e); | |
} | |
} | |
} | |
/** | |
* | |
* {@inheritDoc} | |
* | |
* @see org.eclipse.emf.emfstore.internal.client.model.ProjectSpace#undoLastOperation() | |
*/ | |
public void undoLastOperation() { | |
undoLastOperations(1); | |
} | |
/** | |
* | |
* {@inheritDoc} | |
* | |
* @see org.eclipse.emf.emfstore.internal.client.model.ProjectSpace#undoLastOperation() | |
*/ | |
public void undoLastOperations(int numberOfOperations) { | |
if (numberOfOperations <= 0) { | |
return; | |
} | |
if (!getOperations().isEmpty()) { | |
final List<AbstractOperation> operations = getOperations(); | |
final AbstractOperation lastOperation = operations.get(operations.size() - 1); | |
applyOperations(Collections.singletonList(lastOperation.reverse()), false); | |
operationManager.notifyOperationUndone(lastOperation); | |
operations.remove(lastOperation); | |
undoLastOperations(--numberOfOperations); | |
} | |
updateDirtyState(); | |
} | |
/** | |
* | |
* {@inheritDoc} | |
* | |
* @see org.eclipse.emf.emfstore.internal.client.model.ProjectSpace#update(org.eclipse.core.runtime.IProgressMonitor) | |
*/ | |
public PrimaryVersionSpec update(IProgressMonitor monitor) throws ESException { | |
return update(Versions.createHEAD(getBaseVersion()), null, monitor); | |
} | |
/** | |
* | |
* {@inheritDoc} | |
* | |
* @see org.eclipse.emf.emfstore.internal.client.model.ProjectSpace#update(org.eclipse.emf.emfstore.internal.server.model.versioning.VersionSpec) | |
*/ | |
public PrimaryVersionSpec update(final VersionSpec version) throws ESException { | |
return update(version, null, null); | |
} | |
/** | |
* | |
* {@inheritDoc} | |
* | |
* @see org.eclipse.emf.emfstore.internal.client.model.ProjectSpace#update(org.eclipse.emf.emfstore.internal.server.model.versioning.VersionSpec, | |
* org.eclipse.emf.emfstore.client.callbacks.ESUpdateCallback, org.eclipse.core.runtime.IProgressMonitor) | |
*/ | |
public PrimaryVersionSpec update(VersionSpec version, ESUpdateCallback callback, IProgressMonitor progress) | |
throws ESException { | |
return new UpdateController(this, version, callback, progress).execute(); | |
} | |
/** | |
* Updates the dirty state of the project space. | |
*/ | |
public void updateDirtyState() { | |
setDirty(!getOperations().isEmpty()); | |
} | |
/** | |
* | |
* {@inheritDoc} | |
* | |
* @see org.eclipse.emf.emfstore.internal.common.ESDisposable#dispose() | |
*/ | |
@SuppressWarnings("unchecked") | |
public void dispose() { | |
if (disposed) { | |
return; | |
} | |
stopChangeRecording(); | |
if (crossReferenceAdapter != null) { | |
getProject().eAdapters().remove(crossReferenceAdapter); | |
} | |
final ESCommandStack commandStack = (ESCommandStack) contentEditingDomain.getCommandStack(); | |
commandStack.removeCommandStackObserver(operationManager); | |
commandStack.removeCommandStackObserver(resourcePersister); | |
getProject().removeIdEObjectCollectionChangeObserver(operationManager); | |
getProject().removeIdEObjectCollectionChangeObserver(resourcePersister); | |
ESWorkspaceProviderImpl.getObserverBus().unregister(resourcePersister); | |
ESWorkspaceProviderImpl.getObserverBus().unregister(this, ESLoginObserver.class); | |
ESWorkspaceProviderImpl.getObserverBus().unregister(this); | |
operationManager.dispose(); | |
resourcePersister.dispose(); | |
operationManager = null; | |
resourcePersister = null; | |
if (getProject().eResource() != null) { | |
getProject().eResource().getResourceSet().getResources().remove(getProject().eResource()); | |
} | |
if (getLocalChangePackage().eResource() != null) { | |
getLocalChangePackage().eResource().getResourceSet().getResources() | |
.remove(getLocalChangePackage().eResource()); | |
} | |
if (eResource() instanceof EMFStoreResource) { | |
final EMFStoreResource emfStoreResource = (EMFStoreResource) eResource(); | |
emfStoreResource.getEObjectToIDMap().clear(); | |
emfStoreResource.getIDToEObjectMap().clear(); | |
} | |
if (getProject().eResource() instanceof EMFStoreResource) { | |
final EMFStoreResource emfStoreResource = (EMFStoreResource) getProject().eResource(); | |
emfStoreResource.getEObjectToIDMap().clear(); | |
emfStoreResource.getIDToEObjectMap().clear(); | |
} | |
if (getLocalChangePackage().eResource() instanceof EMFStoreResource) { | |
final EMFStoreResource emfStoreResource = (EMFStoreResource) getLocalChangePackage().eResource(); | |
emfStoreResource.getEObjectToIDMap().clear(); | |
emfStoreResource.getIDToEObjectMap().clear(); | |
} | |
contentEditingDomain.getCommandStack().flush(); | |
disposed = true; | |
} | |
/** | |
* | |
* {@inheritDoc} | |
* | |
* @see org.eclipse.emf.emfstore.internal.client.model.ProjectSpace#isShared() | |
*/ | |
public boolean isShared() { | |
return getUsersession() != null; | |
} | |
/** | |
* | |
* {@inheritDoc} | |
* | |
* @see org.eclipse.emf.emfstore.internal.client.model.ProjectSpace#isClosed() | |
*/ | |
public boolean isClosed() { | |
return closed; | |
} | |
/** | |
* | |
* {@inheritDoc} | |
* | |
* @see org.eclipse.emf.emfstore.internal.client.model.ProjectSpace#close(boolean) | |
*/ | |
public void close(boolean saveBeforeClose) { | |
if (saveBeforeClose) { | |
save(); | |
} | |
getWorkspace().removeProjectToProjectSpaceEntry(this); | |
dispose(); | |
closed = true; | |
} | |
/** | |
* | |
* {@inheritDoc} | |
* | |
* @see org.eclipse.emf.emfstore.internal.client.model.ProjectSpace#open() | |
*/ | |
public void open() { | |
closed = false; | |
init(); | |
getWorkspace().addProjectToProjectSpaceEntry(this); | |
} | |
/** | |
* {@inheritDoc} | |
* | |
* @see org.eclipse.emf.emfstore.internal.client.model.ProjectSpace#getContentEditingDomain() | |
*/ | |
public EditingDomain getContentEditingDomain() { | |
return contentEditingDomain; | |
} | |
/** | |
* {@inheritDoc} | |
* | |
* @see org.eclipse.emf.emfstore.internal.client.model.ProjectSpace#flushContentCommandStack() | |
*/ | |
public void flushContentCommandStack() { | |
if (contentEditingDomain != null) { | |
contentEditingDomain.getCommandStack().flush(); | |
} | |
} | |
private void notifyPreRevertMyChanges(final ChangePackage changePackage) { | |
ESWorkspaceProviderImpl.getObserverBus().notify(ESMergeObserver.class) | |
.preRevertMyChanges(toAPI(), changePackage.toAPI()); | |
} | |
private void notifyPostRevertMyChanges() { | |
ESWorkspaceProviderImpl.getObserverBus().notify(ESMergeObserver.class).postRevertMyChanges(toAPI()); | |
} | |
private void notifyPostApplyTheirChanges(List<ChangePackage> theirChangePackages) { | |
// TODO ASYNC review this cancel | |
ESWorkspaceProviderImpl.getObserverBus().notify(ESMergeObserver.class) | |
.postApplyTheirChanges(toAPI(), APIUtil.mapToAPI(ESChangePackage.class, theirChangePackages)); | |
} | |
private void notifyPostApplyMergedChanges(ChangePackage changePackage) { | |
ESWorkspaceProviderImpl.getObserverBus().notify(ESMergeObserver.class) | |
.postApplyMergedChanges( | |
toAPI(), changePackage.toAPI()); | |
} | |
/** | |
* | |
* {@inheritDoc} | |
* | |
* @see org.eclipse.emf.emfstore.internal.common.api.APIDelegate#toAPI() | |
*/ | |
public ESLocalProjectImpl toAPI() { | |
if (esLocalProjectImpl == null) { | |
esLocalProjectImpl = createAPI(); | |
} | |
return esLocalProjectImpl; | |
} | |
/** | |
* | |
* {@inheritDoc} | |
* | |
* @see org.eclipse.emf.emfstore.internal.common.api.APIDelegate#createAPI() | |
*/ | |
public ESLocalProjectImpl createAPI() { | |
return new ESLocalProjectImpl(this); | |
} | |
/** | |
* Returns the {@link ESRunnableContext} operations are applied in. | |
* | |
* @return the runnable context operations are executed in | |
*/ | |
public ESRunnableContext getRunnableContext() { | |
return runnableContext; | |
} | |
} |