package org.sef4j.core.api.session;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.sef4j.core.api.EventSender;
import org.sef4j.core.api.def.ioevenchain.InputEventChainDef;
import org.sef4j.core.api.ioeventchain.InputEventChain;
import org.sef4j.core.api.ioeventchain.InputEventChain.ListenerHandle;
import org.sef4j.core.util.CopyOnWriteUtils;
import org.sef4j.core.util.Handle;
import org.sef4j.core.util.HandleGenerator;
import org.sef4j.core.util.MapUtils;
import org.sef4j.core.util.factorydef.ObjectByDefRepositories;
import org.sef4j.core.util.factorydef.SharedRef;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.collect.ImmutableMap;
/**
* class to manage InputEventChain subscriptions per ClientSession
* => redirect events listener from InputEventChain to sessionTransport
*
* <PRE>
* ObjectByDefRepositories
* +-----------+ SessionManager
* | | <--- getOrCreateByDef() +------------+
* +-----------+ \ | |
* | \ (this)Suscriptions +------------+
* | ----- +------------+ <>
* InputEventChain _ | | |
* Factory |\ +------------+ <- \/
* . \ <> \ ClientSession
* . new() \ | \ +-----------+
* \/ <-- addEventListener() \/ -- | | -----> SessionTransport
* InputEventChain SubscriptionEntry --> | | (WebSocket, JMS, ..)
* +-----+ +--------------+ / +-----------+
* | | <-------------------- |SharedRef | -
* | | sendEvent() |listenerHandle|
* +-----+ ----> +--------------+
* sendEvents()
* ---->
* <-- removeEventListener()
*
*
*
* </PRE>
*/
public class ClientSessionInputEventChainSubscriptions {
private static final Logger LOG = LoggerFactory.getLogger(ClientSessionInputEventChainSubscriptions.class);
/** class representing 1 subscription entry */
private static class SubscriptionEntry {
ClientSessionInputEventChainSubscriptions owner;
SharedRef<InputEventChain<?>> inputEventChainHandle;
ListenerHandle<?> listenerHandle;
SubscriptionEntry(ClientSessionInputEventChainSubscriptions owner,
SharedRef<InputEventChain<?>> inputEventChainHandle) {
this.owner = owner;
this.inputEventChainHandle = inputEventChainHandle;
}
@SuppressWarnings({ "unchecked", "rawtypes" })
public void start() {
if (listenerHandle == null) {
EventSender<?> targetEventListener = owner.ownerClientSession.getAppService().getAppEventSender();
InputEventChain<?> inputEventChain = inputEventChainHandle.getObject();
this.listenerHandle = inputEventChain.registerEventListener((EventSender) targetEventListener);
}
}
public void stop() {
if (listenerHandle != null) {
listenerHandle.close();
this.listenerHandle = null;
}
}
public void close() {
if (listenerHandle != null) {
stop();
}
if (inputEventChainHandle != null) {
inputEventChainHandle.close();
this.inputEventChainHandle = null;
this.owner = null;
}
}
}
protected InOutEventsClientSession ownerClientSession;
private ImmutableMap<Handle,SubscriptionEntry> subscriptions = ImmutableMap.of();
private Object subscriptionsLock = new Object();
private HandleGenerator handleGenerator = new HandleGenerator();
private ObjectByDefRepositories sharedObjByDefRepositories;
// ------------------------------------------------------------------------
public ClientSessionInputEventChainSubscriptions(InOutEventsClientSession ownerClientSession) {
this.ownerClientSession = ownerClientSession;
this.sharedObjByDefRepositories = ownerClientSession.getOwnerSessionManager().getSharedObjByDefRepositories();
}
// ------------------------------------------------------------------------
protected ObjectByDefRepositories getSharedObjByDefRepositories() {
return sharedObjByDefRepositories;
}
public Handle addSubscription(InputEventChainDef def, Object key, String displayName, Map<String,Object> options) {
SharedRef<InputEventChain<?>> inputEventChainHandle =
sharedObjByDefRepositories.getOrCreateByDef(def, key);
SubscriptionEntry subscriptionEntry = new SubscriptionEntry(this, inputEventChainHandle);
boolean skipStart = MapUtils.mapGetBooleanOption(options, "skipStart", false);
if (! skipStart) {
subscriptionEntry.start();
}
Handle res = handleGenerator.generate();
synchronized(subscriptionsLock) {
subscriptions = CopyOnWriteUtils.newWithPut(subscriptions, res, subscriptionEntry);
}
return res;
}
public void removeSubscription(Handle handle) {
SubscriptionEntry subscriptionEntry = getSubscriptionOrThrow(handle);
synchronized(subscriptionsLock) {
subscriptions = CopyOnWriteUtils.newWithRemove(subscriptions, handle);
}
subscriptionEntry.close();
}
public void startSubscription(Handle handle) {
SubscriptionEntry subscriptionEntry = getSubscriptionOrThrow(handle);
subscriptionEntry.start();
}
public void stopSubscription(Handle handle) {
SubscriptionEntry subscriptionEntry = getSubscriptionOrThrow(handle);
subscriptionEntry.stop();
}
public List<SubscriptionResponseDTO> handleSubscriptionCommands(List<SubscriptionCommandDTO> cmds) {
List<SubscriptionResponseDTO> res = new ArrayList<SubscriptionResponseDTO>();
LOG.info("handleSubscriptionCommandsRequest for " + ownerClientSession.getSessionDisplayName());
for(SubscriptionCommandDTO cmd : cmds) {
SubscriptionResponseDTO resp = handleSubscriptionCommand(cmd);
res.add(resp);
}
return res;
}
public SubscriptionResponseDTO handleSubscriptionCommand(SubscriptionCommandDTO cmd) {
SubscriptionResponseDTO response = new SubscriptionResponseDTO();
response.setClientCommandId(cmd.getOptClientCommandId());
response.setStatus(true);
try {
String cmdVerb = cmd.getCommand();
String subscriptionDisplayName = cmd.getDisplayName();
Object optKey = cmd.getOptKey();
InputEventChainDef def = (InputEventChainDef) cmd.getDef();
Map<String, Object> cmdOptions = cmd.getOptions();
SubscriptionEntry subscriptionEntry = null;
Handle subscriptionId = cmd.getSubscriptionId();
if (subscriptionId != null) {
subscriptionEntry = subscriptions.get(subscriptionId);
if (subscriptionEntry == null) {
response.setStatus(false);
response.setReasonText("subscription handle not found");
return response;
}
}
if ("ADD".equalsIgnoreCase(cmdVerb)) {
addSubscription(def, optKey, subscriptionDisplayName, cmdOptions);
} else if ("REMOVE".equalsIgnoreCase(cmdVerb)) {
removeSubscription(subscriptionId);
} else if ("START".equalsIgnoreCase(cmdVerb)) {
startSubscription(subscriptionId);
} else if ("STOP".equalsIgnoreCase(cmdVerb)) {
stopSubscription(subscriptionId);
} else {
response.setStatus(false);
LOG.warn("unrecognised subscriptionCommand: " + cmd + " .. ignore");
response.setReasonText("ERROR: unrecognised command " + cmd);
}
} catch(Exception ex) {
response.setStatus(false);
response.setReasonText("Failed: " + ex.getMessage());
}
return response;
}
private SubscriptionEntry getSubscriptionOrThrow(Handle handle) {
SubscriptionEntry subscriptionEntry = subscriptions.get(handle);
if (subscriptionEntry == null) {
throw new IllegalArgumentException("subscription not found for handle");
}
return subscriptionEntry;
}
// ------------------------------------------------------------------------
@Override
public String toString() {
return "ClientSessionInputEventChainSubscriptions [" +
subscriptions.size() + " elt(s)"
+ "]";
}
}