/** Test {@link CDOCollectionLoadingPolicy} on different branches with each having changes. */
  public void testCDORevisionCDOFetchRuleOnOtherBranchWithChanges() throws Exception {
    // Setup
    CDOID companyCDOID = setUpChangesOnBranches();

    // Test
    CDOSession session = openSession();
    InternalCDOSession internalCDOSession = (InternalCDOSession) session;
    CDOFetchRuleManager fetchRuleManager = new CustomCDOFetchRuleManager(companyCDOID);
    internalCDOSession.setFetchRuleManager(fetchRuleManager);
    ISignalProtocol<?> protocol =
        ((org.eclipse.emf.cdo.net4j.CDONet4jSession) session).options().getNet4jProtocol();
    SignalCounter signalCounter = new SignalCounter(protocol);

    CDOBranch currentBranch = session.getBranchManager().getMainBranch();
    testCDORevisionFetchWithChangesOnAllBranches(
        session, currentBranch, signalCounter, companyCDOID, NB_CATEGORY, false);

    currentBranch = currentBranch.getBranch(B1_BRANCH_NAME);
    testCDORevisionFetchWithChangesOnAllBranches(
        session, currentBranch, signalCounter, companyCDOID, 2 * NB_CATEGORY, false);

    currentBranch = currentBranch.getBranch(B11_BRANCH_NAME);
    testCDORevisionFetchWithChangesOnAllBranches(
        session, currentBranch, signalCounter, companyCDOID, 3 * NB_CATEGORY, false);

    protocol.removeListener(signalCounter);
  }
  private Set<CDORemoteSession> sendMessage(
      CDORemoteSessionMessage message, Iterator<CDORemoteSession> recipients) {
    List<CDORemoteSession> subscribed = new ArrayList<CDORemoteSession>();
    while (recipients.hasNext()) {
      CDORemoteSession recipient = recipients.next();
      if (recipient.isSubscribed()) {
        subscribed.add(recipient);
      }
    }

    if (subscribed.isEmpty()) {
      return Collections.emptySet();
    }

    Set<Integer> sessionIDs =
        localSession.getSessionProtocol().sendRemoteMessage(message, subscribed);
    Set<CDORemoteSession> result = new HashSet<CDORemoteSession>();
    for (CDORemoteSession recipient : subscribed) {
      if (sessionIDs.contains(recipient.getSessionID())) {
        result.add(recipient);
      }
    }

    return result;
  }
  public CDORemoteSession[] getRemoteSessions() {
    synchronized (this) {
      if (subscribed) {
        Collection<CDORemoteSession> values = remoteSessions.values();
        return values.toArray(new CDORemoteSession[values.size()]);
      }

      List<CDORemoteSession> loadedRemoteSessions =
          localSession.getSessionProtocol().getRemoteSessions(this, false);
      return loadedRemoteSessions.toArray(new CDORemoteSession[loadedRemoteSessions.size()]);
    }
  }
  /** Needs to be synchronized externally. */
  private IEvent[] subscribe() {
    List<CDORemoteSession> result = localSession.getSessionProtocol().getRemoteSessions(this, true);
    ContainerEvent<CDORemoteSession> event = new ContainerEvent<CDORemoteSession>(this);
    for (CDORemoteSession remoteSession : result) {
      remoteSessions.put(remoteSession.getSessionID(), remoteSession);
      event.addDelta(remoteSession, IContainerDelta.Kind.ADDED);
    }

    subscribed = true;
    IEvent[] events = {new LocalSubscriptionChangedEventImpl(true), event.isEmpty() ? null : event};
    return events;
  }
  /** Needs to be synchronized externally. */
  private IEvent[] unsubscribe() {
    localSession.getSessionProtocol().unsubscribeRemoteSessions();
    ContainerEvent<CDORemoteSession> event = new ContainerEvent<CDORemoteSession>(this);
    for (CDORemoteSession remoteSession : remoteSessions.values()) {
      event.addDelta(remoteSession, IContainerDelta.Kind.REMOVED);
    }

    remoteSessions.clear();
    subscribed = false;
    IEvent[] events = {
      new LocalSubscriptionChangedEventImpl(false), event.isEmpty() ? null : event
    };
    return events;
  }