/* * Copyright (c) 2009, 2011, 2012, 2015, 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 */ package org.eclipse.emf.internal.cdo.session.remote; import org.eclipse.emf.cdo.session.remote.CDORemoteSession; import org.eclipse.emf.cdo.session.remote.CDORemoteSessionEvent; import org.eclipse.emf.cdo.session.remote.CDORemoteSessionManager; import org.eclipse.emf.cdo.session.remote.CDORemoteSessionMessage; import org.eclipse.net4j.util.collection.ArrayIterator; import org.eclipse.net4j.util.container.Container; import org.eclipse.net4j.util.container.ContainerEvent; import org.eclipse.net4j.util.container.IContainerDelta; import org.eclipse.net4j.util.event.Event; import org.eclipse.net4j.util.event.IEvent; import org.eclipse.emf.spi.cdo.InternalCDORemoteSession; import org.eclipse.emf.spi.cdo.InternalCDORemoteSessionManager; import org.eclipse.emf.spi.cdo.InternalCDOSession; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * @author Eike Stepper */ public class CDORemoteSessionManagerImpl extends Container<CDORemoteSession> implements InternalCDORemoteSessionManager { private InternalCDOSession localSession; private boolean forceSubscription; private boolean subscribed; private Map<Integer, CDORemoteSession> remoteSessions = new HashMap<Integer, CDORemoteSession>(); public CDORemoteSessionManagerImpl() { } public InternalCDOSession getLocalSession() { return localSession; } public void setLocalSession(InternalCDOSession localSession) { this.localSession = localSession; } 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()]); } } public CDORemoteSession[] getElements() { return getRemoteSessions(); } public boolean isSubscribed() { synchronized (this) { return subscribed; } } public boolean isForceSubscription() { synchronized (this) { return forceSubscription; } } public void setForceSubscription(boolean forceSubscription) { IEvent[] events = null; synchronized (this) { this.forceSubscription = forceSubscription; if (forceSubscription) { if (!subscribed) { events = subscribe(); } } else { if (!hasListeners()) { events = unsubscribe(); } } } fireEvents(events); } public Set<CDORemoteSession> sendMessage(CDORemoteSessionMessage message, CDORemoteSession... recipients) { return sendMessage(message, new ArrayIterator<CDORemoteSession>(recipients)); } public Set<CDORemoteSession> sendMessage(CDORemoteSessionMessage message, Collection<CDORemoteSession> recipients) { return sendMessage(message, recipients.iterator()); } 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 InternalCDORemoteSession createRemoteSession(int sessionID, String userID, boolean subscribed) { InternalCDORemoteSession remoteSession = new CDORemoteSessionImpl(this, sessionID, userID); remoteSession.setSubscribed(subscribed); return remoteSession; } public void handleRemoteSessionOpened(int sessionID, String userID) { CDORemoteSession remoteSession = createRemoteSession(sessionID, userID, false); synchronized (this) { remoteSessions.put(sessionID, remoteSession); } fireElementAddedEvent(remoteSession); } public void handleRemoteSessionClosed(int sessionID) { CDORemoteSession remoteSession = null; synchronized (this) { remoteSession = remoteSessions.remove(sessionID); } if (remoteSession != null) { fireElementRemovedEvent(remoteSession); } } public void handleRemoteSessionSubscribed(int sessionID, boolean subscribed) { IEvent event = null; synchronized (this) { InternalCDORemoteSession remoteSession = (InternalCDORemoteSession)remoteSessions.get(sessionID); if (remoteSession != null) { remoteSession.setSubscribed(subscribed); event = new SubscriptionChangedEventImpl(remoteSession, subscribed); } } if (event != null) { fireEvent(event); } } public void handleRemoteSessionMessage(int sessionID, final CDORemoteSessionMessage message) { IEvent event = null; synchronized (this) { final CDORemoteSessionManager source = this; final InternalCDORemoteSession remoteSession = (InternalCDORemoteSession)remoteSessions.get(sessionID); if (remoteSession != null) { event = new CDORemoteSessionEvent.MessageReceived() { public CDORemoteSessionManager getSource() { return source; } public CDORemoteSession getRemoteSession() { return remoteSession; } public CDORemoteSessionMessage getMessage() { return message; } }; } } if (event != null) { fireEvent(event); } } @Override protected void firstListenerAdded() { IEvent[] events = null; synchronized (this) { if (!subscribed) { events = subscribe(); } } fireEvents(events); } @Override protected void lastListenerRemoved() { IEvent[] events = null; synchronized (this) { if (!forceSubscription) { events = unsubscribe(); } } fireEvents(events); } /** * 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; } private void fireEvents(IEvent[] events) { if (events != null) { for (int i = 0; i < events.length; i++) { IEvent event = events[i]; if (event != null) { fireEvent(event); } } } } /** * @author Eike Stepper */ private final class LocalSubscriptionChangedEventImpl extends Event implements LocalSubscriptionChangedEvent { private static final long serialVersionUID = 1L; private boolean subscribed; public LocalSubscriptionChangedEventImpl(boolean subscribed) { super(CDORemoteSessionManagerImpl.this); this.subscribed = subscribed; } @Override public CDORemoteSessionManager getSource() { return (CDORemoteSessionManager)super.getSource(); } public boolean isSubscribed() { return subscribed; } } /** * @author Eike Stepper */ private final class SubscriptionChangedEventImpl extends Event implements CDORemoteSessionEvent.SubscriptionChanged { private static final long serialVersionUID = 1L; private InternalCDORemoteSession remoteSession; private boolean subscribed; public SubscriptionChangedEventImpl(InternalCDORemoteSession remoteSession, boolean subscribed) { super(CDORemoteSessionManagerImpl.this); this.remoteSession = remoteSession; this.subscribed = subscribed; } @Override public CDORemoteSessionManager getSource() { return (CDORemoteSessionManager)super.getSource(); } public CDORemoteSession getRemoteSession() { return remoteSession; } public boolean isSubscribed() { return subscribed; } } }