blob: 30303f2e2c14e47fbcf611f282ad917be43fdd12 [file] [log] [blame]
/**
* <copyright>
*
* Copyright (c) 2008-2010 See4sys and others.
* 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:
* See4sys - Initial API and implementation
*
* </copyright>
*/
package org.eclipse.sphinx.emf.workspace.domain.factory;
import java.util.Collection;
import java.util.HashSet;
import org.eclipse.core.commands.operations.IOperationHistory;
import org.eclipse.core.commands.operations.OperationHistoryFactory;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.emf.common.command.Command;
import org.eclipse.emf.common.notify.AdapterFactory;
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.edit.domain.AdapterFactoryEditingDomain;
import org.eclipse.emf.edit.domain.IEditingDomainProvider;
import org.eclipse.emf.edit.provider.ComposedAdapterFactory;
import org.eclipse.emf.transaction.RollbackException;
import org.eclipse.emf.transaction.TransactionalCommandStack;
import org.eclipse.emf.transaction.TransactionalEditingDomain;
import org.eclipse.emf.transaction.impl.AbstractTransactionalCommandStack;
import org.eclipse.emf.transaction.impl.TransactionalEditingDomainImpl;
import org.eclipse.emf.workspace.WorkspaceEditingDomainFactory;
import org.eclipse.emf.workspace.impl.WorkspaceCommandStackImpl;
import org.eclipse.sphinx.emf.domain.factory.EditingDomainFactoryListenerRegistry;
import org.eclipse.sphinx.emf.domain.factory.ITransactionalEditingDomainFactoryListener;
import org.eclipse.sphinx.emf.metamodel.IMetaModelDescriptor;
import org.eclipse.sphinx.emf.resource.ScopingResourceSetImpl;
import org.eclipse.sphinx.emf.util.EcorePlatformUtil;
import org.eclipse.sphinx.emf.util.EcoreResourceUtil;
import org.eclipse.sphinx.emf.util.WorkspaceTransactionUtil;
import org.eclipse.sphinx.platform.IExtendedPlatformConstants;
/**
* Enables adaptable {@linkplain TransactionalEditingDomain Workspace Editing Domain}s to be created which can be
* extended with additional behaviors by clients. Adds an {@linkplain IEditingDomainProvider} adapter on the
* WorkspaceEditingDomain's {@linkplain ResourceSet resource set} so that it can be accessed from {@linkplain EObject}s
* or {@linkplain Resource}s by using {@link AdapterFactoryEditingDomain#getEditingDomainFor(Object)}.<br>
* Supports association and creation of model ResourceFactories based on namespaces of model files being loaded/saved.
* <p>
* <table>
* <tr valign=top>
* <td><b>Note</b>&nbsp;&nbsp;</td>
* <td>This factory implements {@linkplain INotifyingTransactionalEditingDomainFactory} in order to allow performing
* additional treatments when editing domain is going to be disposed.</td>
* </tr>
* </table>
*/
public class ExtendedWorkspaceEditingDomainFactory extends WorkspaceEditingDomainFactory implements IExtendedTransactionalEditingDomainFactory {
/**
* <p align=center>
* <b><em> Model Extended Workspace Editing Domain </em></b>
* </p>
*/
protected class ExtendedWorkspaceEditingDomain extends TransactionalEditingDomainImpl implements IAdaptable {
private Collection<IMetaModelDescriptor> fMetaModelDescriptors = new HashSet<IMetaModelDescriptor>();
public ExtendedWorkspaceEditingDomain(AdapterFactory adapterFactory) {
super(adapterFactory);
}
public ExtendedWorkspaceEditingDomain(AdapterFactory adapterFactory, ResourceSet resourceSet) {
super(adapterFactory, resourceSet);
}
public ExtendedWorkspaceEditingDomain(AdapterFactory adapterFactory, TransactionalCommandStack commandStack) {
super(adapterFactory, commandStack);
}
public ExtendedWorkspaceEditingDomain(AdapterFactory adapterFactory, TransactionalCommandStack commandStack, ResourceSet resourceSet) {
super(adapterFactory, commandStack, resourceSet);
}
/**
* Returns an object which is an instance of the given class associated with this object. Returns
* <code>null</code> if no such object can be found.
* <p>
* This implementation of the method declared by <code>IAdaptable</code> passes the request along to the
* platform's adapter manager; roughly <code>Platform.getAdapterManager().getAdapter(this, adapter)</code>.
* Subclasses may override this method (however, if they do so, they should invoke the method on their
* superclass to ensure that the Platform's adapter manager is consulted).
* </p>
*
* @param adapter
* the class to adapt to
* @return the adapted object or <code>null</code>
* @see IAdaptable#getAdapter(Class)
* @see Platform#getAdapterManager()
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
@Override
public Object getAdapter(Class adapterType) {
Object adapter = super.getAdapter(adapterType);
if (adapter != null) {
return adapter;
}
return Platform.getAdapterManager().getAdapter(this, adapterType);
}
public Collection<IMetaModelDescriptor> getMetaModelDescriptors() {
return fMetaModelDescriptors;
}
@Override
public boolean isReadOnly(Resource resource) {
// FIXME File bug to EMF: NPE is raised when opening a platform:/plugin resource and resolving its URL in an
// editor while workspace is closing
try {
return super.isReadOnly(resource);
} catch (NullPointerException ex) {
return true;
}
}
@SuppressWarnings("deprecation")
@Override
protected boolean isReadOnlyURI(URI uri) {
// FIXME File bug to EMF: NPE is raised when calling this method for an URI that doesn't exist
if (!EcoreResourceUtil.exists(uri)) {
return true;
}
return super.isReadOnlyURI(uri);
}
@Override
public void dispose() {
/*
* !! Important Note !! First unload all resources in order to give a chance to registered
* ResourceSetListeners to act upon as needed. Wait until all of them are done and only then proceed with
* unregistering and disposing editing domain itself.
*/
EcorePlatformUtil.unloadAllResources(this, null);
try {
Job.getJobManager().join(IExtendedPlatformConstants.FAMILY_MODEL_LOADING, null);
} catch (Exception ex) {
// Ignore exception
}
firePreDisposeEditingDomain(fMetaModelDescriptors, this);
super.dispose();
}
@Override
public String toString() {
return getID();
}
}
protected ResourceSet createResourceSet() {
return new ScopingResourceSetImpl();
}
protected IOperationHistory createOperationHistory() {
return OperationHistoryFactory.getOperationHistory();
}
@Override
public TransactionalEditingDomain createEditingDomain(Collection<IMetaModelDescriptor> metaModelDescriptors) {
return createEditingDomain(metaModelDescriptors, createResourceSet(), createOperationHistory());
}
public TransactionalEditingDomain createEditingDomain(Collection<IMetaModelDescriptor> metaModelDescriptors, IOperationHistory history) {
return createEditingDomain(metaModelDescriptors, createResourceSet(), history);
}
@Override
public TransactionalEditingDomain createEditingDomain(Collection<IMetaModelDescriptor> metaModelDescriptors, ResourceSet resourceSet) {
return createEditingDomain(metaModelDescriptors, resourceSet, createOperationHistory());
}
public TransactionalEditingDomain createEditingDomain(Collection<IMetaModelDescriptor> metaModelDescriptors, ResourceSet resourceSet,
IOperationHistory history) {
// Create new WorkspaceCommandStack and TransactionalEditingDomain using given IOperationHistory and ResourceSet
WorkspaceCommandStackImpl stack = new WorkspaceCommandStackImpl(history) {
/*
* Overridden for passing {@link WorkspaceTransactionUtil#getDefaultTransactionOptions()} rather than
* <code>null</code> to {@link WorkspaceCommandStackImpl#execute(Command, Map<?, ?>)}.
*/
@SuppressWarnings("restriction")
@Override
public void execute(Command command) {
try {
execute(command, WorkspaceTransactionUtil.getDefaultTransactionOptions());
} catch (InterruptedException e) {
// just log it. Note that the transaction is already rolled back,
// so handleError() will not find an active transaction
org.eclipse.emf.transaction.internal.Tracing.catching(AbstractTransactionalCommandStack.class, "execute", e); //$NON-NLS-1$
handleError(e);
} catch (RollbackException e) {
// just log it. Note that the transaction is already rolled back,
// so handleError() will not find an active transaction
org.eclipse.emf.transaction.internal.Tracing.catching(AbstractTransactionalCommandStack.class, "execute", e); //$NON-NLS-1$
handleError(e);
}
}
};
TransactionalEditingDomain result = new ExtendedWorkspaceEditingDomain(new ComposedAdapterFactory(
ComposedAdapterFactory.Descriptor.Registry.INSTANCE), stack, resourceSet);
// Do default initialization
mapResourceSet(result);
// Add IEditingDomainProvider adapter which EMF.Edit needs for retrieving EditingDomain from ResourceSet
resourceSet.eAdapters().add(new AdapterFactoryEditingDomain.EditingDomainProvider(result));
// Give the specified meta-model descriptors to the newly created editing domain
((ExtendedWorkspaceEditingDomain) result).getMetaModelDescriptors().addAll(metaModelDescriptors);
firePostCreateEditingDomain(metaModelDescriptors, result);
return result;
}
protected void firePostCreateEditingDomain(Collection<IMetaModelDescriptor> metaModelDescriptors, TransactionalEditingDomain editingDomain) {
for (IMetaModelDescriptor mmd : metaModelDescriptors) {
// Retrieve and notify TEDFactoryListeners contributed to
// 'org.eclipse.sphinx.emf.editingDomainFactoryListeners'
for (ITransactionalEditingDomainFactoryListener listener : EditingDomainFactoryListenerRegistry.INSTANCE.getListeners(mmd)) {
listener.postCreateEditingDomain(editingDomain);
}
}
}
protected void firePreDisposeEditingDomain(Collection<IMetaModelDescriptor> metaModelDescriptors, TransactionalEditingDomain editingDomain) {
for (IMetaModelDescriptor mmd : metaModelDescriptors) {
// Retrieve and notify TEDFactoryListeners contributed to
// 'org.eclipse.sphinx.emf.editingDomainFactoryListeners'
for (ITransactionalEditingDomainFactoryListener listener : EditingDomainFactoryListenerRegistry.INSTANCE.getListeners(mmd)) {
listener.preDisposeEditingDomain(editingDomain);
}
}
}
}