/*
* Copyright (c) 2008-2017 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.bayeux.server;
import java.util.List;
import org.cometd.bayeux.Bayeux;
import org.cometd.bayeux.MarkedReference;
import org.cometd.bayeux.Transport;
import org.cometd.bayeux.client.ClientSession;
import org.cometd.bayeux.client.ClientSessionChannel;
/**
* <p>The server-side Bayeux interface.</p>
* <p>An instance of the {@link BayeuxServer} interface is available to
* web applications via the "{@value #ATTRIBUTE}" attribute
* of the {@code javax.servlet.ServletContext}.</p>
* <p>The {@link BayeuxServer} APIs give access to the
* {@link ServerSession}s via the {@link #getSession(String)}
* method. It also allows new {@link LocalSession} to be
* created within the server using the {@link #newLocalSession(String)}
* method.</p>
* <p>{@link ServerChannel} instances may be accessed via the
* {@link #getChannel(String)} method, but the server has
* no direct relationship with {@link ClientSessionChannel}s or
* {@link ClientSession}.</p>
* <p>If subscription semantics is required, then
* the {@link #newLocalSession(String)} method should be used to
* create a {@link LocalSession} that can subscribe and publish
* like a client-side Bayeux session.</p>
*/
public interface BayeuxServer extends Bayeux {
/**
* ServletContext attribute name used to obtain the Bayeux object
*/
public static final String ATTRIBUTE = "org.cometd.bayeux";
/**
* <p>Adds the given extension to this Bayeux object.</p>
*
* @param extension the extension to add
* @see #removeExtension(Extension)
*/
void addExtension(Extension extension);
/**
* <p>Removes the given extension from this Bayeux object.</p>
*
* @param extension the extension to remove
* @see #addExtension(Extension)
*/
void removeExtension(Extension extension);
/**
* @return an immutable list of extensions present in this BayeuxServer instance
* @see #addExtension(Extension)
*/
List<Extension> getExtensions();
/**
* <p>Adds a listener to this Bayeux object.</p>
*
* @param listener the listener to add
* @see #removeListener(BayeuxServerListener)
*/
void addListener(BayeuxServerListener listener);
/**
* <p>Removes a listener from this Bayeux object.</p>
*
* @param listener the listener to remove
* @see #addListener(BayeuxServerListener)
*/
void removeListener(BayeuxServerListener listener);
/**
* @param channelId the channel identifier
* @return a {@link ServerChannel} with the given {@code channelId},
* or null if no such channel exists
* @see #createChannelIfAbsent(String, ConfigurableServerChannel.Initializer...)
*/
ServerChannel getChannel(String channelId);
/**
* @return the list of channels known to this BayeuxServer object
*/
List<ServerChannel> getChannels();
/**
* <p>Creates a {@link ServerChannel} and initializes it atomically if the
* channel does not exist, or returns it if it already exists.</p>
* <p>This method can be used instead of adding a {@link ChannelListener}
* to atomically initialize a channel. The {@code initializers} will be
* called before any other thread can access the new channel instance.</p>
* <p>This method should be used when a channel needs to be
* initialized (e.g. by adding listeners) before any publish or subscribes
* can occur on the channel, or before any other thread may concurrently
* create the same channel.</p>
*
* @param channelName the channel name
* @param initializers the initializers invoked to configure the channel
* @return a {@link MarkedReference} whose reference is the channel, and
* the mark signals whether the channel has been created because it
* did not exist before.
*/
MarkedReference<ServerChannel> createChannelIfAbsent(String channelName, ConfigurableServerChannel.Initializer... initializers);
/**
* @param clientId the {@link ServerSession} identifier
* @return the {@link ServerSession} with the given {@code clientId}
* or null if no such valid session exists.
*/
ServerSession getSession(String clientId);
/**
* @return the list of {@link ServerSession}s known to this BayeuxServer object
*/
List<ServerSession> getSessions();
/**
* <p>Removes the given {@code session} from this BayeuxServer.</p>
* <p>This method triggers the invocation of all listeners that would be called
* if the session was disconnected or if the session timed out.</p>
*
* @param session the session to remove
* @return true if the session was known to this BayeuxServer and was removed
*/
boolean removeSession(ServerSession session);
/**
* <p>Creates a new {@link LocalSession}.</p>
* <p>A {@link LocalSession} is a server-side ClientSession that allows
* server-side code to have special clients (resident within the same JVM)
* that can be used to publish and subscribe like a client-side session
* would do.</p>
*
* @param idHint a hint to be included in the unique clientId of the session.
* @return a new {@link LocalSession}
*/
LocalSession newLocalSession(String idHint);
/**
* @return a new or recycled mutable message instance.
*/
ServerMessage.Mutable newMessage();
/**
* @return the {@link SecurityPolicy} associated with this session
* @see #setSecurityPolicy(SecurityPolicy)
*/
public SecurityPolicy getSecurityPolicy();
/**
* @param securityPolicy the {@link SecurityPolicy} associated with this session
* @see #getSecurityPolicy()
*/
public void setSecurityPolicy(SecurityPolicy securityPolicy);
/**
* @return the current transport instance of the current thread
*/
public Transport getCurrentTransport();
/**
* @return the current Context, is equivalent to ((ServerTransport){@link #getCurrentTransport()}).{@link ServerTransport#getContext()}
*/
public BayeuxContext getContext();
/**
* <p>Common base interface for all server-side Bayeux listeners.</p>
*/
interface BayeuxServerListener extends BayeuxListener {
}
/**
* <p>Specialized listener for {@link ServerChannel} events.</p>
* <p>The {@link ServerChannel.Initializer#configureChannel(ConfigurableServerChannel)}
* method is called atomically during Channel creation so that the channel may be configured
* before use. It is guaranteed that in case of concurrent channel creation, the
* {@link ServerChannel.Initializer#configureChannel(ConfigurableServerChannel)} is
* invoked exactly once.</p>
* <p>The other methods are called asynchronously when a channel is added to or removed
* from a {@link BayeuxServer}, and there is no guarantee that these methods will be called
* before any other {@link ServerChannel.ServerChannelListener server channel listeners}
* that may be added during channel configuration.</p>
*/
public interface ChannelListener extends BayeuxServerListener, ConfigurableServerChannel.Initializer {
/**
* <p>Callback invoked when a {@link ServerChannel} has been added to a {@link BayeuxServer} object.</p>
*
* @param channel the channel that has been added
*/
public void channelAdded(ServerChannel channel);
/**
* <p>Callback invoked when a {@link ServerChannel} has been removed from a {@link BayeuxServer} object.</p>
*
* @param channelId the channel identifier of the channel that has been removed.
*/
public void channelRemoved(String channelId);
}
/**
* <p>Specialized listener for {@link ServerSession} events.</p>
* <p>This listener is called when a {@link ServerSession} is added
* or removed from a {@link BayeuxServer}.</p>
*/
public interface SessionListener extends BayeuxServerListener {
/**
* <p>Callback invoked when a {@link ServerSession} has been added to a {@link BayeuxServer} object.</p>
*
* @param session the session that has been added
* @param message the handshake message from the client
*/
public void sessionAdded(ServerSession session, ServerMessage message);
/**
* <p>Callback invoked when a {@link ServerSession} has been removed from a {@link BayeuxServer} object.</p>
*
* @param session the session that has been removed
* @param timedout whether the session has been removed for a timeout or not
*/
public void sessionRemoved(ServerSession session, boolean timedout);
}
/**
* <p>Specialized listener for {@link ServerChannel} subscription events.</p>
* <p>This listener is called when a subscribe message or an unsubscribe message
* occurs for any channel known to the {@link BayeuxServer}.</p>
* <p>This interface the correspondent of the {@link ServerChannel.SubscriptionListener}
* interface, but it is invoked for any session and any channel known to the
* {@link BayeuxServer}, <em>after</em> having invoked the {@link ServerChannel.SubscriptionListener}.</p>
*/
public interface SubscriptionListener extends BayeuxServerListener {
/**
* <p>Callback invoked when a {@link ServerSession} subscribes to a {@link ServerChannel}.</p>
*
* @param session the session that subscribes
* @param channel the channel to subscribe to
* @param message the subscription message sent by the client, or null in case of
* server-side subscription via {@link ServerChannel#subscribe(ServerSession)}
*/
public void subscribed(ServerSession session, ServerChannel channel, ServerMessage message);
/**
* <p>Callback invoked when a {@link ServerSession} unsubscribes from a {@link ServerChannel}.</p>
*
* @param session the session that unsubscribes
* @param channel the channel to unsubscribe from
* @param message the unsubscription message sent by the client, or null in case of
* server-side unsubscription via {@link ServerChannel#unsubscribe(ServerSession)}
*/
public void unsubscribed(ServerSession session, ServerChannel channel, ServerMessage message);
}
/**
* <p>Extension API for {@link BayeuxServer}.</p>
* <p>Implementations of this interface allow to modify incoming and outgoing messages
* before any other processing performed by the implementation.</p>
* <p>Multiple extensions can be registered; the extension <em>receive</em> methods
* are invoked in registration order, while the extension <em>send</em> methods are
* invoked in registration reverse order.</p>
*
* @see BayeuxServer#addExtension(Extension)
*/
public interface Extension {
/**
* <p>Callback method invoked every time a normal message is incoming.</p>
*
* @param from the session that sent the message
* @param message the incoming message
* @return true if message processing should continue, false if it should stop
*/
boolean rcv(ServerSession from, ServerMessage.Mutable message);
/**
* <p>Callback method invoked every time a meta message is incoming.</p>
*
* @param from the session that sent the message
* @param message the incoming meta message
* @return true if message processing should continue, false if it should stop
*/
boolean rcvMeta(ServerSession from, ServerMessage.Mutable message);
/**
* <p>Callback method invoked every time a normal message is outgoing.</p>
*
* @param from the session that sent the message or null
* @param to the session the message is sent to, or null for a publish.
* @param message the outgoing message
* @return true if message processing should continue, false if it should stop
*/
boolean send(ServerSession from, ServerSession to, ServerMessage.Mutable message);
/**
* <p>Callback method invoked every time a meta message is outgoing.</p>
*
* @param to the session the message is sent to, or null for a publish.
* @param message the outgoing meta message
* @return true if message processing should continue, false if it should stop
*/
boolean sendMeta(ServerSession to, ServerMessage.Mutable message);
/**
* Empty implementation of {@link Extension}.
*/
public static class Adapter implements Extension {
@Override
public boolean rcv(ServerSession from, ServerMessage.Mutable message) {
return true;
}
@Override
public boolean rcvMeta(ServerSession from, ServerMessage.Mutable message) {
return true;
}
@Override
public boolean send(ServerSession from, ServerSession to, ServerMessage.Mutable message) {
return true;
}
@Override
public boolean sendMeta(ServerSession to, ServerMessage.Mutable message) {
return true;
}
}
}
}