Class HubConnector
- java.lang.Object
-
- org.astrogrid.samp.client.HubConnector
-
- Direct Known Subclasses:
GuiHubConnector
public class HubConnector extends java.lang.Object
Manages a client's connection to SAMP hubs. Normally SAMP client applications will use one instance of this class for as long as they are running. It provides the following services:- Keeps track of other registered clients
- Keeps track of hubs shutting down and starting up
- Manages client metadata and subscription information across hub reconnections
- Facilitates provision of callback services by the client
- Implements simple MTypes such as
samp.app.ping
. - Optionally looks out for hubs starting up and connects automatically when they do
This object provides a
getConnection()
method which provides the currently activeHubConnection
object if one exists or can be acquired. TheHubConnection
can be used for direct calls on the running hub, but in some cases similar methods with additional functionality exist in this class:declareMetadata
declareSubscriptions
- These methods not only make the relevant declarations to the existing hub connection, if one exists, but will retain the metadata and subscriptions information and declare them to other connections if the hub connection is terminated and restarted (with either the same or a different hub) over the lifetime of this object.
callAndWait
- Provides identical semantics to the similarly named
HubConnection
method, but communicates with the hub asynchronously and fakes the synchrony at the client end. This is more robust and almost certainly a better idea. call
callAll
- Convenience methods to make asynchronous calls without having to worry about registering handlers which match up message tags.
It is good practice to call
setActive(false)
when this object is finished with; however if it is not called explicitly, any open connection will unregister itself on object finalisation or JVM termination, as long as the JVM shuts down cleanly.Examples
Here is an example of what use of this class might look like:// Construct a connector ClientProfile profile = DefaultClientProfile.getProfile(); HubConnector conn = new HubConnector(profile) // Configure it with metadata about this application Metadata meta = new Metadata(); meta.setName("Foo"); meta.setDescriptionText("Application that does stuff"); conn.declareMetadata(meta); // Prepare to receive messages with specific MType(s) conn.addMessageHandler(new AbstractMessageHandler("stuff.do") { public Map processCall(HubConnection c, String senderId, Message msg) { // do stuff } }); // This step required even if no custom message handlers added. conn.declareSubscriptions(conn.computeSubscriptions()); // Keep a look out for hubs if initial one shuts down conn.setAutoconnect(10); // Broadcast a message conn.getConnection().notifyAll(new Message("stuff.event.doing"));
A real example, including use of the GUI hooks, can be found in the
HubMonitor
client source code.Backwards Compatibility Note
This class does less than it did in earlier versions; the functionality which is no longer here can now be found in theGuiHubConnector
class instead.- Since:
- 15 Jul 2008
- Author:
- Mark Taylor
-
-
Nested Class Summary
Nested Classes Modifier and Type Class Description private class
HubConnector.CallHandler
ResponseHandler which looks after responses made by calls using the call() and callAll() convenience methods.private class
HubConnector.CallItem
Stores state about a particular set of responses expected by the CallHandler class.private class
HubConnector.ConnectorCallableClient
CallableClient implementation used by this class.
-
Field Summary
Fields Modifier and Type Field Description private int
autoSec_
private HubConnector.ConnectorCallableClient
callable_
private HubConnector.CallHandler
callHandler_
private TrackedClientSet
clientSet_
private ClientTracker
clientTracker_
private HubConnection
connection_
private static java.lang.String
DISCONNECT_MTYPE
private static java.lang.String
GETENV_MTYPE
private int
iCall_
private boolean
isActive_
private java.util.logging.Logger
logger_
private java.util.List
messageHandlerList_
private Metadata
metadata_
private static java.lang.String
PING_MTYPE
private ClientProfile
profile_
private java.util.Timer
regTimer_
private java.util.List
responseHandlerList_
private java.util.Map
responseMap_
private static java.lang.String
SHUTDOWN_MTYPE
private Subscriptions
subscriptions_
-
Constructor Summary
Constructors Constructor Description HubConnector(ClientProfile profile)
Constructs a HubConnector based on a given profile instance.HubConnector(ClientProfile profile, TrackedClientSet clientSet)
Constructs a HubConnector based on a given profile instance using a custom client set implementation.
-
Method Summary
All Methods Instance Methods Concrete Methods Modifier and Type Method Description void
addMessageHandler(MessageHandler handler)
Adds a MessageHandler to this connector, which allows it to respond to incoming messages.void
addResponseHandler(ResponseHandler handler)
Adds a ResponseHandler to this connector, which allows it to receive replies from messages sent asynchronously.void
call(java.lang.String recipientId, java.util.Map msg, ResultHandler resultHandler, int timeout)
Sends a message asynchronously to a single client, making a callback on a supplied ResultHandler object when the result arrives.void
callAll(java.util.Map msg, ResultHandler resultHandler, int timeout)
Sends a message asynchronously to all subscribed clients, making callbacks on a supplied ResultHandler object when the results arrive.Response
callAndWait(java.lang.String recipientId, java.util.Map msg, int timeout)
Sends a message synchronously to a client, waiting for the response.private void
checkHubMessage(HubConnection connection, java.lang.String senderId, java.lang.String mtype)
Performs sanity checking on a message which is normally expected to be sent only by the hub client itself.Subscriptions
computeSubscriptions()
Works out the subscriptions map for this connector.void
configureConnection(HubConnection connection)
Configures a connection with a hub in accordance with the state of this object.private void
configureRegisterTimer(int autoSec)
Configures a timer thread to attempt registration periodically.protected void
connectionChanged(boolean isConnected)
Method which is called every time this connector changes its connection status (from disconnected to connected, or vice versa).protected HubConnection
createConnection()
Invoked by this class to create a hub connection.java.lang.String
createTag(java.lang.Object owner)
Generates a newmsgTag
for use with this connector.void
declareMetadata(java.util.Map meta)
Declares the metadata for this client.void
declareSubscriptions(java.util.Map subscriptions)
Declares the MType subscriptions for this client.protected void
disconnect()
Unregisters from the currently connected hub, if any.java.util.Map
getClientMap()
Returns a map which keeps track of other clients currently registered with the hub to which this object is connected, including their currently declared metadata and subscriptions.protected TrackedClientSet
getClientSet()
Returns the tracked client set implementation which is used to keep track of the currently registered clients.HubConnection
getConnection()
If necessary attempts to acquire, and returns, a connection to a running hub.Metadata
getMetadata()
Returns this client's own metadata.Subscriptions
getSubscriptions()
Returns this client's own subscriptions.boolean
isConnected()
Indicates whether this connector is currently registered with a running hub.void
removeMessageHandler(MessageHandler handler)
Removes a previously-added MessageHandler to this connector.void
removeResponseHandler(ResponseHandler handler)
Removes a ResponseHandler from this connector.void
setActive(boolean active)
Sets whether this connector is active or not.void
setAutoconnect(int autoSec)
Sets the interval at which this connector attempts to connect to a hub if no connection currently exists.
-
-
-
Field Detail
-
profile_
private final ClientProfile profile_
-
clientSet_
private final TrackedClientSet clientSet_
-
messageHandlerList_
private final java.util.List messageHandlerList_
-
responseHandlerList_
private final java.util.List responseHandlerList_
-
callable_
private final HubConnector.ConnectorCallableClient callable_
-
responseMap_
private final java.util.Map responseMap_
-
clientTracker_
private final ClientTracker clientTracker_
-
callHandler_
private final HubConnector.CallHandler callHandler_
-
isActive_
private volatile boolean isActive_
-
connection_
private volatile HubConnection connection_
-
metadata_
private volatile Metadata metadata_
-
subscriptions_
private volatile Subscriptions subscriptions_
-
autoSec_
private volatile int autoSec_
-
regTimer_
private volatile java.util.Timer regTimer_
-
iCall_
private volatile int iCall_
-
logger_
private final java.util.logging.Logger logger_
-
SHUTDOWN_MTYPE
private static final java.lang.String SHUTDOWN_MTYPE
- See Also:
- Constant Field Values
-
DISCONNECT_MTYPE
private static final java.lang.String DISCONNECT_MTYPE
- See Also:
- Constant Field Values
-
PING_MTYPE
private static final java.lang.String PING_MTYPE
- See Also:
- Constant Field Values
-
GETENV_MTYPE
private static final java.lang.String GETENV_MTYPE
- See Also:
- Constant Field Values
-
-
Constructor Detail
-
HubConnector
public HubConnector(ClientProfile profile)
Constructs a HubConnector based on a given profile instance. A default client set implementation is used.- Parameters:
profile
- profile implementation
-
HubConnector
public HubConnector(ClientProfile profile, TrackedClientSet clientSet)
Constructs a HubConnector based on a given profile instance using a custom client set implementation.- Parameters:
profile
- profile implementationclientSet
- object to keep track of registered clients
-
-
Method Detail
-
setAutoconnect
public void setAutoconnect(int autoSec)
Sets the interval at which this connector attempts to connect to a hub if no connection currently exists. Otherwise, a connection will be attempted whenevergetConnection()
is called.- Parameters:
autoSec
- number of seconds between attempts; <=0 means no automatic connections are attempted
-
configureRegisterTimer
private void configureRegisterTimer(int autoSec)
Configures a timer thread to attempt registration periodically.- Parameters:
autoSec
- number of seconds between attempts; <=0 means no automatic connections are attempted
-
declareMetadata
public void declareMetadata(java.util.Map meta)
Declares the metadata for this client. This declaration affects the current connection and any future ones.- Parameters:
meta
-Metadata
-like map
-
getMetadata
public Metadata getMetadata()
Returns this client's own metadata.- Returns:
- metadata
-
declareSubscriptions
public void declareSubscriptions(java.util.Map subscriptions)
Declares the MType subscriptions for this client. This declaration affects the current connection and any future ones.Note that this call must be made, with a subscription list which includes the various hub administrative messages, in order for this connector to act on those messages (for instance to update its client map and so on). For this reason, it is usual to call it with the
subs
argument given by the result of callingcomputeSubscriptions()
.- Parameters:
subscriptions
-Subscriptions
-like map
-
getSubscriptions
public Subscriptions getSubscriptions()
Returns this client's own subscriptions.- Returns:
- subscriptions
-
computeSubscriptions
public Subscriptions computeSubscriptions()
Works out the subscriptions map for this connector. This is based on the subscriptions declared by for anyMessageHandler
s installed in this connector as well as any MTypes which this connector implements internally. The result of this method is usually a suitable value to pass todeclareSubscriptions(java.util.Map)
. However you might wish to remove some entries from the result if there are temporarily unsubscribed services.- Returns:
- subscription list for MTypes apparently implemented by this connector
-
addMessageHandler
public void addMessageHandler(MessageHandler handler)
Adds a MessageHandler to this connector, which allows it to respond to incoming messages. Note that this does not in itself update the list of subscriptions for this connector; you may want to follow it with a call todeclareSubscriptions(computeSubscriptions());
- Parameters:
handler
- handler to add
-
removeMessageHandler
public void removeMessageHandler(MessageHandler handler)
Removes a previously-added MessageHandler to this connector. Note that this does not in itself update the list of subscriptions for this connector; you may want to follow it with a call todeclareSubscriptions(computeSubscriptions());
- Parameters:
handler
- handler to remove
-
addResponseHandler
public void addResponseHandler(ResponseHandler handler)
Adds a ResponseHandler to this connector, which allows it to receive replies from messages sent asynchronously.Note however that this class's
callAndWait
method can provide a synchronous facade for fully asynchronous messaging, which in many cases will be more convenient than installing your own response handlers to deal with asynchronous replies.- Parameters:
handler
- handler to add
-
removeResponseHandler
public void removeResponseHandler(ResponseHandler handler)
Removes a ResponseHandler from this connector.- Parameters:
handler
- handler to remove
-
setActive
public void setActive(boolean active)
Sets whether this connector is active or not. If set false, any existing connection will be terminated (the client will unregister) and autoconnection attempts will be suspended. If set true, if there is no existing connection an attempt will be made to register, and autoconnection attempts will begin if applicable.- Parameters:
active
- whether this connector should be active- See Also:
setAutoconnect(int)
-
callAndWait
public Response callAndWait(java.lang.String recipientId, java.util.Map msg, int timeout) throws SampException
Sends a message synchronously to a client, waiting for the response. If more seconds elapse than the value of thetimeout
parameter, an exception will result.The semantics of this call are, as far as the caller is concerned, identical to that of the similarly named
HubConnection
method. However, in this case the client communicates with the hub asynchronously and internally simulates the synchrony for the caller, rather than letting the hub do that. This is more robust and almost certainly a better idea.- Parameters:
recipientId
- public-id of client to receive messagemsg
-Message
-like maptimeout
- timeout in seconds, or <=0 for no timeout- Returns:
- response
- Throws:
SampException
-
call
public void call(java.lang.String recipientId, java.util.Map msg, ResultHandler resultHandler, int timeout) throws SampException
Sends a message asynchronously to a single client, making a callback on a supplied ResultHandler object when the result arrives. TheResultHandler.done()
method will be called after the result has arrived or the timeout elapses, whichever happens first.This convenience method allows the user to make an asynchronous call without having to worry registering message handlers and matching message tags.
- Parameters:
recipientId
- public-id of client to receive messagemsg
-Message
-like mapresultHandler
- object called back when response arrives or timeout is exceededtimeout
- timeout in seconds, or <=0 for no timeout- Throws:
SampException
-
callAll
public void callAll(java.util.Map msg, ResultHandler resultHandler, int timeout) throws SampException
Sends a message asynchronously to all subscribed clients, making callbacks on a supplied ResultHandler object when the results arrive. TheResultHandler.done()
method will be called after all the results have arrived or the timeout elapses, whichever happens first.This convenience method allows the user to make an asynchronous call without having to worry registering message handlers and matching message tags.
- Parameters:
msg
-Message
-like mapresultHandler
- object called back when response arrives or timeout is exceededtimeout
- timeout in seconds, or <=0 for no timeout- Throws:
SampException
-
isConnected
public boolean isConnected()
Indicates whether this connector is currently registered with a running hub. If true, the result ofgetConnection()
will be non-null.- Returns:
- true if currently connected to a hub
-
getConnection
public HubConnection getConnection() throws SampException
If necessary attempts to acquire, and returns, a connection to a running hub. If there is an existing connection representing a registration with a hub, it is returned. If not, and this connector is active, an attempt is made to connect and register, followed by a call toconfigureConnection
, is made.Note that if
setActive(false)
has been called, null will be returned.- Returns:
- hub connection representing configured registration with a hub if a hub is running; if not, null
- Throws:
SampException
- in the case of some unexpected error
-
configureConnection
public void configureConnection(HubConnection connection) throws SampException
Configures a connection with a hub in accordance with the state of this object. The hub is made aware of how to perform callbacks on the registered client, and any current metadata and subscriptions are declared.- Parameters:
connection
- connection representing registration with a hub- Throws:
SampException
-
getClientMap
public java.util.Map getClientMap()
Returns a map which keeps track of other clients currently registered with the hub to which this object is connected, including their currently declared metadata and subscriptions. Map keys are public IDs and values areClient
s.This map is
synchronized
which means that to iterate over any of its views you must synchronize on it. When the map or any of its contents changes, it will receive aObject.notifyAll()
.To keep itself up to date, the client map reads hub status messages. These will only be received if
declareSubscriptions(computeSubscriptions())
has been called. Hence, this method should only be called afterdeclareSubscriptions(java.util.Map)
has been called. If this order is not observed, a warning will be emitted through the logging system.- Returns:
- id->Client map
-
getClientSet
protected TrackedClientSet getClientSet()
Returns the tracked client set implementation which is used to keep track of the currently registered clients.- Returns:
- client set implementation
-
createConnection
protected HubConnection createConnection() throws SampException
Invoked by this class to create a hub connection. The default implementation just callsprofile.register()
.- Returns:
- new hub connection
- Throws:
SampException
-
disconnect
protected void disconnect()
Unregisters from the currently connected hub, if any. Performs any associated required cleanup.
-
connectionChanged
protected void connectionChanged(boolean isConnected)
Method which is called every time this connector changes its connection status (from disconnected to connected, or vice versa). The default implementation does nothing, but it may be overridden by subclasses wishing to be informed of these events.- Parameters:
isConnected
- true if we've just registered; false if we've just unregistered
-
checkHubMessage
private void checkHubMessage(HubConnection connection, java.lang.String senderId, java.lang.String mtype)
Performs sanity checking on a message which is normally expected to be sent only by the hub client itself.- Parameters:
connection
- connection to the hubsenderId
- public client id of sendermtype
- MType of sent message
-
createTag
public java.lang.String createTag(java.lang.Object owner)
Generates a newmsgTag
for use with this connector. It is guaranteed to return a different value on each invocation. It is advisable to use this method whenever a message tag is required to prevent clashes.- Parameters:
owner
- object to identify caller (not really necessary - may be null)- Returns:
- unique tag for this connector
-
-