| /* |
| * Copyright (c) 2009-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 |
| * Simon McDuff - maintenance |
| * Victor Roldan Betancort - maintenance |
| */ |
| package org.eclipse.emf.internal.cdo.view; |
| |
| import org.eclipse.emf.cdo.CDONotification; |
| import org.eclipse.emf.cdo.CDOObject; |
| import org.eclipse.emf.cdo.CDOState; |
| import org.eclipse.emf.cdo.common.CDOCommonView; |
| import org.eclipse.emf.cdo.common.branch.CDOBranch; |
| import org.eclipse.emf.cdo.common.branch.CDOBranchPoint; |
| import org.eclipse.emf.cdo.common.id.CDOID; |
| import org.eclipse.emf.cdo.common.id.CDOIDUtil; |
| import org.eclipse.emf.cdo.common.lock.CDOLockChangeInfo; |
| import org.eclipse.emf.cdo.common.lock.CDOLockChangeInfo.Operation; |
| import org.eclipse.emf.cdo.common.lock.CDOLockOwner; |
| import org.eclipse.emf.cdo.common.lock.CDOLockState; |
| import org.eclipse.emf.cdo.common.lock.CDOLockUtil; |
| import org.eclipse.emf.cdo.common.revision.CDOIDAndBranch; |
| import org.eclipse.emf.cdo.common.revision.CDOIDAndVersion; |
| import org.eclipse.emf.cdo.common.revision.CDORevision; |
| import org.eclipse.emf.cdo.common.revision.CDORevisionKey; |
| import org.eclipse.emf.cdo.common.revision.CDORevisionManager; |
| import org.eclipse.emf.cdo.common.revision.CDORevisionsLoadedEvent; |
| import org.eclipse.emf.cdo.common.revision.delta.CDORevisionDelta; |
| import org.eclipse.emf.cdo.common.util.CDOCommonUtil; |
| import org.eclipse.emf.cdo.common.util.CDOException; |
| import org.eclipse.emf.cdo.spi.common.branch.CDOBranchUtil; |
| import org.eclipse.emf.cdo.spi.common.lock.InternalCDOLockState; |
| import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision; |
| import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevisionDelta; |
| import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevisionManager; |
| import org.eclipse.emf.cdo.transaction.CDOCommitContext; |
| import org.eclipse.emf.cdo.transaction.CDOTransaction; |
| import org.eclipse.emf.cdo.util.CDOUtil; |
| import org.eclipse.emf.cdo.util.LockTimeoutException; |
| import org.eclipse.emf.cdo.util.ReadOnlyException; |
| import org.eclipse.emf.cdo.util.StaleRevisionLockException; |
| import org.eclipse.emf.cdo.view.CDOAdapterPolicy; |
| import org.eclipse.emf.cdo.view.CDOFeatureAnalyzer; |
| import org.eclipse.emf.cdo.view.CDOInvalidationPolicy; |
| import org.eclipse.emf.cdo.view.CDORevisionPrefetchingPolicy; |
| import org.eclipse.emf.cdo.view.CDOStaleReferencePolicy; |
| import org.eclipse.emf.cdo.view.CDOView; |
| import org.eclipse.emf.cdo.view.CDOViewDurabilityChangedEvent; |
| import org.eclipse.emf.cdo.view.CDOViewInvalidationEvent; |
| import org.eclipse.emf.cdo.view.CDOViewLocksChangedEvent; |
| |
| import org.eclipse.emf.internal.cdo.bundle.OM; |
| import org.eclipse.emf.internal.cdo.messages.Messages; |
| import org.eclipse.emf.internal.cdo.object.CDODeltaNotificationImpl; |
| import org.eclipse.emf.internal.cdo.object.CDOInvalidationNotificationImpl; |
| import org.eclipse.emf.internal.cdo.object.CDONotificationBuilder; |
| import org.eclipse.emf.internal.cdo.session.SessionUtil; |
| import org.eclipse.emf.internal.cdo.util.DefaultLocksChangedEvent; |
| |
| import org.eclipse.net4j.util.ObjectUtil; |
| import org.eclipse.net4j.util.WrappedException; |
| import org.eclipse.net4j.util.collection.HashBag; |
| import org.eclipse.net4j.util.collection.Pair; |
| import org.eclipse.net4j.util.concurrent.ConcurrencyUtil; |
| import org.eclipse.net4j.util.concurrent.ExecutorWorkSerializer; |
| import org.eclipse.net4j.util.concurrent.IExecutorServiceProvider; |
| import org.eclipse.net4j.util.concurrent.IRWLockManager.LockType; |
| import org.eclipse.net4j.util.concurrent.IWorkSerializer; |
| import org.eclipse.net4j.util.event.IEvent; |
| import org.eclipse.net4j.util.event.IListener; |
| import org.eclipse.net4j.util.event.Notifier; |
| import org.eclipse.net4j.util.event.ThrowableEvent; |
| import org.eclipse.net4j.util.lifecycle.LifecycleException; |
| import org.eclipse.net4j.util.lifecycle.LifecycleUtil; |
| import org.eclipse.net4j.util.om.log.OMLogger; |
| import org.eclipse.net4j.util.om.monitor.EclipseMonitor; |
| import org.eclipse.net4j.util.om.monitor.OMMonitor; |
| import org.eclipse.net4j.util.om.trace.ContextTracer; |
| import org.eclipse.net4j.util.options.IOptionsEvent; |
| import org.eclipse.net4j.util.options.OptionsEvent; |
| import org.eclipse.net4j.util.ref.ReferenceType; |
| import org.eclipse.net4j.util.ref.ReferenceValueMap; |
| |
| import org.eclipse.emf.common.notify.Adapter; |
| import org.eclipse.emf.common.notify.NotificationChain; |
| import org.eclipse.emf.ecore.EObject; |
| import org.eclipse.emf.ecore.InternalEObject; |
| import org.eclipse.emf.spi.cdo.CDOSessionProtocol; |
| import org.eclipse.emf.spi.cdo.CDOSessionProtocol.LockObjectsResult; |
| import org.eclipse.emf.spi.cdo.CDOSessionProtocol.UnlockObjectsResult; |
| import org.eclipse.emf.spi.cdo.FSMUtil; |
| import org.eclipse.emf.spi.cdo.InternalCDOObject; |
| import org.eclipse.emf.spi.cdo.InternalCDOSession; |
| import org.eclipse.emf.spi.cdo.InternalCDOTransaction; |
| import org.eclipse.emf.spi.cdo.InternalCDOView; |
| import org.eclipse.emf.spi.cdo.InternalCDOViewSet; |
| |
| import org.eclipse.core.runtime.IProgressMonitor; |
| |
| import java.text.MessageFormat; |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.LinkedList; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.WeakHashMap; |
| import java.util.concurrent.ExecutorService; |
| |
| /** |
| * @author Eike Stepper |
| */ |
| public class CDOViewImpl extends AbstractCDOView implements IExecutorServiceProvider |
| { |
| private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG_VIEW, CDOViewImpl.class); |
| |
| private int viewID; |
| |
| private InternalCDOSession session; |
| |
| private String durableLockingID; |
| |
| private ChangeSubscriptionManager changeSubscriptionManager = new ChangeSubscriptionManager(); |
| |
| private AdapterManager adapterManager = new AdapterManager(); |
| |
| private OptionsImpl options; |
| |
| private long lastUpdateTime; |
| |
| private CDOLockOwner lockOwner; |
| |
| private Map<CDOObject, CDOLockState> lockStates = new WeakHashMap<CDOObject, CDOLockState>(); |
| |
| private ExecutorWorkSerializer invalidationRunner = createInvalidationRunner(); |
| |
| private volatile boolean invalidationRunnerActive; |
| |
| /** |
| * @since 2.0 |
| */ |
| public CDOViewImpl(CDOBranch branch, long timeStamp) |
| { |
| super(branch.getPoint(timeStamp)); |
| options = createOptions(); |
| } |
| |
| public CDOViewImpl(String durableLockingID) |
| { |
| this.durableLockingID = durableLockingID; |
| options = createOptions(); |
| } |
| |
| /** |
| * @since 2.0 |
| */ |
| public OptionsImpl options() |
| { |
| return options; |
| } |
| |
| public int getViewID() |
| { |
| return viewID; |
| } |
| |
| /** |
| * @since 2.0 |
| */ |
| public void setViewID(int viewId) |
| { |
| viewID = viewId; |
| } |
| |
| public ExecutorService getExecutorService() |
| { |
| return ConcurrencyUtil.getExecutorService(session); |
| } |
| |
| /** |
| * @since 2.0 |
| */ |
| public InternalCDOSession getSession() |
| { |
| return session; |
| } |
| |
| /** |
| * @since 2.0 |
| */ |
| public void setSession(InternalCDOSession session) |
| { |
| this.session = session; |
| } |
| |
| public int getSessionID() |
| { |
| return session.getSessionID(); |
| } |
| |
| public synchronized boolean setBranchPoint(CDOBranchPoint branchPoint, IProgressMonitor progressMonitor) |
| { |
| checkActive(); |
| branchPoint = adjustBranchPoint(branchPoint); |
| |
| long timeStamp = branchPoint.getTimeStamp(); |
| long creationTimeStamp = session.getRepositoryInfo().getCreationTime(); |
| if (timeStamp != UNSPECIFIED_DATE && timeStamp < creationTimeStamp) |
| { |
| throw new IllegalArgumentException(MessageFormat.format("timeStamp ({0}) < repository creation time ({1})", //$NON-NLS-1$ |
| CDOCommonUtil.formatTimeStamp(timeStamp), CDOCommonUtil.formatTimeStamp(creationTimeStamp))); |
| } |
| |
| CDOBranchPoint oldBranchPoint = CDOBranchUtil.copyBranchPoint(getBranchPoint()); |
| if (branchPoint.equals(oldBranchPoint)) |
| { |
| return false; |
| } |
| |
| if (TRACER.isEnabled()) |
| { |
| TRACER.format("Changing view target to {0}", branchPoint); //$NON-NLS-1$ |
| } |
| |
| Map<CDOID, InternalCDORevision> oldRevisions = CDOIDUtil.createMap(); |
| List<CDORevisionKey> allChangedObjects = new ArrayList<CDORevisionKey>(); |
| List<CDOIDAndVersion> allDetachedObjects = new ArrayList<CDOIDAndVersion>(); |
| |
| List<InternalCDOObject> invalidObjects = getInvalidObjects(branchPoint); |
| for (InternalCDOObject object : invalidObjects) |
| { |
| InternalCDORevision revision = object.cdoRevision(); |
| if (revision != null) |
| { |
| oldRevisions.put(object.cdoID(), revision); |
| } |
| } |
| |
| CDOSessionProtocol sessionProtocol = session.getSessionProtocol(); |
| OMMonitor monitor = progressMonitor != null ? new EclipseMonitor(progressMonitor) : null; |
| sessionProtocol.switchTarget(viewID, branchPoint, invalidObjects, allChangedObjects, allDetachedObjects, monitor); |
| |
| basicSetBranchPoint(branchPoint); |
| CDOBranch branch = branchPoint.getBranch(); |
| |
| try |
| { |
| CDOStateMachine.SWITCHING_TARGET.set(Boolean.TRUE); |
| doInvalidate(branch, UNSPECIFIED_DATE, allChangedObjects, allDetachedObjects, oldRevisions, true); |
| } |
| finally |
| { |
| CDOStateMachine.SWITCHING_TARGET.remove(); |
| } |
| |
| IListener[] listeners = getListeners(); |
| if (listeners != null) |
| { |
| fireViewTargetChangedEvent(oldBranchPoint, listeners); |
| } |
| |
| return true; |
| } |
| |
| private List<InternalCDOObject> getInvalidObjects(CDOBranchPoint branchPoint) |
| { |
| List<InternalCDOObject> result = new ArrayList<InternalCDOObject>(); |
| for (InternalCDOObject object : getModifiableObjects().values()) |
| { |
| CDORevision revision = object.cdoRevision(false); |
| if (revision == null || !revision.isValid(branchPoint)) |
| { |
| result.add(object); |
| } |
| } |
| |
| return result; |
| } |
| |
| private Set<? extends CDOObject> getSet(Collection<? extends CDOObject> objects) |
| { |
| if (objects instanceof Set) |
| { |
| return (Set<? extends CDOObject>)objects; |
| } |
| |
| return new HashSet<CDOObject>(objects); |
| } |
| |
| /** |
| * @throws InterruptedException |
| * @since 2.0 |
| */ |
| public synchronized void lockObjects(Collection<? extends CDOObject> objects, LockType lockType, long timeout) |
| throws InterruptedException |
| { |
| lockObjects(objects, lockType, timeout, false); |
| } |
| |
| public synchronized void lockObjects(Collection<? extends CDOObject> objects, LockType lockType, long timeout, |
| boolean recursive) throws InterruptedException |
| { |
| checkActive(); |
| checkState(getTimeStamp() == UNSPECIFIED_DATE, "Locking not supported for historial views"); |
| |
| Set<? extends CDOObject> uniqueObjects = getSet(objects); |
| int size = uniqueObjects.size(); |
| |
| List<CDORevisionKey> revisionKeys = new ArrayList<CDORevisionKey>(size); |
| List<CDOLockState> locksOnNewObjects = new ArrayList<CDOLockState>(size); |
| |
| for (CDOObject object : uniqueObjects) |
| { |
| if (FSMUtil.isNew(object)) |
| { |
| CDOLockState lockState = createUpdatedLockStateForNewObject(object, lockType, true); |
| locksOnNewObjects.add(lockState); |
| } |
| else |
| { |
| InternalCDORevision revision = getRevision(object); |
| if (revision != null) |
| { |
| revisionKeys.add(revision); |
| } |
| } |
| } |
| |
| LockObjectsResult result = null; |
| if (!revisionKeys.isEmpty()) |
| { |
| CDOSessionProtocol sessionProtocol = session.getSessionProtocol(); |
| result = sessionProtocol.lockObjects2(revisionKeys, viewID, getBranch(), lockType, recursive, timeout); |
| |
| if (!result.isSuccessful()) |
| { |
| if (result.isTimedOut()) |
| { |
| throw new LockTimeoutException(); |
| } |
| |
| CDORevisionKey[] staleRevisions = result.getStaleRevisions(); |
| if (staleRevisions != null) |
| { |
| throw new StaleRevisionLockException(staleRevisions); |
| } |
| |
| throw new AssertionError("Unexpected lock result state"); |
| } |
| |
| if (result.isWaitForUpdate()) |
| { |
| if (!session.options().isPassiveUpdateEnabled()) |
| { |
| throw new AssertionError( |
| "Lock result requires client to wait, but client does not have passiveUpdates enabled"); |
| } |
| |
| long requiredTimestamp = result.getRequiredTimestamp(); |
| if (!waitForUpdate(requiredTimestamp, 10000L)) |
| { |
| throw new AssertionError("Lock result requires client to wait for commit " + requiredTimestamp |
| + ", but client did not receive invalidations after " + lastUpdateTime); |
| } |
| |
| InternalCDOSession session = this.session; |
| InternalCDORevisionManager revisionManager = session.getRevisionManager(); |
| |
| for (CDORevisionKey requiredKey : result.getStaleRevisions()) |
| { |
| CDOID id = requiredKey.getID(); |
| InternalCDOObject object = getObject(id); |
| |
| CDORevision revision = object.cdoRevision(true); |
| if (!requiredKey.equals(revision)) |
| { |
| InternalCDORevision requiredRevision = revisionManager.getRevisionByVersion(id, requiredKey, |
| CDORevision.UNCHUNKED, true); |
| InternalCDORevisionDelta revisionDelta = requiredRevision.compare(revision); |
| CDOStateMachine.INSTANCE.invalidate(object, revisionDelta); |
| } |
| } |
| } |
| } |
| |
| CDOLockState[] locksOnNewObjectsArray = locksOnNewObjects.toArray(new CDOLockState[locksOnNewObjects.size()]); |
| updateLockStates(locksOnNewObjectsArray); |
| |
| if (result != null) |
| { |
| updateAndNotifyLockStates(Operation.LOCK, lockType, result.getTimestamp(), result.getNewLockStates()); |
| } |
| } |
| |
| protected void updateAndNotifyLockStates(Operation op, LockType type, long timestamp, CDOLockState[] newLockStates) |
| { |
| updateLockStates(newLockStates); |
| notifyOtherViewsAboutLockChanges(op, type, timestamp, newLockStates); |
| } |
| |
| /** |
| * Updates the lock states of objects held in this view |
| */ |
| protected void updateLockStates(CDOLockState[] newLockStates) |
| { |
| for (CDOLockState lockState : newLockStates) |
| { |
| Object lockedObject = lockState.getLockedObject(); |
| CDOID id; |
| |
| if (lockedObject instanceof CDOID) |
| { |
| id = (CDOID)lockedObject; |
| } |
| else if (lockedObject instanceof CDOIDAndBranch) |
| { |
| id = ((CDOIDAndBranch)lockedObject).getID(); |
| } |
| else if (lockedObject instanceof EObject) |
| { |
| CDOObject newObj = CDOUtil.getCDOObject((EObject)lockedObject); |
| id = newObj.cdoID(); |
| } |
| else |
| { |
| throw new IllegalStateException("Unexpected: " + lockedObject.getClass().getSimpleName()); |
| } |
| |
| InternalCDOObject object = getObject(id, false); |
| if (object != null) |
| { |
| InternalCDOLockState existingLockState = (InternalCDOLockState)lockStates.get(object); |
| if (existingLockState != null) |
| { |
| Object lockTarget = getLockTarget(object); |
| existingLockState.updateFrom(lockTarget, lockState); |
| } |
| else |
| { |
| lockStates.put(object, lockState); |
| } |
| } |
| } |
| } |
| |
| /** |
| * Notifies other views of lock changes performed in this view |
| */ |
| private void notifyOtherViewsAboutLockChanges(Operation op, LockType type, long timestamp, CDOLockState[] lockStates) |
| { |
| if (lockStates.length > 0) |
| { |
| CDOLockChangeInfo lockChangeInfo = makeLockChangeInfo(op, type, timestamp, lockStates); |
| session.handleLockNotification(lockChangeInfo, this); |
| |
| if (isActive()) |
| { |
| fireLocksChangedEvent(this, lockChangeInfo); |
| } |
| } |
| } |
| |
| private CDOLockChangeInfo makeLockChangeInfo(Operation op, LockType type, long timestamp, |
| CDOLockState[] newLockStates) |
| { |
| return CDOLockUtil.createLockChangeInfo(timestamp, this, getBranch(), op, type, newLockStates); |
| } |
| |
| public void handleLockNotification(InternalCDOView sender, CDOLockChangeInfo lockChangeInfo) |
| { |
| CDOLockChangeInfo event = null; |
| |
| try |
| { |
| synchronized (lockStates) |
| { |
| if (!options().isLockNotificationEnabled()) |
| { |
| return; |
| } |
| |
| if (lockChangeInfo.isInvalidateAll()) |
| { |
| lockStates.clear(); |
| event = lockChangeInfo; |
| return; |
| } |
| |
| // If lockChangeInfo pertains to a different view, do nothing. |
| CDOBranch lockChangeBranch = lockChangeInfo.getBranch(); |
| CDOBranch viewBranch = getBranch(); |
| if (lockChangeBranch != viewBranch) |
| { |
| return; |
| } |
| |
| if (lockChangeInfo.getLockOwner().equals(lockOwner)) |
| { |
| return; |
| } |
| |
| // TODO (CD) I know it is Eike's desideratum that this be done asynchronously.. but beware, |
| // this will require the tests to be fixed to listen for the view events instead of the |
| // session events. |
| updateLockStates(lockChangeInfo.getLockStates()); |
| event = lockChangeInfo; |
| } |
| } |
| finally |
| { |
| if (event != null) |
| { |
| fireLocksChangedEvent(sender, event); |
| } |
| } |
| } |
| |
| private void fireLocksChangedEvent(InternalCDOView sender, CDOLockChangeInfo lockChangeInfo) |
| { |
| IListener[] listeners = getListeners(); |
| if (listeners != null) |
| { |
| fireEvent(new LocksChangedEvent(sender, lockChangeInfo), listeners); |
| } |
| } |
| |
| protected InternalCDORevision getRevision(CDOObject object) |
| { |
| if (object.cdoState() == CDOState.NEW) |
| { |
| return null; |
| } |
| |
| InternalCDORevision revision = (InternalCDORevision)object.cdoRevision(); |
| if (revision == null) |
| { |
| revision = CDOStateMachine.INSTANCE.read((InternalCDOObject)object); |
| } |
| |
| return revision; |
| } |
| |
| /** |
| * @since 2.0 |
| */ |
| public synchronized void unlockObjects(Collection<? extends CDOObject> objects, LockType lockType) |
| { |
| unlockObjects(objects, lockType, false); |
| } |
| |
| /** |
| * Note: This may get called with objects == null, and lockType == null, which is a request to remove all locks on all |
| * objects in this view. |
| */ |
| public synchronized void unlockObjects(Collection<? extends CDOObject> objects, LockType lockType, boolean recursive) |
| { |
| checkActive(); |
| |
| List<CDOID> objectIDs = null; |
| List<CDOLockState> locksOnNewObjects = new LinkedList<CDOLockState>(); |
| |
| if (objects != null) |
| { |
| objectIDs = new ArrayList<CDOID>(); |
| |
| for (CDOObject object : getSet(objects)) |
| { |
| if (FSMUtil.isNew(object)) |
| { |
| CDOLockState lockState = createUpdatedLockStateForNewObject(object, lockType, false); |
| locksOnNewObjects.add(lockState); |
| } |
| else |
| { |
| objectIDs.add(object.cdoID()); |
| } |
| } |
| } |
| else |
| { |
| locksOnNewObjects.addAll(createUnlockedLockStatesForAllNewObjects()); |
| } |
| |
| UnlockObjectsResult result = null; |
| if (objectIDs == null || !objectIDs.isEmpty()) |
| { |
| CDOSessionProtocol sessionProtocol = session.getSessionProtocol(); |
| result = sessionProtocol.unlockObjects2(this, objectIDs, lockType, recursive); |
| } |
| |
| CDOLockState[] locksOnNewObjectsArray = locksOnNewObjects.toArray(new CDOLockState[locksOnNewObjects.size()]); |
| updateLockStates(locksOnNewObjectsArray); |
| |
| if (result != null) |
| { |
| updateAndNotifyLockStates(Operation.UNLOCK, lockType, result.getTimestamp(), result.getNewLockStates()); |
| } |
| } |
| |
| protected InternalCDOLockState createUpdatedLockStateForNewObject(CDOObject object, LockType lockType, boolean on) |
| { |
| throw new ReadOnlyException(); |
| } |
| |
| protected Collection<CDOLockState> createUnlockedLockStatesForAllNewObjects() |
| { |
| return Collections.emptyList(); |
| } |
| |
| /** |
| * @since 2.0 |
| */ |
| public synchronized void unlockObjects() |
| { |
| unlockObjects(null, null); |
| } |
| |
| /** |
| * @since 2.0 |
| */ |
| public synchronized boolean isObjectLocked(CDOObject object, LockType lockType, boolean byOthers) |
| { |
| checkActive(); |
| CDOSessionProtocol sessionProtocol = session.getSessionProtocol(); |
| return sessionProtocol.isObjectLocked(this, object, lockType, byOthers); |
| } |
| |
| public boolean isDurableView() |
| { |
| return durableLockingID != null; |
| } |
| |
| public synchronized String getDurableLockingID() |
| { |
| return durableLockingID; |
| } |
| |
| @Deprecated |
| public String enableDurableLocking(boolean enable) |
| { |
| if (enable) |
| { |
| return enableDurableLocking(); |
| } |
| |
| disableDurableLocking(false); |
| return null; |
| } |
| |
| public String enableDurableLocking() |
| { |
| final String oldID = durableLockingID; |
| |
| try |
| { |
| synchronized (this) |
| { |
| CDOSessionProtocol sessionProtocol = session.getSessionProtocol(); |
| if (durableLockingID == null) |
| { |
| durableLockingID = sessionProtocol.changeLockArea(this, true); |
| } |
| |
| return durableLockingID; |
| } |
| } |
| finally |
| { |
| fireDurabilityChangedEvent(oldID); |
| } |
| } |
| |
| public void disableDurableLocking(boolean releaseLocks) |
| { |
| final String oldID = durableLockingID; |
| |
| try |
| { |
| synchronized (this) |
| { |
| CDOSessionProtocol sessionProtocol = session.getSessionProtocol(); |
| if (durableLockingID != null) |
| { |
| sessionProtocol.changeLockArea(this, false); |
| durableLockingID = null; |
| |
| if (releaseLocks) |
| { |
| unlockObjects(); |
| } |
| } |
| } |
| } |
| finally |
| { |
| fireDurabilityChangedEvent(oldID); |
| } |
| } |
| |
| private void fireDurabilityChangedEvent(final String oldID) |
| { |
| if (!ObjectUtil.equals(oldID, durableLockingID)) |
| { |
| fireEvent(new CDOViewDurabilityChangedEvent() |
| { |
| public CDOView getSource() |
| { |
| return CDOViewImpl.this; |
| } |
| |
| public String getOldDurableLockingID() |
| { |
| return oldID; |
| } |
| |
| public String getNewDurableLockingID() |
| { |
| return durableLockingID; |
| } |
| }); |
| } |
| } |
| |
| /** |
| * @since 2.0 |
| */ |
| @Deprecated |
| public synchronized CDOFeatureAnalyzer getFeatureAnalyzer() |
| { |
| return options().getFeatureAnalyzer(); |
| } |
| |
| /** |
| * @since 2.0 |
| */ |
| @Deprecated |
| public synchronized void setFeatureAnalyzer(CDOFeatureAnalyzer featureAnalyzer) |
| { |
| options.setFeatureAnalyzer(featureAnalyzer); |
| } |
| |
| /** |
| * @since 2.0 |
| */ |
| public InternalCDOTransaction toTransaction() |
| { |
| checkActive(); |
| if (this instanceof InternalCDOTransaction) |
| { |
| return (InternalCDOTransaction)this; |
| } |
| |
| throw new ReadOnlyException(MessageFormat.format(Messages.getString("CDOViewImpl.0"), this)); //$NON-NLS-1$ |
| } |
| |
| public synchronized InternalCDORevision getRevision(CDOID id, boolean loadOnDemand) |
| { |
| InternalCDORevisionManager revisionManager = session.getRevisionManager(); |
| int initialChunkSize = session.options().getCollectionLoadingPolicy().getInitialChunkSize(); |
| CDOBranchPoint branchPoint = getBranchPointForID(id); |
| return revisionManager.getRevision(id, branchPoint, initialChunkSize, CDORevision.DEPTH_NONE, loadOnDemand); |
| } |
| |
| @Override |
| public synchronized void remapObject(CDOID oldID) |
| { |
| InternalCDOObject object = getObject(oldID, false); |
| InternalCDOLockState oldLockState = (InternalCDOLockState)lockStates.get(object); |
| if (oldLockState != null) |
| { |
| oldLockState.updateFrom(getLockTarget(object), oldLockState); |
| } |
| super.remapObject(oldID); |
| } |
| |
| @Override |
| public synchronized InternalCDOObject removeObject(CDOID id) |
| { |
| InternalCDOObject removedObject = super.removeObject(id); |
| removeLockState(removedObject); |
| return removedObject; |
| } |
| |
| public synchronized CDOLockState[] getLockStates(Collection<CDOID> ids) |
| { |
| return getLockStates(ids, true); |
| } |
| |
| protected synchronized CDOLockState[] getLockStates(Collection<CDOID> ids, boolean loadOnDemand) |
| { |
| List<CDOID> missing = new LinkedList<CDOID>(); |
| List<CDOLockState> lockStates = new LinkedList<CDOLockState>(); |
| List<CDOLockState> locksOnNewObjects = new ArrayList<CDOLockState>(ids.size()); |
| |
| for (CDOID id : ids) |
| { |
| CDOLockState lockState = null; |
| InternalCDOObject obj = getObject(id, false); |
| if (obj != null) |
| { |
| lockState = this.lockStates.get(obj); |
| } |
| |
| if (lockState != null) |
| { |
| lockStates.add(lockState); |
| } |
| else if (loadOnDemand && obj != null && FSMUtil.isNew(obj)) |
| { |
| CDOLockState defaultLockState = CDOLockUtil.createLockState(getLockTarget(obj)); |
| locksOnNewObjects.add(defaultLockState); |
| lockStates.add(defaultLockState); |
| } |
| else |
| { |
| missing.add(id); |
| } |
| } |
| |
| if (loadOnDemand && (missing.size() > 0 || ids.isEmpty())) |
| { |
| CDOSessionProtocol sessionProtocol = session.getSessionProtocol(); |
| CDOLockState[] loadedLockStates = sessionProtocol.getLockStates(viewID, missing, CDOLockState.DEPTH_NONE); |
| List<CDOLockState> newLockStateForCache = new ArrayList<CDOLockState>(loadedLockStates.length + missing.size()); |
| for (CDOLockState loadedLockState : loadedLockStates) |
| { |
| lockStates.add(loadedLockState); |
| newLockStateForCache.add(loadedLockState); |
| |
| CDOID cdoID = CDOIDUtil.getCDOID(loadedLockState.getLockedObject()); |
| if (cdoID != null) |
| { |
| missing.remove(cdoID); |
| } |
| } |
| |
| for (CDOID missingLockStateForCDOID : missing) |
| { |
| Object target; |
| |
| InternalCDOObject obj = getObject(missingLockStateForCDOID, false); |
| if (obj != null) |
| { |
| target = getLockTarget(obj); |
| } |
| else |
| { |
| target = missingLockStateForCDOID; |
| } |
| |
| CDOLockState defaultLockState = CDOLockUtil.createLockState(target); |
| lockStates.add(defaultLockState); |
| newLockStateForCache.add(defaultLockState); |
| } |
| |
| if (options().isLockNotificationEnabled()) |
| { |
| updateLockStates(newLockStateForCache.toArray(new CDOLockState[newLockStateForCache.size()])); |
| } |
| } |
| |
| CDOLockState[] locksOnNewObjectsArray = locksOnNewObjects.toArray(new CDOLockState[locksOnNewObjects.size()]); |
| updateLockStates(locksOnNewObjectsArray); |
| |
| return lockStates.toArray(new CDOLockState[lockStates.size()]); |
| } |
| |
| protected CDOLockState removeLockState(CDOObject object) |
| { |
| return lockStates.remove(object); |
| } |
| |
| protected CDOLockState getLockState(CDOObject object) |
| { |
| return lockStates.get(object); |
| } |
| |
| private CDOBranchPoint getBranchPointForID(CDOID id) |
| { |
| // If this view's timestamp is something other than UNSPECIFIED_DATE, |
| // then this is an 'audit' view, and so this timestamp must always be |
| // used without any concern for possible sticky-view behavior |
| CDOBranchPoint branchPoint = getNormalizedBranchPoint(); |
| if (branchPoint.getTimeStamp() != UNSPECIFIED_DATE) |
| { |
| return branchPoint; |
| } |
| |
| if (session.isSticky()) |
| { |
| branchPoint = session.getCommittedSinceLastRefresh(id); |
| if (branchPoint == null) |
| { |
| branchPoint = getBranch().getPoint(session.getLastUpdateTime()); |
| } |
| |
| return branchPoint; |
| } |
| |
| return this; |
| } |
| |
| public synchronized void prefetchRevisions(CDOID id, int depth) |
| { |
| checkArg(depth != CDORevision.DEPTH_NONE, "Prefetch depth must not be zero"); //$NON-NLS-1$ |
| int initialChunkSize = session.options().getCollectionLoadingPolicy().getInitialChunkSize(); |
| prefetchRevisions(id, depth, initialChunkSize); |
| } |
| |
| protected void prefetchRevisions(CDOID id, int depth, int initialChunkSize) |
| { |
| CDORevisionManager revisionManager = session.getRevisionManager(); |
| revisionManager.getRevision(id, this, initialChunkSize, depth, true); |
| } |
| |
| /* |
| * Must not by synchronized on the view! |
| */ |
| @Deprecated |
| public/* synchronized */void invalidate(CDOBranch branch, long lastUpdateTime, List<CDORevisionKey> allChangedObjects, |
| List<CDOIDAndVersion> allDetachedObjects, Map<CDOID, InternalCDORevision> oldRevisions, boolean async) |
| { |
| invalidate(branch, lastUpdateTime, allChangedObjects, allDetachedObjects, oldRevisions, async, true); |
| } |
| |
| /* |
| * Must not by synchronized on the view! |
| */ |
| public/* synchronized */void invalidate(CDOBranch branch, long lastUpdateTime, List<CDORevisionKey> allChangedObjects, |
| List<CDOIDAndVersion> allDetachedObjects, Map<CDOID, InternalCDORevision> oldRevisions, boolean async, |
| boolean clearResourcePathCache) |
| { |
| if (async) |
| { |
| IWorkSerializer serializer = getInvalidationRunner(); |
| serializer.addWork(new InvalidationRunnable(branch, lastUpdateTime, allChangedObjects, allDetachedObjects, |
| oldRevisions, clearResourcePathCache)); |
| } |
| else |
| { |
| doInvalidate(branch, lastUpdateTime, allChangedObjects, allDetachedObjects, oldRevisions, clearResourcePathCache); |
| } |
| } |
| |
| protected synchronized void doInvalidate(CDOBranch branch, long lastUpdateTime, |
| List<CDORevisionKey> allChangedObjects, List<CDOIDAndVersion> allDetachedObjects, |
| Map<CDOID, InternalCDORevision> oldRevisions, boolean clearResourcePathCache) |
| { |
| if (getTimeStamp() != UNSPECIFIED_DATE && CDOStateMachine.SWITCHING_TARGET.get() != Boolean.TRUE) |
| { |
| // Don't invalidate historical views unless during a branch point switch. |
| return; |
| } |
| |
| try |
| { |
| // Also false for FailureCommitInfos (because of branch==null). Only setLastUpdateTime() is called below. |
| if (branch == getBranch()) |
| { |
| if (clearResourcePathCache) |
| { |
| clearResourcePathCacheIfNecessary(null); |
| } |
| |
| List<CDORevisionDelta> deltas = new ArrayList<CDORevisionDelta>(); |
| Map<CDOObject, CDORevisionDelta> revisionDeltas = new HashMap<CDOObject, CDORevisionDelta>(); |
| Set<CDOObject> detachedObjects = new HashSet<CDOObject>(); |
| |
| Map<CDOObject, Pair<CDORevision, CDORevisionDelta>> conflicts = invalidate(allChangedObjects, |
| allDetachedObjects, deltas, revisionDeltas, detachedObjects); |
| handleConflicts(lastUpdateTime, conflicts, deltas); |
| |
| sendInvalidationNotifications(revisionDeltas.keySet(), detachedObjects); |
| fireInvalidationEvent(lastUpdateTime, Collections.unmodifiableMap(revisionDeltas), |
| Collections.unmodifiableSet(detachedObjects)); |
| |
| // Then send the notifications. The deltas could have been modified by the conflict resolvers. |
| if (!deltas.isEmpty() || !detachedObjects.isEmpty()) |
| { |
| sendDeltaNotifications(deltas, detachedObjects, oldRevisions); |
| } |
| |
| fireAdaptersNotifiedEvent(lastUpdateTime); |
| } |
| } |
| catch (RuntimeException ex) |
| { |
| if (isActive()) |
| { |
| fireEvent(new ThrowableEvent(this, ex)); |
| throw ex; |
| } |
| } |
| finally |
| { |
| setLastUpdateTime(lastUpdateTime); |
| } |
| } |
| |
| public ExecutorWorkSerializer getInvalidationRunner() |
| { |
| return invalidationRunner; |
| } |
| |
| private ExecutorWorkSerializer createInvalidationRunner() |
| { |
| return new ExecutorWorkSerializer() |
| { |
| @Override |
| protected void noWork() |
| { |
| if (isClosed()) |
| { |
| dispose(); |
| } |
| } |
| }; |
| } |
| |
| public boolean isInvalidationRunnerActive() |
| { |
| return invalidationRunnerActive; |
| } |
| |
| private void sendInvalidationNotifications(Set<CDOObject> dirtyObjects, Set<CDOObject> detachedObjects) |
| { |
| if (options().isInvalidationNotificationEnabled()) |
| { |
| for (CDOObject dirtyObject : dirtyObjects) |
| { |
| if (((InternalCDOObject)dirtyObject).eNotificationRequired()) |
| { |
| CDOInvalidationNotificationImpl notification = new CDOInvalidationNotificationImpl(dirtyObject); |
| dirtyObject.eNotify(notification); |
| } |
| } |
| |
| for (CDOObject detachedObject : detachedObjects) |
| { |
| if (((InternalCDOObject)detachedObject).eNotificationRequired()) |
| { |
| CDOInvalidationNotificationImpl notification = new CDOInvalidationNotificationImpl(detachedObject); |
| detachedObject.eNotify(notification); |
| } |
| } |
| } |
| } |
| |
| /** |
| * @since 2.0 |
| */ |
| private void fireInvalidationEvent(long timeStamp, Map<CDOObject, CDORevisionDelta> revisionDeltas, |
| Set<CDOObject> detachedObjects) |
| { |
| if (!revisionDeltas.isEmpty() || !detachedObjects.isEmpty()) |
| { |
| IListener[] listeners = getListeners(); |
| if (listeners != null) |
| { |
| fireEvent(new InvalidationEvent(timeStamp, revisionDeltas, detachedObjects), listeners); |
| } |
| } |
| } |
| |
| /** |
| * @since 2.0 |
| */ |
| public synchronized void sendDeltaNotifications(Collection<CDORevisionDelta> deltas, Set<CDOObject> detachedObjects, |
| Map<CDOID, InternalCDORevision> oldRevisions) |
| { |
| if (deltas != null) |
| { |
| CDONotificationBuilder builder = new CDONotificationBuilder(this); |
| Map<CDOID, InternalCDOObject> objects = getModifiableObjects(); |
| for (CDORevisionDelta delta : deltas) |
| { |
| CDOID id = delta.getID(); |
| InternalCDOObject object = objects.get(id); |
| if (object != null && object.eNotificationRequired()) |
| { |
| // if (!isLocked(object)) |
| { |
| InternalCDORevision oldRevision = null; |
| if (oldRevisions != null) |
| { |
| oldRevision = oldRevisions.get(id); |
| } |
| |
| NotificationChain notification = builder.buildNotification(object, oldRevision, delta, detachedObjects); |
| if (notification != null) |
| { |
| notification.dispatch(); |
| } |
| } |
| } |
| } |
| } |
| |
| if (detachedObjects != null && !detachedObjects.isEmpty()) |
| { |
| if (options().isDetachmentNotificationEnabled()) |
| { |
| for (CDOObject detachedObject : detachedObjects) |
| { |
| InternalCDOObject object = (InternalCDOObject)detachedObject; |
| if (object.eNotificationRequired()) |
| { |
| // if (!isLocked(object)) |
| { |
| new CDODeltaNotificationImpl(object, CDONotification.DETACH_OBJECT, null, null, null).dispatch(); |
| } |
| } |
| } |
| } |
| |
| getChangeSubscriptionManager().handleDetachedObjects(detachedObjects); |
| } |
| } |
| |
| /** |
| * TODO For this method to be useable locks must be cached locally! |
| */ |
| @SuppressWarnings("unused") |
| private boolean isLocked(InternalCDOObject object) |
| { |
| if (object.cdoWriteLock().isLocked()) |
| { |
| return true; |
| } |
| |
| if (object.cdoReadLock().isLocked()) |
| { |
| return true; |
| } |
| |
| return false; |
| } |
| |
| /** |
| * @since 2.0 |
| */ |
| protected final AdapterManager getAdapterManager() |
| { |
| return adapterManager; |
| } |
| |
| /** |
| * @since 2.0 |
| */ |
| public synchronized void handleAddAdapter(InternalCDOObject eObject, Adapter adapter) |
| { |
| if (!FSMUtil.isNew(eObject)) |
| { |
| subscribe(eObject, adapter); |
| } |
| |
| adapterManager.attachAdapter(eObject, adapter); |
| } |
| |
| /** |
| * @since 2.0 |
| */ |
| public synchronized void handleRemoveAdapter(InternalCDOObject eObject, Adapter adapter) |
| { |
| if (!FSMUtil.isNew(eObject)) |
| { |
| unsubscribe(eObject, adapter); |
| } |
| |
| adapterManager.detachAdapter(eObject, adapter); |
| } |
| |
| /** |
| * @since 2.0 |
| */ |
| public synchronized void subscribe(EObject eObject, Adapter adapter) |
| { |
| if (changeSubscriptionManager != null) |
| { |
| changeSubscriptionManager.subscribe(eObject, adapter); |
| } |
| } |
| |
| /** |
| * @since 2.0 |
| */ |
| public synchronized void unsubscribe(EObject eObject, Adapter adapter) |
| { |
| if (changeSubscriptionManager != null) |
| { |
| changeSubscriptionManager.unsubscribe(eObject, adapter); |
| } |
| } |
| |
| /** |
| * @since 2.0 |
| */ |
| public synchronized boolean hasSubscription(CDOID id) |
| { |
| if (changeSubscriptionManager != null) |
| { |
| return changeSubscriptionManager.getSubcribeObject(id) != null; |
| } |
| |
| return false; |
| } |
| |
| /** |
| * @since 2.0 |
| */ |
| protected final ChangeSubscriptionManager getChangeSubscriptionManager() |
| { |
| return changeSubscriptionManager; |
| } |
| |
| /** |
| * @since 2.0 |
| */ |
| protected OptionsImpl createOptions() |
| { |
| return new OptionsImpl(); |
| } |
| |
| /** |
| * @since 2.0 |
| */ |
| @Override |
| protected void doBeforeActivate() throws Exception |
| { |
| super.doBeforeActivate(); |
| checkState(session, "session"); //$NON-NLS-1$ |
| checkState(viewID > 0, "viewID"); //$NON-NLS-1$ |
| } |
| |
| /** |
| * @since 2.0 |
| */ |
| @Override |
| protected void doActivate() throws Exception |
| { |
| super.doActivate(); |
| |
| CDOSessionProtocol sessionProtocol = session.getSessionProtocol(); |
| if (durableLockingID != null) |
| { |
| CDOBranchPoint branchPoint = sessionProtocol.openView(viewID, isReadOnly(), durableLockingID); |
| basicSetBranchPoint(branchPoint); |
| } |
| else |
| { |
| sessionProtocol.openView(viewID, isReadOnly(), this); |
| } |
| |
| CDOViewRegistryImpl.INSTANCE.register(this); |
| |
| Runnable runnable = SessionUtil.getTestDelayInViewActivation(); |
| if (runnable != null) |
| { |
| runnable.run(); |
| } |
| |
| lockOwner = CDOLockUtil.createLockOwner(this); |
| } |
| |
| @Override |
| protected void doAfterActivate() throws Exception |
| { |
| super.doAfterActivate(); |
| |
| ExecutorService executorService = ConcurrencyUtil.getExecutorService(session); |
| invalidationRunner.setExecutor(executorService); |
| |
| try |
| { |
| LifecycleUtil.activate(invalidationRunner); |
| } |
| catch (LifecycleException ex) |
| { |
| // Don't pollute the log if the worker thread is interrupted due to asynchronous view.close() |
| if (!(ex.getCause() instanceof InterruptedException)) |
| { |
| throw ex; |
| } |
| } |
| } |
| |
| @Override |
| protected void doBeforeDeactivate() throws Exception |
| { |
| // Detach viewset from the view |
| InternalCDOViewSet viewSet = getViewSet(); |
| viewSet.remove(this); |
| |
| super.doBeforeDeactivate(); |
| } |
| |
| /** |
| * @since 2.0 |
| */ |
| @Override |
| protected void doDeactivate() throws Exception |
| { |
| CDOViewRegistryImpl.INSTANCE.deregister(this); |
| LifecycleUtil.deactivate(invalidationRunner, OMLogger.Level.WARN); |
| |
| try |
| { |
| CDOSessionProtocol sessionProtocol = session.getSessionProtocol(); |
| if (LifecycleUtil.isActive(sessionProtocol)) |
| { |
| sessionProtocol.closeView(viewID); |
| } |
| } |
| catch (Exception ex) |
| { |
| OM.LOG.error(ex); |
| } |
| finally |
| { |
| synchronized (lockStates) |
| { |
| if (options.lockStatePrefetcher != null) |
| { |
| options.lockStatePrefetcher.dispose(); |
| options.lockStatePrefetcher = null; |
| } |
| |
| if (session.isActive() && !lockStates.isEmpty()) |
| { |
| List<CDOLockState> result = new ArrayList<CDOLockState>(); |
| for (CDOLockState lockState : lockStates.values()) |
| { |
| if (((InternalCDOLockState)lockState).removeOwner(lockOwner)) |
| { |
| result.add(lockState); |
| } |
| } |
| |
| if (!result.isEmpty()) |
| { |
| CDOLockState[] deactivateLockStates = result.toArray(new CDOLockState[result.size()]); |
| long timeStamp = session.getLastUpdateTime(); |
| notifyOtherViewsAboutLockChanges(Operation.UNLOCK, null, timeStamp, deactivateLockStates); |
| } |
| |
| lockStates.clear(); |
| lockOwner = null; |
| } |
| } |
| } |
| |
| try |
| { |
| session.viewDetached(this); |
| } |
| catch (Exception ex) |
| { |
| OM.LOG.error(ex); |
| } |
| |
| changeSubscriptionManager = null; |
| super.doDeactivate(); |
| } |
| |
| public synchronized long getLastUpdateTime() |
| { |
| return lastUpdateTime; |
| } |
| |
| public synchronized void setLastUpdateTime(long lastUpdateTime) |
| { |
| if (this.lastUpdateTime < lastUpdateTime) |
| { |
| this.lastUpdateTime = lastUpdateTime; |
| } |
| |
| notifyAll(); |
| } |
| |
| public boolean waitForUpdate(long updateTime, long timeoutMillis) |
| { |
| long end = timeoutMillis == NO_TIMEOUT ? Long.MAX_VALUE : System.currentTimeMillis() + timeoutMillis; |
| synchronized (this) |
| { |
| for (;;) |
| { |
| if (lastUpdateTime >= updateTime) |
| { |
| return true; |
| } |
| |
| long now = System.currentTimeMillis(); |
| if (now >= end) |
| { |
| return false; |
| } |
| |
| try |
| { |
| long waitMillis = end - now; |
| wait(waitMillis); |
| } |
| catch (InterruptedException ex) |
| { |
| throw WrappedException.wrap(ex); |
| } |
| } |
| } |
| } |
| |
| public boolean runAfterUpdate(final long updateTime, final Runnable runnable) |
| { |
| synchronized (this) |
| { |
| long lastUpdateTime = getLastUpdateTime(); |
| if (lastUpdateTime < updateTime) |
| { |
| addListener(new IListener() |
| { |
| public void notifyEvent(IEvent event) |
| { |
| if (event instanceof CDOViewInvalidationEvent) |
| { |
| CDOViewInvalidationEvent e = (CDOViewInvalidationEvent)event; |
| if (e.getTimeStamp() >= updateTime) |
| { |
| removeListener(this); |
| runnable.run(); |
| } |
| } |
| } |
| }); |
| |
| return false; |
| } |
| } |
| |
| runnable.run(); |
| return true; |
| } |
| |
| protected static Object getLockTarget(CDOObject object) |
| { |
| CDOView view = object.cdoView(); |
| if (view == null) |
| { |
| return null; |
| } |
| |
| CDOID id = object.cdoID(); |
| boolean branching = view.getSession().getRepositoryInfo().isSupportingBranches(); |
| if (branching) |
| { |
| return CDOIDUtil.createIDAndBranch(id, view.getBranch()); |
| } |
| |
| return id; |
| } |
| |
| /** |
| * @author Simon McDuff |
| * @since 2.0 |
| */ |
| protected final class AdapterManager |
| { |
| private Set<CDOObject> objects = new HashBag<CDOObject>(); |
| |
| public AdapterManager() |
| { |
| } |
| |
| public void committedTransaction(CDOTransaction transaction, CDOCommitContext commitContext) |
| { |
| if (options().getStrongReferencePolicy() != CDOAdapterPolicy.NONE) |
| { |
| for (CDOObject object : commitContext.getNewObjects().values()) |
| { |
| attachObject(object); |
| } |
| |
| for (CDOObject object : commitContext.getDetachedObjects().values()) |
| { |
| detachObject(object); |
| } |
| } |
| } |
| |
| private void attachObject(CDOObject object) |
| { |
| if (((InternalEObject)object).eNotificationRequired()) |
| { |
| CDOAdapterPolicy strongReferencePolicy = options().getStrongReferencePolicy(); |
| int count = 0; |
| for (Adapter adapter : object.eAdapters()) |
| { |
| if (strongReferencePolicy.isValid(object, adapter)) |
| { |
| count++; |
| } |
| } |
| |
| for (int i = 0; i < count; i++) |
| { |
| objects.add(object); |
| } |
| } |
| } |
| |
| private void detachObject(CDOObject object) |
| { |
| while (objects.remove(object)) |
| { |
| // Do nothing |
| } |
| } |
| |
| private void attachAdapter(CDOObject object, Adapter adapter) |
| { |
| if (options().getStrongReferencePolicy().isValid(object, adapter)) |
| { |
| objects.add(object); |
| } |
| } |
| |
| private void detachAdapter(CDOObject object, Adapter adapter) |
| { |
| if (options().getStrongReferencePolicy().isValid(object, adapter)) |
| { |
| objects.remove(object); |
| } |
| } |
| |
| private void reset() |
| { |
| // Keep the objects in memory |
| Set<CDOObject> oldObjects = objects; |
| objects = new HashBag<CDOObject>(); |
| if (options().getStrongReferencePolicy() != CDOAdapterPolicy.NONE) |
| { |
| for (InternalCDOObject object : getObjectsList()) |
| { |
| attachObject(object); |
| } |
| } |
| |
| oldObjects.clear(); |
| } |
| } |
| |
| /** |
| * @author Simon McDuff |
| * @since 2.0 |
| */ |
| protected final class ChangeSubscriptionManager |
| { |
| private Map<CDOID, SubscribeEntry> subscriptions = CDOIDUtil.createMap(); |
| |
| public ChangeSubscriptionManager() |
| { |
| } |
| |
| public void committedTransaction(CDOTransaction transaction, CDOCommitContext commitContext) |
| { |
| handleNewObjects(commitContext.getNewObjects().values()); |
| handleDetachedObjects(commitContext.getDetachedObjects().values()); |
| } |
| |
| private void subscribe(EObject eObject, Adapter adapter) |
| { |
| subscribe(eObject, adapter, 1); |
| } |
| |
| private void unsubscribe(EObject eObject, Adapter adapter) |
| { |
| subscribe(eObject, adapter, -1); |
| } |
| |
| /** |
| * Register to the server all objects from the active list |
| */ |
| private void notifyChangeSubcriptionPolicy() |
| { |
| boolean policiesPresent = options().hasChangeSubscriptionPolicies(); |
| subscriptions.clear(); |
| List<CDOID> ids = new ArrayList<CDOID>(); |
| if (policiesPresent) |
| { |
| for (InternalCDOObject object : getObjectsList()) |
| { |
| int count = getNumberOfValidAdapters(object); |
| if (count > 0) |
| { |
| ids.add(object.cdoID()); |
| addEntry(object.cdoID(), object, count); |
| } |
| } |
| } |
| |
| request(ids, true, true); |
| } |
| |
| private void handleDetachedObjects(Collection<CDOObject> detachedObjects) |
| { |
| for (CDOObject detachedObject : detachedObjects) |
| { |
| CDOID id = detachedObject.cdoID(); |
| SubscribeEntry entry = subscriptions.get(id); |
| if (entry != null) |
| { |
| detachObject(id); |
| } |
| } |
| } |
| |
| private void handleNewObjects(Collection<? extends CDOObject> newObjects) |
| { |
| for (CDOObject object : newObjects) |
| { |
| InternalCDOObject cdoDetachedObject = (InternalCDOObject)object; |
| if (cdoDetachedObject != null) |
| { |
| int count = getNumberOfValidAdapters(cdoDetachedObject); |
| if (count > 0) |
| { |
| subscribe(cdoDetachedObject.cdoID(), cdoDetachedObject, count); |
| } |
| } |
| } |
| } |
| |
| private InternalCDOObject getSubcribeObject(CDOID id) |
| { |
| SubscribeEntry entry = subscriptions.get(id); |
| if (entry != null) |
| { |
| return entry.getObject(); |
| } |
| |
| return null; |
| } |
| |
| private void request(List<CDOID> ids, boolean clear, boolean subscribeMode) |
| { |
| CDOSessionProtocol sessionProtocol = session.getSessionProtocol(); |
| sessionProtocol.changeSubscription(getViewID(), ids, subscribeMode, clear); |
| } |
| |
| private int getNumberOfValidAdapters(InternalCDOObject object) |
| { |
| int count = 0; |
| if (!FSMUtil.isTransient(object) && !FSMUtil.isNew(object)) |
| { |
| if (object.eNotificationRequired()) |
| { |
| EObject instance = CDOUtil.getEObject(object); |
| for (Adapter adapter : instance.eAdapters()) |
| { |
| if (shouldSubscribe(object, adapter)) |
| { |
| ++count; |
| } |
| } |
| } |
| } |
| |
| return count; |
| } |
| |
| private void subscribe(EObject eObject, Adapter adapter, int adjust) |
| { |
| if (shouldSubscribe(eObject, adapter)) |
| { |
| CDOView view = CDOViewImpl.this; |
| InternalCDOObject internalCDOObject = FSMUtil.adapt(eObject, view); |
| if (internalCDOObject.cdoView() != view) |
| { |
| throw new CDOException(MessageFormat.format(Messages.getString("CDOViewImpl.27"), internalCDOObject)); //$NON-NLS-1$ |
| } |
| |
| subscribe(internalCDOObject.cdoID(), internalCDOObject, adjust); |
| } |
| } |
| |
| private boolean shouldSubscribe(EObject eObject, Adapter adapter) |
| { |
| for (CDOAdapterPolicy policy : options().getChangeSubscriptionPolicies()) |
| { |
| if (policy.isValid(eObject, adapter)) |
| { |
| return true; |
| } |
| } |
| |
| return false; |
| } |
| |
| private void subscribe(CDOID id, InternalCDOObject cdoObject, int adjust) |
| { |
| boolean policiesPresent = options().hasChangeSubscriptionPolicies(); |
| |
| int count = 0; |
| SubscribeEntry entry = subscriptions.get(id); |
| if (entry == null) |
| { |
| // Cannot adjust negative value |
| if (adjust < 0) |
| { |
| return; |
| } |
| |
| // Notification need to be enable to send correct value to the server |
| if (policiesPresent) |
| { |
| request(Collections.singletonList(id), false, true); |
| } |
| } |
| else |
| { |
| count = entry.getCount(); |
| } |
| |
| count += adjust; |
| |
| // Look if objects need to be unsubscribe |
| if (count <= 0) |
| { |
| subscriptions.remove(id); |
| |
| // Notification need to be enable to send correct value to the server |
| if (policiesPresent) |
| { |
| request(Collections.singletonList(id), false, false); |
| } |
| } |
| else |
| { |
| if (entry == null) |
| { |
| addEntry(id, cdoObject, count); |
| } |
| else |
| { |
| entry.setCount(count); |
| } |
| } |
| } |
| |
| private void detachObject(CDOID id) |
| { |
| subscribe(id, null, Integer.MIN_VALUE); |
| } |
| |
| private void addEntry(CDOID key, InternalCDOObject object, int count) |
| { |
| subscriptions.put(key, new SubscribeEntry(object, count)); |
| } |
| } |
| |
| /** |
| * @author Eike Stepper |
| */ |
| private static final class SubscribeEntry |
| { |
| private InternalCDOObject object; |
| |
| private int count; |
| |
| public SubscribeEntry(InternalCDOObject object, int count) |
| { |
| this.object = object; |
| this.count = count; |
| } |
| |
| public InternalCDOObject getObject() |
| { |
| return object; |
| } |
| |
| public int getCount() |
| { |
| return count; |
| } |
| |
| public void setCount(int count) |
| { |
| this.count = count; |
| } |
| } |
| |
| /** |
| * A {@link IListener} to prefetch {@link CDOLockState lockstates} when {@link CDORevision revisions} are loaded, according to {@link Options#setLockStatePrefetchEnabled(boolean)} option. |
| * |
| * @author Esteban Dugueperoux |
| */ |
| private final class LockStatePrefetcher implements IListener |
| { |
| public LockStatePrefetcher() |
| { |
| session.getRevisionManager().addListener(this); |
| } |
| |
| public void notifyEvent(IEvent event) |
| { |
| if (event instanceof CDORevisionsLoadedEvent) |
| { |
| CDORevisionsLoadedEvent revisionsLoadedEvent = (CDORevisionsLoadedEvent)event; |
| updateCDOViewObjectsCache(revisionsLoadedEvent); |
| } |
| } |
| |
| private void updateCDOViewObjectsCache(CDORevisionsLoadedEvent revisionsLoadedEvent) |
| { |
| Set<CDOID> ids = new HashSet<CDOID>(); |
| CDOLockStateLoadingPolicy lockStateLoadingPolicy = options().getLockStateLoadingPolicy(); |
| for (CDORevision revision : revisionsLoadedEvent.getPrimaryLoadedRevisions()) |
| { |
| // Bug 466721 : Check null if it is a about a DetachedRevision |
| if (revision != null) |
| { |
| CDOID id = revision.getID(); |
| if (id != null && lockStateLoadingPolicy.loadLockState(id)) |
| { |
| // - Don't ask to create an object for CDOResource as the caller of ResourceSet.getResource() |
| // can have created it but not yet registered in CDOView. |
| // - Don't ask others CDOResourceNode either as it will create some load revisions request |
| // in addition to mode without lock state prefetch |
| boolean isResourceNode = revision.isResourceNode(); |
| InternalCDOObject object = getObject(id, !isResourceNode); |
| if (object != null) |
| { |
| ids.add(id); |
| } |
| } |
| } |
| } |
| |
| if (!ids.isEmpty()) |
| { |
| // direct call the session protocol |
| CDOSessionProtocol sessionProtocol = session.getSessionProtocol(); |
| CDOLockState[] lockStates = sessionProtocol.getLockStates(viewID, ids, revisionsLoadedEvent.getPrefetchDepth()); |
| |
| updateLockStatesForAllViews(lockStates); |
| |
| // add missing lock states |
| List<CDOLockState> missingLockStates = new ArrayList<CDOLockState>(); |
| for (CDOID id : ids) |
| { |
| InternalCDOObject obj = getObject(id, false); |
| |
| if (obj != null && CDOViewImpl.this.lockStates.get(obj) == null) |
| { |
| missingLockStates.add(CDOLockUtil.createLockState(getLockTarget(obj))); |
| } |
| } |
| |
| for (CDORevision revision : revisionsLoadedEvent.getAdditionalLoadedRevisions()) |
| { |
| CDOID id = revision.getID(); |
| if (id != null && lockStateLoadingPolicy.loadLockState(id)) |
| { |
| boolean isResourceNode = revision.isResourceNode(); |
| InternalCDOObject obj = getObject(id, !isResourceNode); |
| if (obj != null && CDOViewImpl.this.lockStates.get(obj) == null) |
| { |
| missingLockStates.add(CDOLockUtil.createLockState(getLockTarget(obj))); |
| } |
| } |
| } |
| |
| updateLockStatesForAllViews(missingLockStates.toArray(new CDOLockState[missingLockStates.size()])); |
| } |
| } |
| |
| private void updateLockStatesForAllViews(CDOLockState[] lockStates) |
| { |
| updateLockStates(lockStates); |
| |
| for (CDOCommonView view : getSession().getViews()) |
| { |
| if (view != CDOViewImpl.this && view.getBranch() == getBranch()) |
| { |
| updateLockStates(lockStates); |
| } |
| } |
| } |
| |
| public void dispose() |
| { |
| session.getRevisionManager().removeListener(this); |
| } |
| } |
| |
| /** |
| * @author Eike Stepper |
| */ |
| private final class InvalidationRunnable implements Runnable |
| { |
| private final CDOBranch branch; |
| |
| private final long lastUpdateTime; |
| |
| private final List<CDORevisionKey> allChangedObjects; |
| |
| private final List<CDOIDAndVersion> allDetachedObjects; |
| |
| private final Map<CDOID, InternalCDORevision> oldRevisions; |
| |
| private boolean clearResourcePathCache; |
| |
| private InvalidationRunnable(CDOBranch branch, long lastUpdateTime, List<CDORevisionKey> allChangedObjects, |
| List<CDOIDAndVersion> allDetachedObjects, Map<CDOID, InternalCDORevision> oldRevisions, |
| boolean clearResourcePathCache) |
| { |
| this.branch = branch; |
| this.lastUpdateTime = lastUpdateTime; |
| this.allChangedObjects = allChangedObjects; |
| this.allDetachedObjects = allDetachedObjects; |
| this.oldRevisions = oldRevisions; |
| this.clearResourcePathCache = clearResourcePathCache; |
| } |
| |
| public void run() |
| { |
| try |
| { |
| invalidationRunnerActive = true; |
| doInvalidate(branch, lastUpdateTime, allChangedObjects, allDetachedObjects, oldRevisions, |
| clearResourcePathCache); |
| } |
| catch (Exception ex) |
| { |
| if (isActive()) |
| { |
| OM.LOG.error(ex); |
| } |
| } |
| finally |
| { |
| invalidationRunnerActive = false; |
| } |
| } |
| } |
| |
| /** |
| * @author Simon McDuff |
| */ |
| private final class InvalidationEvent extends Event implements CDOViewInvalidationEvent |
| { |
| private static final long serialVersionUID = 1L; |
| |
| private long timeStamp; |
| |
| private Map<CDOObject, CDORevisionDelta> revisionDeltas; |
| |
| private Set<CDOObject> detachedObjects; |
| |
| public InvalidationEvent(long timeStamp, Map<CDOObject, CDORevisionDelta> revisionDeltas, |
| Set<CDOObject> detachedObjects) |
| { |
| this.timeStamp = timeStamp; |
| this.revisionDeltas = revisionDeltas; |
| this.detachedObjects = detachedObjects; |
| } |
| |
| public long getTimeStamp() |
| { |
| return timeStamp; |
| } |
| |
| public Set<CDOObject> getDirtyObjects() |
| { |
| return revisionDeltas.keySet(); |
| } |
| |
| public Map<CDOObject, CDORevisionDelta> getRevisionDeltas() |
| { |
| return revisionDeltas; |
| } |
| |
| public Set<CDOObject> getDetachedObjects() |
| { |
| return detachedObjects; |
| } |
| |
| @Override |
| public String toString() |
| { |
| return "CDOViewInvalidationEvent: " + revisionDeltas; //$NON-NLS-1$ |
| } |
| } |
| |
| /** |
| * @author Caspar De Groot |
| * @since 4.1 |
| */ |
| private final class LocksChangedEvent extends DefaultLocksChangedEvent implements CDOViewLocksChangedEvent |
| { |
| private static final long serialVersionUID = 1L; |
| |
| public LocksChangedEvent(InternalCDOView sender, CDOLockChangeInfo lockChangeInfo) |
| { |
| super(CDOViewImpl.this, sender, lockChangeInfo); |
| } |
| |
| @Override |
| public InternalCDOView getSource() |
| { |
| return (InternalCDOView)super.getSource(); |
| } |
| |
| public EObject[] getAffectedObjects() |
| { |
| List<EObject> objects = new ArrayList<EObject>(); |
| CDOView view = getSource(); |
| |
| CDOLockState[] lockStates = getLockStates(); |
| for (int i = 0; i < lockStates.length; i++) |
| { |
| CDOLockState lockState = lockStates[i]; |
| Object lockedObject = lockState.getLockedObject(); |
| |
| CDOID id = null; |
| if (lockedObject instanceof CDOIDAndBranch) |
| { |
| CDOIDAndBranch idAndBranch = (CDOIDAndBranch)lockedObject; |
| if (idAndBranch.getBranch().getID() == view.getBranch().getID()) |
| { |
| id = idAndBranch.getID(); |
| } |
| } |
| else if (lockedObject instanceof CDOID) |
| { |
| id = (CDOID)lockedObject; |
| } |
| |
| if (id != null) |
| { |
| CDOObject object = view.getObject(id, false); |
| if (object != null) |
| { |
| objects.add(CDOUtil.getEObject(object)); |
| } |
| } |
| } |
| |
| return objects.toArray(new EObject[objects.size()]); |
| } |
| } |
| |
| /** |
| * @author Eike Stepper |
| * @since 2.0 |
| */ |
| public class OptionsImpl extends Notifier implements Options |
| { |
| private boolean loadNotificationEnabled; |
| |
| private boolean detachmentNotificationEnabled; |
| |
| private boolean invalidationNotificationEnabled; |
| |
| private CDOInvalidationPolicy invalidationPolicy = CDOInvalidationPolicy.DEFAULT; |
| |
| private boolean lockNotificationsEnabled; |
| |
| private boolean lockStatePrefetchEnabled; |
| |
| private CDOLockStateLoadingPolicy lockStateLoadingPolicy = new CDODefaultLockStateLoadingPolicy(); |
| |
| private LockStatePrefetcher lockStatePrefetcher; |
| |
| private CDORevisionPrefetchingPolicy revisionPrefetchingPolicy = CDOUtil |
| .createRevisionPrefetchingPolicy(NO_REVISION_PREFETCHING); |
| |
| private CDOFeatureAnalyzer featureAnalyzer = CDOFeatureAnalyzer.NOOP; |
| |
| private CDOStaleReferencePolicy staleReferencePolicy = CDOStaleReferencePolicy.DEFAULT; |
| |
| private HashBag<CDOAdapterPolicy> changeSubscriptionPolicies = new HashBag<CDOAdapterPolicy>(); |
| |
| private CDOAdapterPolicy strongReferencePolicy = CDOAdapterPolicy.ALL; |
| |
| public OptionsImpl() |
| { |
| } |
| |
| public CDOViewImpl getContainer() |
| { |
| return CDOViewImpl.this; |
| } |
| |
| public boolean isLoadNotificationEnabled() |
| { |
| synchronized (CDOViewImpl.this) |
| { |
| return loadNotificationEnabled; |
| } |
| } |
| |
| public void setLoadNotificationEnabled(boolean enabled) |
| { |
| checkActive(); |
| |
| IEvent event = null; |
| synchronized (CDOViewImpl.this) |
| { |
| if (loadNotificationEnabled != enabled) |
| { |
| loadNotificationEnabled = enabled; |
| event = new LoadNotificationEventImpl(); |
| } |
| } |
| |
| fireEvent(event); |
| } |
| |
| public boolean isDetachmentNotificationEnabled() |
| { |
| synchronized (CDOViewImpl.this) |
| { |
| return detachmentNotificationEnabled; |
| } |
| } |
| |
| public void setDetachmentNotificationEnabled(boolean enabled) |
| { |
| checkActive(); |
| |
| IEvent event = null; |
| synchronized (CDOViewImpl.this) |
| { |
| if (detachmentNotificationEnabled != enabled) |
| { |
| detachmentNotificationEnabled = enabled; |
| event = new DetachmentNotificationEventImpl(); |
| } |
| } |
| |
| fireEvent(event); |
| } |
| |
| public boolean isInvalidationNotificationEnabled() |
| { |
| synchronized (CDOViewImpl.this) |
| { |
| return invalidationNotificationEnabled; |
| } |
| } |
| |
| public void setInvalidationNotificationEnabled(boolean enabled) |
| { |
| checkActive(); |
| |
| IEvent event = null; |
| synchronized (CDOViewImpl.this) |
| { |
| if (invalidationNotificationEnabled != enabled) |
| { |
| invalidationNotificationEnabled = enabled; |
| event = new InvalidationNotificationEventImpl(); |
| } |
| } |
| |
| fireEvent(event); |
| } |
| |
| public CDOInvalidationPolicy getInvalidationPolicy() |
| { |
| synchronized (CDOViewImpl.this) |
| { |
| return invalidationPolicy; |
| } |
| } |
| |
| public void setInvalidationPolicy(CDOInvalidationPolicy policy) |
| { |
| checkActive(); |
| |
| IEvent event = null; |
| synchronized (CDOViewImpl.this) |
| { |
| if (invalidationPolicy != policy) |
| { |
| invalidationPolicy = policy; |
| event = new InvalidationPolicyEventImpl(); |
| } |
| } |
| |
| fireEvent(event); |
| } |
| |
| public boolean isLockNotificationEnabled() |
| { |
| return lockNotificationsEnabled; |
| } |
| |
| public void setLockNotificationEnabled(boolean enabled) |
| { |
| checkActive(); |
| |
| IEvent event = null; |
| synchronized (CDOViewImpl.this) |
| { |
| if (enabled != lockNotificationsEnabled) |
| { |
| CDOSessionProtocol protocol = session.getSessionProtocol(); |
| protocol.enableLockNotifications(viewID, enabled); |
| lockNotificationsEnabled = enabled; |
| event = new LockNotificationEventImpl(enabled); |
| } |
| } |
| |
| fireEvent(event); |
| } |
| |
| public boolean isLockStatePrefetchEnabled() |
| { |
| return lockStatePrefetchEnabled; |
| } |
| |
| public void setLockStatePrefetchEnabled(boolean enabled) |
| { |
| checkActive(); |
| |
| IEvent event = null; |
| synchronized (CDOViewImpl.this) |
| { |
| if (enabled != lockStatePrefetchEnabled) |
| { |
| lockStatePrefetchEnabled = enabled; |
| if (enabled) |
| { |
| lockStatePrefetcher = new LockStatePrefetcher(); |
| } |
| else |
| { |
| lockStatePrefetcher.dispose(); |
| lockStatePrefetcher = null; |
| } |
| |
| event = new LockStatePrefetchEventImpl(); |
| } |
| } |
| |
| fireEvent(event); |
| } |
| |
| public CDOLockStateLoadingPolicy getLockStateLoadingPolicy() |
| { |
| synchronized (CDOViewImpl.this) |
| { |
| return lockStateLoadingPolicy; |
| } |
| } |
| |
| public void setLockStateLoadingPolicy(CDOLockStateLoadingPolicy lockStateLoadingPolicy) |
| { |
| checkActive(); |
| |
| synchronized (CDOViewImpl.this) |
| { |
| this.lockStateLoadingPolicy = lockStateLoadingPolicy; |
| } |
| } |
| |
| public boolean hasChangeSubscriptionPolicies() |
| { |
| synchronized (CDOViewImpl.this) |
| { |
| return !changeSubscriptionPolicies.isEmpty(); |
| } |
| } |
| |
| public CDOAdapterPolicy[] getChangeSubscriptionPolicies() |
| { |
| synchronized (CDOViewImpl.this) |
| { |
| return changeSubscriptionPolicies.toArray(new CDOAdapterPolicy[changeSubscriptionPolicies.size()]); |
| } |
| } |
| |
| public void addChangeSubscriptionPolicy(CDOAdapterPolicy policy) |
| { |
| checkActive(); |
| |
| IEvent event = null; |
| synchronized (CDOViewImpl.this) |
| { |
| if (changeSubscriptionPolicies.add(policy)) |
| { |
| changeSubscriptionManager.notifyChangeSubcriptionPolicy(); |
| event = new ChangeSubscriptionPoliciesEventImpl(); |
| } |
| } |
| |
| fireEvent(event); |
| } |
| |
| public void removeChangeSubscriptionPolicy(CDOAdapterPolicy policy) |
| { |
| checkActive(); |
| |
| IEvent event = null; |
| synchronized (CDOViewImpl.this) |
| { |
| if (changeSubscriptionPolicies.remove(policy) && !changeSubscriptionPolicies.contains(policy)) |
| { |
| changeSubscriptionManager.notifyChangeSubcriptionPolicy(); |
| event = new ChangeSubscriptionPoliciesEventImpl(); |
| } |
| } |
| |
| fireEvent(event); |
| } |
| |
| public CDOAdapterPolicy getStrongReferencePolicy() |
| { |
| synchronized (CDOViewImpl.this) |
| { |
| return strongReferencePolicy; |
| } |
| } |
| |
| public void setStrongReferencePolicy(CDOAdapterPolicy adapterPolicy) |
| { |
| checkActive(); |
| |
| if (adapterPolicy == null) |
| { |
| adapterPolicy = CDOAdapterPolicy.ALL; |
| } |
| |
| IEvent event = null; |
| synchronized (CDOViewImpl.this) |
| { |
| if (strongReferencePolicy != adapterPolicy) |
| { |
| strongReferencePolicy = adapterPolicy; |
| adapterManager.reset(); |
| event = new ReferencePolicyEventImpl(); |
| } |
| } |
| |
| fireEvent(event); |
| } |
| |
| public CDORevisionPrefetchingPolicy getRevisionPrefetchingPolicy() |
| { |
| synchronized (CDOViewImpl.this) |
| { |
| return revisionPrefetchingPolicy; |
| } |
| } |
| |
| public void setRevisionPrefetchingPolicy(CDORevisionPrefetchingPolicy prefetchingPolicy) |
| { |
| checkActive(); |
| |
| if (prefetchingPolicy == null) |
| { |
| prefetchingPolicy = CDORevisionPrefetchingPolicy.NO_PREFETCHING; |
| } |
| |
| IEvent event = null; |
| synchronized (CDOViewImpl.this) |
| { |
| if (revisionPrefetchingPolicy != prefetchingPolicy) |
| { |
| revisionPrefetchingPolicy = prefetchingPolicy; |
| event = new RevisionPrefetchingPolicyEventImpl(); |
| } |
| } |
| |
| fireEvent(event); |
| } |
| |
| public CDOFeatureAnalyzer getFeatureAnalyzer() |
| { |
| synchronized (CDOViewImpl.this) |
| { |
| return featureAnalyzer; |
| } |
| } |
| |
| public void setFeatureAnalyzer(CDOFeatureAnalyzer featureAnalyzer) |
| { |
| checkActive(); |
| |
| if (featureAnalyzer == null) |
| { |
| featureAnalyzer = CDOFeatureAnalyzer.NOOP; |
| } |
| |
| IEvent event = null; |
| synchronized (CDOViewImpl.this) |
| { |
| if (this.featureAnalyzer != featureAnalyzer) |
| { |
| this.featureAnalyzer = featureAnalyzer; |
| event = new FeatureAnalyzerEventImpl(); |
| } |
| } |
| |
| fireEvent(event); |
| } |
| |
| @Deprecated |
| public CDOStaleReferencePolicy getStaleReferenceBehaviour() |
| { |
| return getStaleReferencePolicy(); |
| } |
| |
| @Deprecated |
| public void setStaleReferenceBehaviour(CDOStaleReferencePolicy policy) |
| { |
| setStaleReferencePolicy(policy); |
| } |
| |
| public CDOStaleReferencePolicy getStaleReferencePolicy() |
| { |
| synchronized (CDOViewImpl.this) |
| { |
| return staleReferencePolicy; |
| } |
| } |
| |
| public void setStaleReferencePolicy(CDOStaleReferencePolicy policy) |
| { |
| checkActive(); |
| |
| if (policy == null) |
| { |
| policy = CDOStaleReferencePolicy.DEFAULT; |
| } |
| |
| IEvent event = null; |
| synchronized (CDOViewImpl.this) |
| { |
| if (staleReferencePolicy != policy) |
| { |
| staleReferencePolicy = policy; |
| event = new StaleReferencePolicyEventImpl(); |
| } |
| } |
| |
| fireEvent(event); |
| } |
| |
| public ReferenceType getCacheReferenceType() |
| { |
| synchronized (CDOViewImpl.this) |
| { |
| Map<CDOID, InternalCDOObject> objects = getModifiableObjects(); |
| if (objects instanceof ReferenceValueMap.Strong<?, ?>) |
| { |
| return ReferenceType.STRONG; |
| } |
| |
| if (objects instanceof ReferenceValueMap.Soft<?, ?>) |
| { |
| return ReferenceType.SOFT; |
| } |
| |
| if (objects instanceof ReferenceValueMap.Weak<?, ?>) |
| { |
| return ReferenceType.WEAK; |
| } |
| |
| throw new IllegalStateException(Messages.getString("CDOViewImpl.29")); //$NON-NLS-1$ |
| } |
| } |
| |
| public boolean setCacheReferenceType(ReferenceType referenceType) |
| { |
| checkActive(); |
| |
| if (referenceType == null) |
| { |
| referenceType = ReferenceType.SOFT; |
| } |
| |
| synchronized (CDOViewImpl.this) |
| { |
| if (!initObjectsMap(referenceType)) |
| { |
| return false; |
| } |
| } |
| |
| IListener[] listeners = getListeners(); |
| if (listeners != null) |
| { |
| fireEvent(new CacheReferenceTypeEventImpl(), listeners); |
| } |
| |
| return true; |
| } |
| |
| /** |
| * @author Eike Stepper |
| */ |
| private final class CacheReferenceTypeEventImpl extends OptionsEvent implements CacheReferenceTypeEvent |
| { |
| private static final long serialVersionUID = 1L; |
| |
| public CacheReferenceTypeEventImpl() |
| { |
| super(OptionsImpl.this); |
| } |
| } |
| |
| /** |
| * @author Eike Stepper |
| */ |
| private final class ChangeSubscriptionPoliciesEventImpl extends OptionsEvent |
| implements ChangeSubscriptionPoliciesEvent |
| { |
| private static final long serialVersionUID = 1L; |
| |
| public ChangeSubscriptionPoliciesEventImpl() |
| { |
| super(OptionsImpl.this); |
| } |
| } |
| |
| /** |
| * @author Eike Stepper |
| */ |
| private final class LoadNotificationEventImpl extends OptionsEvent implements LoadNotificationEvent |
| { |
| private static final long serialVersionUID = 1L; |
| |
| public LoadNotificationEventImpl() |
| { |
| super(OptionsImpl.this); |
| } |
| } |
| |
| /** |
| * @author Eike Stepper |
| */ |
| private final class DetachmentNotificationEventImpl extends OptionsEvent implements DetachmentNotificationEvent |
| { |
| private static final long serialVersionUID = 1L; |
| |
| public DetachmentNotificationEventImpl() |
| { |
| super(OptionsImpl.this); |
| } |
| } |
| |
| /** |
| * @author Eike Stepper |
| */ |
| private final class InvalidationNotificationEventImpl extends OptionsEvent implements InvalidationNotificationEvent |
| { |
| private static final long serialVersionUID = 1L; |
| |
| public InvalidationNotificationEventImpl() |
| { |
| super(OptionsImpl.this); |
| } |
| } |
| |
| /** |
| * @author Eike Stepper |
| */ |
| private final class InvalidationPolicyEventImpl extends OptionsEvent implements InvalidationPolicyEvent |
| { |
| private static final long serialVersionUID = 1L; |
| |
| public InvalidationPolicyEventImpl() |
| { |
| super(OptionsImpl.this); |
| } |
| } |
| |
| /** |
| * @author Caspar De Groot |
| */ |
| private final class LockNotificationEventImpl extends OptionsEvent implements LockNotificationEvent |
| { |
| private static final long serialVersionUID = 1L; |
| |
| private boolean enabled; |
| |
| public LockNotificationEventImpl(boolean enabled) |
| { |
| super(OptionsImpl.this); |
| this.enabled = enabled; |
| } |
| |
| public boolean getEnabled() |
| { |
| return enabled; |
| } |
| } |
| |
| /** |
| * An {@link IOptionsEvent options event} fired from common view {@link CDOCommonView#options() options} when the |
| * {@link OptionsImpl#setLockStatePrefetchEnabled(boolean) lock state prefetch enabled} option has changed. |
| * |
| * @author Esteban Dugueperoux |
| * @noextend This interface is not intended to be extended by clients. |
| * @noimplement This interface is not intended to be implemented by clients. |
| * @since 4.4 |
| */ |
| private final class LockStatePrefetchEventImpl extends OptionsEvent |
| { |
| private static final long serialVersionUID = 1L; |
| |
| public LockStatePrefetchEventImpl() |
| { |
| super(OptionsImpl.this); |
| } |
| } |
| |
| /** |
| * @author Eike Stepper |
| */ |
| private final class RevisionPrefetchingPolicyEventImpl extends OptionsEvent |
| implements RevisionPrefetchingPolicyEvent |
| { |
| private static final long serialVersionUID = 1L; |
| |
| public RevisionPrefetchingPolicyEventImpl() |
| { |
| super(OptionsImpl.this); |
| } |
| } |
| |
| /** |
| * @author Eike Stepper |
| */ |
| private final class FeatureAnalyzerEventImpl extends OptionsEvent implements FeatureAnalyzerEvent |
| { |
| private static final long serialVersionUID = 1L; |
| |
| public FeatureAnalyzerEventImpl() |
| { |
| super(OptionsImpl.this); |
| } |
| } |
| |
| /** |
| * @author Eike Stepper |
| */ |
| @SuppressWarnings("deprecation") |
| private final class ReferencePolicyEventImpl extends OptionsEvent implements ReferencePolicyEvent |
| { |
| private static final long serialVersionUID = 1L; |
| |
| public ReferencePolicyEventImpl() |
| { |
| super(OptionsImpl.this); |
| } |
| } |
| |
| /** |
| * @author Simon McDuff |
| */ |
| private final class StaleReferencePolicyEventImpl extends OptionsEvent implements StaleReferencePolicyEvent |
| { |
| private static final long serialVersionUID = 1L; |
| |
| public StaleReferencePolicyEventImpl() |
| { |
| super(OptionsImpl.this); |
| } |
| } |
| } |
| } |