Skip to main content
summaryrefslogblamecommitdiffstats
blob: 0c8f68d62992b5fc7cfab54aa565d834dfb32bca (plain) (tree)
1
2
  
                                                                     
















                                                                        
                                                                          
                                                          




                                                         
                                                                              



                                                                
                                                               
                                                           
                                                                  

                                                                       
                                                     






                                                                          
                                                         




                                                             
                                          








                                                              

                                                       
 



                                                
                         
                      
                     
                     




                                                 
                                                                        














                                                                                                



                                   




                                                   
                                                                                  


                                                             








                                                                                            

































                                                                                                         




                                                     












                                            




                                                      

















                                       




                                      
















                                               
                                                                                                                                   












































                                                                                
             







                                     




















                                                      









                                     




                             









                                        



                                                                    




                                         




                               







































                                                                                    





                              








                                           







                                         










                                                         

                                                                                                                                           
   
                                                                                              
                                                                                         
     








                                                                                                      
                                                                                                                                               















                                                                                                                      
                                                                                          



                                                                          
                                                                              

     
                                                                                    

   
                                                                                                                                 







                                                                
                                                                                                                                      



                                                              
                                                                                                                                                            






                                                                                   
             

                                                                               




                                                                                                      

                         
                                                          


     


                                                                               
                                              

   


                                                                                                               
                                              

   
                                                                                              










                                  

                                                                    
     

                                                                                
 
                                                             
       
                                                            
       
     
 
                                                                    
 






                                                                                                   
 









                                                                                   
                                                             


                                     

                                                                          






                                                                                     

                                                                                   




                                                      
                                                           
       


                                                                   
         




                                                        
           
                                                                              
           





















                                                                                                            
           
                        



           

                

   
                                                               
   

                                                                          

                                   





                                     




                                                     

                          
       



                                                                                            





















                                                                                                                     

                                                
   
                                                   

   


                          









                                                              





                                                                                   




































                                                             













































































































                                                                                                         
                                                  



































                                                                                                            
 
/*
 * Copyright (c) 2007-2016 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 - bug 201266
 *    Simon McDuff - bug 230832
 *    Simon McDuff - bug 233490
 *    Simon McDuff - bug 213402
 */
package org.eclipse.emf.cdo.internal.server;

import org.eclipse.emf.cdo.common.CDOCommonRepository;
import org.eclipse.emf.cdo.common.CDOCommonSession;
import org.eclipse.emf.cdo.common.branch.CDOBranch;
import org.eclipse.emf.cdo.common.branch.CDOBranchChangedEvent.ChangeKind;
import org.eclipse.emf.cdo.common.branch.CDOBranchManager;
import org.eclipse.emf.cdo.common.branch.CDOBranchPoint;
import org.eclipse.emf.cdo.common.commit.CDOCommitInfo;
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.protocol.CDOProtocol.CommitNotificationInfo;
import org.eclipse.emf.cdo.common.protocol.CDOProtocolConstants;
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.CDORevisionProvider;
import org.eclipse.emf.cdo.common.revision.CDORevisionUtil;
import org.eclipse.emf.cdo.common.revision.delta.CDORevisionDelta;
import org.eclipse.emf.cdo.common.security.CDOPermission;
import org.eclipse.emf.cdo.internal.common.commit.DelegatingCommitInfo;
import org.eclipse.emf.cdo.internal.server.bundle.OM;
import org.eclipse.emf.cdo.server.IPermissionManager;
import org.eclipse.emf.cdo.server.IView;
import org.eclipse.emf.cdo.session.remote.CDORemoteSessionMessage;
import org.eclipse.emf.cdo.spi.common.branch.InternalCDOBranch;
import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevision;
import org.eclipse.emf.cdo.spi.common.revision.InternalCDORevisionManager;
import org.eclipse.emf.cdo.spi.server.ISessionProtocol;
import org.eclipse.emf.cdo.spi.server.InternalRepository;
import org.eclipse.emf.cdo.spi.server.InternalSession;
import org.eclipse.emf.cdo.spi.server.InternalSessionManager;
import org.eclipse.emf.cdo.spi.server.InternalTransaction;
import org.eclipse.emf.cdo.spi.server.InternalView;

import org.eclipse.net4j.util.AdapterUtil;
import org.eclipse.net4j.util.ReflectUtil.ExcludeFromDump;
import org.eclipse.net4j.util.collection.IndexedList;
import org.eclipse.net4j.util.container.Container;
import org.eclipse.net4j.util.event.EventUtil;
import org.eclipse.net4j.util.event.IListener;
import org.eclipse.net4j.util.lifecycle.ILifecycle;
import org.eclipse.net4j.util.lifecycle.LifecycleEventAdapter;
import org.eclipse.net4j.util.lifecycle.LifecycleUtil;
import org.eclipse.net4j.util.om.log.OMLogger;
import org.eclipse.net4j.util.registry.HashMapRegistry;
import org.eclipse.net4j.util.registry.IRegistry;

import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;

import java.text.MessageFormat;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author Eike Stepper
 */
public class Session extends Container<IView> implements InternalSession
{
  private InternalSessionManager manager;

  private ISessionProtocol protocol;

  private int sessionID;

  private String userID;

  private boolean passiveUpdateEnabled = true;

  private PassiveUpdateMode passiveUpdateMode = PassiveUpdateMode.INVALIDATIONS;

  private LockNotificationMode lockNotificationMode = LockNotificationMode.IF_REQUIRED_BY_VIEWS;

  private boolean openOnClientSide;

  private long firstUpdateTime;

  private long lastUpdateTime;

  @ExcludeFromDump
  private Object lastUpdateTimeLock = new Object();

  private Map<Integer, InternalView> views = new HashMap<Integer, InternalView>();

  private AtomicInteger lastTempViewID = new AtomicInteger();

  private final IRegistry<String, Object> properties = new HashMapRegistry<String, Object>()
  {
    @Override
    public void setAutoCommit(boolean autoCommit)
    {
      throw new UnsupportedOperationException();
    }
  };

  @ExcludeFromDump
  private IListener protocolListener = new LifecycleEventAdapter()
  {
    @Override
    protected void onDeactivated(ILifecycle lifecycle)
    {
      deactivate();
    }
  };

  private boolean subscribed;

  /**
   * @since 2.0
   */
  public Session(InternalSessionManager manager, ISessionProtocol protocol, int sessionID, String userID)
  {
    this.manager = manager;
    this.protocol = protocol;
    this.sessionID = sessionID;
    this.userID = userID;

    EventUtil.addListener(protocol, protocolListener);
    activate();
  }

  /**
   * @since 2.0
   */
  public Options options()
  {
    return this;
  }

  public final IRegistry<String, Object> properties()
  {
    return properties;
  }

  /**
   * @since 2.0
   */
  public CDOCommonSession getContainer()
  {
    return this;
  }

  public InternalSessionManager getManager()
  {
    return manager;
  }

  public CDOBranchManager getBranchManager()
  {
    return manager.getRepository().getBranchManager();
  }

  public ISessionProtocol getProtocol()
  {
    return protocol;
  }

  public int getSessionID()
  {
    return sessionID;
  }

  /**
   * @since 2.0
   */
  public String getUserID()
  {
    return userID;
  }

  public void setUserID(String userID)
  {
    this.userID = userID;
  }

  /**
   * @since 2.0
   */
  public boolean isSubscribed()
  {
    return subscribed;
  }

  /**
   * @since 2.0
   */
  public void setSubscribed(boolean subscribed)
  {
    checkActive();
    if (this.subscribed != subscribed)
    {
      this.subscribed = subscribed;
      byte opcode = subscribed ? CDOProtocolConstants.REMOTE_SESSION_SUBSCRIBED : CDOProtocolConstants.REMOTE_SESSION_UNSUBSCRIBED;
      manager.sendRemoteSessionNotification(this, opcode);
    }
  }

  /**
   * @since 2.0
   */
  public boolean isPassiveUpdateEnabled()
  {
    return passiveUpdateEnabled;
  }

  /**
   * @since 2.0
   */
  public void setPassiveUpdateEnabled(boolean passiveUpdateEnabled)
  {
    checkActive();
    this.passiveUpdateEnabled = passiveUpdateEnabled;
  }

  public PassiveUpdateMode getPassiveUpdateMode()
  {
    return passiveUpdateMode;
  }

  public void setPassiveUpdateMode(PassiveUpdateMode passiveUpdateMode)
  {
    checkActive();
    checkArg(passiveUpdateMode, "passiveUpdateMode");
    this.passiveUpdateMode = passiveUpdateMode;
  }

  public LockNotificationMode getLockNotificationMode()
  {
    return lockNotificationMode;
  }

  public void setLockNotificationMode(LockNotificationMode lockNotificationMode)
  {
    checkActive();
    checkArg(lockNotificationMode, "lockNotificationMode");
    this.lockNotificationMode = lockNotificationMode;
  }

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

  public long getFirstUpdateTime()
  {
    return firstUpdateTime;
  }

  public void setFirstUpdateTime(long firstUpdateTime)
  {
    this.firstUpdateTime = firstUpdateTime;
  }

  public boolean isOpenOnClientSide()
  {
    return openOnClientSide;
  }

  public void setOpenOnClientSide()
  {
    openOnClientSide = true;
    manager.openedOnClientSide(this);
  }

  public InternalView[] getElements()
  {
    checkActive();
    return getViews();
  }

  @Override
  public boolean isEmpty()
  {
    checkActive();

    synchronized (views)
    {
      return views.isEmpty();
    }
  }

  public InternalView[] getViews()
  {
    checkActive();
    return getViewsArray();
  }

  private InternalView[] getViewsArray()
  {
    synchronized (views)
    {
      return views.values().toArray(new InternalView[views.size()]);
    }
  }

  public InternalView getView(int viewID)
  {
    checkActive();

    synchronized (views)
    {
      return views.get(viewID);
    }
  }

  /**
   * @since 2.0
   */
  public InternalView openView(int viewID, CDOBranchPoint branchPoint)
  {
    checkActive();
    if (viewID == TEMP_VIEW_ID)
    {
      viewID = -lastTempViewID.incrementAndGet();
    }

    InternalView view = new View(this, viewID, branchPoint);
    view.activate();
    addView(view);
    return view;
  }

  /**
   * @since 2.0
   */
  public InternalTransaction openTransaction(int viewID, CDOBranchPoint branchPoint)
  {
    checkActive();
    if (viewID == TEMP_VIEW_ID)
    {
      viewID = -lastTempViewID.incrementAndGet();
    }

    InternalTransaction transaction = new Transaction(this, viewID, branchPoint);
    transaction.activate();
    addView(transaction);
    return transaction;
  }

  private void addView(InternalView view)
  {
    checkActive();
    int viewID = view.getViewID();

    synchronized (views)
    {
      views.put(viewID, view);
    }

    fireElementAddedEvent(view);
  }

  /**
   * @since 2.0
   */
  public void viewClosed(InternalView view)
  {
    int viewID = view.getViewID();
    InternalView removedView;

    synchronized (views)
    {
      removedView = views.remove(viewID);
    }

    if (removedView == view)
    {
      view.doClose();
      fireElementRemovedEvent(view);
    }
  }

  /**
   * TODO I can't see how recursion is controlled/limited
   *
   * @since 2.0
   */
  public void collectContainedRevisions(InternalCDORevision revision, CDOBranchPoint branchPoint, int referenceChunk, Set<CDOID> revisions,
      List<CDORevision> additionalRevisions)
  {
    InternalCDORevisionManager revisionManager = manager.getRepository().getRevisionManager();
    for (EStructuralFeature feature : revision.getClassInfo().getAllPersistentFeatures())
    {
      // TODO Clarify feature maps
      if (feature instanceof EReference && !feature.isMany() && ((EReference)feature).isContainment())
      {
        Object value = revision.getValue(feature);
        if (value instanceof CDOID)
        {
          CDOID id = (CDOID)value;
          if (!CDOIDUtil.isNull(id) && !revisions.contains(id))
          {
            InternalCDORevision containedRevision = revisionManager.getRevision(id, branchPoint, referenceChunk, CDORevision.DEPTH_NONE, true);
            revisions.add(id);
            additionalRevisions.add(containedRevision);

            // Recurse
            collectContainedRevisions(containedRevision, branchPoint, referenceChunk, revisions, additionalRevisions);
          }
        }
      }
    }
  }

  public CDOID provideCDOID(Object idObject)
  {
    return (CDOID)idObject;
  }

  public CDOPermission getPermission(CDORevision revision, CDOBranchPoint securityContext)
  {
    IPermissionManager permissionManager = manager.getPermissionManager();
    if (permissionManager != null)
    {
      return permissionManager.getPermission(revision, securityContext, this);
    }

    return CDORevision.PERMISSION_PROVIDER.getPermission(revision, securityContext);
  }

  public void sendRepositoryTypeNotification(CDOCommonRepository.Type oldType, CDOCommonRepository.Type newType) throws Exception
  {
    if (protocol != null)
    {
      protocol.sendRepositoryTypeNotification(oldType, newType);
    }
  }

  @Deprecated
  public void sendRepositoryStateNotification(CDOCommonRepository.State oldState, CDOCommonRepository.State newState) throws Exception
  {
    sendRepositoryStateNotification(oldState, newState, null);
  }

  public void sendRepositoryStateNotification(CDOCommonRepository.State oldState, CDOCommonRepository.State newState, CDOID rootResourceID) throws Exception
  {
    if (protocol != null)
    {
      protocol.sendRepositoryStateNotification(oldState, newState, rootResourceID);
    }
  }

  @Deprecated
  public void sendBranchNotification(InternalCDOBranch branch) throws Exception
  {
    sendBranchNotification(branch, ChangeKind.CREATED);
  }

  public void sendBranchNotification(InternalCDOBranch branch, ChangeKind changeKind) throws Exception
  {
    if (protocol != null)
    {
      protocol.sendBranchNotification(branch, changeKind);
    }
  }

  @Deprecated
  public void sendCommitNotification(CDOCommitInfo commitInfo) throws Exception
  {
    throw new UnsupportedOperationException();
  }

  @Deprecated
  public void sendCommitNotification(CDOCommitInfo commitInfo, boolean clearResourcePathCache) throws Exception
  {
    throw new UnsupportedOperationException();
  }

  public void sendCommitNotification(CommitNotificationInfo notificationInfo) throws Exception
  {
    if (protocol == null)
    {
      return;
    }

    if (!isPassiveUpdateEnabled())
    {
      return;
    }

    byte securityImpact = notificationInfo.getSecurityImpact();
    if (securityImpact == CommitNotificationInfo.IMPACT_PERMISSIONS)
    {
      IPermissionManager permissionManager = manager.getPermissionManager();
      Set<? extends Object> impactedRules = notificationInfo.getImpactedRules();

      if (!permissionManager.hasAnyRule(this, impactedRules))
      {
        securityImpact = CommitNotificationInfo.IMPACT_NONE;
      }
    }

    CommitInfo sessionCommitInfo = new CommitInfo(notificationInfo);

    CommitNotificationInfo sessionNotificationInfo = new CommitNotificationInfo();
    sessionNotificationInfo.setSender(notificationInfo.getSender());
    sessionNotificationInfo.setCommitInfo(sessionCommitInfo);
    sessionNotificationInfo.setRevisionProvider(notificationInfo.getRevisionProvider());
    sessionNotificationInfo.setClearResourcePathCache(notificationInfo.isClearResourcePathCache());
    sessionNotificationInfo.setNewPermissions(sessionCommitInfo.getNewPermissions());
    sessionNotificationInfo.setSecurityImpact(securityImpact);

    CDOLockChangeInfo lockChangeInfo = notificationInfo.getLockChangeInfo();
    if (lockChangeInfo != null)
    {
      Object lockNotificationRequired = isLockNotificationRequired(lockChangeInfo);
      if (lockNotificationRequired != null)
      {
        sessionNotificationInfo.setLockChangeInfo(lockChangeInfo);
      }
    }

    protocol.sendCommitNotification(sessionNotificationInfo);

    synchronized (lastUpdateTimeLock)
    {
      CDOCommitInfo originalCommitInfo = notificationInfo.getCommitInfo();
      lastUpdateTime = originalCommitInfo.getTimeStamp();
    }
  }

  public void sendLockNotification(CDOLockChangeInfo lockChangeInfo) throws Exception
  {
    if (protocol != null)
    {
      Object lockNotificationRequired = isLockNotificationRequired(lockChangeInfo);
      if (lockNotificationRequired == Boolean.TRUE)
      {
        protocol.sendLockNotification(lockChangeInfo);
        return;
      }

      if (lockNotificationRequired instanceof InternalView)
      {
        InternalView view = (InternalView)lockNotificationRequired;

        try
        {
          protocol.sendLockNotification(lockChangeInfo);
        }
        catch (Exception ex)
        {
          if (!view.isClosed())
          {
            OM.LOG.warn("A problem occured while notifying view " + view, ex);
          }
        }
      }
    }
  }

  private Object isLockNotificationRequired(CDOLockChangeInfo lockChangeInfo)
  {
    LockNotificationMode lockNotificationMode = options().getLockNotificationMode();
    if (lockNotificationMode == LockNotificationMode.ALWAYS)
    {
      return Boolean.TRUE;
    }

    if (lockNotificationMode == LockNotificationMode.IF_REQUIRED_BY_VIEWS)
    {
      // We send the lockChangeInfo only if this session has one (or more) views configured for this branch.
      for (InternalView view : getViews())
      {
        if (view.options().isLockNotificationEnabled())
        {
          CDOBranch affectedBranch = lockChangeInfo.getBranch();
          if (view.getBranch() == affectedBranch || affectedBranch == null)
          {
            return view;
          }
        }
      }
    }

    return null;
  }

  private boolean isDeltaNeeded(CDOID id, InternalView[] views)
  {
    boolean supportingUnits = manager.getRepository().isSupportingUnits();

    for (InternalView view : views)
    {
      try
      {
        if (view.hasSubscription(id))
        {
          return true;
        }

        if (supportingUnits && view.isInOpenUnit(id))
        {
          return true;
        }
      }
      catch (Exception ex)
      {
        if (!view.isClosed())
        {
          OM.LOG.warn("A problem occured while checking subscriptions of view " + view, ex);
        }
      }
    }

    return false;
  }

  public void sendRemoteSessionNotification(InternalSession sender, byte opcode) throws Exception
  {
    if (protocol != null)
    {
      protocol.sendRemoteSessionNotification(sender, opcode);
    }
  }

  public void sendRemoteMessageNotification(InternalSession sender, CDORemoteSessionMessage message) throws Exception
  {
    if (protocol != null)
    {
      protocol.sendRemoteMessageNotification(sender, message);
    }
  }

  @SuppressWarnings({ "unchecked", "rawtypes" })
  public Object getAdapter(Class adapter)
  {
    return AdapterUtil.adapt(this, adapter, false);
  }

  @Override
  public String toString()
  {
    String name = "unknown";
    if (manager != null)
    {
      InternalRepository repository = manager.getRepository();
      if (repository != null)
      {
        name = repository.getName();
      }
    }

    if (userID != null && userID.length() != 0)
    {
      name = userID + "@" + name;
    }

    return MessageFormat.format("Session{0} [{1}]", sessionID, name); //$NON-NLS-1$
  }

  /**
   * @since 2.0
   */
  public void close()
  {
    LifecycleUtil.deactivate(this, OMLogger.Level.DEBUG);
  }

  /**
   * @since 2.0
   */
  public boolean isClosed()
  {
    return !isActive();
  }

  @Override
  protected void doDeactivate() throws Exception
  {
    EventUtil.removeListener(protocol, protocolListener);
    protocolListener = null;

    LifecycleUtil.deactivate(protocol, OMLogger.Level.DEBUG);
    protocol = null;

    for (IView view : getViewsArray())
    {
      view.close();
    }

    views = null;
    manager.sessionClosed(this);
    manager = null;
    super.doDeactivate();
  }

  /**
   * @author Eike Stepper
   */
  private final class CommitInfo extends DelegatingCommitInfo
  {
    private final CDOCommitInfo delegate;

    private final CDORevisionProvider revisionProvider;

    private final InternalView[] views;

    private final IPermissionManager permissionManager;

    private final Map<CDOID, CDOPermission> newPermissions;

    private final boolean additions;

    private final boolean changes;

    public CommitInfo(CommitNotificationInfo notificationInfo)
    {
      delegate = notificationInfo.getCommitInfo();
      revisionProvider = notificationInfo.getRevisionProvider();

      views = getViews();
      permissionManager = manager.getPermissionManager();
      if (permissionManager != null)
      {
        newPermissions = CDOIDUtil.createMap();
      }
      else
      {
        newPermissions = null;
      }

      PassiveUpdateMode passiveUpdateMode = getPassiveUpdateMode();
      additions = passiveUpdateMode == PassiveUpdateMode.ADDITIONS;
      changes = additions || passiveUpdateMode == PassiveUpdateMode.CHANGES;
    }

    @Override
    protected CDOCommitInfo getDelegate()
    {
      return delegate;
    }

    protected void addNewPermission(CDOID id, CDOPermission permission)
    {
      newPermissions.put(id, permission);
    }

    public Map<CDOID, CDOPermission> getNewPermissions()
    {
      return newPermissions;
    }

    @Override
    public List<CDOIDAndVersion> getNewObjects()
    {
      final List<CDOIDAndVersion> newObjects = super.getNewObjects();
      return new IndexedList<CDOIDAndVersion>()
      {
        @Override
        public CDOIDAndVersion get(int index)
        {
          CDORevision revision = (CDORevision)newObjects.get(index);
          if (additions)
          {
            if (permissionManager == null)
            {
              // Return full revision
              return revision;
            }

            CDOPermission permission = permissionManager.getPermission(revision, delegate, Session.this);
            CDOID id = revision.getID();
            addNewPermission(id, permission);

            if (permission != CDOPermission.NONE)
            {
              // Return full revision
              return revision;
            }
          }

          // Prevent sending full revision by copying the id and version
          return CDOIDUtil.createIDAndVersion(revision);
        }

        @Override
        public int size()
        {
          return newObjects.size();
        }
      };
    }

    @Override
    public List<CDORevisionKey> getChangedObjects()
    {
      final List<CDORevisionKey> changedObjects = super.getChangedObjects();
      return new IndexedList<CDORevisionKey>()
      {
        @Override
        public CDORevisionKey get(int index)
        {
          CDORevisionDelta revisionDelta = (CDORevisionDelta)changedObjects.get(index);
          CDOID id = revisionDelta.getID();

          if (changes || isDeltaNeeded(id, views))
          {
            if (permissionManager == null)
            {
              // Return full delta
              return revisionDelta;
            }

            if (revisionProvider == null)
            {
              // Return full delta
              return revisionDelta;
            }

            CDORevision newRevision = revisionProvider.getRevision(id);
            CDOPermission permission = permissionManager.getPermission(newRevision, delegate, Session.this);
            addNewPermission(id, permission);

            if (permission != CDOPermission.NONE)
            {
              // Return full delta
              return revisionDelta;
            }
          }

          // Prevent sending full delta by copying the id and version
          return CDORevisionUtil.copyRevisionKey(revisionDelta);
        }

        @Override
        public int size()
        {
          return changedObjects.size();
        }
      };
    }
  }
}

Back to the top