blob: 6ea07243f20452cdb9b61df2a4a7689522d710de [file] [log] [blame]
/**
* <copyright>
*
* Copyright (c) 2008-2010 See4sys, BMW Car IT 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
* BMW Car IT - Added/Updated javadoc
*
* </copyright>
*/
package org.eclipse.sphinx.emf.workspace.domain.mapping;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;
import org.eclipse.core.commands.operations.IOperationHistoryListener;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.ListenerList;
import org.eclipse.emf.transaction.ResourceSetListener;
import org.eclipse.emf.transaction.TransactionalEditingDomain;
import org.eclipse.emf.workspace.util.WorkspaceSynchronizer;
import org.eclipse.osgi.util.NLS;
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.metamodel.MetaModelDescriptorRegistry;
import org.eclipse.sphinx.emf.model.IModelDescriptor;
import org.eclipse.sphinx.emf.model.ModelDescriptorRegistry;
import org.eclipse.sphinx.emf.saving.IResourceSaveIndicator;
import org.eclipse.sphinx.emf.util.WorkspaceTransactionUtil;
import org.eclipse.sphinx.emf.workspace.Activator;
import org.eclipse.sphinx.emf.workspace.domain.WorkspaceEditingDomainManager;
import org.eclipse.sphinx.emf.workspace.domain.factory.IExtendedTransactionalEditingDomainFactory;
import org.eclipse.sphinx.emf.workspace.internal.messages.Messages;
import org.eclipse.sphinx.emf.workspace.internal.saving.ResourceSaveIndicator;
import org.eclipse.sphinx.platform.resources.AbstractResourceVisitor;
import org.eclipse.sphinx.platform.util.PlatformLogUtil;
/**
* Abstract implementation of the {@link IWorkspaceEditingDomainMapping} which provides default implementations for some
* of the methods. The class implements the {@link ITransactionalEditingDomainFactoryListener} interface in order to
* stay up-to-date with the current EditingDomains. GlobalListeners are handled this way.
*/
public abstract class AbstractWorkspaceEditingDomainMapping implements IWorkspaceEditingDomainMapping, ITransactionalEditingDomainFactoryListener {
protected static final String EDITING_DOMAIN_ID_PREFIX = "editingDomainFor"; //$NON-NLS-1$
/**
* Returns a default identifier for the specified {@link TransactionalEditingDomain editingDomain}. It is composed
* of the prefix {@value #EDITING_DOMAIN_ID_PREFIX} followed by the identifiers of the specified
* {@link IMetaModelDescriptor}s. Implemented as static method in order to be accessible from test cases.
*
* @param mmDescriptors
* A list of {@linkplain IMetaModelDescriptor}s the given editing domain should be associated to.
* @return An unique identifier for the specified {@link TransactionalEditingDomain editingDomain}.
*/
public static String getDefaultEditingDomainId(Collection<IMetaModelDescriptor> mmDescriptors) {
StringBuilder id = new StringBuilder(EDITING_DOMAIN_ID_PREFIX);
for (IMetaModelDescriptor descriptor : mmDescriptors) {
id.append("_"); //$NON-NLS-1$
id.append(descriptor.getIdentifier());
}
return id.toString();
}
protected Map<TransactionalEditingDomain, IResourceSaveIndicator> resourceSaveIndicators = new WeakHashMap<TransactionalEditingDomain, IResourceSaveIndicator>();
protected Map<TransactionalEditingDomain, WorkspaceSynchronizer> modelWorkspaceSynchronizers = new WeakHashMap<TransactionalEditingDomain, WorkspaceSynchronizer>();
protected ListenerList globalResourceSetListeners = new ListenerList();
protected ListenerList globalOperationHistoryListeners = new ListenerList();
protected AbstractWorkspaceEditingDomainMapping() {
// Register this EditingDomainMapping as listener of EditingDomainFactory
EditingDomainFactoryListenerRegistry.INSTANCE.addListener(MetaModelDescriptorRegistry.ANY_MM, null, this, null);
}
protected TransactionalEditingDomain createEditingDomain(IExtendedTransactionalEditingDomainFactory factory,
Collection<IMetaModelDescriptor> mmDescriptors) {
Assert.isNotNull(factory);
// Create new EditingDomain using appropriate EditingDomainFactory
TransactionalEditingDomain editingDomain = factory.createEditingDomain(mmDescriptors);
String editingDomainId = getEditingDomainId(editingDomain, mmDescriptors);
// Register newly created EdtingDomain in order to enable ResourceSetListeners to be statically registered
// upon it (see
// http://help.eclipse.org/ganymede/index.jsp?topic=/org.eclipse.emf.transaction.doc/references/overview/
// listeners.html
// for details)
TransactionalEditingDomain.Registry.INSTANCE.add(editingDomainId, editingDomain);
return editingDomain;
}
protected IResourceSaveIndicator createResourceSaveIndicator(TransactionalEditingDomain editingDomain) {
return new ResourceSaveIndicator(editingDomain);
}
protected IExtendedTransactionalEditingDomainFactory getEditingDomainFactory(IMetaModelDescriptor mmDescriptor) {
IExtendedTransactionalEditingDomainFactory factory = WorkspaceEditingDomainManager.INSTANCE.getEditingDomainFactory(mmDescriptor);
if (factory == null) {
throw new NullPointerException(NLS.bind(Messages.error_notFound_editingDomainFactory, mmDescriptor.getName()));
}
return factory;
}
/**
* Returns a unique identifier for the specified {@link TransactionalEditingDomain editingDomain}, considering the
* given <code>mmDescriptors</code>parameter. This returned string identifier is used as key in the map of
* {@linkplain TransactionalEditingDomain editingDomain}s owned by this {@linkplain IWorkspaceEditingDomainMapping
* mapping}.
*
* @param editingDomain
* The {@linkplain TransactionalEditingDomain editing domain} for which an identifier must be returned.
* @param mmDescriptors
* A list of {@linkplain IMetaModelDescriptor}s the given editing domain should be associated to.
* @return An unique identifier for the specified {@link TransactionalEditingDomain editingDomain}.
*/
protected String getEditingDomainId(TransactionalEditingDomain editingDomain, Collection<IMetaModelDescriptor> mmDescriptors) {
return getDefaultEditingDomainId(mmDescriptors);
}
@Override
public TransactionalEditingDomain getEditingDomain(IFile file) {
IMetaModelDescriptor descriptor = MetaModelDescriptorRegistry.INSTANCE.getEffectiveDescriptor(file);
if (descriptor != null) {
return getEditingDomain(file.getParent(), descriptor);
}
return null;
}
/**
* {@inheritDoc}
* <p>
* Delegates to the right protected method according to the type of the specified {@link IContainer container}.
*/
@Override
public final List<TransactionalEditingDomain> getEditingDomains(IContainer container) {
if (container instanceof IFolder) {
return getEditingDomains((IFolder) container);
} else if (container instanceof IProject) {
return getEditingDomains((IProject) container);
} else if (container instanceof IWorkspaceRoot) {
return getEditingDomains((IWorkspaceRoot) container);
}
return Collections.emptyList();
}
protected List<TransactionalEditingDomain> getEditingDomains(IFolder folder) {
if (folder != null) {
final List<TransactionalEditingDomain> editingDomains = new ArrayList<TransactionalEditingDomain>();
try {
folder.accept(new AbstractResourceVisitor() {
@Override
public boolean doVisit(IResource resource) throws CoreException {
if (resource instanceof IFile) {
IFile file = (IFile) resource;
if (file.isAccessible()) {
TransactionalEditingDomain editingDomain = getEditingDomain(file);
if (editingDomain != null && !editingDomains.contains(editingDomain)) {
editingDomains.add(editingDomain);
}
}
}
return true;
}
});
} catch (CoreException ex) {
PlatformLogUtil.logAsError(Activator.getPlugin(), ex);
}
return editingDomains;
}
return Collections.emptyList();
}
protected List<TransactionalEditingDomain> getEditingDomains(IProject project) {
List<TransactionalEditingDomain> editingDomains = new ArrayList<TransactionalEditingDomain>();
for (IModelDescriptor modelDescriptor : ModelDescriptorRegistry.INSTANCE.getModels(project)) {
editingDomains.add(modelDescriptor.getEditingDomain());
}
return editingDomains;
}
protected List<TransactionalEditingDomain> getEditingDomains(IWorkspaceRoot workspaceRoot) {
return getEditingDomains();
}
@Override
public void addGlobalResourceSetListener(ResourceSetListener listener) {
for (TransactionalEditingDomain editingDomain : getEditingDomains()) {
editingDomain.addResourceSetListener(listener);
}
globalResourceSetListeners.add(listener);
}
@Override
public void removeGlobalResourceSetListener(ResourceSetListener listener) {
for (TransactionalEditingDomain editingDomain : getEditingDomains()) {
editingDomain.removeResourceSetListener(listener);
}
globalResourceSetListeners.remove(listener);
}
@Override
public void addGlobalOperationHistoryListener(IOperationHistoryListener listener) {
for (TransactionalEditingDomain editingDomain : getEditingDomains()) {
WorkspaceTransactionUtil.getOperationHistory(editingDomain).addOperationHistoryListener(listener);
}
globalOperationHistoryListeners.add(listener);
}
@Override
public void removeGlobalOperationHistoryListener(IOperationHistoryListener listener) {
for (TransactionalEditingDomain editingDomain : getEditingDomains()) {
WorkspaceTransactionUtil.getOperationHistory(editingDomain).removeOperationHistoryListener(listener);
}
globalOperationHistoryListeners.remove(listener);
}
@Override
public IResourceSaveIndicator getResourceSaveIndicator(TransactionalEditingDomain editingDomain) {
return resourceSaveIndicators.get(editingDomain);
}
@Override
public void postCreateEditingDomain(TransactionalEditingDomain editingDomain) {
// Install a WorkspaceSynchronizer with an IResourceSaveIndicator delegate on newly created EditingDomain
IResourceSaveIndicator resourceSaveIndicator = createResourceSaveIndicator(editingDomain);
resourceSaveIndicators.put(editingDomain, resourceSaveIndicator);
WorkspaceSynchronizer workspaceSynchronizer = new WorkspaceSynchronizer(editingDomain, resourceSaveIndicator);
modelWorkspaceSynchronizers.put(editingDomain, workspaceSynchronizer);
// Register global ResourceSetListeners and IOperationHistoryListeners on newly created EditingDomain
for (Object listener : globalResourceSetListeners.getListeners()) {
editingDomain.addResourceSetListener((ResourceSetListener) listener);
}
for (Object listener : globalOperationHistoryListeners.getListeners()) {
WorkspaceTransactionUtil.getOperationHistory(editingDomain).addOperationHistoryListener((IOperationHistoryListener) listener);
}
}
@Override
public void preDisposeEditingDomain(TransactionalEditingDomain editingDomain) {
// Discard WorkspaceSynchronizer and IResourceSaveIndicator associated with EditingDomain to be disposed
resourceSaveIndicators.remove(editingDomain);
WorkspaceSynchronizer workspaceSynchronizer = modelWorkspaceSynchronizers.remove(editingDomain);
if (workspaceSynchronizer != null) {
workspaceSynchronizer.dispose();
}
// Unregister global ResourceSetListeners and IOperationHistoryListeners on EditingDomain to be disposed
for (Object listener : globalResourceSetListeners.getListeners()) {
editingDomain.removeResourceSetListener((ResourceSetListener) listener);
}
for (Object listener : globalOperationHistoryListeners.getListeners()) {
WorkspaceTransactionUtil.getOperationHistory(editingDomain).removeOperationHistoryListener((IOperationHistoryListener) listener);
}
}
@Override
public void dispose() {
// Unregister this EditingDomainMapping as listener of all encountered EditingDomainFactories
EditingDomainFactoryListenerRegistry.INSTANCE.removeListener(this);
}
}