| /* |
| * Copyright (c) 2010-2013, 2015 Eike Stepper (Berlin, Germany) 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: |
| * Eike Stepper - initial API and implementation |
| */ |
| package org.eclipse.emf.spi.cdo; |
| |
| import org.eclipse.emf.cdo.CDOObject; |
| import org.eclipse.emf.cdo.common.CDOCommonSession.Options.PassiveUpdateMode; |
| import org.eclipse.emf.cdo.common.branch.CDOBranchPoint; |
| import org.eclipse.emf.cdo.common.commit.CDOChangeSet; |
| import org.eclipse.emf.cdo.common.commit.CDOChangeSetData; |
| import org.eclipse.emf.cdo.common.revision.CDORevisionUtil; |
| import org.eclipse.emf.cdo.common.revision.delta.CDOFeatureDelta; |
| import org.eclipse.emf.cdo.common.util.CDOTimeProvider; |
| import org.eclipse.emf.cdo.session.CDOSessionInvalidationEvent; |
| import org.eclipse.emf.cdo.transaction.CDOCommitContext; |
| import org.eclipse.emf.cdo.transaction.CDOConflictResolver.NonConflictAware; |
| import org.eclipse.emf.cdo.transaction.CDODefaultTransactionHandler; |
| import org.eclipse.emf.cdo.transaction.CDOTransaction; |
| import org.eclipse.emf.cdo.transaction.CDOTransactionHandler; |
| import org.eclipse.emf.cdo.view.CDOAdapterPolicy; |
| |
| /** |
| * If the meaning of this type isn't clear, there really should be more of a description here... |
| * |
| * @author Eike Stepper |
| * @since 4.0 |
| */ |
| public abstract class AbstractChangeSetsConflictResolver extends AbstractConflictResolver implements NonConflictAware |
| { |
| private CDOTransactionHandler handler = new CDODefaultTransactionHandler() |
| { |
| @Override |
| public void attachingObject(CDOTransaction transaction, CDOObject object) |
| { |
| if (getTransaction() == transaction) |
| { |
| transactionAttachingObject(object); |
| } |
| } |
| |
| @Override |
| public void detachingObject(CDOTransaction transaction, CDOObject object) |
| { |
| if (getTransaction() == transaction) |
| { |
| transactionDetachingObject(object); |
| } |
| } |
| |
| @Override |
| public void modifyingObject(CDOTransaction transaction, CDOObject object, CDOFeatureDelta featureDelta) |
| { |
| if (getTransaction() == transaction) |
| { |
| transactionModifyingObject(object, featureDelta); |
| } |
| } |
| |
| @Override |
| public void committingTransaction(CDOTransaction transaction, CDOCommitContext commitContext) |
| { |
| if (getTransaction() == transaction) |
| { |
| transactionCommitting(commitContext); |
| } |
| } |
| |
| @Override |
| public void committedTransaction(CDOTransaction transaction, CDOCommitContext commitContext) |
| { |
| if (getTransaction() == transaction) |
| { |
| transactionCommitted(commitContext); |
| } |
| } |
| |
| @Override |
| public void rolledBackTransaction(CDOTransaction transaction) |
| { |
| // Reset the accumulation only if it rolled back the transaction completely |
| if (getTransaction() == transaction && transaction.getLastSavepoint().getPreviousSavepoint() == null) |
| { |
| transactionRolledBack(); |
| } |
| } |
| }; |
| |
| private CDOChangeSubscriptionAdapter adapter; |
| |
| private RemoteInvalidationEventQueue remoteInvalidationEvents; |
| |
| private boolean ensureRemoteNotifications = true; |
| |
| private long remoteTimeStamp; |
| |
| public AbstractChangeSetsConflictResolver() |
| { |
| } |
| |
| /** |
| * @param ensureRemoteNotifications boolean to disable the use of {@link CDOAdapterPolicy} to ensure remote changes reception for conflict resolution, true by default. Can be disabled to limit network traffic when {@link PassiveUpdateMode} is enabled and in {@link PassiveUpdateMode#CHANGES} or {@link PassiveUpdateMode#ADDITIONS} |
| * @since 4.4 |
| */ |
| public AbstractChangeSetsConflictResolver(boolean ensureRemoteNotifications) |
| { |
| this.ensureRemoteNotifications = ensureRemoteNotifications; |
| } |
| |
| public CDOChangeSetData getLocalChangeSetData() |
| { |
| return getTransaction().getChangeSetData(); |
| } |
| |
| public CDOChangeSet getLocalChangeSet() |
| { |
| CDOChangeSetData changeSetData = getLocalChangeSetData(); |
| return createChangeSet(changeSetData); |
| } |
| |
| public CDOChangeSetData getRemoteChangeSetData() |
| { |
| return remoteInvalidationEvents.poll(); |
| } |
| |
| public CDOChangeSet getRemoteChangeSet() |
| { |
| remoteTimeStamp = CDOBranchPoint.UNSPECIFIED_DATE; |
| |
| CDOChangeSetData changeSetData = getRemoteChangeSetData(); |
| if (changeSetData == null) |
| { |
| return null; |
| } |
| |
| if (changeSetData instanceof CDOTimeProvider) |
| { |
| remoteTimeStamp = ((CDOTimeProvider)changeSetData).getTimeStamp(); |
| } |
| |
| return createChangeSet(changeSetData); |
| } |
| |
| /** |
| * @since 4.4 |
| */ |
| public final long getRemoteTimeStamp() |
| { |
| return remoteTimeStamp; |
| } |
| |
| /** |
| * @since 4.3 |
| */ |
| public void handleNonConflict(long updateTime) |
| { |
| remoteInvalidationEvents.remove(updateTime); |
| } |
| |
| @Override |
| protected void hookTransaction(CDOTransaction transaction) |
| { |
| if (ensureRemoteNotifications) |
| { |
| adapter = new CDOChangeSubscriptionAdapter(getTransaction()); |
| transaction.addTransactionHandler(handler); |
| } |
| |
| remoteInvalidationEvents = new RemoteInvalidationEventQueue(); |
| } |
| |
| @Override |
| protected void unhookTransaction(CDOTransaction transaction) |
| { |
| if (ensureRemoteNotifications) |
| { |
| transaction.removeTransactionHandler(handler); |
| if (!transaction.isClosed()) |
| { |
| adapter.dispose(); |
| } |
| |
| adapter = null; |
| } |
| |
| remoteInvalidationEvents.dispose(); |
| remoteInvalidationEvents = null; |
| } |
| |
| /** |
| * @since 4.4 |
| */ |
| protected void transactionAttachingObject(CDOObject object) |
| { |
| // Do nothing. |
| } |
| |
| /** |
| * @since 4.4 |
| */ |
| protected void transactionDetachingObject(CDOObject object) |
| { |
| // Do nothing. |
| } |
| |
| /** |
| * @since 4.4 |
| */ |
| protected void transactionModifyingObject(CDOObject object, CDOFeatureDelta featureDelta) |
| { |
| adapter.attach(object); |
| } |
| |
| /** |
| * @since 4.4 |
| */ |
| protected void transactionCommitting(CDOCommitContext commitContext) |
| { |
| // Do nothing. |
| } |
| |
| /** |
| * @since 4.4 |
| */ |
| protected void transactionCommitted(CDOCommitContext commitContext) |
| { |
| adapter.reset(); |
| remoteInvalidationEvents.reset(); |
| } |
| |
| /** |
| * @since 4.4 |
| */ |
| protected void transactionRolledBack() |
| { |
| adapter.reset(); |
| remoteInvalidationEvents.reset(); |
| } |
| |
| private CDOChangeSet createChangeSet(CDOChangeSetData changeSetData) |
| { |
| CDOTransaction transaction = getTransaction(); |
| return CDORevisionUtil.createChangeSet(transaction, transaction, changeSetData); |
| } |
| |
| /** |
| * @author Eike Stepper |
| */ |
| private final class RemoteInvalidationEventQueue extends CDOSessionInvalidationEventQueue |
| { |
| public RemoteInvalidationEventQueue() |
| { |
| super(getTransaction().getSession()); |
| } |
| |
| @Override |
| protected void handleEvent(CDOSessionInvalidationEvent event) throws Exception |
| { |
| CDOTransaction transaction = getTransaction(); |
| if (event.getLocalTransaction() == transaction) |
| { |
| // Don't handle own changes |
| return; |
| } |
| |
| if (event.getBranch() != transaction.getBranch()) |
| { |
| // Don't handle changes in other branches |
| return; |
| } |
| |
| super.handleEvent(event); |
| } |
| } |
| } |