/******************************************************************************* * Copyright (c) 2010, 2011 Obeo. * 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: * Obeo - initial API and implementation *******************************************************************************/ package org.eclipse.mylyn.docs.intent.collab.cdo.adapters; import java.util.Collection; import java.util.HashMap; import java.util.LinkedHashSet; import java.util.Map; import java.util.Set; import org.eclipse.emf.cdo.CDOObject; import org.eclipse.emf.cdo.common.CDOCommonSession.Options.PassiveUpdateMode; import org.eclipse.emf.cdo.common.id.CDOID; import org.eclipse.emf.cdo.common.revision.CDORevisionKey; import org.eclipse.emf.cdo.session.CDOSession; import org.eclipse.emf.cdo.transaction.CDOTransaction; import org.eclipse.emf.cdo.util.CDOURIUtil; import org.eclipse.emf.cdo.util.CommitException; import org.eclipse.emf.cdo.util.ReadOnlyException; import org.eclipse.emf.cdo.view.CDOAdapterPolicy; import org.eclipse.emf.cdo.view.CDOInvalidationPolicy; import org.eclipse.emf.cdo.view.CDOView; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.emf.ecore.resource.Resource; import org.eclipse.emf.ecore.resource.ResourceSet; import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; import org.eclipse.emf.spi.cdo.InternalCDOObject; import org.eclipse.mylyn.docs.intent.collab.handlers.adapters.IntentCommand; import org.eclipse.mylyn.docs.intent.collab.handlers.adapters.RepositoryAdapter; import org.eclipse.mylyn.docs.intent.collab.handlers.adapters.RepositoryStructurer; import org.eclipse.mylyn.docs.intent.collab.handlers.adapters.SaveException; import org.eclipse.mylyn.docs.intent.collab.handlers.notification.Notificator; import org.eclipse.mylyn.docs.intent.collab.repository.Repository; import org.eclipse.net4j.util.event.IListener; /** * Adapter that allows the RepositoryObjectHandler to work with a CDO repository. * * @author <a href="mailto:alex.lagarde@obeo.fr">Alex Lagarde</a> */ public class CDOAdapter implements RepositoryAdapter { /** * The {@link CDOInvalidationPolicy} used by intent (more permissive than default). */ private static final CDOInvalidationPolicy INTENT_CDO_INVALIDATION_POLICY = new CDOInvalidationPolicy() { public void handleInvalidation(CDOObject object, CDORevisionKey key) { if (object instanceof InternalCDOObject) { ((InternalCDOObject)object).cdoInternalSetRevision(null); } } public void handleInvalidObject(CDOObject object) { // We do no throw exception to catch these error silently } }; /** * The session used in this adapter. */ private CDOSession session; /** * The current opened context. */ private CDOView currentContext; /** * Indicates if the current opened context is ReadOnly (false if Read/Write). */ private boolean isReadOnlyContext; /** * Map that associate Notificators to the typeListner created (used to close detach theses listeners). */ private Map<Notificator, Set<IListener>> notificatorToListener; /** * Booleans indicating whether this adapter must allow changeSubscriptionPolicy on its transactions. */ private boolean allowChangeSubscriptionPolicy; /** * The {@link Repository} from witch this adapter has been created. */ private Repository repository; /** * CDOAdapter Constructor. * * @param repository * the {@link Repository} from witch this adapter has been created * @param object * the session to use. */ public CDOAdapter(Repository repository, Object object) { this.notificatorToListener = new HashMap<Notificator, Set<IListener>>(); this.allowChangeSubscriptionPolicy = false; this.repository = repository; setSession(object); } /** * Sets the session. * * @param session * the session */ public void setSession(Object session) { if (session instanceof CDOSession) { this.session = (CDOSession)session; } else { throw new IllegalArgumentException("The session associated to CDOAdapter must be a CDOSession"); } } /** * Returns the session. * * @return the session */ public Object getSession() { return session; } /** * {@inheritDoc} * * @see org.eclipse.mylyn.docs.intent.collab.handlers.adapters.RepositoryAdapter#openSaveContext() */ public Object openSaveContext() { if (this.currentContext == null) { this.currentContext = session.openTransaction(new ResourceSetImpl()); currentContext.options().setInvalidationPolicy(INTENT_CDO_INVALIDATION_POLICY); setChangeSubscriptionPolicy(); this.isReadOnlyContext = false; } return getContext(); } /** * Initialize a changeSubscriptionPolicy on the currentTransaction. */ private void setChangeSubscriptionPolicy() { if (this.allowChangeSubscriptionPolicy) { if (this.currentContext != null) { // The CDOAdapterPolicy.CDO means that we will only be notified by CDOAdapters (see CDO // documentation). this.currentContext.options().addChangeSubscriptionPolicy(CDOAdapterPolicy.ALL); } } } /** * {@inheritDoc} * * @see org.eclipse.mylyn.docs.intent.collab.handlers.adapters.RepositoryAdapter#openReadOnlyContext() */ public Object openReadOnlyContext() { this.isReadOnlyContext = true; if (this.currentContext == null) { this.currentContext = session.openView(); } return null; } /** * {@inheritDoc} * * @see org.eclipse.mylyn.docs.intent.collab.handlers.adapters.RepositoryAdapter#save() */ public void save() throws SaveException, ReadOnlyException { if (isReadOnlyContext) { throw new ReadOnlyException( "Cannot save with a read-only context. The context should have been started with the 'openSaveContext' method."); } try { ((CDOTransaction)this.currentContext).commit(); } catch (CommitException ce) { SaveException e = new SaveException(ce.getMessage()); e.setStackTrace(ce.getStackTrace()); throw e; } catch (ReadOnlyException roe) { SaveException e = new SaveException(roe.getMessage()); e.setStackTrace(roe.getStackTrace()); throw e; } } /** * {@inheritDoc} * * @see org.eclipse.mylyn.docs.intent.collab.handlers.adapters.RepositoryAdapter#undo() */ public void undo() throws ReadOnlyException { if (this.isReadOnlyContext) { throw new ReadOnlyException( "Cannot undo action with a read-only context. The context should have been started with the 'openSaveContext' method."); } if (this.currentContext != null) { ((CDOTransaction)this.currentContext).rollback(); } } /** * {@inheritDoc} * * @see org.eclipse.mylyn.docs.intent.collab.handlers.adapters.RepositoryAdapter#closeContext() */ public void closeContext() { if (this.currentContext != null) { this.currentContext.close(); this.isReadOnlyContext = false; } } /** * {@inheritDoc} * * @see org.eclipse.mylyn.docs.intent.collab.handlers.adapters.RepositoryAdapter#attachSessionListenerForTypes(org.eclipse.mylyn.docs.intent.collab.handlers.notification.Notificator, * java.util.Set) */ public void attachSessionListenerForTypes(Notificator typeNotificator, Set<EStructuralFeature> types) { this.session.options().setPassiveUpdateMode(PassiveUpdateMode.ADDITIONS); CDOTypeListener typeListener = new CDOTypeListener(typeNotificator, types); if (this.notificatorToListener.get(typeNotificator) == null) { this.notificatorToListener.put(typeNotificator, new LinkedHashSet<IListener>()); } this.notificatorToListener.get(typeNotificator).add(typeListener); this.session.addListener(typeListener); } /** * {@inheritDoc} * * @see org.eclipse.mylyn.docs.intent.collab.handlers.adapters.RepositoryAdapter#detachSessionListenerForTypes(org.eclipse.mylyn.docs.intent.collab.handlers.notification.Notificator) */ public void detachSessionListenerForTypes(Notificator typeNotificator) { for (IListener listenerToRemove : this.notificatorToListener.get(typeNotificator)) { this.session.removeListener(listenerToRemove); } this.notificatorToListener.remove(typeNotificator); } /** * {@inheritDoc} * * @see org.eclipse.mylyn.docs.intent.collab.handlers.adapters.RepositoryAdapter#getContext() */ public Object getContext() { return this.currentContext; } /** * {@inheritDoc} * * @see org.eclipse.mylyn.docs.intent.collab.handlers.adapters.RepositoryAdapter#allowChangeSubscriptionPolicy() */ public void allowChangeSubscriptionPolicy() { this.allowChangeSubscriptionPolicy = true; setChangeSubscriptionPolicy(); } /** * {@inheritDoc} * * @see org.eclipse.mylyn.docs.intent.collab.handlers.adapters.RepositoryAdapter#getResource(java.lang.String) */ public Resource getResource(String path) { return this.currentContext.getResource(path); } /** * {@inheritDoc} * * @see org.eclipse.mylyn.docs.intent.collab.handlers.adapters.RepositoryAdapter#getOrCreateResource(java.lang.String) */ public Resource getOrCreateResource(String path) { if (this.isReadOnlyContext) { throw new ReadOnlyException( "Cannot create any resource with a read-only context. The context should have been started with the 'openSaveContext' method."); } if (this.currentContext != null) { return ((CDOTransaction)this.currentContext).getOrCreateResource(path); } return null; } /** * {@inheritDoc} * * @see org.eclipse.mylyn.docs.intent.collab.handlers.adapters.RepositoryAdapter#getElementWithID(java.lang.Object) */ public EObject getElementWithID(Object id) { if (id instanceof CDOID) { return this.currentContext.getObject((CDOID)id); } return null; } /** * {@inheritDoc} * * @see org.eclipse.mylyn.docs.intent.collab.handlers.adapters.RepositoryAdapter#getIDFromElement(org.eclipse.emf.ecore.EObject) */ public Object getIDFromElement(EObject element) { if (element instanceof CDOObject) { return ((CDOObject)element).cdoID(); } return null; } /** * {@inheritDoc} * * @see org.eclipse.mylyn.docs.intent.collab.handlers.adapters.RepositoryAdapter#attachRepositoryStructurer(org.eclipse.mylyn.docs.intent.collab.handlers.adapters.RepositoryStructurer) */ public void attachRepositoryStructurer(RepositoryStructurer structurer) { // TODO if the use cases show this is useful, we should integrate a structurer to CDO Adapters. throw new UnsupportedOperationException("Can't define structurer on aCDO Repository."); } /** * {@inheritDoc} * * @see org.eclipse.mylyn.docs.intent.collab.handlers.adapters.RepositoryAdapter#setSendSessionWarningBeforeSaving(boolean) */ public void setSendSessionWarningBeforeSaving(boolean notifySessionBeforeSaving) { // Such a warning mechanism is already implemented between CDOResources and CDOSessions // That's why we don't have anything to do here. } /** * {@inheritDoc} * * @see org.eclipse.mylyn.docs.intent.collab.handlers.adapters.RepositoryAdapter#setSendSessionWarningBeforeSaving(java.util.Collection) */ public void setSendSessionWarningBeforeSaving(Collection<String> resourcesToIgnorePaths) { // TODO Auto-generated method stub } /** * {@inheritDoc} * * @see org.eclipse.mylyn.docs.intent.collab.handlers.adapters.RepositoryAdapter#reload(org.eclipse.emf.ecore.EObject) */ public EObject reload(EObject elementToReload) { if (elementToReload instanceof CDOObject) { ((CDOObject)elementToReload).cdoReload(); return elementToReload; } throw new IllegalArgumentException("Cannot reload an element which is not a CDOObject"); } /** * {@inheritDoc} * * @see org.eclipse.mylyn.docs.intent.collab.handlers.adapters.RepositoryAdapter#getResourcePath(org.eclipse.emf.common.util.URI) */ public String getResourcePath(URI resourceURI) { return CDOURIUtil.extractResourcePath(resourceURI); } /** * {@inheritDoc} * * @see org.eclipse.mylyn.docs.intent.collab.handlers.adapters.RepositoryAdapter#execute(org.eclipse.mylyn.docs.intent.collab.handlers.adapters.IntentCommand) */ public void execute(IntentCommand command) { command.execute(); } /** * {@inheritDoc} * * @see org.eclipse.mylyn.docs.intent.collab.handlers.adapters.RepositoryAdapter#getRepository() */ public Repository getRepository() { return this.repository; } /** * {@inheritDoc} * * @see org.eclipse.mylyn.docs.intent.collab.handlers.adapters.RepositoryAdapter#getResourceSet() */ public ResourceSet getResourceSet() { if (this.currentContext != null) { return this.currentContext.getResourceSet(); } return null; } }