Caucho Technology
  • resin 4.0
  • bam


    BAM (Brokered Agent Messaging) is a simplified messaging API designed around federated, addressable services, model-based messages, and supports both message and rpc-style communication. As an abstraction of the Jabber protocol, it supports instant messaging, queued (SEDA) services, publish/subscribe, interactive games, and event notification applications. BAM supports multiple protocols including local messaging, Hessian protocol and XMPP (Jabber).

    Overview

    • Jabber compatible: Since BAM is a generalization of the Jabber IM architecture, Jabber services like IM, multi-user chat, pub/sub are straightforward to implement with the BAM api.
    • Streaming: At the core, BAM sends unidirectional messages through a single BamStream interface for clients, services, and the broker. The streaming architecture allows for filters, queuing, translators, and routing for sophisticated applications.
    • Federated addressing: BAM requests are addressable like email or Jabber IM messages, so applications log on once to their local broker, and send messages to any service in the BAM network.
    • Model-based payloads: Messages in BAM can be any Serializable object, letting developers choose appropriate object models for their messages.
    • Typed, mixin services: Since messages are typed, services are designed around a mixin architecture. Each set of messages provides a sub-service. So a single service address might provide chat, pub/sub and custom query capabilities just by providing handlers for each message type.

    Quick Start Examples

    Queued Messages

    Sending a message from a client to a named service is a simple and important use of BAM. Typical applications include message queuing, chat text, game updates, Atom/RSS updates, pub/sub messaging, and event notification for administration consoles. In out example, a servlet sends a message to an internal logging service.

    The sending agent calls message() to send a message with the jid address of the target agent (to), and a message payload. The broker routes the message based on the address and calls the message() method on the target service to process the message. As the service processes the message, the client returns from its message() call and continues processing. If a new message arrives for the service, the broker will queue the message until the service is ready to process it. The queue isolates the producing thread from the service, improving response time and even allowing to be processed on a separate machine or cluster as a batch job.

    The message can be any serializable object appropriate to the service, either a custom Java model bean, or an XML string, or a defined protocol message, like a Jabber IM message. This flexibility lets services define messages appropriate to the application, and avoids tying the service into knots trying to conform to a restricted encoding like SOAP. If remoting is used, the remoting protocol might restrict the possible messages. HMTP (Hessian) will allow any serializable object, while XMPP (Jabber) is restricted to XML and ImMessage.

    Since BAM messages are addressible and routed through the broker, clients have flexibility in choosing their destination at runtime. BAM messages use a JID (Jabber ID) for addressing, which looks like service@domain or service@domain/resource. The second service@domain/resource is used for dynamic agent, e.g. a user logged into messaging with a cellphone.

    Writing a BAM client involves the following steps:

    1. Create an ActorClient
    2. Sending messages

    In the example, the servlet creates a ActorClient and sends the message. The special jid syntax "service@" uses the local domain as a destination.

    Example: TestClient.java
    package example;
    
    import javax.servlet.*;
    import com.caucho.bam.ActorClient;
    import com.caucho.bam.LocalActorClient;
    
    public class TestClient extends GenericServlet
    {
      private ActorClient _client = new LocalActorClient();
    
      public void service(ServletRequest req, ServletResponse response)
      {
        _client.message("test@", "Hello, world!");
      }
    }
    

    Writing a BAM message/queuing service involves the following steps:

    1. Implementing Actor (usually by extending SimpleActor)
    2. Configuring the Actor using <resin:BamService>, which will automatically register the service with the Broker.
    3. Receiving messages by creating message in SimpleActor.

    By configuring <resin:BamService>, the service automatically gains a queuing ability. The broker will queue the message and spawn a new thread before calling the service's message, in order to isolate the receiver from the sender. Advanced applications can disable the queue if appropriate.

    Example: LogService.java
    package example;
    
    import com.caucho.bam.SimpleActor;
    import com.caucho.bam.Message;
    import java.io.Serializable;
    import java.util.logging.*;
    
    public class LogService extends SimpleActor
    {
      private static final Logger log
        = Logger.getLogger(LogService.class.getName());
    
      @Message 
      public void doMessage(String to, String from, Serializable value)
      {
        log.info(this + " message from=" + from + " value=" + value);
      }
    }
    

    The BAM configuration the service configured with CanDI.

    Example: WEB-INF/resin-web.xml
    <web-app xmlns="http://caucho.com/ns/resin"
              xmlns:resin="urn:java:com.caucho.resin"
              xmlns:example="urn:java:example">
    
        <example:LogService>
          <resin:BamService name="test"/>
        </example:LogService>
    
    </web-app>
    

    Client queryGet (RPC) example

    Remote calls in BAM can query or update a service based on the type of the query message. Since the query is typed, a service can be defined by the set of query types it understands and even mixin multiple capabilities, like implementing both a chat and a pub/sub service. In this example, we just query a service for some basic information.

    We'll use a remote client to show how BAM can be used as a remote service as well a local organization. HmtpClient, which extends the same BamConnection API as the local BamClient implements BAM using Hessian as the wire protocol. For local messages, we could use BamClient instead. Once the connection is established, the remaining code is identical.

    When you create a HmtpClient, you'll send it the URL of the HMTP service, then call connect() and login to authenticate. The login() method will register an agent with the broker, letting the client send and receive messages. The example sends a single TestQuery query to the test@localhost service.

    Example: TestClient.java
    package example;
    
    import com.caucho.bam.ActorClient;
    import com.caucho.hmtp.client.HmtpClient;
    
    public class TestClient
    {
      public static void main(String []args)
        throws Exception
      {
        HmtpClient client = new HmtpClient("http://localhost:8080/hmtp");
        client.connect();
        client.login("user@localhost", null);
    
        Object value = client.queryGet("test@localhost", new TestQuery());
    
        System.out.println(value);
    
        client.close();
      }
    }
    

    To implement the server side of an RPC call, the service implements queryGet or querySet and examines the query to see if it understands the query class. To simplify the query dispatching, SimpleActor introspects the methods looking for @QueryGet annotations and creating a map of query types, in this case TestQuery.

    For a query, the service must always send a QueryResult message or a QueryError message with the same id back to the caller to match responses to the calls. If the service understands the query, it will send a result message and return true. If it does not understand the query, it will return false, which tells the broker to send a query error message.

    The id matches responses to the corresponding queries. Since BAM is a bidirectional streaming architecture, queries can be unordered and start from either direction. The id turns this unordered mess into a coherent request-response pattern for RPC-style calls.

    Example: TestService.java
    package example;
    
    import com.caucho.bam.SimpleActor;
    import com.caucho.bam.QueryGet;
    
    public class TestService extends SimpleActor
    {
      @QueryGet
      public void testQueryGet(long id, String to, String from,
                               TestQuery query)
      {
        getBrokerStream().sendQueryResult(id, to, from, "hello response");
      }
    }
    

    The configuration for a service now has two components:

    1. Any registered Actor, e.g. the TestService
    2. The exposed HMTP service protocol, implemented with HempServlet

    The BAM service itself does not know or care that it's being called remotely. The remote HMTP servlet exists only so the remote client can login to the local broker.

    Example: WEB-INF/resin-web.xml
    <web-app xmlns="http://caucho.com/ns/resin"
             xmlns:resin="urn:java:com.caucho.resin"
             xmlns:example="urn:java:example">
    
        <example:TestService>
          <resin:BamService name="test"/>
        </example:TestService>
    
        <servlet-mapping url-pattern="/hmtp"
                         servlet-class="com.caucho.hemp.servlet.HempServlet"/>
    
    </web-app>
    

    Brokered Agent Messaging (BAM)

    Applications using BAM will generally follow a Brokered Agent Messaging pattern, a hub-and-spoke messaging topology where the agents act as dynamic services, joining and detaching from the broker as the application progresses.

    Services and clients register one or more agents with the BamBroker and send messages between the agents. Each remote client will register a local agent with the local broker. and each service will register one or more agents with the broker. In a tic-tac -toe game, the game instance might register two agents: one for each player in a particular game.

    The diagram above has four agents: two agents for the game's players, and one agent for each logged-in user. tictactoe@host.com/1 is the game's agent for player #1, and harry@host.com/x is Harry's agent for his flash client. In the tic-tac-toe game, each user's agent talks to the matching game player, so harry@host.com/x always talks to tictactoe@host.com/1, and draco@host.com/y always talks to tictactoe@host.com/1.

    The game's agents are ephemeral. When a new game begins, a TicTacTocGame instance registers two new agents for the new game, with unique names, e.g. tictactoe@host.com/3 and tictactoe@host.com/4. When the game ends, the instance will unregister its agents.

    Because the game's agents are only created when a game begins, the tic-tac-toe game has a persistent agent for registration, tictactoe@host.com. When Harry logs on, the client will send a query to tictactoe@host.com asking for a new game. As soon as Draco asks for a match, the registration server will create a new game instance and tell Harry's client the name of his player agent, tictactoe@host.com/1.

    Addressing (JIDs)

    BAM resources all have unique identifiers called JIDs (Jabber IDs), which look and act like extended email addresses. Because IM applications can have multiple connections for the same user, each address has an optional resource providing a unique name for the connection.

    The id looks like:

    JID format
    service@domain/resource
    • domain is an virtual host name. Like email or HTTP, BAM messages can be routed to any internet host, i.e. BAM is a federated architecture, not a strict client-server architecture.
    • service is the service name within the domain. In IM services, each user is represented as a separate service.
    • resource is an ephemeral agent name. Since each agent needs a addressable name, the resource identifies each user login or service agent uniquely.

    The service and resource are optional.

    example jids
    JIDDESCRIPTION
    ferg@foo.comIM user resource
    ferg@foo.com/xB8User login agent, i.e. the BAM address corresponding to a logged in IM session.
    batch@foo.comApplication queuing service (like an EJB message driven bean)
    mail@foo.comMail notification service
    tictactoe@foo.comtic-tac-toc game manager resource
    tictactoe@foo.com/1player #1 agent of a tic-tac-toe game
    tictactoe@foo.com/2player #2 agent of a tic-tac-toe game
    tictactoe@foo.com/3player #1 agent of a tic-tac-toe game #2
    tictactoe@foo.com/4player #2 agent of a tic-tac-toe game #2
    myroom@foo.comchatroom instance
    myroom@foo.com/harrychatroom nickname for user #1
    myroom@foo.com/dracochatroom nickname for user #2
    announcements@foo.compublish/subscribe resource

    Resin Services

    Resin includes a number of predefined BAM services for JMS compatibility, logging, and mail messages. The services are all configured with <bam-service>.

    Predefined Services
    URIDESCRIPTION
    caucho.jmsforwards messages to a JMS queue
    caucho.loglogs messages to java.util.logging
    caucho.mailsends an email with a summary of recent messages
    caucho.phpconfigures a service written in PHP

    JMS

    The JMS service forwards BAM messages to a JMS queue, wrapping each message in a JMS ObjectMessage. Applications can use this BAM to JMS bridge to queue messages from a Java client.

    Example: JMS configuration
    <web-app xmlns="http://caucho.com/ns/resin">
    
      <jms-connection-factory name="jms_cf" uri="resin:"/>
      <jms-queue name="queue" uri="memory:"/>
    
      <bam-service name="jms" uri="caucho.jms:">
        <init>
          <connection-factory>${jms_cf}</connection-factory>
          <queue>${queue}</queue>
        </init>
      </bam-service>
      
    </web-app>
    

    Logging

    The logging service adds BAM messages to a java.util.logging Logger. An application could use the logging service as a chat-room recording or debugging service.

    caucho.log attributes
    ATTRIBUTEDESCRIPTION
    namelogger name
    levellogger level
    Example: Log configuration
    <web-app xmlns="http://caucho.com/ns/resin">
    
      <bam-service name="log" uri="caucho.log:">
        <init>
          <name>com.foo.chat</name>
          <level>info</level>
        </init>
      </bam-service>
      
    </web-app>
    

    Mail

    The mail service sends BAM messages to an email address. This can be used to notify any issues with an application that may need administration.

    caucho.mail attributes
    ATTRIBUTEDESCRIPTION
    delay-timea pause interval to gather groups of messages before sending
    mail-sessiona javax.mail.Session object
    propertiesjavamail properties
    subjectthe mail subject
    toa mail destination address
    Example: Mail configuration
    <web-app xmlns="http://caucho.com/ns/resin">
    
      <bam-service name="mail" uri="caucho.mail:">
        <init>
          <to>bam@foo.com</name>
          <subject>BAM Notification</subject>
          <properties>
            mail.from=bamservice@foo.com
          </properties>
        </init>
      </bam-service>
      
    </web-app>
    

    PHP

    The php service configures a PHP script as a service handler.

    caucho.php attributes
    ATTRIBUTEDESCRIPTION
    scripta path to the PHP script
    Example: PHP configuration
    <web-app xmlns="http://caucho.com/ns/resin">
    
      <bam-service name="php" uri="caucho.php:">
        <init>
          <script>WEB-INF/php/php-service.php</script>
        </init>
      </bam-service>
      
    </web-app>
    
    Example: WEB-INF/php/php-service.php
    <?php
    
    bam_message($to, $from, $message)
    {
      resin_debug($message);
    }
    
    bam_dispatch();
      
    ?>
    

    Protocols

    Local (JVM calls)

    Local JVM applications can use BAM to organize internal applications like queuing consumers to replace JMS, or service-oriented architectures. Because BAM passes messages by reference, it avoids the cpu and memory overhead of serialization, improving performance.

    The local clients can take advantage of BAM's federated addressing and can send messages to foreign machines while logging into the local broker.

    HMTP (Hessian)

    HMTP (Hessian Message Transport Protocol) is a streaming mode of the Hessian protocol supporting BAM. Since Hessian can serialize any Java object, it can support all of BAM's capabilities for remote services and since Hessian has been ported to many languages including Flash/ActionScript, multilanguage clients can use BAM directly though HMTP.

    XMPP (Jabber)

    BAM is an adaptation of the XMPP (Jabber) instant messaging protocol. Where XMPP (Xml Messaging and Presence Protocol) is based on XML, HMTP (Hessian Message Transport Protocol) is based on Hessian. Because BAM is designed to follow XMPP, its architecture and protocols are essentially identical until the very lowest layer.

    Because of the close relationship to XMPP, you may want to browse the XMPP specifications for a deeper understanding of how HMTP works. Since XMPP is only a wire protocol, not an API, it does not include all of the HMTP classes, but the architecture remains the same.

    The primary advantages HMTP offers over XMPP include the performance advantages of Hessian over XML, and more importantly a more strict layering than XMPP provides. Because the payloads of the HMTP messages are all Serializable, applications have enormous flexibility in developing their own messages using application objects. In contrast, XMPP messages are always XML, so applications are not only restricted to XML data, but also must create their own XML parsers and formatters.

    Packet types

    BAM provides three categories of packets: messages, queries (rpc), and presence announcements. A queuing or messaging application might only use message packets, while a pub/sub service might use messages and queries. Chat, conference room, and monitoring software will use presence messages to announce joining or startup events.

    Messages are unidirectional fire-and-forget packets. They can be used for queuing systems as a replacement JMS queues.

    Queries are request-response pairs. Each request must have a corresponding response or error.

    Presence announcements are used to organize subscriptions. There are presence announcements to subscribe and unsubscribe, and presence notifications that a user has logged on, sent to all other users subscribed to his presence.

    Message Packets

    The main Message packet contains a target ("to"), a sender ("from"), and a payload ("value"). In BAM, the payload can be any serializable value. Example messages could be IM text messages, queued tasks, administration console graph, game updates, or updated stock quotes. Since BAM is bidirectional, messages can flow to and from any client.

    • Message - sends a message to a resource
    • MessageError - sends a message error to a resource

    Query Packets

    Query packages are RPC get and set packets with a matching response or error. Because the query will always have a matching response packet or an error packet, clients can either block for the result or attach a callback.

    Like the other packets, queries are bidirectional, so a service can query a client as well as the usual client querying the server.

    Query packets have an associated id field to match requests with responses. The client will increment the id for each new query.

    • QueryGet - sends an information request
    • QuerySet - sends an action query
    • QueryResponse - returns a response
    • QueryError - returns an error

    Presence Packets

    Presence packets send specialized information for subscription notification. Many applications will not need to use any presence packets at all.

    • Presense - sends a presence (login) notification
    • PresenseUnavailable - sends unavailable (logout) notification
    • PresenseProbe - query probe for IM clients
    • PresenseSubscribe - request to subscribe to a service
    • PresenseSubscribed - acknowledgement of a subscription
    • PresenseUnsubscribe - notification of an unsubscription
    • PresenseUnsubscribed - notification of an unsubscription
    • PresenseError - error message

    API

    Applications use BamClient, BamStream and SimpleBamService as their main BAM APIs. Conceptually, BAM is designed around BamStream as the central, unidirectional streaming interface. BamClient and SimpleBamService provide appropriate facades around the underlying streaming architecture for a cleaner and simpler application model.

    • Broker - Interface for the hub message routing, and service/agent registration.
    • LocalActorClient - Client class for sending and receiving messages calls from a local Java client, implementing ActorClient.
    • ActorClient - Client interface for sending and receving messages/rpc calls.
    • QueryCallback - client API to handle asyncronous RPC responses.
    • Actor - Interface implemented by all registered BAM services.
    • ActorManager - Optional interface for dynamically registered services, e.g. an IM user manager.
    • ActorStream - Stream interface for all message routing and filtering.
    • HmtpClient - client class for remote Hessian messaging
    • SimpleActor - abstract class extended by most BAM services, providing automatic typed dispatching.
    • XmppClient - client class for remote XMPP (Jabber)

    Client API

    ActorClient

    ActorClient is the primary client class for local clients. The ActorClient will automatically create a connection with the local broker. Messages are sent using the ActorStream methods. Messages are received by setting a ActorStream handler.

    BamClient
    package com.caucho.bam;
    
    public class BamClient implements BamConnection
    {
      public BamClient();
      public BamClient(String uid, String password);
      public BamClient(String uid, String password, String resource);
    
      String getJid();
    
      // message
      void message(String to, Serializable value);
    
      // rpc
      Serializable queryGet(String to, Serializable query);
      Serializable querySet(String to, Serializable query);
      void queryGet(String to, Serializable query, BamQueryCallback callback);
      void querySet(String to, Serializable query, BamQueryCallback callback);
    
      // presence
      void presence(Serializable data);
      void presence(String to, Serializable data);
      void presenceUnavailable(Serializable data);
      void presenceUnavailable(String to, Serializable data);
      void presenceProbe(String to, Serializable data);
      void presenceSubscribe(String to, Serializable data);
      void presenceSubscribed(String to, Serializable data);
      void presenceUnsubscribe(String to, Serializable data);
      void presenceUnsubscribed(String to, Serializable data);
      void presenceError(String to, Serializable data, BamError error);
      
      // callback handler for receiving messages
      void setStreamHandler(BamStream handler);
    
      // raw stream to return rpc responses
      BamStream getBrokerStream();
    }
    

    BamConnection

    BamConnection is the primary client interface for both local and remote clients. Messages are sent using the BamConnection methods. Messages are received by setting a BamStream handler.

    An active BamConnection has an associated agent registered with the broker. The agent's jid is available with the getJid() call.

    For clients that need low-level access to the broker stream, e.g. to implement an RPC/Query handler, getBrokerStream() returns the underlying stream.

    BamConnection
    package com.caucho.bam;
    
    public interface BamConnection
    {
      String getJid();
    
      boolean isClosed();
      void close();
    
      // message
      void message(String to, Serializable value);
    
      // rpc
      Serializable queryGet(String to, Serializable query);
      Serializable querySet(String to, Serializable query);
      void queryGet(String to, Serializable query, BamQueryCallback callback);
      void querySet(String to, Serializable query, BamQueryCallback callback);
    
      // presence
      void presence(Serializable data);
      void presence(String to, Serializable data);
      void presenceUnavailable(Serializable data);
      void presenceUnavailable(String to, Serializable data);
      void presenceProbe(String to, Serializable data);
      void presenceSubscribe(String to, Serializable data);
      void presenceSubscribed(String to, Serializable data);
      void presenceUnsubscribe(String to, Serializable data);
      void presenceUnsubscribed(String to, Serializable data);
      void presenceError(String to, Serializable data, BamError error);
    
      // callback handler for receiving messages
      void setStreamHandler(BamStream handler);
      
      // raw stream to return rpc responses
      BamStream getBrokerStream();
    }
    

    BamConnectionFactory

    The BamConnectionFactory produces BamConnection agents for client code. Typically, the factory implementation will be a BamBroker, although that is not required by the clients.

    BamConnectionFactory
    package com.caucho.bam;
    
    public interface BamConnectionFactory
    {
      BamConnection getConnection(String uid, String password);
      
      BamConnection getConnection(String uid, String password, String resourceId);
    }
    

    BamQueryCallback

    BamQueryCallback is used for callback-style RPC. When the query response completes, the agent will call the BamQueryCallback with the query's response.

    QueryCallback
    package com.caucho.bam;
    
    public interface BamQueryCallback
    {
      void onQueryResult(String to, String from, Serializable value);
      
      void onQueryError(String to, String from, Serializable value,
                        BamError error);
    }
    

    Remote Client API

    HmtpClient is the remote client API for Java clients. Most of the methods are extended from BamConnection. The additional method provide some control for connection and login. Once the client is logged in, applications will typically use BamConnection methods to send messages and set handlers to receive messages.

    HmtpClient

    HmtpClient
    package com.caucho.bam;
    
    public class HmtpClient implements BamConnection
    {
      public HmtpClient(String url);
    
      public void connect() throws IOException;
    
      public void login(String uid, String password);
    
      // BamConnection methods
      String getJid();
    
      boolean isClosed();
      void close();
      
      void setStreamHandler(BamStream handler);
    
      void message(String to, Serializable value);
    
      Serializable queryGet(String to, Serializable query);
      Serializable querySet(String to, Serializable query);
    
      void queryGet(String to, Serializable query, BamQueryCallback callback);
      void querySet(String to, Serializable query, BamQueryCallback callback);
    
      void presence(Serializable data);
      void presence(String to, Serializable data);
      void presenceUnavailable(Serializable data);
      void presenceUnavailable(String to, Serializable data);
      void presenceProbe(String to, Serializable data);
      void presenceSubscribe(String to, Serializable data);
      void presenceSubscribed(String to, Serializable data);
      void presenceUnsubscribe(String to, Serializable data);
      void presenceUnsubscribed(String to, Serializable data);
      void presenceError(String to, Serializable data, BamError error);
      
      BamStream getBrokerStream();
    }
    

    Protocol(Packet) API

    BamStream

    BamStream is the core streaming API for the broker and its registered agents. It is simply a combination of all the message, query and presence packets.

    Applications will implement HmtpQueryStream to receive RPC calls and responses from the agent. If the application implements sendQueryGet, it must either send a QueryResponse to the sender, or send a QueryError or return false from the method. Queries will always have a response or an error.

    The presence methods implement the specialized subscription and presence messages. IM applications use presence messages to announce availability to people in a buddy list (roster).

    Publish/Subscribe applications can also use subscription packets to subscribe and unsubscribe from the publishing service.

    BamStream
    package com.caucho.bam;
    
    public interface BamStream
    {
      public String getJid();
    
      // message
      public void message(String to, String from, Serializable value);
      public void messageError(String to, String from, Serializable value,
                               BamError error);
    
      // rpc
      boolean queryGet(long id, String to, String from, Serializable query);
      boolean querySet(long id, String to, String from, Serializable query);
      void queryResult(long id, String to, String from, Serializable value);
      void queryError(long id, String to, String from, Serializable query,
                      BamError error);
    
      // presence
      void presence(String to, String from, Serializable data);
      void presenceUnavailable(String to, String from, Serializable data);
      void presenceProbe(String to, String from, Serializable data);
      void presenceSubscribe(String to, String from, Serializable data);
      void presenceSubscribed(String to, String from, Serializable data);
      void presenceUnsubscribe(String to, String from, Serializable data);
      void presenceUnsubscribed(String to, String from, Serializable data);
      void presenceError(String to, String from, Serializable data,
                         BamError error);
    }
    

    Service APIs

    BamBroker

    BamBroker is the central player in the HMTP server. It's responsible for routing messages between the agents, for any forwarding to remote servers, and managing dynamic agents and services.

    For all that responsibility, the API is fairly simple. The BamBroker extends BamConnectionFactory, enabling client agents, and allows custom BamService services to be implemented. Most importantly, it implements a broker stream (BamStream) which serves as the destination for all inbound messages.

    BamBroker
    package com.caucho.bam;
    
    public interface BamBroker extends BamConnectionFactory
    {
      BamStream getBrokerStream();
    
      void addService(BamService service);
      void removeService(BamService service);
    
      void addServiceManager(ServiceManager manager);
    }
    

    BamService

    BamService represents a registered, persistent service with a known jid address. Typically the services will be registered in a configuration file, although they can also be created dynamically using the BamServiceManager. Most applications will extend the SimpleBamService instead of implementing BamService directly.

    The key methods are getJid and getAgentStream. The jid is used for registration with the BamBroker and getAgentStream is used to receive any messages.

    The additional methods are used for specialized applications like instant messaging and multiuser-chat, to manage clients logging in.

    BamService
    package com.caucho.bam;
    
    public interface BamService
    {
      public String getJid();
      
      public BamStream getAgentStream();
      
      public boolean startAgent(String jid);
      public boolean stopAgent(String jid);
    
      public void onAgentStart(String jid);
      public void onAgentStop(String jid);
    
      public BamStream getAgentFilter(BamStream stream);
      public BamStream getBrokerFilter(BamStream stream);
    }
    

    BamServiceManager

    BamServiceManager is a specialized manager for finding persistent sessions. In instant messaging, for example, the registered users might be stored in a database. When a message goes to harry@host.com, the BamServiceManager will lookup the appropriate user.

    BamServiceManager
    package com.caucho.bam;
    
    public interface BamServiceManager
    {
      public BamService findService(String jid);
    }
    

    SimpleBamService

    SimpleBamService
    package com.caucho.bam;
    
    abstract public class SimpleBamService implements BamService, BamStream
    {
      public String getJid();
    
      // message
      public void message(String to, String from, Serializable value);
      public void messageError(String to, String from, Serializable value,
                               BamError error);
    
      // rpc
      boolean queryGet(long id, String to, String from, Serializable query);
      boolean querySet(long id, String to, String from, Serializable query);
      void queryResult(long id, String to, String from, Serializable value);
      void queryError(long id, String to, String from, Serializable query,
                      BamError error);
    
      // presence
      void presence(String to, String from, Serializable data);
      void presenceUnavailable(String to, String from, Serializable data);
      void presenceProbe(String to, String from, Serializable data);
      void presenceSubscribe(String to, String from, Serializable data);
      void presenceSubscribed(String to, String from, Serializable data);
      void presenceUnsubscribe(String to, String from, Serializable data);
      void presenceUnsubscribed(String to, String from, Serializable data);
      void presenceError(String to, String from, Serializable data,
                         BamError error);
    
      // BamService methods
      public BamStream getAgentStream();
      
      public boolean startAgent(String jid);
      public boolean stopAgent(String jid);
    
      public void onAgentStart(String jid);
      public void onAgentStop(String jid);
    
      public BamStream getAgentFilter(BamStream stream);
      public BamStream getBrokerFilter(BamStream stream);
    }
    

    annotations

    annotations
    package com.caucho.bam;
    
    public @interface Message {}
    public @interface MessageError {}
    
    public @interface QueryGet {}
    public @interface QuerySet {}
    public @interface QueryResult {}
    public @interface QueryError {}
    
    public @interface Presence {}
    public @interface PresenceProbe {}
    public @interface PresenceUnavailable {}
    public @interface PresenceSubscribe {}
    public @interface PresenceSubscribed {}
    public @interface PresenceUnsubscribe {}
    public @interface PresenceUnsubscribed {}
    public @interface PresenceError {}
    

    Copyright © 1998-2010 Caucho Technology, Inc. All rights reserved.
    Resin ® is a registered trademark, and Quercustm, Ambertm, and Hessiantm are trademarks of Caucho Technology.