Package org.igniterealtime.jbosh
Class BOSHClient
- java.lang.Object
-
- org.igniterealtime.jbosh.BOSHClient
-
public final class BOSHClient extends java.lang.ObjectBOSH Client session instance. Each communication session with a remote connection manager is represented and handled by an instance of this class. This is the main entry point for client-side communications. To create a new session, a client configuration must first be created and then used to create a client instance:BOSHClientConfig cfg = BOSHClientConfig.Builder.create( "http://server:1234/httpbind", "jabber.org") .setFrom("user@jabber.org") .build(); BOSHClient client = BOSHClient.create(cfg);Additional client configuration options are available. See theBOSHClientConfig.Builderclass for more information. Once aBOSHClientinstance has been created, communication with the remote connection manager can begin. No attempt will be made to establish a connection to the connection manager until the first call is made to thesend(ComposableBody)method. Note that it is possible to send an empty body to cause an immediate connection attempt to the connection manager. Sending an empty message would look like the following:client.send(ComposableBody.builder().build());
For more information on creating body messages with content, see theComposableBody.Builderclass documentation. Once a session has been successfully started, the client instance can be used to send arbitrary payload data. All aspects of the BOSH protocol involving setting and processing attributes in the BOSH namespace will be handled by the client code transparently and behind the scenes. The user of the client instance can therefore concentrate entirely on the content of the message payload, leaving the semantics of the BOSH protocol to the client implementation. To be notified of incoming messages from the remote connection manager, aBOSHClientResponseListenershould be added to the client instance. All incoming messages will be published to all response listeners as they arrive and are processed. As with the transmission of payload data via thesend(ComposableBody)method, there is no need to worry about handling of the BOSH attributes, since this is handled behind the scenes. If the connection to the remote connection manager is terminated (either explicitly or due to a terminal condition of some sort), all connection listeners will be notified. After the connection has been closed, the client instance is considered dead and a new one must be created in order to resume communications with the remote server. Instances of this class are thread-safe.
-
-
Nested Class Summary
Nested Classes Modifier and Type Class Description (package private) static classBOSHClient.ExchangeInterceptorClass used in testing to dynamically manipulate received exchanges at test runtime.
-
Field Summary
Fields Modifier and Type Field Description private static booleanASSERTIONSFlag indicating whether or not we want to perform assertions.private BOSHClientConfigcfgSession configuration.private CMSessionParamscmParamsConnection Manager session parameters.private java.util.Set<BOSHClientConnListener>connListenersConnection listeners.private static intDEFAULT_EMPTY_REQUEST_DELAYDefault empty request delay.private static intDEFAULT_PAUSE_MARGINDefault value for the pause margin.private java.util.concurrent.locks.ConditiondrainedCondition indicating that there are no outstanding connections.private static intEMPTY_REQUEST_DELAYAmount of time to wait before sending an empty request, in milliseconds.private java.util.concurrent.ScheduledFutureemptyRequestFutureFuture for sending a deferred empty request, if needed.private java.lang.RunnableemptyRequestRunnableProcessor thread runnable instance.private static java.lang.StringERRORValue of the 'type' attribute used for recoverable errors.private java.util.Queue<HTTPExchange>exchangesList of active/outstanding requests.private java.util.concurrent.atomic.AtomicReference<BOSHClient.ExchangeInterceptor>exchInterceptorStorage for test hook implementation.private HTTPSenderhttpSenderHTTPSender instance.private static java.lang.StringINTERRUPTEDMessage to use for interrupted exceptions.private java.util.concurrent.locks.ReentrantLocklockLock instance.private static java.util.logging.LoggerLOGLogger.private java.util.concurrent.locks.ConditionnotEmptyCondition indicating that there are messages to be exchanged.private java.util.concurrent.locks.ConditionnotFullCondition indicating that there are available slots for sending messages.private static java.lang.StringNULL_LISTENERMessage used whena null listener is detected.private static intPAUSE_MARGINThe amount of time in milliseconds which will be reserved as a safety margin when scheduling empty requests against a maxpause value.private java.util.List<ComposableBody>pendingRequestAcksList of requests which have been made but not yet acknowledged.private java.util.SortedSet<java.lang.Long>pendingResponseAcksSet of RIDs which have been received, for the purpose of sending response acknowledgements.private java.lang.RunnableprocRunnableProcessor thread runnable instance.private java.lang.ThreadprocThreadThread which is used to process responses from the connection manager.private RequestIDSequencerequestIDSeqRequest ID sequence to use for the session.private java.util.Set<BOSHClientRequestListener>requestListenersRequest listeners.private java.lang.LongresponseAckThe highest RID that we've already received a response for.private java.util.Set<BOSHClientResponseListener>responseListenersResponse listeners.private java.util.concurrent.ScheduledExecutorServiceschedExecScheduledExcecutor to use for deferred tasks.private static java.lang.StringTERMINATEValue of the 'type' attribute used for session termination.private static java.lang.StringUNHANDLEDMessage used for unhandled exceptions.
-
Constructor Summary
Constructors Modifier Constructor Description privateBOSHClient(BOSHClientConfig sessCfg)Prevent direct construction.
-
Method Summary
All Methods Static Methods Instance Methods Concrete Methods Modifier and Type Method Description voidaddBOSHClientConnListener(BOSHClientConnListener listener)Adds a connection listener to the session.voidaddBOSHClientRequestListener(BOSHClientRequestListener listener)Adds a request message listener to the session.voidaddBOSHClientResponseListener(BOSHClientResponseListener listener)Adds a response message listener to the session.private voidapplyFrom(ComposableBody.Builder builder)Applies the local station ID information to the request message who's builder has been provided.private voidapplyResponseAcknowledgement(ComposableBody.Builder builder, long rid)Sets the 'ack' attribute of the request to the value of the highest 'rid' of a request for which it has already received a response in the case where it has also received all responses associated with lower 'rid' values.private voidapplyRoute(ComposableBody.Builder builder)Applies routing information to the request message who's builder has been provided.private ComposableBodyapplySessionCreationRequest(long rid, ComposableBody orig)Modifies the specified body message such that it becomes a new BOSH session creation request.private ComposableBodyapplySessionData(long rid, ComposableBody orig)Applies existing session data to the outbound request, returning the modified request.private voidassertLocked()Assert that the internal lock is held.private voidassertUnlocked()Assert that the internal lock is *not* held.private voidblockUntilSendable(AbstractBody msg)Blocks until either the message provided becomes immediately sendable or until the session is terminated.private voidcheckForTerminalBindingConditions(AbstractBody body, int code)Checks to see if the response indicates a terminal binding condition (as per XEP-0124 section 17).private voidclearEmptyRequest()Clears any scheduled empty requests.voidclose()Forcibly close this client session instance.static BOSHClientcreate(BOSHClientConfig clientCfg)Create a new BOSH client session using the client configuration information provided.voiddisconnect()End the BOSH session by disconnecting from the remote BOSH connection manager.voiddisconnect(ComposableBody msg)End the BOSH session by disconnecting from the remote BOSH connection manager, sending the provided content in the final connection termination message.private voiddispose(java.lang.Throwable cause)Destroy this session.(package private) voiddrain()Wait until no more messages are waiting to be processed.private voidfireConnectionClosed()Notifies all connection listeners that the session has been terminated normally.private voidfireConnectionClosedOnError(java.lang.Throwable cause)Notifies all connection listeners that the session has been terminated due to the exceptional condition provided.private voidfireConnectionEstablished()Notifies all connection listeners that the session has been successfully established.private voidfireRequestSent(AbstractBody request)Notifies all request listeners that the specified request is being sent.private voidfireResponseReceived(AbstractBody response)Notifies all response listeners that the specified response has been received.BOSHClientConfiggetBOSHClientConfig()Get the client configuration that was used to create this client instance.(package private) CMSessionParamsgetCMSessionParams()Get the current CM session params.private longgetDefaultEmptyRequestDelay()Calculates the default empty request delay/interval to use for the active session.private TerminalBindingConditiongetTerminalBindingCondition(int respCode, AbstractBody respBody)Evaluates the HTTP response code and response message and returns the terminal binding condition that it describes, if any.private voidinit()Initialize the session.private booleanisImmediatelySendable(AbstractBody msg)Determines if the message specified is immediately sendable or if it needs to block until the session state changes.private static booleanisPause(AbstractBody msg)Determines if the message body specified indicates a request to pause the session.private static booleanisRecoverableBindingCondition(AbstractBody resp)Determines whether or not the response indicates a recoverable binding condition (as per XEP-0124 section 17).private static booleanisTermination(AbstractBody msg)Determines if the message body specified indicates a termination of the session.private booleanisWorking()Determines whether or not the session is still active.private HTTPExchangenextExchange()Get the next message exchange to process, blocking until one becomes available if nothing is already waiting for processing.booleanpause()Attempt to pause the current session.private voidprocessExchange(HTTPExchange exch)Process the next, provided exchange.private voidprocessMessages()While we are "connected", process received responses.private longprocessPauseRequest(AbstractBody req)Process the request to determine if the empty request delay can be determined by looking to see if the request is a pause request.private voidprocessRequestAcknowledgements(AbstractBody req, AbstractBody resp)Check the response for request acknowledgements and take appropriate action.private voidprocessResponseAcknowledgementData(AbstractBody req)Process the response in order to update the response acknowlegement data.private HTTPExchangeprocessResponseAcknowledgementReport(AbstractBody resp)Process the response in order to check for and respond to any potential ack reports.voidremoveBOSHClientConnListener(BOSHClientConnListener listener)Removes a connection listener from the session.voidremoveBOSHClientRequestListener(BOSHClientRequestListener listener)Removes a request message listener from the session, if previously added.voidremoveBOSHClientResponseListener(BOSHClientResponseListener listener)Removes a response message listener from the session, if previously added.private voidscheduleEmptyRequest(long delay)Schedule an empty request to be sent if no other requests are sent in a reasonable amount of time.voidsend(ComposableBody body)Send the provided message data to the remote connection manager.private voidsendEmptyRequest()Sends an empty request to maintain session requirements.(package private) voidsetExchangeInterceptor(BOSHClient.ExchangeInterceptor interceptor)Test method used to forcibly discard next exchange.
-
-
-
Field Detail
-
LOG
private static final java.util.logging.Logger LOG
Logger.
-
TERMINATE
private static final java.lang.String TERMINATE
Value of the 'type' attribute used for session termination.- See Also:
- Constant Field Values
-
ERROR
private static final java.lang.String ERROR
Value of the 'type' attribute used for recoverable errors.- See Also:
- Constant Field Values
-
INTERRUPTED
private static final java.lang.String INTERRUPTED
Message to use for interrupted exceptions.- See Also:
- Constant Field Values
-
UNHANDLED
private static final java.lang.String UNHANDLED
Message used for unhandled exceptions.- See Also:
- Constant Field Values
-
NULL_LISTENER
private static final java.lang.String NULL_LISTENER
Message used whena null listener is detected.- See Also:
- Constant Field Values
-
DEFAULT_EMPTY_REQUEST_DELAY
private static final int DEFAULT_EMPTY_REQUEST_DELAY
Default empty request delay.- See Also:
- Constant Field Values
-
EMPTY_REQUEST_DELAY
private static final int EMPTY_REQUEST_DELAY
Amount of time to wait before sending an empty request, in milliseconds.
-
DEFAULT_PAUSE_MARGIN
private static final int DEFAULT_PAUSE_MARGIN
Default value for the pause margin.- See Also:
- Constant Field Values
-
PAUSE_MARGIN
private static final int PAUSE_MARGIN
The amount of time in milliseconds which will be reserved as a safety margin when scheduling empty requests against a maxpause value. This should give us enough time to build the message and transport it to the remote host.
-
ASSERTIONS
private static final boolean ASSERTIONS
Flag indicating whether or not we want to perform assertions.
-
connListeners
private final java.util.Set<BOSHClientConnListener> connListeners
Connection listeners.
-
requestListeners
private final java.util.Set<BOSHClientRequestListener> requestListeners
Request listeners.
-
responseListeners
private final java.util.Set<BOSHClientResponseListener> responseListeners
Response listeners.
-
lock
private final java.util.concurrent.locks.ReentrantLock lock
Lock instance.
-
notEmpty
private final java.util.concurrent.locks.Condition notEmpty
Condition indicating that there are messages to be exchanged.
-
notFull
private final java.util.concurrent.locks.Condition notFull
Condition indicating that there are available slots for sending messages.
-
drained
private final java.util.concurrent.locks.Condition drained
Condition indicating that there are no outstanding connections.
-
cfg
private final BOSHClientConfig cfg
Session configuration.
-
procRunnable
private final java.lang.Runnable procRunnable
Processor thread runnable instance.
-
emptyRequestRunnable
private final java.lang.Runnable emptyRequestRunnable
Processor thread runnable instance.
-
httpSender
private final HTTPSender httpSender
HTTPSender instance.
-
exchInterceptor
private final java.util.concurrent.atomic.AtomicReference<BOSHClient.ExchangeInterceptor> exchInterceptor
Storage for test hook implementation.
-
requestIDSeq
private final RequestIDSequence requestIDSeq
Request ID sequence to use for the session.
-
schedExec
private final java.util.concurrent.ScheduledExecutorService schedExec
ScheduledExcecutor to use for deferred tasks.
-
procThread
private java.lang.Thread procThread
Thread which is used to process responses from the connection manager. Becomes null when session is terminated.
-
emptyRequestFuture
private java.util.concurrent.ScheduledFuture emptyRequestFuture
Future for sending a deferred empty request, if needed.
-
cmParams
private CMSessionParams cmParams
Connection Manager session parameters. Only available when in a connected state.
-
exchanges
private java.util.Queue<HTTPExchange> exchanges
List of active/outstanding requests.
-
pendingResponseAcks
private java.util.SortedSet<java.lang.Long> pendingResponseAcks
Set of RIDs which have been received, for the purpose of sending response acknowledgements.
-
responseAck
private java.lang.Long responseAck
The highest RID that we've already received a response for. This value is used to implement response acks.
-
pendingRequestAcks
private java.util.List<ComposableBody> pendingRequestAcks
List of requests which have been made but not yet acknowledged. This list remains unpopulated if the CM is not acking requests.
-
-
Constructor Detail
-
BOSHClient
private BOSHClient(BOSHClientConfig sessCfg)
Prevent direct construction.
-
-
Method Detail
-
create
public static BOSHClient create(BOSHClientConfig clientCfg)
Create a new BOSH client session using the client configuration information provided.- Parameters:
clientCfg- session configuration- Returns:
- BOSH session instance
-
getBOSHClientConfig
public BOSHClientConfig getBOSHClientConfig()
Get the client configuration that was used to create this client instance.- Returns:
- client configuration
-
addBOSHClientConnListener
public void addBOSHClientConnListener(BOSHClientConnListener listener)
Adds a connection listener to the session.- Parameters:
listener- connection listener to add, if not already added
-
removeBOSHClientConnListener
public void removeBOSHClientConnListener(BOSHClientConnListener listener)
Removes a connection listener from the session.- Parameters:
listener- connection listener to remove, if previously added
-
addBOSHClientRequestListener
public void addBOSHClientRequestListener(BOSHClientRequestListener listener)
Adds a request message listener to the session.- Parameters:
listener- request listener to add, if not already added
-
removeBOSHClientRequestListener
public void removeBOSHClientRequestListener(BOSHClientRequestListener listener)
Removes a request message listener from the session, if previously added.- Parameters:
listener- instance to remove
-
addBOSHClientResponseListener
public void addBOSHClientResponseListener(BOSHClientResponseListener listener)
Adds a response message listener to the session.- Parameters:
listener- response listener to add, if not already added
-
removeBOSHClientResponseListener
public void removeBOSHClientResponseListener(BOSHClientResponseListener listener)
Removes a response message listener from the session, if previously added.- Parameters:
listener- instance to remove
-
send
public void send(ComposableBody body) throws BOSHException
Send the provided message data to the remote connection manager. The provided message body does not need to have any BOSH-specific attribute information set. It only needs to contain the actual message payload that should be delivered to the remote server. The first call to this method will result in a connection attempt to the remote connection manager. Subsequent calls to this method will block until the underlying session state allows for the message to be transmitted. In certain scenarios - such as when the maximum number of outbound connections has been reached - calls to this method will block for short periods of time.- Parameters:
body- message data to send to remote server- Throws:
BOSHException- on message transmission failure
-
pause
public boolean pause()
Attempt to pause the current session. When supported by the remote connection manager, pausing the session will result in the connection manager closing out all outstanding requests (including the pause request) and increases the inactivity timeout of the session. The exact value of the temporary timeout is dependent upon the connection manager. This method should be used if a client encounters an exceptional temporary situation during which it will be unable to send requests to the connection manager for a period of time greater than the maximum inactivity period. The session will revert back to it's normal, unpaused state when the client sends it's next message.- Returns:
trueif the connection manager supports session pausing,falseif the connection manager does not support session pausing or if the session has not yet been established
-
disconnect
public void disconnect() throws BOSHExceptionEnd the BOSH session by disconnecting from the remote BOSH connection manager.- Throws:
BOSHException- when termination message cannot be sent
-
disconnect
public void disconnect(ComposableBody msg) throws BOSHException
End the BOSH session by disconnecting from the remote BOSH connection manager, sending the provided content in the final connection termination message.- Parameters:
msg- final message to send- Throws:
BOSHException- when termination message cannot be sent
-
close
public void close()
Forcibly close this client session instance. The preferred mechanism to close the connection is to send a disconnect message and wait for organic termination. Calling this method simply shuts down the local session without sending a termination message, releasing all resources associated with the session.
-
getCMSessionParams
CMSessionParams getCMSessionParams()
Get the current CM session params.- Returns:
- current session params, or
null
-
drain
void drain()
Wait until no more messages are waiting to be processed.
-
setExchangeInterceptor
void setExchangeInterceptor(BOSHClient.ExchangeInterceptor interceptor)
Test method used to forcibly discard next exchange.- Parameters:
interceptor- exchange interceptor
-
init
private void init()
Initialize the session. This initializes the underlying HTTP transport implementation and starts the receive thread.
-
dispose
private void dispose(java.lang.Throwable cause)
Destroy this session.- Parameters:
cause- the reason for the session termination, ornullfor normal termination
-
isPause
private static boolean isPause(AbstractBody msg)
Determines if the message body specified indicates a request to pause the session.- Parameters:
msg- message to evaluate- Returns:
trueif the message is a pause request,falseotherwise
-
isTermination
private static boolean isTermination(AbstractBody msg)
Determines if the message body specified indicates a termination of the session.- Parameters:
msg- message to evaluate- Returns:
trueif the message is a session termination,falseotherwise
-
getTerminalBindingCondition
private TerminalBindingCondition getTerminalBindingCondition(int respCode, AbstractBody respBody)
Evaluates the HTTP response code and response message and returns the terminal binding condition that it describes, if any.- Parameters:
respCode- HTTP response coderespBody- response body- Returns:
- terminal binding condition, or
nullif not a terminal binding condition message
-
isImmediatelySendable
private boolean isImmediatelySendable(AbstractBody msg)
Determines if the message specified is immediately sendable or if it needs to block until the session state changes.- Parameters:
msg- message to evaluate- Returns:
trueif the message can be immediately sent,falseotherwise
-
isWorking
private boolean isWorking()
Determines whether or not the session is still active.- Returns:
trueif it is,falseotherwise
-
blockUntilSendable
private void blockUntilSendable(AbstractBody msg)
Blocks until either the message provided becomes immediately sendable or until the session is terminated.- Parameters:
msg- message to evaluate
-
applySessionCreationRequest
private ComposableBody applySessionCreationRequest(long rid, ComposableBody orig) throws BOSHException
Modifies the specified body message such that it becomes a new BOSH session creation request.- Parameters:
rid- request ID to useorig- original body to modify- Returns:
- modified message which acts as a session creation request
- Throws:
BOSHException
-
applyRoute
private void applyRoute(ComposableBody.Builder builder)
Applies routing information to the request message who's builder has been provided.- Parameters:
builder- builder instance to add routing information to
-
applyFrom
private void applyFrom(ComposableBody.Builder builder)
Applies the local station ID information to the request message who's builder has been provided.- Parameters:
builder- builder instance to add station ID information to
-
applySessionData
private ComposableBody applySessionData(long rid, ComposableBody orig) throws BOSHException
Applies existing session data to the outbound request, returning the modified request. This method assumes the lock is currently held.- Parameters:
rid- request ID to useorig- original/raw request- Returns:
- modified request with session information applied
- Throws:
BOSHException
-
applyResponseAcknowledgement
private void applyResponseAcknowledgement(ComposableBody.Builder builder, long rid)
Sets the 'ack' attribute of the request to the value of the highest 'rid' of a request for which it has already received a response in the case where it has also received all responses associated with lower 'rid' values. The only exception is that, after its session creation request, the client SHOULD NOT include an 'ack' attribute in any request if it has received responses to all its previous requests.- Parameters:
builder- message builderrid- current request RID
-
processMessages
private void processMessages()
While we are "connected", process received responses. This method is run in the processing thread.
-
nextExchange
private HTTPExchange nextExchange()
Get the next message exchange to process, blocking until one becomes available if nothing is already waiting for processing.- Returns:
- next available exchange to process, or
nullif no exchanges are immediately available
-
processExchange
private void processExchange(HTTPExchange exch)
Process the next, provided exchange. This is the main processing method of the receive thread.- Parameters:
exch- message exchange to process
-
clearEmptyRequest
private void clearEmptyRequest()
Clears any scheduled empty requests.
-
getDefaultEmptyRequestDelay
private long getDefaultEmptyRequestDelay()
Calculates the default empty request delay/interval to use for the active session.- Returns:
- delay in milliseconds
-
scheduleEmptyRequest
private void scheduleEmptyRequest(long delay)
Schedule an empty request to be sent if no other requests are sent in a reasonable amount of time.
-
sendEmptyRequest
private void sendEmptyRequest()
Sends an empty request to maintain session requirements. If a request is sent within a reasonable time window, the empty request transmission will be cancelled.
-
assertLocked
private void assertLocked()
Assert that the internal lock is held.
-
assertUnlocked
private void assertUnlocked()
Assert that the internal lock is *not* held.
-
checkForTerminalBindingConditions
private void checkForTerminalBindingConditions(AbstractBody body, int code) throws BOSHException
Checks to see if the response indicates a terminal binding condition (as per XEP-0124 section 17). If it does, an exception is thrown.- Parameters:
body- response body to evaluatecode- HTTP response code- Throws:
BOSHException- if a terminal binding condition is detected
-
isRecoverableBindingCondition
private static boolean isRecoverableBindingCondition(AbstractBody resp)
Determines whether or not the response indicates a recoverable binding condition (as per XEP-0124 section 17).- Parameters:
resp- response body- Returns:
trueif it does,falseotherwise
-
processPauseRequest
private long processPauseRequest(AbstractBody req)
Process the request to determine if the empty request delay can be determined by looking to see if the request is a pause request. If it can, the request's delay is returned, otherwise the default delay is returned.- Returns:
- delay in milliseconds that should elapse prior to an empty message being sent
-
processRequestAcknowledgements
private void processRequestAcknowledgements(AbstractBody req, AbstractBody resp)
Check the response for request acknowledgements and take appropriate action. This method assumes the lock is currently held.- Parameters:
req- requestresp- response
-
processResponseAcknowledgementData
private void processResponseAcknowledgementData(AbstractBody req)
Process the response in order to update the response acknowlegement data. This method assumes the lock is currently held.- Parameters:
req- request
-
processResponseAcknowledgementReport
private HTTPExchange processResponseAcknowledgementReport(AbstractBody resp) throws BOSHException
Process the response in order to check for and respond to any potential ack reports. This method assumes the lock is currently held.- Parameters:
resp- response- Returns:
- exchange to transmit if a resend is to be performed, or
nullif no resend is necessary - Throws:
BOSHException- when a a retry is needed but cannot be performed
-
fireRequestSent
private void fireRequestSent(AbstractBody request)
Notifies all request listeners that the specified request is being sent.- Parameters:
request- request being sent
-
fireResponseReceived
private void fireResponseReceived(AbstractBody response)
Notifies all response listeners that the specified response has been received.- Parameters:
response- response received
-
fireConnectionEstablished
private void fireConnectionEstablished()
Notifies all connection listeners that the session has been successfully established.
-
fireConnectionClosed
private void fireConnectionClosed()
Notifies all connection listeners that the session has been terminated normally.
-
fireConnectionClosedOnError
private void fireConnectionClosedOnError(java.lang.Throwable cause)
Notifies all connection listeners that the session has been terminated due to the exceptional condition provided.- Parameters:
cause- cause of the termination
-
-