Class BOSHClient


  • public final class BOSHClient
    extends java.lang.Object
    BOSH 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 the BOSHClientConfig.Builder class for more information.

    Once a BOSHClient instance 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 the send(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 the ComposableBody.Builder class 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, a BOSHClientResponseListener should 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 the send(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.

    See Also:
    BOSHClientConfig.Builder, BOSHClientResponseListener, BOSHClientConnListener, ComposableBody.Builder
    • 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.
      • 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.
      • 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:
        true if the connection manager supports session pausing, false if the connection manager does not support session pausing or if the session has not yet been established
      • disconnect

        public void disconnect()
                        throws BOSHException
        End 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, or null for 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:
        true if the message is a pause request, false otherwise
      • 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:
        true if the message is a session termination, false otherwise
      • 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 code
        respBody - response body
        Returns:
        terminal binding condition, or null if 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:
        true if the message can be immediately sent, false otherwise
      • isWorking

        private boolean isWorking()
        Determines whether or not the session is still active.
        Returns:
        true if it is, false otherwise
      • 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 use
        orig - 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 use
        orig - 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 builder
        rid - 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 null if 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 evaluate
        code - 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:
        true if it does, false otherwise
      • 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 - request
        resp - 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 null if 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