org.cometd.common.AbstractClientSession Maven / Gradle / Ivy
/*
* Copyright (c) 2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.cometd.common;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicInteger;
import org.cometd.bayeux.ChannelId;
import org.cometd.bayeux.Message;
import org.cometd.bayeux.client.ClientSession;
import org.cometd.bayeux.client.ClientSessionChannel;
import org.eclipse.jetty.util.AttributesMap;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
/**
* Partial implementation of {@link ClientSession}.
* It handles extensions and batching, and provides utility methods to be used by subclasses.
*/
public abstract class AbstractClientSession implements ClientSession
{
private final List _extensions = new CopyOnWriteArrayList();
private final AttributesMap _attributes = new AttributesMap();
private final ConcurrentMap _channels = new ConcurrentHashMap();
private final AtomicInteger _batch = new AtomicInteger();
private final AtomicInteger _idGen = new AtomicInteger(0);
/* ------------------------------------------------------------ */
protected AbstractClientSession()
{
}
/* ------------------------------------------------------------ */
protected String newMessageId()
{
return String.valueOf(_idGen.incrementAndGet());
}
/* ------------------------------------------------------------ */
public void addExtension(Extension extension)
{
_extensions.add(extension);
}
/* ------------------------------------------------------------ */
public void removeExtension(Extension extension)
{
_extensions.remove(extension);
}
/* ------------------------------------------------------------ */
protected boolean extendSend(Message.Mutable message)
{
if (message.isMeta())
{
for (Extension extension : _extensions)
if (!extension.sendMeta(this, message))
return false;
}
else
{
for (Extension extension : _extensions)
if (!extension.send(this, message))
return false;
}
return true;
}
/* ------------------------------------------------------------ */
protected boolean extendRcv(Message.Mutable message)
{
if (message.isMeta())
{
for (Extension extension : _extensions)
if (!extension.rcvMeta(this, message))
return false;
}
else
{
for (Extension extension : _extensions)
if (!extension.rcv(this, message))
return false;
}
return true;
}
/* ------------------------------------------------------------ */
protected abstract ChannelId newChannelId(String channelId);
/* ------------------------------------------------------------ */
protected abstract AbstractSessionChannel newChannel(ChannelId channelId);
/* ------------------------------------------------------------ */
public ClientSessionChannel getChannel(String channelId)
{
AbstractSessionChannel channel = _channels.get(channelId);
if (channel==null)
{
ChannelId id = newChannelId(channelId);
AbstractSessionChannel new_channel=newChannel(id);
channel=_channels.putIfAbsent(channelId,new_channel);
if (channel==null)
channel=new_channel;
}
return channel;
}
/* ------------------------------------------------------------ */
protected ConcurrentMap getChannels()
{
return _channels;
}
/* ------------------------------------------------------------ */
public void startBatch()
{
_batch.incrementAndGet();
}
/* ------------------------------------------------------------ */
protected abstract void sendBatch();
/* ------------------------------------------------------------ */
public boolean endBatch()
{
if (_batch.decrementAndGet()==0)
{
sendBatch();
return true;
}
return false;
}
/* ------------------------------------------------------------ */
public void batch(Runnable batch)
{
startBatch();
try
{
batch.run();
}
finally
{
endBatch();
}
}
/* ------------------------------------------------------------ */
protected boolean isBatching()
{
return _batch.get() > 0;
}
/* ------------------------------------------------------------ */
public Object getAttribute(String name)
{
return _attributes.getAttribute(name);
}
/* ------------------------------------------------------------ */
public Set getAttributeNames()
{
return _attributes.getAttributeNameSet();
}
/* ------------------------------------------------------------ */
public Object removeAttribute(String name)
{
Object old = _attributes.getAttribute(name);
_attributes.removeAttribute(name);
return old;
}
/* ------------------------------------------------------------ */
public void setAttribute(String name, Object value)
{
_attributes.setAttribute(name,value);
}
/* ------------------------------------------------------------ */
protected void resetSubscriptions()
{
for (AbstractSessionChannel ch : _channels.values())
ch.resetSubscriptions();
}
/* ------------------------------------------------------------ */
/**
* Receives a message (from the server) and process it.
* Processing the message involves calling the receive {@link Extension extensions}
* and the channel {@link ClientSessionChannel.ClientSessionChannelListener listeners}.
* @param message the message received.
* @param mutable the mutable version of the message received
*/
public void receive(final Message.Mutable message)
{
String id = message.getChannel();
if (id == null)
throw new IllegalArgumentException("Bayeux messages must have a channel, " + message);
if (!extendRcv(message))
return;
AbstractSessionChannel channel = (AbstractSessionChannel)getChannel(id);
ChannelId channelId = channel.getChannelId();
channel.notifyMessageListeners(message);
for (String channelPattern : channelId.getWilds())
{
ChannelId channelIdPattern = newChannelId(channelPattern);
if (channelIdPattern.matches(channelId))
{
AbstractSessionChannel wildChannel = (AbstractSessionChannel)getChannel(channelPattern);
wildChannel.notifyMessageListeners(message);
}
}
}
/* ------------------------------------------------------------ */
public void dump(StringBuilder b,String indent)
{
b.append(toString());
b.append('\n');
int leaves=_channels.size();
int i=0;
for (AbstractSessionChannel child : _channels.values())
{
b.append(indent);
b.append(" +-");
child.dump(b,indent+((++i==leaves)?" ":" | "));
}
}
/* ------------------------------------------------------------ */
/**
* A channel scoped to a {@link ClientSession}.
*/
protected abstract static class AbstractSessionChannel implements ClientSessionChannel
{
protected final Logger logger = Log.getLogger(getClass().getName());
private final ChannelId _id;
private final AttributesMap _attributes = new AttributesMap();
private final CopyOnWriteArrayList _subscriptions = new CopyOnWriteArrayList();
private final AtomicInteger _subscriptionCount = new AtomicInteger();
private final CopyOnWriteArrayList _listeners = new CopyOnWriteArrayList();
/* ------------------------------------------------------------ */
protected AbstractSessionChannel(ChannelId id)
{
_id=id;
}
/* ------------------------------------------------------------ */
public ChannelId getChannelId()
{
return _id;
}
/* ------------------------------------------------------------ */
public void addListener(ClientSessionChannelListener listener)
{
_listeners.add(listener);
}
/* ------------------------------------------------------------ */
public void removeListener(ClientSessionChannelListener listener)
{
_listeners.remove(listener);
}
/* ------------------------------------------------------------ */
protected abstract void sendSubscribe();
/* ------------------------------------------------------------ */
protected abstract void sendUnSubscribe();
/* ------------------------------------------------------------ */
public void subscribe(MessageListener listener)
{
boolean added = _subscriptions.add(listener);
if (added)
{
int count = _subscriptionCount.incrementAndGet();
if (count == 1)
sendSubscribe();
}
}
/* ------------------------------------------------------------ */
public void unsubscribe(MessageListener listener)
{
boolean removed = _subscriptions.remove(listener);
if (removed)
{
int count = _subscriptionCount.decrementAndGet();
if (count == 0)
sendUnSubscribe();
}
}
/* ------------------------------------------------------------ */
public void unsubscribe()
{
for (MessageListener listener : _subscriptions)
unsubscribe(listener);
}
/* ------------------------------------------------------------ */
protected void resetSubscriptions()
{
for (MessageListener l : _subscriptions)
{
if (_subscriptions.remove(l))
_subscriptionCount.decrementAndGet();
}
}
/* ------------------------------------------------------------ */
public String getId()
{
return _id.toString();
}
/* ------------------------------------------------------------ */
public boolean isDeepWild()
{
return _id.isDeepWild();
}
/* ------------------------------------------------------------ */
public boolean isMeta()
{
return _id.isMeta();
}
/* ------------------------------------------------------------ */
public boolean isService()
{
return _id.isService();
}
public boolean isBroadcast()
{
return !isMeta() && !isService();
}
/* ------------------------------------------------------------ */
public boolean isWild()
{
return _id.isWild();
}
protected void notifyMessageListeners(Message message)
{
for (ClientSessionChannelListener listener : _listeners)
{
if (listener instanceof ClientSessionChannel.MessageListener)
notifyOnMessage((MessageListener)listener, message);
}
for (ClientSessionChannelListener listener : _subscriptions)
{
if (listener instanceof ClientSessionChannel.MessageListener)
{
if (message.getData() != null)
notifyOnMessage((MessageListener)listener, message);
}
}
}
private void notifyOnMessage(MessageListener listener, Message message)
{
try
{
listener.onMessage(this, message);
}
catch (Exception x)
{
logger.info("Exception while invoking listener " + listener, x);
}
}
public void setAttribute(String name, Object value)
{
_attributes.setAttribute(name, value);
}
public Object getAttribute(String name)
{
return _attributes.getAttribute(name);
}
public Set getAttributeNames()
{
return _attributes.keySet();
}
public Object removeAttribute(String name)
{
Object old = getAttribute(name);
_attributes.removeAttribute(name);
return old;
}
protected void dump(StringBuilder b,String indent)
{
b.append(toString());
b.append('\n');
for (ClientSessionChannelListener child : _listeners)
{
b.append(indent);
b.append(" +-");
b.append(child);
b.append('\n');
}
for (MessageListener child : _subscriptions)
{
b.append(indent);
b.append(" +-");
b.append(child);
b.append('\n');
}
}
/* ------------------------------------------------------------ */
@Override
public String toString()
{
return _id.toString();
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy