From 3f89370275f963802955bfe11248ad859d92ae53 Mon Sep 17 00:00:00 2001 From: Florian Hoelzl <hoelzl@fortiss.org> Date: Tue, 24 May 2011 15:10:22 +0000 Subject: [PATCH] Implemented IPersistencyService and IStorageProvider for Eclipse workspace projects. --- .../trunk/META-INF/MANIFEST.MF | 9 +- .../trunk/icons/server.png | Bin 3153 -> 0 bytes org.fortiss.tooling.kernel/trunk/plugin.xml | 71 ---- .../IStorageProvider.java} | 32 +- .../ITopLevelElementChangeListener.java} | 27 +- .../kernel/internal/ActionService.java | 9 +- .../kernel/internal/CommandStackService.java | 166 +------- .../kernel/internal/PersistencyService.java | 130 ++++++ .../EclipseWorkspaceLocationProviderBase.java | 99 ----- .../NavigatorTreeContentProvider.java | 29 +- .../navigator/NavigatorTreeLabelProvider.java | 2 + .../internal/navigator/NavigatorViewPart.java | 122 +----- .../properties/PropertiesAdapterFactory.java | 5 +- .../storage/eclipse/AutoUndoCommandStack.java | 141 +++++++ .../eclipse/EMFTransactionalCommand.java | 182 ++++++++ .../eclipse/EMultiContentsIterator.java} | 79 ++-- .../EclipseResourceStorageProvider.java | 233 +++++++++++ .../storage/eclipse/ModelContext.java | 390 ++++++++++++++++++ .../kernel/services/IPersistencyService.java | 39 +- .../EMFResourceUtils.java} | 47 ++- .../kernel/util/ProjectRootElementUtils.java | 23 +- 21 files changed, 1268 insertions(+), 567 deletions(-) delete mode 100644 org.fortiss.tooling.kernel/trunk/icons/server.png rename org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/{internal/emfstore/EclipseWorkspaceUnicaseClientLocationProvider.java => interfaces/IStorageProvider.java} (66%) rename org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/{internal/emfstore/EclipseWorkspaceEMFStoreLocationProvider.java => interfaces/ITopLevelElementChangeListener.java} (66%) delete mode 100644 org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/internal/emfstore/EclipseWorkspaceLocationProviderBase.java create mode 100644 org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/internal/storage/eclipse/AutoUndoCommandStack.java create mode 100644 org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/internal/storage/eclipse/EMFTransactionalCommand.java rename org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/internal/{handler/ProjectModelElementHandler.java => storage/eclipse/EMultiContentsIterator.java} (50%) create mode 100644 org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/internal/storage/eclipse/EclipseResourceStorageProvider.java create mode 100644 org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/internal/storage/eclipse/ModelContext.java rename org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/{internal/compose/ProjectCompositor.java => util/EMFResourceUtils.java} (54%) diff --git a/org.fortiss.tooling.kernel/trunk/META-INF/MANIFEST.MF b/org.fortiss.tooling.kernel/trunk/META-INF/MANIFEST.MF index 3b108be87..9a1cbf726 100644 --- a/org.fortiss.tooling.kernel/trunk/META-INF/MANIFEST.MF +++ b/org.fortiss.tooling.kernel/trunk/META-INF/MANIFEST.MF @@ -14,12 +14,9 @@ Require-Bundle: org.eclipse.core.runtime;visibility:=reexport, org.eclipse.gef;visibility:=reexport, org.conqat.ide.commons;bundle-version="2.7.0";visibility:=reexport, org.conqat.ide.commons.ui;bundle-version="2.7.0";visibility:=reexport, - org.conqat.ide.commons.gef;bundle-version="2.7.0", - org.eclipse.jdt.ui;bundle-version="3.6.2", - org.eclipse.emf.transaction;bundle-version="1.4.0", - org.eclipse.emf.emfstore.server;bundle-version="0.7.3", - org.eclipse.emf.emfstore.client;bundle-version="0.7.3", - org.eclipse.emf.emfstore.client.ui;bundle-version="0.7.3" + org.conqat.ide.commons.gef;bundle-version="2.7.0";visibility:=reexport, + org.eclipse.emf.ecore.xmi;bundle-version="2.5.0", + org.eclipse.emf.transaction;bundle-version="1.4.0" Bundle-RequiredExecutionEnvironment: JavaSE-1.6 Bundle-ActivationPolicy: lazy Export-Package: org.fortiss.tooling.kernel;uses:="org.eclipse.jface.resource,org.eclipse.ui.plugin,org.osgi.framework", diff --git a/org.fortiss.tooling.kernel/trunk/icons/server.png b/org.fortiss.tooling.kernel/trunk/icons/server.png deleted file mode 100644 index 4e472dd74433e92014ba5198172235eadc404aec..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3153 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 diff --git a/org.fortiss.tooling.kernel/trunk/plugin.xml b/org.fortiss.tooling.kernel/trunk/plugin.xml index 004894271..02b98324e 100644 --- a/org.fortiss.tooling.kernel/trunk/plugin.xml +++ b/org.fortiss.tooling.kernel/trunk/plugin.xml @@ -13,18 +13,6 @@ uri="http://www.fortiss.org/tooling/kernel"> </package> </extension> - <extension - point="org.eclipse.emf.emfstore.server.locationprovider"> - <LocationProvider - providerClass="org.fortiss.tooling.kernel.internal.emfstore.EclipseWorkspaceEMFStoreLocationProvider"> - </LocationProvider> - </extension> - <extension - point="org.eclipse.emf.emfstore.client.workspaceLocationProvider"> - <LocationProvider - providerClass="org.fortiss.tooling.kernel.internal.emfstore.EclipseWorkspaceUnicaseClientLocationProvider"> - </LocationProvider> - </extension> <extension point="org.eclipse.ui.editors"> <editor @@ -76,51 +64,6 @@ </dynamic> </menu> </menuContribution> - <menuContribution - allPopups="false" - locationURI="popup:org.fortiss.tooling.kernel.model.navigator?after=repository"> - <menu - icon="icons/server.png" - id="org.fortiss.tooling.kernel.model.navigator.repositorymenu" - label="Repository"> - <visibleWhen - checkEnabled="false"> - <with - variable="activeMenuSelection"> - <iterate> - <adapt - type="org.eclipse.emf.emfstore.client.model.ProjectSpace"> - </adapt> - </iterate> - </with> - </visibleWhen> - <command - commandId="org.eclipse.emf.emfstore.client.ui.commitProject" - label="Commit..." - style="push"> - </command> - <command - commandId="org.eclipse.emf.emfstore.client.ui.updateProject" - label="Update to HEAD" - style="push"> - </command> - <command - commandId="org.eclipse.emf.emfstore.client.ui.updateProjectVersion" - label="Update to Version..." - style="push"> - </command> - <command - commandId="org.eclipse.emf.emfstore.client.ui.revert" - label="Revert" - style="push"> - </command> - <command - commandId="org.eclipse.emf.emfstore.client.ui.deleteProject" - label="Delete Local Project" - style="push"> - </command> - </menu> - </menuContribution> </extension> <extension point="org.eclipse.core.runtime.adapters"> @@ -182,19 +125,5 @@ </propertySection> </propertySections> </extension> - <extension - point="org.fortiss.tooling.kernel.modelElementHandler"> - <modelElementHandler - handler="org.fortiss.tooling.kernel.internal.handler.ProjectModelElementHandler" - modelElementClass="org.eclipse.emf.emfstore.common.model.Project"> - </modelElementHandler> - </extension> - <extension - point="org.fortiss.tooling.kernel.modelElementCompositor"> - <modelElementCompositor - compositor="org.fortiss.tooling.kernel.internal.compose.ProjectCompositor" - modelElementClass="org.eclipse.emf.emfstore.common.model.Project"> - </modelElementCompositor> - </extension> </plugin> diff --git a/org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/internal/emfstore/EclipseWorkspaceUnicaseClientLocationProvider.java b/org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/interfaces/IStorageProvider.java similarity index 66% rename from org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/internal/emfstore/EclipseWorkspaceUnicaseClientLocationProvider.java rename to org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/interfaces/IStorageProvider.java index d2144334e..58a620d44 100644 --- a/org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/internal/emfstore/EclipseWorkspaceUnicaseClientLocationProvider.java +++ b/org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/interfaces/IStorageProvider.java @@ -15,32 +15,30 @@ $Id$ | See the License for the specific language governing permissions and | | limitations under the License. | +--------------------------------------------------------------------------*/ -package org.fortiss.tooling.kernel.internal.emfstore; +package org.fortiss.tooling.kernel.interfaces; -import org.eclipse.emf.emfstore.server.LocationProvider; +import java.util.List; + +import org.eclipse.emf.common.command.CommandStack; +import org.eclipse.emf.ecore.EObject; /** - * A {@link LocationProvider} which uses the Eclipse workspace location as base - * location. This provider is intended to be used with the - * <code>org.unicase.workspace.workspaceLocationProvider</code> extension point. + * An {@link IStorageProvider} implements a storage mechanism for EMF models. * * @author hoelzlf * @author $Author$ * @version $Rev$ * @levd.rating RED Rev: */ -public final class EclipseWorkspaceUnicaseClientLocationProvider extends - EclipseWorkspaceLocationProviderBase { +public interface IStorageProvider { + + /** Returns the top-level elements provided by this storage provider. */ + List<EObject> getTopLevelElements(); + + /** Returns the command stack for accessing the stored model. */ + CommandStack getCommandStack(EObject modelElement); - /** {@inheritDoc} */ - @Override - protected String getWorkspaceProjectName() { - return ".unicase_client"; - } + /** Executes the given {@link Runnable} as model changing command-. */ + void runAsCommand(EObject modelElement, Runnable runner); - /** {@inheritDoc} */ - @Override - protected String getBackupProjectName() { - return ".unicase_client_backup"; - } } diff --git a/org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/internal/emfstore/EclipseWorkspaceEMFStoreLocationProvider.java b/org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/interfaces/ITopLevelElementChangeListener.java similarity index 66% rename from org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/internal/emfstore/EclipseWorkspaceEMFStoreLocationProvider.java rename to org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/interfaces/ITopLevelElementChangeListener.java index c46d678d1..38119cc5b 100644 --- a/org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/internal/emfstore/EclipseWorkspaceEMFStoreLocationProvider.java +++ b/org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/interfaces/ITopLevelElementChangeListener.java @@ -15,31 +15,24 @@ $Id$ | See the License for the specific language governing permissions and | | limitations under the License. | +--------------------------------------------------------------------------*/ -package org.fortiss.tooling.kernel.internal.emfstore; +package org.fortiss.tooling.kernel.interfaces; -import org.eclipse.emf.emfstore.server.LocationProvider; +import org.eclipse.emf.ecore.EObject; /** - * A {@link LocationProvider} which uses the Eclipse workspace location as base - * location. This provider is intended to be used with the - * <code>org.unicase.emfstore.locationprovider</code> extension point. + * Listener interface notified by the persistency service whenever the list of + * top-level elements changes. * * @author hoelzlf * @author $Author$ * @version $Rev$ * @levd.rating RED Rev: */ -public final class EclipseWorkspaceEMFStoreLocationProvider extends - EclipseWorkspaceLocationProviderBase { - /** {@inheritDoc} */ - @Override - protected String getWorkspaceProjectName() { - return ".emfStoreServerWorkspaceProject"; - } +public interface ITopLevelElementChangeListener { - /** {@inheritDoc} */ - @Override - protected String getBackupProjectName() { - return ".emfStoreServerBackupProject"; - } + /** Notifies the listener about the adding of the given element. */ + void topLevelElementAdded(EObject topLevelElement); + + /** Notifies the listener about the removal of the given element. */ + void topLevelElementRemoved(EObject topLevelElement); } diff --git a/org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/internal/ActionService.java b/org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/internal/ActionService.java index e41893138..3861ea32a 100644 --- a/org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/internal/ActionService.java +++ b/org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/internal/ActionService.java @@ -19,8 +19,6 @@ package org.fortiss.tooling.kernel.internal; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.util.EcoreUtil; -import org.eclipse.emf.emfstore.client.model.ProjectSpace; -import org.eclipse.emf.emfstore.common.model.Project; import org.eclipse.jface.action.IMenuManager; import org.eclipse.ui.IActionBars; import org.eclipse.ui.IEditorSite; @@ -32,6 +30,7 @@ import org.fortiss.tooling.kernel.base.EObjectAction; import org.fortiss.tooling.kernel.model.IRemovable; import org.fortiss.tooling.kernel.services.IActionService; import org.fortiss.tooling.kernel.services.ICommandStackService; +import org.fortiss.tooling.kernel.services.IPersistencyService; import org.fortiss.tooling.kernel.util.EObjectSelectionUtils; /** @@ -157,9 +156,9 @@ public class ActionService implements IActionService { boolean canDelete = (target instanceof IRemovable) && ((IRemovable) target).canRemove(); - canDelete = canDelete || !(target instanceof Project) - && !(target instanceof ProjectSpace) - && target.eContainer() != null; + canDelete = canDelete + || !IPersistencyService.INSTANCE.getTopLevelElements() + .contains(target); globalDeleteAction.setTarget(target); globalDeleteAction.setEnabled(canDelete); } diff --git a/org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/internal/CommandStackService.java b/org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/internal/CommandStackService.java index aff44d5db..7609c5d7c 100644 --- a/org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/internal/CommandStackService.java +++ b/org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/internal/CommandStackService.java @@ -17,28 +17,13 @@ $Id$ +--------------------------------------------------------------------------*/ package org.fortiss.tooling.kernel.internal; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.Map; -import java.util.Stack; - -import org.eclipse.emf.common.command.BasicCommandStack; -import org.eclipse.emf.common.notify.Notification; -import org.eclipse.emf.common.notify.impl.AdapterImpl; import org.eclipse.emf.ecore.EObject; -import org.eclipse.emf.emfstore.client.model.Configuration; -import org.eclipse.emf.emfstore.client.model.ModelPackage; -import org.eclipse.emf.emfstore.client.model.ProjectSpace; -import org.eclipse.emf.emfstore.client.model.Workspace; -import org.eclipse.emf.emfstore.client.model.WorkspaceManager; -import org.eclipse.emf.emfstore.client.model.impl.ProjectSpaceImpl; -import org.eclipse.emf.emfstore.client.model.observers.OperationListener; -import org.eclipse.emf.emfstore.client.model.util.EMFStoreCommand; -import org.eclipse.emf.emfstore.server.model.versioning.operations.AbstractOperation; import org.fortiss.tooling.kernel.services.ICommandStackService; +import org.fortiss.tooling.kernel.services.IPersistencyService; /** - * This class implements the {@link ICommandStackService} interface. + * This class implements the {@link ICommandStackService} interface. This class + * mainly delegates its calls to the {@link IPersistencyService}. * * @author hoelzl * @author $Author$ @@ -46,165 +31,34 @@ import org.fortiss.tooling.kernel.services.ICommandStackService; * @levd.rating RED Rev: */ public class CommandStackService implements ICommandStackService { - - /** Stores the EMFStore command stack. */ - private BasicCommandStack emfStoreCommandStack; - - /** Stores the project state observers. */ - private Map<ProjectSpace, ProjectSpaceObserver> projectSpaceObserverMap = new HashMap<ProjectSpace, CommandStackService.ProjectSpaceObserver>(); - - /** Stores the workspace listener. */ - private AdapterImpl workspaceListener; - - /** Constructor. */ - public CommandStackService() { - - Workspace ws = WorkspaceManager.getInstance().getCurrentWorkspace(); - createWorkspaceListener(); - ws.eAdapters().add(workspaceListener); - - for (ProjectSpace ps : ws.getProjectSpaces()) { - ProjectSpaceObserver state = new ProjectSpaceObserver(ps); - projectSpaceObserverMap.put(ps, state); - } - - emfStoreCommandStack = (BasicCommandStack) Configuration - .getEditingDomain().getCommandStack(); - } - /** {@inheritDoc} */ @Override - public void runAsCommand(EObject target, final Runnable runner) { - EMFStoreCommand command = new EMFStoreCommand() { - - @Override - protected void doRun() { - runner.run(); - } - }; - emfStoreCommandStack.execute(command); + public void runAsCommand(EObject target, Runnable runner) { + IPersistencyService.INSTANCE.getStorageProviderFor(target) + .runAsCommand(target, runner); } /** {@inheritDoc} */ @Override public boolean canUndo(EObject target) { - ProjectSpace projectSpace = WorkspaceManager.getProjectSpace(target); - return !projectSpace.getOperations().isEmpty(); + return IPersistencyService.INSTANCE.getCommandStack(target).canUndo(); } /** {@inheritDoc} */ @Override public boolean canRedo(EObject target) { - ProjectSpace projectSpace = WorkspaceManager.getProjectSpace(target); - return projectSpaceObserverMap.get(projectSpace).canRedo(); + return IPersistencyService.INSTANCE.getCommandStack(target).canRedo(); } /** {@inheritDoc} */ @Override public void undo(EObject target) { - final ProjectSpace projectSpace = WorkspaceManager - .getProjectSpace(target); - // also pushes the operation on the project state observer's redo stack - emfStoreCommandStack.execute(new EMFStoreCommand() { - - @Override - protected void doRun() { - projectSpace.undoLastOperation(); - } - }); + IPersistencyService.INSTANCE.getCommandStack(target).undo(); } /** {@inheritDoc} */ @Override public void redo(EObject target) { - ProjectSpace projectSpace = WorkspaceManager.getProjectSpace(target); - projectSpaceObserverMap.get(projectSpace).redo(); - } - - /** Creates the workspace listener. */ - private void createWorkspaceListener() { - workspaceListener = new AdapterImpl() { - @Override - public void notifyChanged(Notification msg) { - if ((msg.getFeatureID(Workspace.class)) == ModelPackage.WORKSPACE__PROJECT_SPACES) { - if (msg.getEventType() == Notification.ADD - && ModelPackage.eINSTANCE.getProjectSpace() - .isInstance(msg.getNewValue())) { - ProjectSpace projectSpace = (ProjectSpace) msg - .getNewValue(); - ProjectSpaceObserver obs = new ProjectSpaceObserver( - projectSpace); - projectSpaceObserverMap.put(projectSpace, obs); - } else if (msg.getEventType() == Notification.REMOVE - && ModelPackage.eINSTANCE.getProjectSpace() - .isInstance(msg.getOldValue())) { - ProjectSpace projectSpace = (ProjectSpace) msg - .getOldValue(); - ProjectSpaceObserver obs = projectSpaceObserverMap - .remove(projectSpace); - obs.dispose(); - } - } - } - }; - } - - /** Observes the state of a {@link ProjectSpace}. */ - private class ProjectSpaceObserver implements OperationListener { - - /** Stores the project space reference. */ - private final ProjectSpace projectSpace; - - /** Stores the redo stack. */ - private final Stack<AbstractOperation> redoStack = new Stack<AbstractOperation>(); - - /** Flag indicating the current operation is a redo. */ - private boolean redoInProgress = false; - - /** Constructor. */ - public ProjectSpaceObserver(ProjectSpace projectSpace) { - this.projectSpace = projectSpace; - projectSpace.addOperationListener(this); - } - - /** {@inheritDoc} */ - @Override - public void operationExecuted(AbstractOperation operation) { - if (!redoInProgress) { - // clear stack if not observing a redo - redoStack.clear(); - } - } - - /** {@inheritDoc} */ - @Override - public void operationUnDone(AbstractOperation operation) { - redoStack.add(operation); - } - - /** Returns whether redo is possible. */ - public boolean canRedo() { - return !redoStack.isEmpty(); - } - - /** Redo the last operation. */ - public void redo() { - final LinkedList<AbstractOperation> ops = new LinkedList<AbstractOperation>(); - ops.add(redoStack.pop()); - emfStoreCommandStack.execute(new EMFStoreCommand() { - - @Override - protected void doRun() { - redoInProgress = true; - ((ProjectSpaceImpl) projectSpace).applyOperations(ops); - redoInProgress = false; - } - }); - } - - /** Disposes the project state observer. */ - public void dispose() { - projectSpace.removeOperationListener(this); - } + IPersistencyService.INSTANCE.getCommandStack(target).redo(); } } diff --git a/org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/internal/PersistencyService.java b/org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/internal/PersistencyService.java index 1231b3ea9..0e4c389ae 100644 --- a/org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/internal/PersistencyService.java +++ b/org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/internal/PersistencyService.java @@ -17,6 +17,18 @@ $Id$ +--------------------------------------------------------------------------*/ package org.fortiss.tooling.kernel.internal; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.conqat.lib.commons.collections.CollectionUtils; +import org.conqat.lib.commons.collections.UnmodifiableList; +import org.eclipse.emf.common.command.CommandStack; +import org.eclipse.emf.ecore.EObject; +import org.fortiss.tooling.kernel.interfaces.IStorageProvider; +import org.fortiss.tooling.kernel.interfaces.ITopLevelElementChangeListener; +import org.fortiss.tooling.kernel.internal.storage.eclipse.EclipseResourceStorageProvider; import org.fortiss.tooling.kernel.services.IPersistencyService; /** @@ -29,4 +41,122 @@ import org.fortiss.tooling.kernel.services.IPersistencyService; */ public class PersistencyService implements IPersistencyService { + /** Stores the storage providers and their element caches. */ + private final Map<IStorageProvider, List<EObject>> storageProviderCache = new HashMap<IStorageProvider, List<EObject>>(); + + /** Stores the top-level element listeners. */ + private final List<ITopLevelElementChangeListener> listeners = new ArrayList<ITopLevelElementChangeListener>(); + + /** Constructor. */ + public PersistencyService() { + // TODO (FH): replace with extension mechanism + IStorageProvider provider = new EclipseResourceStorageProvider(); + storageProviderCache.put(provider, provider.getTopLevelElements()); + + refreshAllProviderElements(); + } + + /** {@inheritDoc} */ + @Override + public UnmodifiableList<EObject> getTopLevelElements() { + List<EObject> result = new ArrayList<EObject>(); + for (IStorageProvider provider : storageProviderCache.keySet()) { + result.addAll(storageProviderCache.get(provider)); + } + return CollectionUtils.asUnmodifiable(result); + } + + /** {@inheritDoc} */ + @Override + public void refreshTopLevelElements(IStorageProvider provider) { + if (!storageProviderCache.containsKey(provider)) { + return; + } + List<EObject> elementCache = storageProviderCache.get(provider); + List<EObject> providedElements = provider.getTopLevelElements(); + for (EObject top : elementCache) { + if (!providedElements.contains(top)) { + elementCache.remove(top); + notifyListenersAboutRemove(top); + } + } + for (EObject top : providedElements) { + if (!elementCache.contains(top)) { + elementCache.add(top); + notifyListenersAboutAdd(top); + } + } + } + + /** Refreshes all providers' top-level elements. */ + private void refreshAllProviderElements() { + for (IStorageProvider provider : storageProviderCache.keySet()) { + refreshTopLevelElements(provider); + } + } + + /** Notifies listener about top-level element adding. */ + private void notifyListenersAboutAdd(EObject top) { + for (ITopLevelElementChangeListener listener : listeners) { + listener.topLevelElementAdded(top); + } + } + + /** Notifies listener about top-level element removal. */ + private void notifyListenersAboutRemove(EObject top) { + for (ITopLevelElementChangeListener listener : listeners) { + listener.topLevelElementRemoved(top); + } + } + + /** {@inheritDoc} */ + @Override + public void addTopLevelElementListener( + ITopLevelElementChangeListener listener) { + if (!listeners.contains(listener)) { + listeners.add(listener); + } + } + + /** {@inheritDoc} */ + @Override + public void removeTopLevelElementListener( + ITopLevelElementChangeListener listener) { + listeners.remove(listener); + } + + /** {@inheritDoc} */ + @Override + public EObject getTopLevelElementFor(EObject modelElement) { + while (modelElement != null) { + for (List<EObject> topLevelElements : storageProviderCache.values()) { + if (topLevelElements.contains(modelElement)) { + return modelElement; + } + } + modelElement = modelElement.eContainer(); + } + return null; + } + + /** {@inheritDoc} */ + @Override + public IStorageProvider getStorageProviderFor(EObject modelElement) { + while (modelElement != null) { + for (IStorageProvider provider : storageProviderCache.keySet()) { + if (storageProviderCache.get(provider).contains(modelElement)) { + return provider; + } + } + modelElement = modelElement.eContainer(); + } + return null; + } + + /** {@inheritDoc} */ + @Override + public CommandStack getCommandStack(EObject modelElement) { + return getStorageProviderFor(modelElement) + .getCommandStack(modelElement); + } } diff --git a/org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/internal/emfstore/EclipseWorkspaceLocationProviderBase.java b/org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/internal/emfstore/EclipseWorkspaceLocationProviderBase.java deleted file mode 100644 index e8f3f179e..000000000 --- a/org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/internal/emfstore/EclipseWorkspaceLocationProviderBase.java +++ /dev/null @@ -1,99 +0,0 @@ -/*--------------------------------------------------------------------------+ -$Id$ -| | -| Copyright 2011 ForTISS GmbH | -| | -| Licensed under the Apache License, Version 2.0 (the "License"); | -| you may not use this file except in compliance with the License. | -| You may obtain a copy of the License at | -| | -| http://www.apache.org/licenses/LICENSE-2.0 | -| | -| Unless required by applicable law or agreed to in writing, software | -| distributed under the License is distributed on an "AS IS" BASIS, | -| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | -| See the License for the specific language governing permissions and | -| limitations under the License. | -+--------------------------------------------------------------------------*/ -package org.fortiss.tooling.kernel.internal.emfstore; - -import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.IWorkspaceRoot; -import org.eclipse.core.resources.ResourcesPlugin; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.emf.emfstore.server.LocationProvider; - -/** - * Base implementation of a {@link LocationProvider} which uses the Eclipse - * workspace location as base location. - * - * @author hoelzlf - * @author $Author$ - * @version $Rev$ - * @levd.rating RED Rev: - */ -public abstract class EclipseWorkspaceLocationProviderBase implements - LocationProvider { - - /** Store the workspace location. */ - private IProject workspaceProject; - - /** Stores the backup location. */ - private IProject backupProject; - - /** Stores initilization flag. */ - private boolean initialized = false; - - /** Initialize the locations. */ - private void initialize() { - IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot(); - this.workspaceProject = workspaceRoot - .getProject(getWorkspaceProjectName()); - if (!workspaceProject.exists()) { - try { - workspaceProject.create(null); - } catch (CoreException e) { - printCreationError(getWorkspaceProjectName(), e); - } - } - this.backupProject = workspaceRoot.getProject(getBackupProjectName()); - if (!backupProject.exists()) { - try { - backupProject.create(null); - } catch (CoreException e) { - printCreationError(getBackupProjectName(), e); - } - } - initialized = true; - } - - /** Prints error message to standard error. */ - private final void printCreationError(String projectName, Exception ex) { - System.err.println("Could not create project " + projectName); - ex.printStackTrace(System.err); - } - - /** Returns the name of the workspace project. */ - protected abstract String getWorkspaceProjectName(); - - /** Returns the name of the backup project. */ - protected abstract String getBackupProjectName(); - - /** {@inheritDoc} */ - @Override - public final String getWorkspaceDirectory() { - if (!initialized) { - initialize(); - } - return workspaceProject.getLocation().toString(); - } - - /** {@inheritDoc} */ - @Override - public final String getBackupDirectory() { - if (!initialized) { - initialize(); - } - return backupProject.getLocation().toString(); - } -} diff --git a/org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/internal/navigator/NavigatorTreeContentProvider.java b/org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/internal/navigator/NavigatorTreeContentProvider.java index 35f60cb74..6ec7533b1 100644 --- a/org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/internal/navigator/NavigatorTreeContentProvider.java +++ b/org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/internal/navigator/NavigatorTreeContentProvider.java @@ -17,17 +17,12 @@ $Id$ +--------------------------------------------------------------------------*/ package org.fortiss.tooling.kernel.internal.navigator; -import java.util.ArrayList; -import java.util.List; - import org.eclipse.emf.ecore.EObject; -import org.eclipse.emf.emfstore.client.model.ProjectSpace; -import org.eclipse.emf.emfstore.client.model.Workspace; -import org.eclipse.emf.emfstore.common.model.Project; import org.eclipse.jface.viewers.ITreeContentProvider; import org.eclipse.jface.viewers.Viewer; import org.fortiss.tooling.kernel.interfaces.IHandler; import org.fortiss.tooling.kernel.services.IModelElementService; +import org.fortiss.tooling.kernel.services.IPersistencyService; /** * Content provider for the model navigator tree viewer. @@ -42,20 +37,14 @@ public class NavigatorTreeContentProvider implements ITreeContentProvider { /** {@inheritDoc} */ @Override public Object[] getElements(Object inputElement) { - if (inputElement instanceof Workspace) { - List<Project> result = new ArrayList<Project>(); - for (ProjectSpace space : ((Workspace) inputElement) - .getProjectSpaces()) { - result.add(space.getProject()); - } - return result.toArray(); - } - return null; + // delegate to the top-level elements of the persistency service + return IPersistencyService.INSTANCE.getTopLevelElements().toArray(); } /** {@inheritDoc} */ @Override public Object[] getChildren(Object parentElement) { + // delegate to the model element handlers if (parentElement instanceof EObject) { IHandler<EObject> handler = IModelElementService.INSTANCE .getModelElementHandler((EObject) parentElement); @@ -69,8 +58,11 @@ public class NavigatorTreeContentProvider implements ITreeContentProvider { /** {@inheritDoc} */ @Override public Object getParent(Object element) { - if (element instanceof EObject && !(element instanceof Workspace)) { - return ((EObject) element).eContainer(); + if (element instanceof EObject + && IPersistencyService.INSTANCE.getTopLevelElements().contains( + element)) { + // delegate to persistency service + return IPersistencyService.INSTANCE; } return null; } @@ -90,6 +82,7 @@ public class NavigatorTreeContentProvider implements ITreeContentProvider { /** {@inheritDoc} */ @Override public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { - // FIXME (FH): ignore? + // the input of this viewer is the persistency service singleton and + // therefore never changes. } } diff --git a/org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/internal/navigator/NavigatorTreeLabelProvider.java b/org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/internal/navigator/NavigatorTreeLabelProvider.java index 0a3eede08..ec06fb910 100644 --- a/org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/internal/navigator/NavigatorTreeLabelProvider.java +++ b/org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/internal/navigator/NavigatorTreeLabelProvider.java @@ -38,6 +38,7 @@ public final class NavigatorTreeLabelProvider extends BaseLabelProvider /** {@inheritDoc} */ @Override public Image getImage(Object element) { + // delegate to the model element handlers if (element instanceof EObject) { IHandler<EObject> handler = IModelElementService.INSTANCE .getModelElementHandler((EObject) element); @@ -51,6 +52,7 @@ public final class NavigatorTreeLabelProvider extends BaseLabelProvider /** {@inheritDoc} */ @Override public String getText(Object element) { + // delegate to the model element handlers if (element instanceof EObject) { IHandler<EObject> handler = IModelElementService.INSTANCE .getModelElementHandler((EObject) element); diff --git a/org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/internal/navigator/NavigatorViewPart.java b/org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/internal/navigator/NavigatorViewPart.java index 699317bd4..b1d43b138 100644 --- a/org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/internal/navigator/NavigatorViewPart.java +++ b/org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/internal/navigator/NavigatorViewPart.java @@ -23,15 +23,7 @@ import java.util.List; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; -import org.eclipse.emf.common.notify.Notification; -import org.eclipse.emf.common.notify.impl.AdapterImpl; import org.eclipse.emf.ecore.EObject; -import org.eclipse.emf.emfstore.client.model.ModelPackage; -import org.eclipse.emf.emfstore.client.model.ProjectSpace; -import org.eclipse.emf.emfstore.client.model.Workspace; -import org.eclipse.emf.emfstore.client.model.WorkspaceManager; -import org.eclipse.emf.emfstore.common.model.Project; -import org.eclipse.emf.emfstore.common.model.util.ProjectChangeObserver; import org.eclipse.jface.action.IContributionItem; import org.eclipse.jface.action.MenuManager; import org.eclipse.jface.viewers.DecoratingLabelProvider; @@ -60,6 +52,7 @@ import org.fortiss.tooling.kernel.services.IActionService; import org.fortiss.tooling.kernel.services.IContextMenuService; import org.fortiss.tooling.kernel.services.IEditorService; import org.fortiss.tooling.kernel.services.INavigatorService; +import org.fortiss.tooling.kernel.services.IPersistencyService; import org.fortiss.tooling.kernel.services.IPropertiesService; import org.fortiss.tooling.kernel.util.EObjectSelectionUtils; @@ -78,15 +71,6 @@ public final class NavigatorViewPart extends ViewPart implements /** Stores the TreeViewer. */ private TreeViewer viewer; - /** Stores the EmfStore workspace. */ - private Workspace workspace; - - /** Stores the workspace listener. */ - private AdapterImpl workspaceListener; - - /** Stores the project listener. */ - private ProjectChangeObserver projectListener; - /** Stores the menu manager. */ private MenuManager menuManager; @@ -101,107 +85,39 @@ public final class NavigatorViewPart extends ViewPart implements /** Constructor. */ public NavigatorViewPart() { - workspace = WorkspaceManager.getInstance().getCurrentWorkspace(); - - createWorkspaceListener(); - createProjectListener(); ((NavigatorService) INavigatorService.INSTANCE) .setNavigatorViewPart(this); } - /** Creates the project listener. */ - private void createProjectListener() { - projectListener = new ProjectChangeObserver() { - - @Override - public void projectDeleted(Project project) { - updateUI.schedule(); - } - - @Override - public void notify(Notification notification, Project project, - EObject modelElement) { - updateUI.schedule(); - } - - @Override - public void modelElementRemoved(Project project, - EObject modelElement) { - updateUI.schedule(); - } - - @Override - public void modelElementAdded(Project project, EObject modelElement) { - updateUI.schedule(); - } - }; - - for (ProjectSpace projectSpace : workspace.getProjectSpaces()) { - projectSpace.getProject().addProjectChangeObserver(projectListener); - } - } - - /** Creates the workspace listener. */ - private void createWorkspaceListener() { - workspaceListener = new AdapterImpl() { - @Override - public void notifyChanged(Notification msg) { - if ((msg.getFeatureID(Workspace.class)) == ModelPackage.WORKSPACE__PROJECT_SPACES) { - if (msg.getEventType() == Notification.ADD - && ModelPackage.eINSTANCE.getProjectSpace() - .isInstance(msg.getNewValue())) { - ProjectSpace projectSpace = (ProjectSpace) msg - .getNewValue(); - projectSpace.getProject().addProjectChangeObserver( - projectListener); - } else if (msg.getEventType() == Notification.REMOVE - && ModelPackage.eINSTANCE.getProjectSpace() - .isInstance(msg.getOldValue())) { - ProjectSpace projectSpace = (ProjectSpace) msg - .getOldValue(); - projectSpace.getProject().removeProjectChangeObserver( - projectListener); - } - updateUI.schedule(); - } - super.notifyChanged(msg); - } - - }; - workspace.eAdapters().add(workspaceListener); - } - /** {@inheritDoc} */ @Override public void createPartControl(Composite parent) { viewer = new TreeViewer(parent, SWT.MULTI); - if (workspace != null) { - // NOTE that the order of this important. See also JDT package - // explorer. - IDecoratorManager decoratorManager = PlatformUI.getWorkbench() - .getDecoratorManager(); - viewer.setLabelProvider(new DecoratingLabelProvider( - new NavigatorTreeLabelProvider(), decoratorManager - .getLabelDecorator())); - viewer.setContentProvider(new NavigatorTreeContentProvider()); + // NOTE that the order of this important. See also JDT package + // explorer. + IDecoratorManager decoratorManager = PlatformUI.getWorkbench() + .getDecoratorManager(); + viewer.setLabelProvider(new DecoratingLabelProvider( + new NavigatorTreeLabelProvider(), decoratorManager + .getLabelDecorator())); + viewer.setContentProvider(new NavigatorTreeContentProvider()); - getSite().setSelectionProvider(viewer); - createContextMenu(); - viewer.addSelectionChangedListener(this); + getSite().setSelectionProvider(viewer); + createContextMenu(); + viewer.addSelectionChangedListener(this); - viewer.setInput(workspace); + viewer.setInput(IPersistencyService.INSTANCE); - viewer.addDoubleClickListener(this); + viewer.addDoubleClickListener(this); - IActionService.INSTANCE.registerGlobalActions(getViewSite()); + IActionService.INSTANCE.registerGlobalActions(getViewSite()); - PlatformUI.getWorkbench().getActiveWorkbenchWindow() - .getSelectionService().addSelectionListener(this); - } + PlatformUI.getWorkbench().getActiveWorkbenchWindow() + .getSelectionService().addSelectionListener(this); - // FIXME: whats that good for? + // FIXME (FH): whats that good for? // if (viewer.getTree().getItems().length > 0) { // setActiveECPProject(viewer.getTree().getItem(0).getData()); // viewer.getTree().select(viewer.getTree().getItem(0)); @@ -243,7 +159,6 @@ public final class NavigatorViewPart extends ViewPart implements /** {@inheritDoc} */ @Override public void dispose() { - workspace.eAdapters().remove(workspaceListener); ((NavigatorService) INavigatorService.INSTANCE) .setNavigatorViewPart(null); @@ -257,6 +172,7 @@ public final class NavigatorViewPart extends ViewPart implements /** {@inheritDoc} */ @Override public void doubleClick(DoubleClickEvent event) { + // delegate to the editor service if (event.getSelection() instanceof IStructuredSelection) { EObject element = EObjectSelectionUtils.getFirstElement(event .getSelection()); diff --git a/org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/internal/properties/PropertiesAdapterFactory.java b/org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/internal/properties/PropertiesAdapterFactory.java index 836ce2931..d6a2d6cbf 100644 --- a/org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/internal/properties/PropertiesAdapterFactory.java +++ b/org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/internal/properties/PropertiesAdapterFactory.java @@ -19,8 +19,8 @@ package org.fortiss.tooling.kernel.internal.properties; import org.eclipse.core.runtime.IAdapterFactory; import org.eclipse.emf.ecore.EObject; -import org.eclipse.emf.emfstore.common.model.util.ModelUtil; import org.eclipse.ui.views.properties.tabbed.ITabbedPropertySheetPageContributor; +import org.fortiss.tooling.kernel.services.IPersistencyService; import org.fortiss.tooling.kernel.services.IPropertiesService; /** @@ -40,7 +40,8 @@ public final class PropertiesAdapterFactory implements IAdapterFactory { if (adapterType == ITabbedPropertySheetPageContributor.class && adaptableObject instanceof EObject) { EObject modelElement = (EObject) adaptableObject; - if (ModelUtil.getProject(modelElement) != null) { + if (IPersistencyService.INSTANCE + .getTopLevelElementFor(modelElement) != null) { return new ITabbedPropertySheetPageContributor() { @Override diff --git a/org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/internal/storage/eclipse/AutoUndoCommandStack.java b/org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/internal/storage/eclipse/AutoUndoCommandStack.java new file mode 100644 index 000000000..8bd3d86ea --- /dev/null +++ b/org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/internal/storage/eclipse/AutoUndoCommandStack.java @@ -0,0 +1,141 @@ +/*--------------------------------------------------------------------------+ +$Id$ +| | +| Copyright 2011 ForTISS GmbH | +| | +| Licensed under the Apache License, Version 2.0 (the "License"); | +| you may not use this file except in compliance with the License. | +| You may obtain a copy of the License at | +| | +| http://www.apache.org/licenses/LICENSE-2.0 | +| | +| Unless required by applicable law or agreed to in writing, software | +| distributed under the License is distributed on an "AS IS" BASIS, | +| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | +| See the License for the specific language governing permissions and | +| limitations under the License. | ++--------------------------------------------------------------------------*/ +package org.fortiss.tooling.kernel.internal.storage.eclipse; + +import java.util.Map; + +import org.eclipse.emf.common.command.Command; +import org.eclipse.emf.common.command.CommandStackListener; +import org.eclipse.emf.transaction.ExceptionHandler; +import org.eclipse.emf.transaction.RollbackException; +import org.eclipse.emf.transaction.TransactionalCommandStack; +import org.eclipse.emf.transaction.TransactionalEditingDomain; + +/** + * This command stack warps a {@link TransactionalEditingDomain} and forwards + * all calls to its command stack. However all commands which are executed are + * wrapped in an AutoUndoCommand first. + * + * @author hummelb + * @author $Author$ + * @version $Rev$ + * @levd.rating YELLOW Hash: 5D53FF5E73D3F0E9DFBD7F3CE61548D5 + */ +public class AutoUndoCommandStack implements TransactionalCommandStack { + + /** The underlying editing domain. */ + private final TransactionalEditingDomain editingDomain; + + /** The underlying command stack. */ + private final TransactionalCommandStack commandStack; + + /** Constructor. */ + public AutoUndoCommandStack(TransactionalEditingDomain editingDomain) { + this.editingDomain = editingDomain; + commandStack = (TransactionalCommandStack) editingDomain + .getCommandStack(); + } + + /** {@inheritDoc} */ + @Override + public void addCommandStackListener(CommandStackListener listener) { + commandStack.addCommandStackListener(listener); + } + + /** {@inheritDoc} */ + @Override + public boolean canRedo() { + return commandStack.canRedo(); + } + + /** {@inheritDoc} */ + @Override + public boolean canUndo() { + return commandStack.canUndo(); + } + + /** {@inheritDoc} */ + @SuppressWarnings("rawtypes") + @Override + public void execute(Command command, Map options) + throws InterruptedException, RollbackException { + commandStack.execute( + new EMFTransactionalCommand(command, editingDomain), options); + } + + /** {@inheritDoc} */ + @Override + public void execute(Command command) { + commandStack + .execute(new EMFTransactionalCommand(command, editingDomain)); + } + + /** {@inheritDoc} */ + @Override + public void flush() { + commandStack.flush(); + } + + /** {@inheritDoc} */ + @Override + public ExceptionHandler getExceptionHandler() { + return commandStack.getExceptionHandler(); + } + + /** {@inheritDoc} */ + @Override + public Command getMostRecentCommand() { + return commandStack.getMostRecentCommand(); + } + + /** {@inheritDoc} */ + @Override + public Command getRedoCommand() { + return commandStack.getRedoCommand(); + } + + /** {@inheritDoc} */ + @Override + public Command getUndoCommand() { + return commandStack.getUndoCommand(); + } + + /** {@inheritDoc} */ + @Override + public void redo() { + commandStack.redo(); + } + + /** {@inheritDoc} */ + @Override + public void removeCommandStackListener(CommandStackListener listener) { + commandStack.removeCommandStackListener(listener); + } + + /** {@inheritDoc} */ + @Override + public void setExceptionHandler(ExceptionHandler handler) { + commandStack.setExceptionHandler(handler); + } + + /** {@inheritDoc} */ + @Override + public void undo() { + commandStack.undo(); + } +} diff --git a/org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/internal/storage/eclipse/EMFTransactionalCommand.java b/org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/internal/storage/eclipse/EMFTransactionalCommand.java new file mode 100644 index 000000000..2fa2733fb --- /dev/null +++ b/org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/internal/storage/eclipse/EMFTransactionalCommand.java @@ -0,0 +1,182 @@ +/*--------------------------------------------------------------------------+ +$Id$ +| | +| Copyright 2011 ForTISS GmbH | +| | +| Licensed under the Apache License, Version 2.0 (the "License"); | +| you may not use this file except in compliance with the License. | +| You may obtain a copy of the License at | +| | +| http://www.apache.org/licenses/LICENSE-2.0 | +| | +| Unless required by applicable law or agreed to in writing, software | +| distributed under the License is distributed on an "AS IS" BASIS, | +| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | +| See the License for the specific language governing permissions and | +| limitations under the License. | ++--------------------------------------------------------------------------*/ +package org.fortiss.tooling.kernel.internal.storage.eclipse; + +import java.util.Collection; + +import org.conqat.ide.commons.ui.logging.LoggingUtils; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.emf.common.command.Command; +import org.eclipse.emf.common.command.CompoundCommand; +import org.eclipse.emf.transaction.RecordingCommand; +import org.eclipse.emf.transaction.RollbackException; +import org.eclipse.emf.transaction.Transaction; +import org.eclipse.emf.transaction.TransactionalEditingDomain; +import org.eclipse.emf.transaction.impl.InternalTransactionalEditingDomain; +import org.fortiss.tooling.kernel.ToolingKernelActivator; + +/** + * This class wraps another EMF command and makes sure that all execute methods + * ({@link #execute()}, {@link #undo()}, {@link #redo()}) are executed inside of + * a transaction. As a bonus the undo and redo methods are based on the + * transaction of the execute call (i.e. are coming for free). + * + * @author hummelb + * @author $Author$ + * @version $Rev$ + * @levd.rating YELLOW Hash: 625F16187EE652EBF03196972D41AFE9 + */ +public class EMFTransactionalCommand implements Command { + + /** The wrapped command. */ + private final Command inner; + + /** The recording command used. */ + private final RecordingCommand recordingCommand; + + /** The editing domain. */ + private final InternalTransactionalEditingDomain editingDomain; + + /** Constructor. */ + public EMFTransactionalCommand(Command command, + TransactionalEditingDomain editingDomain) { + inner = command; + recordingCommand = new RecordingCommand(editingDomain) { + @Override + protected void doExecute() { + inner.execute(); + } + }; + this.editingDomain = (InternalTransactionalEditingDomain) editingDomain; + } + + /** {@inheritDoc} */ + @Override + public void execute() { + runInTransaction(new Runnable() { + @Override + public void run() { + recordingCommand.execute(); + } + }); + } + + /** {@inheritDoc} */ + @Override + public void redo() { + runInTransaction(new Runnable() { + @Override + public void run() { + recordingCommand.redo(); + } + }); + } + + /** {@inheritDoc} */ + @Override + public void undo() { + runInTransaction(new Runnable() { + @Override + public void run() { + recordingCommand.undo(); + } + }); + } + + /** + * Executes the given runnable in a transaction. + */ + private void runInTransaction(Runnable runnable) { + Transaction tx = null; + try { + tx = editingDomain.startTransaction(false, null); + runnable.run(); + } catch (InterruptedException e) { + LoggingUtils.error(ToolingKernelActivator.getDefault(), + "Had unexpected interruption in command execution!", e); + } finally { + if (tx != null) { + try { + tx.commit(); + } catch (RollbackException e) { + // There is nothing we can do about. + // Maybe it even was intended, so ignore. + } + } else { + LoggingUtils.log(ToolingKernelActivator.getDefault(), + "Was not able to start transaction!", IStatus.ERROR); + } + } + } + + /** {@inheritDoc} */ + @Override + public boolean canExecute() { + return inner.canExecute(); + } + + /** {@inheritDoc} */ + @Override + public boolean canUndo() { + return recordingCommand.canUndo(); + } + + /** {@inheritDoc} */ + @Override + public Collection<?> getAffectedObjects() { + return inner.getAffectedObjects(); + } + + /** {@inheritDoc} */ + @Override + public String getDescription() { + return inner.getDescription(); + } + + /** {@inheritDoc} */ + @Override + public String getLabel() { + return inner.getLabel(); + } + + /** {@inheritDoc} */ + @Override + public Collection<?> getResult() { + return inner.getResult(); + } + + /** {@inheritDoc} */ + @Override + public Command chain(Command command) { + if (command == null) { + return this; + } + + final CompoundCommand result = new CompoundCommand(); + result.append(this); + result.append(command); + return result; + } + + /** {@inheritDoc} */ + @Override + public void dispose() { + inner.dispose(); + recordingCommand.dispose(); + } +} diff --git a/org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/internal/handler/ProjectModelElementHandler.java b/org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/internal/storage/eclipse/EMultiContentsIterator.java similarity index 50% rename from org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/internal/handler/ProjectModelElementHandler.java rename to org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/internal/storage/eclipse/EMultiContentsIterator.java index d657e121d..6bd463b0e 100644 --- a/org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/internal/handler/ProjectModelElementHandler.java +++ b/org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/internal/storage/eclipse/EMultiContentsIterator.java @@ -15,58 +15,73 @@ $Id$ | See the License for the specific language governing permissions and | | limitations under the License. | +--------------------------------------------------------------------------*/ -package org.fortiss.tooling.kernel.internal.handler; +package org.fortiss.tooling.kernel.internal.storage.eclipse; -import java.util.ArrayList; -import java.util.List; +import java.util.Collection; +import java.util.Iterator; import org.eclipse.emf.ecore.EObject; -import org.eclipse.emf.emfstore.client.model.WorkspaceManager; -import org.eclipse.emf.emfstore.common.model.Project; -import org.eclipse.jface.resource.ImageDescriptor; -import org.fortiss.tooling.kernel.ToolingKernelActivator; -import org.fortiss.tooling.kernel.base.HandlerBase; -import org.fortiss.tooling.kernel.interfaces.IHandler; -import org.fortiss.tooling.kernel.model.IProjectRootElement; /** - * {@link IHandler} for {@link Project}s. + * An iterator class which is similar to the iterator returned from + * {@link EObject#eAllContents()}, but can be used on multiple objects and also + * includes the objects themselves. * - * @author hoelzlf + * @author hummelb * @author $Author$ * @version $Rev$ - * @levd.rating RED Rev: + * @levd.rating GREEN Rev: 1794 */ -public final class ProjectModelElementHandler extends HandlerBase<Project> { +public class EMultiContentsIterator implements Iterator<EObject> { - /** {@inheritDoc} */ - @Override - public String getName(Project element) { - return WorkspaceManager.getProjectSpace(element).getProjectName(); + /** The objects to iterate on. */ + private final EObject[] objects; + + /** Current index into the array. */ + private int currentIndex = 0; + + /** Inner iterator. */ + private Iterator<EObject> inner = null; + + /** Constructor. */ + public EMultiContentsIterator(EObject... objects) { + this.objects = objects; } - /** {@inheritDoc} */ - @Override - public String getDescription(Project element) { - return WorkspaceManager.getProjectSpace(element) - .getProjectDescription(); + /** Constructor. */ + public EMultiContentsIterator(Collection<EObject> objects) { + this.objects = objects.toArray(new EObject[objects.size()]); } /** {@inheritDoc} */ @Override - public ImageDescriptor getIconImageDescriptor() { - return ToolingKernelActivator.getImageDescriptor("icons/project.png"); + public boolean hasNext() { + return currentIndex < objects.length; } /** {@inheritDoc} */ @Override - public List<EObject> getSubnodes(Project element) { - List<EObject> list = new ArrayList<EObject>(); - for (EObject node : element.getModelElements()) { - if (node instanceof IProjectRootElement) { - list.add(node); - } + public EObject next() { + EObject result; + if (inner == null) { + result = objects[currentIndex]; + inner = result.eAllContents(); + } else { + result = inner.next(); } - return list; + + // already check whether there is more to come + if (!inner.hasNext()) { + inner = null; + currentIndex++; + } + + return result; + } + + /** Removal is not supported. */ + @Override + public void remove() { + throw new UnsupportedOperationException(); } } diff --git a/org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/internal/storage/eclipse/EclipseResourceStorageProvider.java b/org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/internal/storage/eclipse/EclipseResourceStorageProvider.java new file mode 100644 index 000000000..992b4aa09 --- /dev/null +++ b/org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/internal/storage/eclipse/EclipseResourceStorageProvider.java @@ -0,0 +1,233 @@ +/*--------------------------------------------------------------------------+ +$Id$ +| | +| Copyright 2011 ForTISS GmbH | +| | +| Licensed under the Apache License, Version 2.0 (the "License"); | +| you may not use this file except in compliance with the License. | +| You may obtain a copy of the License at | +| | +| http://www.apache.org/licenses/LICENSE-2.0 | +| | +| Unless required by applicable law or agreed to in writing, software | +| distributed under the License is distributed on an "AS IS" BASIS, | +| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | +| See the License for the specific language governing permissions and | +| limitations under the License. | ++--------------------------------------------------------------------------*/ +package org.fortiss.tooling.kernel.internal.storage.eclipse; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.IdentityHashMap; +import java.util.List; +import java.util.Map; + +import org.conqat.ide.commons.ui.dialog.MessageUtils; +import org.conqat.ide.commons.ui.logging.LoggingUtils; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IResourceChangeEvent; +import org.eclipse.core.resources.IResourceChangeListener; +import org.eclipse.core.resources.IResourceDelta; +import org.eclipse.core.resources.IResourceDeltaVisitor; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.emf.common.command.CommandStack; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.util.EcoreUtil; +import org.eclipse.swt.widgets.Display; +import org.fortiss.tooling.kernel.ToolingKernelActivator; +import org.fortiss.tooling.kernel.interfaces.IStorageProvider; +import org.fortiss.tooling.kernel.services.IPersistencyService; + +/** + * This class implements the persistency service behavior for Eclipse file + * storage. + * + * @author hoelzlf + * @author $Author$ + * @version $Rev$ + * @levd.rating RED Rev: + */ +public class EclipseResourceStorageProvider implements IStorageProvider, + IResourceChangeListener { + /** Cache of models loaded so far. */ + private final Map<IFile, ModelContext> loadedContexts = new HashMap<IFile, ModelContext>(); + + /** Map from toplevel elements to context. */ + private final Map<EObject, ModelContext> rootElementContexts = new IdentityHashMap<EObject, ModelContext>(); + + /** Constructor. */ + public EclipseResourceStorageProvider() { + ResourcesPlugin.getWorkspace().addResourceChangeListener(this); + searchWorkspaceForModels(); + } + + /** Searches existing models in Eclipse project roots. */ + private synchronized void searchWorkspaceForModels() { + for (IProject project : ResourcesPlugin.getWorkspace().getRoot() + .getProjects()) { + if (!project.isOpen()) { + continue; + } + try { + for (IResource res : project.members()) { + if (res instanceof IFile) { + IFile file = (IFile) res; + // TODO (FH): use an extension mechanism for this check + if (file.getFileExtension().equals("af3_20")) { + loadContext(file); + } + } + } + } catch (CoreException e) { + // ignore + } catch (IOException ioex) { + // ignore + } + } + } + + /** {@inheritDoc} */ + @Override + public void resourceChanged(IResourceChangeEvent event) { + synchronized (this) { + if (event.getDelta() == null) { + return; + } + try { + event.getDelta().accept(new IResourceDeltaVisitor() { + @Override + public boolean visit(IResourceDelta delta) { + if ((delta.getFlags() & IResourceDelta.CONTENT) == 0) { + return true; + } + + if (delta.getResource() instanceof IFile + && isLoaded((IFile) delta.getResource())) { + if (delta.getKind() == IResourceDelta.REMOVED) { + unloadContext((IFile) delta.getResource()); + // Refresh the top-level elements + IPersistencyService.INSTANCE + .refreshTopLevelElements(EclipseResourceStorageProvider.this); + } else if (delta.getKind() == IResourceDelta.CHANGED) { + // this also refreshes top-level elements + handleChange((IFile) delta.getResource()); + } + } + return true; + } + }); + } catch (final CoreException e) { + LoggingUtils.error(ToolingKernelActivator.getDefault(), + "Should not happen!", e); + } + } + } + + /** Handles a change of the given file (which is actually managed). */ + private void handleChange(final IFile file) { + final ModelContext context = loadedContexts.get(file); + if (!context.getLastChangeWasIntended()) { + Display.getDefault().asyncExec(new Runnable() { + @Override + public void run() { + final boolean reload = MessageUtils.askQuestion( + "Reload changed file?", + "The file " + + file.getName() + + " changed on disk. " + + "Load these changes? " + + "Note that loading the changes will discard all editors, " + + "so all unsaved changes and the undo history will be lost. " + + "However if you do not reload now, " + + "the contents of the file will be overwritten " + + "the next time you perform a save."); + + if (reload) { + unloadContext(file); + try { + loadContext(file).setLastChangeWasIntended(); + + // perform touch to make sure the viewer does a + // refresh + file.touch(null); + } catch (final Exception e) { + LoggingUtils.error( + ToolingKernelActivator.getDefault(), + "Had an error during reloading the file!", + e); + } + } + + // Refresh the top-level elements + IPersistencyService.INSTANCE + .refreshTopLevelElements(EclipseResourceStorageProvider.this); + } + }); + } + } + + /** Returns whether the given file has been loaded by this manager. */ + public synchronized boolean isLoaded(IFile file) { + return loadedContexts.containsKey(file); + } + + /** Loads a file and creates a new context from its contents. */ + private ModelContext loadContext(IFile file) throws IOException { + ModelContext mc = new ModelContext(file); + loadedContexts.put(file, mc); + for (EObject top : mc.getTopLevelElements()) { + rootElementContexts.put(top, mc); + } + return mc; + } + + /** Loads a file and creates a new context from its contents. */ + private void unloadContext(IFile file) { + final ModelContext context = loadedContexts.remove(file); + if (context != null) { + for (EObject top : context.getTopLevelElements()) { + rootElementContexts.remove(top); + } + context.destroy(); + } + } + + /** + * Returns the model context for the given model element. This operation is + * implemented by traversing upwards along the parent hierarchy and checking + * all known model contexts if they include the top-most element. If no + * context is found, null is returned. + */ + private synchronized ModelContext getContext(EObject o) { + return rootElementContexts.get(EcoreUtil.getRootContainer(o)); + } + + /** {@inheritDoc} */ + @Override + public List<EObject> getTopLevelElements() { + List<EObject> result = new ArrayList<EObject>(); + result.addAll(rootElementContexts.keySet()); + return result; + } + + /** {@inheritDoc} */ + @Override + public CommandStack getCommandStack(EObject modelElement) { + ModelContext mc = getContext(modelElement); + if (mc != null) { + return mc.getTransactionalCommandStack(); + } + return null; + } + + /** {@inheritDoc} */ + @Override + public void runAsCommand(EObject modelElement, Runnable runner) { + getContext(modelElement).runAsCommand(runner); + } +} diff --git a/org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/internal/storage/eclipse/ModelContext.java b/org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/internal/storage/eclipse/ModelContext.java new file mode 100644 index 000000000..560cf3cc3 --- /dev/null +++ b/org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/internal/storage/eclipse/ModelContext.java @@ -0,0 +1,390 @@ +/*--------------------------------------------------------------------------+ +$Id$ +| | +| Copyright 2011 ForTISS GmbH | +| | +| Licensed under the Apache License, Version 2.0 (the "License"); | +| you may not use this file except in compliance with the License. | +| You may obtain a copy of the License at | +| | +| http://www.apache.org/licenses/LICENSE-2.0 | +| | +| Unless required by applicable law or agreed to in writing, software | +| distributed under the License is distributed on an "AS IS" BASIS, | +| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | +| See the License for the specific language governing permissions and | +| limitations under the License. | ++--------------------------------------------------------------------------*/ +package org.fortiss.tooling.kernel.internal.storage.eclipse; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import org.conqat.ide.commons.ui.logging.LoggingUtils; +import org.conqat.lib.commons.collections.CollectionUtils; +import org.conqat.lib.commons.collections.IdentityHashSet; +import org.conqat.lib.commons.collections.UnmodifiableList; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.WorkspaceJob; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.emf.common.command.AbstractCommand; +import org.eclipse.emf.common.command.BasicCommandStack; +import org.eclipse.emf.common.command.CommandStack; +import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.emf.ecore.resource.ResourceSet; +import org.eclipse.emf.transaction.TransactionalCommandStack; +import org.eclipse.emf.transaction.TransactionalEditingDomain; +import org.eclipse.ui.IEditorPart; +import org.fortiss.tooling.kernel.ToolingKernelActivator; +import org.fortiss.tooling.kernel.model.IIdLabeled; +import org.fortiss.tooling.kernel.services.IModelElementService; +import org.fortiss.tooling.kernel.util.EMFResourceUtils; + +/** + * The model context provides additional commands and hooks for a model. + * Additionally an editing domain is provided. + * + * @author hummelb + * @author $Author$ + * @version $Rev$ + * @levd.rating YELLOW Rev: 1101 + */ +class ModelContext { + + /** The resource set we are using. */ + private final ResourceSet rset; + + /** The file this model is from. */ + private final IFile file; + + /** The resource containing the model. */ + private final Resource r; + + /** The editing domain used for this model. */ + private final TransactionalEditingDomain editingDomain; + + /** The transactional command stack. */ + private final AutoUndoCommandStack transactionalCommandStack; + + /** + * Set of editors which depend on this context. These editors are closed + * when the underlying file is deleted or changed. + */ + private final Set<IEditorPart> dependentEditors = new IdentityHashSet<IEditorPart>(); + + /** Flag for remembering whether the last change of the file was intended. */ + private boolean lastChangeWasIntended = false; + + /** The maximal ID used in this model (used to generate new IDs). */ + private int maxId = -1; + + /** Constructor. */ + /* package */ModelContext(IFile file) throws IOException { + this.file = file; + + editingDomain = TransactionalEditingDomain.Factory.INSTANCE + .createEditingDomain(); + rset = editingDomain.getResourceSet(); + + r = rset.createResource(URI.createPlatformResourceURI(file + .getFullPath().toString(), true)); + r.load(EMFResourceUtils.buildOptionsMap()); + + transactionalCommandStack = new AutoUndoCommandStack(editingDomain); + + checkIDs(); + } + + /** Checks whether all IDs are present and updates {@link #maxId}. */ + private void checkIDs() { + boolean hadMissing = false; + for (final Iterator<EObject> i = new EMultiContentsIterator( + getTopLevelElements()); i.hasNext();) { + final EObject eo = i.next(); + if (eo instanceof IIdLabeled) { + if (((IIdLabeled) eo).getId() <= 0) { + hadMissing = true; + } + maxId = Math.max(maxId, ((IIdLabeled) eo).getId()); + } + } + maxId = Math.max(0, maxId); + if (hadMissing) { + runAsCommand(new Runnable() { + @Override + public void run() { + generateMissingIDs(); + } + }); + } + } + + /** Generates missing IDs. Must be called within transaction. */ + private void generateMissingIDs() { + for (final Iterator<EObject> i = new EMultiContentsIterator( + getTopLevelElements()); i.hasNext();) { + final EObject eo = i.next(); + if (eo instanceof IIdLabeled) { + if (((IIdLabeled) eo).getId() <= 0) { + ((IIdLabeled) eo).setId((++maxId)); + } + } + } + } + + /** + * Scans the given objects and sets up its IDs such that the uniqueness of + * IDs will be maintained in this model even after it has been composed into + * this model. + */ + /* package */void prepareIDsForCompose(EObject other) { + boolean needSmart = false; + for (final Iterator<EObject> i = new EMultiContentsIterator(other); i + .hasNext();) { + final EObject eo = i.next(); + if (eo instanceof IIdLabeled) { + if (((IIdLabeled) eo).getId() <= 0) { + ((IIdLabeled) eo).setId(++maxId); + } else { + needSmart = true; + } + } + } + + if (needSmart) { + final Set<Integer> usedIDs = new HashSet<Integer>(); + for (final Iterator<EObject> i = new EMultiContentsIterator( + getTopLevelElements()); i.hasNext();) { + final EObject eo = i.next(); + if (eo instanceof IIdLabeled) { + usedIDs.add(((IIdLabeled) eo).getId()); + } + } + + for (final Iterator<EObject> i = new EMultiContentsIterator(other); i + .hasNext();) { + final EObject eo = i.next(); + if (eo instanceof IIdLabeled) { + if (!usedIDs.add(((IIdLabeled) eo).getId())) { + final int newId = ++maxId; + ((IIdLabeled) eo).setId(newId); + usedIDs.add(newId); + } + } + } + } + } + + /** + * Add a dependent editor part which will be closed when this context + * becomes invalid. + */ + /* package */void addDependentEditor(IEditorPart editor) { + dependentEditors.add(editor); + } + + /** Removes an editor added via {@link #addDependentEditor(IEditorPart)}. */ + /* package */void removeDependentEditor(IEditorPart editor) { + dependentEditors.remove(editor); + } + + /** Destroys this context and closes all dependent editors. */ + public void destroy() { + // discard changes + ((BasicCommandStack) editingDomain.getCommandStack()).saveIsDone(); + + final List<IEditorPart> editors = new ArrayList<IEditorPart>( + dependentEditors); + dependentEditors.clear(); + + for (final IEditorPart editor : editors) { + editor.getSite().getShell().getDisplay().asyncExec(new Runnable() { + @Override + public void run() { + editor.getSite().getPage().closeEditor(editor, false); + } + }); + } + } + + /** Returns the top-level elements of this model. */ + public UnmodifiableList<EObject> getTopLevelElements() { + return CollectionUtils.asUnmodifiable(r.getContents()); + } + + /** Returns the file associated with this model. */ + public IFile getFile() { + return file; + } + + /** Returns whether the model is dirty (i.e. if there are unsaved changes). */ + public boolean isDirty() { + return ((BasicCommandStack) editingDomain.getCommandStack()) + .isSaveNeeded(); + } + + /** Perform saving of the model. */ + public synchronized void doSave(IProgressMonitor monitor) + throws IOException, CoreException { + monitor.beginTask("Saving...", 2); + + // perform ID checking before safe to not produce inconsistent models + checkIDs(); + + // we use a two-state save process, as otherwise inconsistencies in the + // model can lead to partially written files which are unreadable and + // thus cause data loss. + final ByteArrayOutputStream bytes = new ByteArrayOutputStream(); + r.save(bytes, EMFResourceUtils.buildOptionsMap()); + monitor.worked(1); + + setLastChangeWasIntended(); + file.setContents(new ByteArrayInputStream(bytes.toByteArray()), false, + true, monitor); + + monitor.worked(1); + + ((BasicCommandStack) editingDomain.getCommandStack()).saveIsDone(); + performNotifyListeners(editingDomain.getCommandStack()); + + monitor.done(); + + // schedule actual marker creation as separate job + // we use a WorkspaceJob here since marker creation + // results in resource changed notifications that should + // be batched. + new WorkspaceJob("Create CCTS markers") { + @Override + public IStatus runInWorkspace(IProgressMonitor monitor) { + // TODO (FH): call marker service + // createMarkers(); + return Status.OK_STATUS; + } + }.schedule(); + } + + /** + * Returns whether the last change was caused by a save. This method has a + * side effect! The {@link #lastChangeWasIntended} flag will be reset, so + * this method should only be called once per change event. + */ + public synchronized boolean getLastChangeWasIntended() { + final boolean result = lastChangeWasIntended; + lastChangeWasIntended = false; + return result; + } + + /** Sets the {@link #lastChangeWasIntended} flag to true. */ + public synchronized void setLastChangeWasIntended() { + lastChangeWasIntended = true; + } + + /** + * Returns the editing domain of this model's context. Note that the command + * stack contained in the returned editing domain is raw (i.e. does not deal + * with transactions). Usually you should use the command stack returned + * from {@link #getTransactionalCommandStack()}, unless you know what you + * are doing. + */ + public TransactionalEditingDomain getEditingDomain() { + return editingDomain; + } + + /** + * Returns the command stack to be used, which automatically wraps all + * commands in a transaction and provides easy undo/redo. + */ + public TransactionalCommandStack getTransactionalCommandStack() { + return transactionalCommandStack; + } + + /** Runs the given runnable as a command. */ + public void runAsCommand(final Runnable runnable) { + transactionalCommandStack.execute(new AbstractCommand() { + + @Override + public boolean canExecute() { + return true; + } + + @Override + public void execute() { + runnable.run(); + } + + @Override + public void redo() { + // we do nothing here, as redo is handled by our command stack. + } + }); + } + + /** + * Returns the object from this context, whose qualified name is provided. + * If none is found, null is returned. This method is relatively expensive + * as the search is not efficient. + */ + /* package */EObject findElementByName(String qualifiedName) { + EObject result = null; + int lastPos = 0; + + // TODO (FH): that is bad code! + final int l = qualifiedName.length(); + OUTER: while (lastPos <= l) { + int sepPos = qualifiedName.indexOf("/", lastPos); + while (sepPos >= 0 && sepPos + 1 < l + && qualifiedName.charAt(sepPos + 1) == '/') { + sepPos = qualifiedName.indexOf("/", sepPos + 2); + } + if (sepPos < 0) { + sepPos = l; + } + + final String namePart = qualifiedName.substring(lastPos, sepPos); + lastPos = sepPos + 1; + + List<EObject> children; + if (result == null) { + children = getTopLevelElements(); + } else { + children = result.eContents(); + } + for (final EObject e : children) { + if (namePart.equals(IModelElementService.INSTANCE + .getModelElementHandler(e).getName(e))) { + result = e; + continue OUTER; + } + } + return null; + } + + return result; + } + + /** Helper method for calling notifyListeners on the given stack. */ + /* package */void performNotifyListeners(CommandStack commandStack) { + try { + Method notifyListenersMethod = BasicCommandStack.class + .getDeclaredMethod("notifyListeners"); + notifyListenersMethod.setAccessible(true); + notifyListenersMethod.invoke(commandStack); + } catch (Exception e) { + LoggingUtils.error(ToolingKernelActivator.getDefault(), + "Notification after save failed!", e); + } + } + +} diff --git a/org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/services/IPersistencyService.java b/org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/services/IPersistencyService.java index 6f90f1efc..923ebf32e 100644 --- a/org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/services/IPersistencyService.java +++ b/org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/services/IPersistencyService.java @@ -17,11 +17,18 @@ $Id$ +--------------------------------------------------------------------------*/ package org.fortiss.tooling.kernel.services; +import java.util.List; + +import org.eclipse.emf.common.command.CommandStack; +import org.eclipse.emf.ecore.EObject; +import org.fortiss.tooling.kernel.interfaces.IStorageProvider; +import org.fortiss.tooling.kernel.interfaces.ITopLevelElementChangeListener; import org.fortiss.tooling.kernel.internal.PersistencyService; /** - * The persistency service provides the access to the different persistency - * options, namely an EMFStore or local XML files within an Eclipse project. + * The persistency service provides the transparent access to the different + * persistency options, namely an EMFStore or local XML files within an Eclipse + * project. * * @author hoelzl * @author $Author$ @@ -33,5 +40,31 @@ public interface IPersistencyService { /** Returns the singleton instance of the service. */ public static final IPersistencyService INSTANCE = new PersistencyService(); - // TODO (FH): define + /** + * Returns the list of top level {@link EObject}s provided by + * {@link IStorageProvider}s. + */ + List<EObject> getTopLevelElements(); + + /** + * Refreshes the list of top-level elements. This method should be called by + * storage providers whenever their list of provided top-level elements + * changes. + */ + void refreshTopLevelElements(IStorageProvider provider); + + /** Adds a top-level element listener. */ + void addTopLevelElementListener(ITopLevelElementChangeListener listener); + + /** Removes a top-level element listener. */ + void removeTopLevelElementListener(ITopLevelElementChangeListener listener); + + /** Returns the top-level element for the given model element. */ + EObject getTopLevelElementFor(EObject modelElement); + + /** Returns the storage provider for the given model element. */ + IStorageProvider getStorageProviderFor(EObject modelElement); + + /** Returns the command stack for the given model element. */ + CommandStack getCommandStack(EObject modelElement); } diff --git a/org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/internal/compose/ProjectCompositor.java b/org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/util/EMFResourceUtils.java similarity index 54% rename from org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/internal/compose/ProjectCompositor.java rename to org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/util/EMFResourceUtils.java index dc8d0923f..b33b2da63 100644 --- a/org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/internal/compose/ProjectCompositor.java +++ b/org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/util/EMFResourceUtils.java @@ -15,36 +15,47 @@ $Id$ | See the License for the specific language governing permissions and | | limitations under the License. | +--------------------------------------------------------------------------*/ -package org.fortiss.tooling.kernel.internal.compose; +package org.fortiss.tooling.kernel.util; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.core.resources.IFile; +import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.EObject; -import org.eclipse.emf.emfstore.common.model.Project; -import org.fortiss.tooling.kernel.interfaces.ICompositionContext; -import org.fortiss.tooling.kernel.interfaces.ICompositor; -import org.fortiss.tooling.kernel.model.IProjectRootElement; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; +import org.eclipse.emf.ecore.xmi.XMLResource; /** - * {@link ICompositor} implementation for the {@link IProjectRootElement}s. + * Utility methods used for Eclipse resource storage. * * @author hoelzlf * @author $Author$ * @version $Rev$ * @levd.rating RED Rev: */ -public final class ProjectCompositor implements ICompositor<Project> { +public final class EMFResourceUtils { + /** + * Stores the given EObject in the Eclipse workspace creating the given + * IFile. + */ + public static void createNewEclipseWorkspaceProject(IFile file, + EObject topLevelElement) throws IOException { - /** {@inheritDoc} */ - @Override - public boolean canCompose(Project container, EObject contained, - ICompositionContext context) { - return contained instanceof IProjectRootElement; + final Resource r = new ResourceSetImpl() + .createResource(URI.createPlatformResourceURI(file + .getFullPath().toString(), true)); + r.getContents().add(topLevelElement); + r.save(buildOptionsMap()); } - /** {@inheritDoc} */ - @Override - public boolean compose(Project container, EObject contained, - ICompositionContext context) { - container.addModelElement(contained); - return true; + /** Build the map of options used for IO of EMF models. */ + public static Map<String, Object> buildOptionsMap() { + Map<String, Object> options = new HashMap<String, Object>(); + options.put(XMLResource.OPTION_ENCODING, "UTF-8"); + options.put(Resource.OPTION_ZIP, false); + return options; } } diff --git a/org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/util/ProjectRootElementUtils.java b/org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/util/ProjectRootElementUtils.java index cf11b33f3..68cb87f73 100644 --- a/org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/util/ProjectRootElementUtils.java +++ b/org.fortiss.tooling.kernel/trunk/src/org/fortiss/tooling/kernel/util/ProjectRootElementUtils.java @@ -17,14 +17,10 @@ $Id$ +--------------------------------------------------------------------------*/ package org.fortiss.tooling.kernel.util; -import org.conqat.ide.commons.ui.logging.LoggingUtils; import org.conqat.lib.commons.reflect.ReflectionUtils; import org.eclipse.emf.ecore.EObject; -import org.eclipse.emf.emfstore.client.model.ProjectSpace; -import org.eclipse.emf.emfstore.client.model.WorkspaceManager; -import org.eclipse.emf.emfstore.common.model.Project; -import org.fortiss.tooling.kernel.ToolingKernelActivator; import org.fortiss.tooling.kernel.model.IProjectRootElement; +import org.fortiss.tooling.kernel.services.IPersistencyService; /** * Utility methods for accessing {@link IProjectRootElement}s. @@ -36,27 +32,14 @@ import org.fortiss.tooling.kernel.model.IProjectRootElement; */ public final class ProjectRootElementUtils { - /** - * Returns the model element's ECP project or <code>null</code> . - */ - public static ProjectSpace getProjectSpace(EObject element) { - try { - return WorkspaceManager.getProjectSpace(element); - } catch (Exception e) { - LoggingUtils.error(ToolingKernelActivator.getDefault(), - "Unable to find ECP project!", e); - } - return null; - } - /** * Returns the instance of a project root element corresponding to the given * class. */ public static <T extends IProjectRootElement> T getRootElement( EObject element, Class<T> clazz) { - Project project = getProjectSpace(element).getProject(); return ReflectionUtils.pickInstanceOf(clazz, - project.getAllModelElements()); + IPersistencyService.INSTANCE.getTopLevelElementFor(element) + .eContents()); } } -- GitLab