Skip to main content
aboutsummaryrefslogblamecommitdiffstats
blob: 5fcc8d3ec3a18ddaf8ba1d303f260e66bc2b228e (plain) (tree)
1
2
3
4
5
6
7
8
9
   
                                                                       



                                                                        
  

                                                   
                                
                                           
   
                                          
 
                                           
                                     

                                                        
                                           
                                                     
                                                       
                                                       
                                                          
                                                              
                                                                  
                                                     
                                                    
                                                                       
                                                                   
                                                                   
                                                                          

                                                        
                                        
                                                  

                                                   
                                                      
                                                             
                                                        
                                                         
 

                                                                    

                                                           
                                              
                                                      
 
                                                          
                                               
                                                 
                                              
                                                                 
                                              
                                             
                                                      
                                                     
                                                   
                                                

                                                    
                                             
                                                  
                                                       
                                                           
                                     
                                             
                                                  
                                                                       
                                       



                                                      
 

                               
                            

                             
                         
                      
                     
                           
                     
                                          
 


                       
                                                
 
                                                                                                  
 
                     
 
                                     
 
                                                                       
 

                                                                                                  
                                                                       
 
                              
 




                                                   


               
                                                      
   
                                                                     
                              









                              
                        
   


                  


               




                                   


               
                                        



                   


               




                                                    
                                                           







                                                                                
                                                                                                                                                                                 

     
                                             





                           
                                                                              




                                                                                               
 
                                     
 






                                                          
                                                                                                  







                                                             

                        





                                            


                
     


                                 
                                                                                                   

                                 
                  
                                                                                                               

                                                
     



                       
                                                                                              

                                        
                                     
           






                                                                                     


           


                                                                                                                                    
                                                                          
                                                          







                                                                                                                    

             
       
                           

       
   
 








                                                                              


               
                                                                                       
   


                                                                      
   
 


               
                             
   
                              

   



                                                                                      
   


                                                                            

   



                                                
   

                           
 





                                                                                               

   



                                               
   

                                               
     
                                          

     
                                                                                                               

   
                                                                        
   



                                                                                                                

   
                                                        
   





                                                               

   
                                                    
   


                                                                                                

   
                                                                             
   

                                                                         

   
     
                                                                                                                        
        
                                                                                                
     
                                                                                     
                                                                                             
   
                                                                         
                                                                      
                                                                                                 
                                                              

       
     
                       
                                                                                                           
                           


           
                         
     
 


                                                                                      
 
                                          



                                         
 

                                                                                                  
     
                                                                    
     
 
                                              
                                      

   
                                                                                                         


                                                      
                                                
       
                                                                     
















                                                                                                             


               

                                                                                                     
   
                                                                
     


                                             
                                                                                                
       
     

   


               

                                                                                                   
   

                       
                                                                        
                                                                     

                                           







                                   
                                                             
         
                                   
           





                                                   
                                                                                                                    



                                      


           
     
 

                                
                                                      
       
                                                                     
                                           
         
                                   




                                                                                                               

         

                                                                            


     


                                                                     
                             

                                                    








                                         



                 


               

                                                                       
                                               




               
                                           






                                
                                                 
   
                                






























                                                                             















                                                            







                                                                   




                                                                    


               







                                       



                                                    

                                                   

   


               

                                              
   

                                                                      

   





                                                

       
                                                                        



                                                  














                                 

                                     
                   
                         

   




















                                                    





























                                                                                                         
     


                         
                                
   
                                                              


                                                                                                
                                                                        





                                                                       








                                                                            
                                                            
       


                                                                                      
         




                                                             
 


                                       
         












                                                                                
                                                                        






                                                                                
                                                                        
       
                               







                                         
                                                                        










                                                        
   




                         
                                                  
   




                                                                                            
     

                       
 

                                                                                                
                                                               
                                                                         

     
                                                           
     
                                     

     
                                                             
     
                                      






                                                              
                                                                               


                                  
                                                    
                            
         
                                                                    




                                                           
                                                            







                                    
                                                                               


                                  
                                                        
         
                                            









































                                                                               
                                                                                 
     


                                                                             

     
                                                                   
     

                                                                 
       
                                           
         
                                                    
           
                                                 


                      

           
       

                   

     



                                                                        
                                              
         

                                                                             
           
                                                                                                                                
           
 
                                                                          



         

                                                                     
                                                                                    









                                             
                                                                             
     
                                                                               

                                  


                                                     



                                         
                   

           
                                                                               
                              
           
                                                                

           



                                   





                                                 
                                   

                                                                               
                              
           
                                                                 



            







                                           



         
                                       
     
                                             

     
                                                                         
     
                                                                
     
 



                                               
     
                        


                                       
                                                                
       



                             




                                          








                                     
     
   
 








                                                                                         
                                                            
 
                                           
 

                                                                                             

                                 
                                           







                                             





                                                               
     
                            

     
                                              






                             
                                                                         

     








                                                                 

                                                                                     
                                                                            
                                                                  
 

                                                                                             

                                                                                                   
                                                                          



                                  






                                     

















                                                                   









                                                                   




                                                                        
































                                                                                                           




                                                                          
















                                                                                                      




                                                                          




                                                      
                                   








                                                                        
                                                 
       
                                              
                                     




                                                               

















                                                                                            




                                                                         


       














                                                                          




                                                                    


       

                                                
                                                                     














                                                            
                                                                                          








                                                                     
                                                                     
                                                             
 





























                                                                              
                                                                                               



                          
                               





                                                                  














                                                                      
                               


                         





                                                                






































                                                                                                                       












                                                                                                           





























                                                                                                     












                                                                                                               
   
 
/**
 * Copyright (c) 2004 - 2010 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.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.CDOIDAndVersion;
import org.eclipse.emf.cdo.common.model.CDOPackageUnit;
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.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.model.InternalCDOPackageRegistry;
import org.eclipse.emf.cdo.spi.common.model.InternalCDOPackageUnit;
import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision;
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.ReadOnlyException;
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.CDOViewInvalidationEvent;

import org.eclipse.emf.internal.cdo.CDODeltaNotificationImpl;
import org.eclipse.emf.internal.cdo.CDOInvalidationNotificationImpl;
import org.eclipse.emf.internal.cdo.CDONotificationBuilder;
import org.eclipse.emf.internal.cdo.CDOStateMachine;
import org.eclipse.emf.internal.cdo.bundle.OM;
import org.eclipse.emf.internal.cdo.messages.Messages;

import org.eclipse.net4j.util.ReflectUtil.ExcludeFromDump;
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.IRWLockManager.LockType;
import org.eclipse.net4j.util.event.IListener;
import org.eclipse.net4j.util.event.Notifier;
import org.eclipse.net4j.util.lifecycle.LifecycleUtil;
import org.eclipse.net4j.util.om.trace.ContextTracer;
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.Notification;
import org.eclipse.emf.common.notify.NotificationChain;
import org.eclipse.emf.common.notify.impl.NotificationImpl;
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.RefreshSessionResult;
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 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.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentMap;

/**
 * @author Eike Stepper
 */
public class CDOViewImpl extends AbstractCDOView
{
  private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG_VIEW, CDOViewImpl.class);

  private int viewID;

  private InternalCDOSession session;

  private CDOFeatureAnalyzer featureAnalyzer = CDOFeatureAnalyzer.NOOP;

  private ChangeSubscriptionManager changeSubscriptionManager = createChangeSubscriptionManager();

  private AdapterManager adapterPolicyManager = createAdapterManager();

  private OptionsImpl options;

  private long lastUpdateTime;

  @ExcludeFromDump
  private Object lastUpdateTimeLock = new Object();

  /**
   * @since 2.0
   */
  public CDOViewImpl(CDOBranch branch, long timeStamp)
  {
    super(branch.getPoint(timeStamp), CDOUtil.isLegacyModeDefault());
    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;
  }

  /**
   * @since 2.0
   */
  public InternalCDOSession getSession()
  {
    return session;
  }

  /**
   * @since 2.0
   */
  public void setSession(InternalCDOSession session)
  {
    this.session = session;
  }

  public boolean setBranchPoint(CDOBranchPoint branchPoint)
  {
    long timeStamp = branchPoint.getTimeStamp();
    long creationTimeStamp = getSession().getRepositoryInfo().getCreationTime();
    if (timeStamp != UNSPECIFIED_DATE && timeStamp < creationTimeStamp)
    {
      throw new IllegalArgumentException(
          MessageFormat
              .format(
                  "timeStamp ({0}) < repository creation time ({1})", CDOCommonUtil.formatTimeStamp(timeStamp), CDOCommonUtil.formatTimeStamp(creationTimeStamp))); //$NON-NLS-1$
    }

    if (branchPoint.equals(getBranchPoint()))
    {
      return false;
    }

    if (TRACER.isEnabled())
    {
      TRACER.format("Changing view target to {0}", branchPoint); //$NON-NLS-1$
    }

    List<InternalCDOObject> invalidObjects = getInvalidObjects(timeStamp);
    CDOSessionProtocol sessionProtocol = getSession().getSessionProtocol();
    boolean[] existanceFlags = sessionProtocol.changeView(viewID, branchPoint, invalidObjects);

    basicSetBranchPoint(branchPoint);

    int i = 0;
    for (InternalCDOObject invalidObject : invalidObjects)
    {
      boolean existanceFlag = existanceFlags[i++];
      if (existanceFlag)
      {
        // --> PROXY
        CDOStateMachine.INSTANCE.invalidate(invalidObject, null, CDOBranchPoint.UNSPECIFIED_DATE);
      }
      else
      {
        // --> DETACHED
        CDOStateMachine.INSTANCE.detachRemote(invalidObject);
      }
    }

    clearRootResource();

    IListener[] listeners = getListeners();
    if (listeners != null)
    {
      fireViewTargetChangedEvent(listeners);
    }

    return true;
  }

  /**
   * @throws InterruptedException
   * @since 2.0
   */
  public void lockObjects(Collection<? extends CDOObject> objects, LockType lockType, long timeout)
      throws InterruptedException
  {
    checkActive();
    checkState(getTimeStamp() == CDOBranchPoint.UNSPECIFIED_DATE, "Locking not supported for historial views");

    synchronized (session.getInvalidationLock())
    {
      getLock().lock();

      try
      {
        Map<CDOID, InternalCDORevision> revisions = new HashMap<CDOID, InternalCDORevision>();
        for (CDOObject object : objects)
        {
          if (!FSMUtil.isNew(object))
          {
            InternalCDORevision revision = (InternalCDORevision)object.cdoRevision();
            if (revision == null)
            {
              revision = CDOStateMachine.INSTANCE.read((InternalCDOObject)object);
            }

            revisions.put(revision.getID(), revision);
          }
        }

        Map<CDOBranch, Map<CDOID, InternalCDORevision>> viewedRevisions = new HashMap<CDOBranch, Map<CDOID, InternalCDORevision>>();
        viewedRevisions.put(getBranch(), revisions);

        CDOSessionProtocol sessionProtocol = session.getSessionProtocol();
        long lastUpdateTime = session.getLastUpdateTime();
        RefreshSessionResult result = sessionProtocol.lockObjects(lastUpdateTime, viewedRevisions, viewID, lockType,
            timeout);

        registerPackageUnits(result.getPackageUnits());

        InternalCDOView view = this;
        List<InternalCDOView> views = Collections.singletonList(view);
        session.processRefreshSessionResult(result, getBranch(), views, viewedRevisions);
      }
      finally
      {
        getLock().unlock();
      }
    }
  }

  private void registerPackageUnits(List<CDOPackageUnit> packageUnits)
  {
    InternalCDOPackageRegistry packageRegistry = session.getPackageRegistry();
    for (CDOPackageUnit newPackageUnit : packageUnits)
    {
      packageRegistry.putPackageUnit((InternalCDOPackageUnit)newPackageUnit);
    }
  }

  /**
   * @since 2.0
   */
  public void unlockObjects(Collection<? extends CDOObject> objects, LockType lockType)
  {
    checkActive();
    CDOSessionProtocol sessionProtocol = session.getSessionProtocol();
    sessionProtocol.unlockObjects(this, objects, lockType);
  }

  /**
   * @since 2.0
   */
  public void unlockObjects()
  {
    unlockObjects(null, null);
  }

  /**
   * @since 2.0
   */
  public boolean isObjectLocked(CDOObject object, LockType lockType, boolean byOthers)
  {
    checkActive();
    CDOSessionProtocol sessionProtocol = session.getSessionProtocol();
    return sessionProtocol.isObjectLocked(this, object, lockType, byOthers);
  }

  /**
   * @since 2.0
   */
  public CDOFeatureAnalyzer getFeatureAnalyzer()
  {
    return featureAnalyzer;
  }

  /**
   * @since 2.0
   */
  public void setFeatureAnalyzer(CDOFeatureAnalyzer featureAnalyzer)
  {
    this.featureAnalyzer = featureAnalyzer == null ? CDOFeatureAnalyzer.NOOP : 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 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);
  }

  protected CDOBranchPoint getBranchPointForID(CDOID id)
  {
    if (isSticky())
    {
      return getBranch().getPoint(session.getLastUpdateTime());
    }

    return this;
  }

  public 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);
  }

  /**
   * Turns registered objects into proxies and synchronously delivers invalidation events to registered event listeners.
   * <p>
   * Note that this method can block for an uncertain amount of time on the reentrant view lock!
   */
  public void invalidate(long lastUpdateTime, List<CDORevisionKey> allChangedObjects,
      List<CDOIDAndVersion> allDetachedObjects, Map<CDOID, InternalCDORevision> oldRevisions)
  {
    Map<CDOObject, Pair<CDORevision, CDORevisionDelta>> conflicts = null;
    List<CDORevisionDelta> deltas = new ArrayList<CDORevisionDelta>();
    Map<CDOObject, CDORevisionDelta> revisionDeltas = new HashMap<CDOObject, CDORevisionDelta>();
    Set<CDOObject> detachedObjects = new HashSet<CDOObject>();

    try
    {
      getLock().lock();
      conflicts = invalidate(lastUpdateTime, allChangedObjects, allDetachedObjects, deltas, revisionDeltas,
          detachedObjects);
    }
    finally
    {
      getLock().unlock();
    }

    sendInvalidationNotifications(revisionDeltas.keySet(), detachedObjects);
    fireInvalidationEvent(lastUpdateTime, Collections.unmodifiableMap(revisionDeltas),
        Collections.unmodifiableSet(detachedObjects));

    // First handle the conflicts, if any.
    if (conflicts != null)
    {
      handleConflicts(conflicts, deltas);
    }

    // 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);
    setLastUpdateTime(lastUpdateTime);
  }

  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 void sendDeltaNotifications(List<CDORevisionDelta> deltas, Set<CDOObject> detachedObjects,
      Map<CDOID, InternalCDORevision> oldRevisions)
  {
    if (deltas != null)
    {
      CDONotificationBuilder builder = new CDONotificationBuilder(this);
      ConcurrentMap<CDOID, InternalCDOObject> objects = getObjects();
      for (CDORevisionDelta delta : deltas)
      {
        CDOID id = delta.getID();

        InternalCDOObject object;
        synchronized (objects)
        {
          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)
    {
      for (CDOObject detachedObject : detachedObjects)
      {
        InternalCDOObject object = (InternalCDOObject)detachedObject;
        if (object.eNotificationRequired())
        {
          // if (!isLocked(object))
          {
            NotificationImpl notification = new CDODeltaNotificationImpl(object, CDONotification.DETACH_OBJECT,
                Notification.NO_FEATURE_ID, null, null);
            notification.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 ChangeSubscriptionManager createChangeSubscriptionManager()
  {
    return new ChangeSubscriptionManager(this);
  }

  /**
   * @since 2.0
   */
  public AdapterManager getAdapterManager()
  {
    return adapterPolicyManager;
  }

  /**
   * @since 2.0
   */
  protected AdapterManager createAdapterManager()
  {
    return new AdapterManager();
  }

  /**
   * @since 2.0
   */
  public void handleAddAdapter(InternalCDOObject eObject, Adapter adapter)
  {
    if (!FSMUtil.isNew(eObject))
    {
      subscribe(eObject, adapter);
    }

    adapterPolicyManager.attachAdapter(eObject, adapter);
  }

  /**
   * @since 2.0
   */
  public void handleRemoveAdapter(InternalCDOObject eObject, Adapter adapter)
  {
    if (!FSMUtil.isNew(eObject))
    {
      unsubscribe(eObject, adapter);
    }

    adapterPolicyManager.detachAdapter(eObject, adapter);
  }

  /**
   * @since 2.0
   */
  public void subscribe(EObject eObject, Adapter adapter)
  {
    changeSubscriptionManager.subscribe(eObject, adapter);
  }

  /**
   * @since 2.0
   */
  public void unsubscribe(EObject eObject, Adapter adapter)
  {
    changeSubscriptionManager.unsubscribe(eObject, adapter);
  }

  /**
   * @since 2.0
   */
  public boolean hasSubscription(CDOID id)
  {
    return changeSubscriptionManager.getSubcribeObject(id) != null;
  }

  /**
   * @since 2.0
   */
  protected 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
  {
    CDOSessionProtocol sessionProtocol = session.getSessionProtocol();
    sessionProtocol.openView(viewID, this, isReadOnly());
  }

  /**
   * @since 2.0
   */
  @Override
  protected void doDeactivate() throws Exception
  {
    try
    {
      CDOSessionProtocol sessionProtocol = session.getSessionProtocol();
      if (LifecycleUtil.isActive(sessionProtocol))
      {
        sessionProtocol.closeView(viewID);
      }
    }
    catch (Exception ex)
    {
      OM.LOG.error(ex);
    }

    try
    {
      session.viewDetached(this);
    }
    catch (Exception ex)
    {
      OM.LOG.error(ex);
    }

    changeSubscriptionManager = null;
    featureAnalyzer = null;
    options = null;
    super.doDeactivate();
  }

  public long getLastUpdateTime()
  {
    synchronized (lastUpdateTimeLock)
    {
      return lastUpdateTime;
    }
  }

  public void setLastUpdateTime(long lastUpdateTime)
  {
    synchronized (lastUpdateTimeLock)
    {
      if (this.lastUpdateTime < lastUpdateTime)
      {
        this.lastUpdateTime = lastUpdateTime;
      }

      lastUpdateTimeLock.notifyAll();
    }
  }

  public boolean waitForUpdate(long updateTime, long timeoutMillis)
  {
    long end = timeoutMillis == NO_TIMEOUT ? Long.MAX_VALUE : System.currentTimeMillis() + timeoutMillis;
    for (;;)
    {
      synchronized (lastUpdateTimeLock)
      {
        if (lastUpdateTime >= updateTime)
        {
          return true;
        }

        long now = System.currentTimeMillis();
        if (now >= end)
        {
          return false;
        }

        try
        {
          lastUpdateTimeLock.wait(end - now);
        }
        catch (InterruptedException ex)
        {
          throw WrappedException.wrap(ex);
        }
      }
    }
  }

  /**
   * @author Simon McDuff
   * @since 2.0
   */
  protected class AdapterManager
  {
    private Set<CDOObject> objects = new HashBag<CDOObject>();

    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);
        }
      }
    }

    protected synchronized 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);
        }
      }
    }

    protected synchronized void detachObject(CDOObject object)
    {
      while (objects.remove(object))
      {
        // Do nothing
      }
    }

    protected synchronized void attachAdapter(CDOObject object, Adapter adapter)
    {
      if (options().getStrongReferencePolicy().isValid(object, adapter))
      {
        objects.add(object);
      }
    }

    protected synchronized void detachAdapter(CDOObject object, Adapter adapter)
    {
      if (options().getStrongReferencePolicy().isValid(object, adapter))
      {
        objects.remove(object);
      }
    }

    public synchronized void reset()
    {
      // Keep the object in memory
      Set<CDOObject> oldObject = objects;
      objects = new HashBag<CDOObject>();
      if (options().getStrongReferencePolicy() != CDOAdapterPolicy.NONE)
      {
        InternalCDOObject objects[] = getObjectsArray();
        for (int i = 0; i < objects.length; i++)
        {
          InternalCDOObject object = objects[i];
          attachObject(object);
        }
      }

      oldObject.clear();
    }
  }

  /**
   * @author Simon McDuff
   * @since 2.0
   */
  protected static class ChangeSubscriptionManager
  {
    private CDOViewImpl view;

    private Map<CDOID, SubscribeEntry> subscriptions = new HashMap<CDOID, SubscribeEntry>();

    public ChangeSubscriptionManager(CDOViewImpl view)
    {
      this.view = view;
    }

    public void committedTransaction(CDOTransaction transaction, CDOCommitContext commitContext)
    {
      handleNewObjects(commitContext.getNewObjects().values());
      handleDetachedObjects(commitContext.getDetachedObjects().values());
    }

    public void subscribe(EObject eObject, Adapter adapter)
    {
      subscribe(eObject, adapter, 1);
    }

    public void unsubscribe(EObject eObject, Adapter adapter)
    {
      subscribe(eObject, adapter, -1);
    }

    /**
     * Register to the server all objects from the active list
     */
    protected void notifyChangeSubcriptionPolicy()
    {
      boolean policiesPresent = view.options().hasChangeSubscriptionPolicies();
      synchronized (subscriptions)
      {
        subscriptions.clear();
        List<CDOID> cdoIDs = new ArrayList<CDOID>();
        if (policiesPresent)
        {
          for (InternalCDOObject cdoObject : view.getObjectsArray())
          {
            int count = getNumberOfValidAdapter(cdoObject);
            if (count > 0)
            {
              cdoIDs.add(cdoObject.cdoID());
              addEntry(cdoObject.cdoID(), cdoObject, count);
            }
          }
        }

        request(cdoIDs, true, true);
      }
    }

    protected void handleDetachedObjects(Collection<CDOObject> detachedObjects)
    {
      synchronized (subscriptions)
      {
        for (CDOObject detachedObject : detachedObjects)
        {
          CDOID id = detachedObject.cdoID();
          SubscribeEntry entry = subscriptions.get(id);
          if (entry != null)
          {
            detachObject(id);
          }
        }
      }
    }

    protected void handleNewObjects(Collection<? extends CDOObject> newObjects)
    {
      synchronized (subscriptions)
      {
        for (CDOObject object : newObjects)
        {
          InternalCDOObject cdoDetachedObject = (InternalCDOObject)object;
          if (cdoDetachedObject != null)
          {
            int count = getNumberOfValidAdapter(cdoDetachedObject);
            if (count > 0)
            {
              subscribe(cdoDetachedObject.cdoID(), cdoDetachedObject, count);
            }
          }
        }
      }
    }

    protected InternalCDOObject getSubcribeObject(CDOID id)
    {
      synchronized (subscriptions)
      {
        SubscribeEntry entry = subscriptions.get(id);
        if (entry != null)
        {
          return entry.getObject();
        }
      }

      return null;
    }

    protected void request(List<CDOID> ids, boolean clear, boolean subscribeMode)
    {
      CDOSessionProtocol sessionProtocol = view.session.getSessionProtocol();
      int viewID = view.getViewID();
      sessionProtocol.changeSubscription(viewID, ids, subscribeMode, clear);
    }

    protected int getNumberOfValidAdapter(InternalCDOObject object)
    {
      int count = 0;
      if (!FSMUtil.isTransient(object) && !FSMUtil.isNew(object))
      {
        if (object.eNotificationRequired())
        {
          for (Adapter adapter : object.eAdapters())
          {
            if (shouldSubscribe(object, adapter))
            {
              count++;
            }
          }
        }
      }

      return count;
    }

    private void subscribe(EObject eObject, Adapter adapter, int adjust)
    {
      synchronized (subscriptions)
      {
        if (shouldSubscribe(eObject, adapter))
        {
          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 : view.options().getChangeSubscriptionPolicies())
      {
        if (policy.isValid(eObject, adapter))
        {
          return true;
        }
      }

      return false;
    }

    private void subscribe(CDOID id, InternalCDOObject cdoObject, int adjust)
    {
      boolean policiesPresent = view.options().hasChangeSubscriptionPolicies();
      synchronized (subscriptions)
      {
        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
     */
    protected static final class SubscribeEntry
    {
      private int count;

      private InternalCDOObject object;

      public SubscribeEntry(InternalCDOObject object, int count)
      {
        this.count = count;
        this.object = object;
      }

      public InternalCDOObject getObject()
      {
        return object;
      }

      public int getCount()
      {
        return count;
      }

      public void setCount(int count)
      {
        this.count = count;
      }
    }
  }

  /**
   * @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 Eike Stepper
   * @since 2.0
   */
  protected class OptionsImpl extends Notifier implements Options
  {
    private boolean invalidationNotificationEnabled;

    private CDOInvalidationPolicy invalidationPolicy = CDOInvalidationPolicy.DEFAULT;

    private CDORevisionPrefetchingPolicy revisionPrefetchingPolicy = CDOUtil
        .createRevisionPrefetchingPolicy(NO_REVISION_PREFETCHING);

    private CDOStaleReferencePolicy staleReferencePolicy = CDOStaleReferencePolicy.EXCEPTION;

    private HashBag<CDOAdapterPolicy> changeSubscriptionPolicies = new HashBag<CDOAdapterPolicy>();

    private CDOAdapterPolicy strongReferencePolicy = CDOAdapterPolicy.ALL;

    public OptionsImpl()
    {
      setCacheReferenceType(null);
    }

    public CDOViewImpl getContainer()
    {
      return CDOViewImpl.this;
    }

    public CDOInvalidationPolicy getInvalidationPolicy()
    {
      return invalidationPolicy;
    }

    public void setInvalidationPolicy(CDOInvalidationPolicy policy)
    {
      if (invalidationPolicy != policy)
      {
        invalidationPolicy = policy;
        IListener[] listeners = getListeners();
        if (listeners != null)
        {
          fireEvent(new InvalidationPolicyEventImpl(), listeners);
        }
      }
    }

    public boolean isInvalidationNotificationEnabled()
    {
      return invalidationNotificationEnabled;
    }

    public void setInvalidationNotificationEnabled(boolean enabled)
    {
      if (invalidationNotificationEnabled != enabled)
      {
        invalidationNotificationEnabled = enabled;
        IListener[] listeners = getListeners();
        if (listeners != null)
        {
          fireEvent(new InvalidationNotificationEventImpl(), listeners);
        }
      }
    }

    public boolean hasChangeSubscriptionPolicies()
    {
      synchronized (changeSubscriptionPolicies)
      {
        return !changeSubscriptionPolicies.isEmpty();
      }
    }

    public CDOAdapterPolicy[] getChangeSubscriptionPolicies()
    {
      synchronized (changeSubscriptionPolicies)
      {
        return changeSubscriptionPolicies.toArray(new CDOAdapterPolicy[changeSubscriptionPolicies.size()]);
      }
    }

    public void addChangeSubscriptionPolicy(CDOAdapterPolicy policy)
    {
      boolean changed = false;
      synchronized (changeSubscriptionPolicies)
      {
        if (changeSubscriptionPolicies.add(policy))
        {
          changeSubscriptionManager.notifyChangeSubcriptionPolicy();
          changed = true;
        }
      }

      if (changed)
      {
        IListener[] listeners = getListeners();
        if (listeners != null)
        {
          fireEvent(new ChangeSubscriptionPoliciesEventImpl(), listeners);
        }
      }
    }

    public void removeChangeSubscriptionPolicy(CDOAdapterPolicy policy)
    {
      boolean changed = false;
      synchronized (changeSubscriptionPolicies)
      {
        if (changeSubscriptionPolicies.remove(policy) && !changeSubscriptionPolicies.contains(policy))
        {
          changeSubscriptionManager.notifyChangeSubcriptionPolicy();
          changed = true;
        }
      }

      if (changed)
      {
        IListener[] listeners = getListeners();
        if (listeners != null)
        {
          fireEvent(new ChangeSubscriptionPoliciesEventImpl(), listeners);
        }
      }
    }

    public CDOAdapterPolicy getStrongReferencePolicy()
    {
      return strongReferencePolicy;
    }

    public void setStrongReferencePolicy(CDOAdapterPolicy adapterPolicy)
    {
      if (adapterPolicy == null)
      {
        adapterPolicy = CDOAdapterPolicy.ALL;
      }

      if (strongReferencePolicy != adapterPolicy)
      {
        strongReferencePolicy = adapterPolicy;
        adapterPolicyManager.reset();
        IListener[] listeners = getListeners();
        if (listeners != null)
        {
          fireEvent(new ReferencePolicyEventImpl(), listeners);
        }
      }
    }

    public CDORevisionPrefetchingPolicy getRevisionPrefetchingPolicy()
    {
      return revisionPrefetchingPolicy;
    }

    public void setRevisionPrefetchingPolicy(CDORevisionPrefetchingPolicy prefetchingPolicy)
    {
      if (prefetchingPolicy == null)
      {
        prefetchingPolicy = CDORevisionPrefetchingPolicy.NO_PREFETCHING;
      }

      if (revisionPrefetchingPolicy != prefetchingPolicy)
      {
        revisionPrefetchingPolicy = prefetchingPolicy;
        IListener[] listeners = getListeners();
        if (listeners != null)
        {
          fireEvent(new RevisionPrefetchingPolicyEventImpl(), listeners);
        }
      }
    }

    public CDOStaleReferencePolicy getStaleReferenceBehaviour()
    {
      return staleReferencePolicy;
    }

    public void setStaleReferenceBehaviour(CDOStaleReferencePolicy policy)
    {
      if (policy == null)
      {
        policy = CDOStaleReferencePolicy.EXCEPTION;
      }

      if (staleReferencePolicy != policy)
      {
        staleReferencePolicy = policy;
        IListener[] listeners = getListeners();
        if (listeners != null)
        {
          fireEvent(new StaleReferencePolicyEventImpl(), listeners);
        }
      }
    }

    public ReferenceType getCacheReferenceType()
    {
      ConcurrentMap<CDOID, InternalCDOObject> objects = getObjects();
      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)
    {
      if (referenceType == null)
      {
        referenceType = ReferenceType.SOFT;
      }

      ConcurrentMap<CDOID, InternalCDOObject> objects = getObjects();
      ReferenceValueMap<CDOID, InternalCDOObject> newObjects;

      switch (referenceType)
      {
      case STRONG:
        if (objects instanceof ReferenceValueMap.Strong<?, ?>)
        {
          return false;
        }

        newObjects = new ReferenceValueMap.Strong<CDOID, InternalCDOObject>();
        break;

      case SOFT:
        if (objects instanceof ReferenceValueMap.Soft<?, ?>)
        {
          return false;
        }

        newObjects = new ReferenceValueMap.Soft<CDOID, InternalCDOObject>();
        break;

      case WEAK:
        if (objects instanceof ReferenceValueMap.Weak<?, ?>)
        {
          return false;
        }

        newObjects = new ReferenceValueMap.Weak<CDOID, InternalCDOObject>();
        break;

      default:
        throw new IllegalArgumentException(Messages.getString("CDOViewImpl.29")); //$NON-NLS-1$
      }

      if (objects == null)
      {
        setObjects(newObjects);
        IListener[] listeners = getListeners();
        if (listeners != null)
        {
          fireEvent(new CacheReferenceTypeEventImpl(), listeners);
        }

        return true;
      }

      for (Entry<CDOID, InternalCDOObject> entry : objects.entrySet())
      {
        InternalCDOObject object = entry.getValue();
        if (object != null)
        {
          newObjects.put(entry.getKey(), object);
        }
      }

      ConcurrentMap<CDOID, InternalCDOObject> oldObjects = objects;
      synchronized (objects)
      {
        setObjects(newObjects);
      }

      oldObjects.clear();
      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 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 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 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);
      }
    }
  }
}

Back to the top