<document>
  <header>
    <product>resin</product>
    <title>BAM</title>
    <type>contents</type>

    <description>
      <p>
      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, <a href="http://hessian.caucho.com/">Hessian</a> protocol and <a href="http://xmpp.org">XMPP</a> (Jabber).
      </p>
    </description>
  </header>

<body>

<localtoc/>

<s1 title="Overview">

<ul>
<li><b>Jabber compatible:</b> 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.</li>
<li><b>Streaming:</b> At the core,
BAM sends unidirectional messages through a single
<code>BamStream</code> interface for clients, services, and the
broker.  The streaming architecture allows for filters, queuing, translators,
and routing for sophisticated applications.</li>
<li><b>Federated addressing:</b> 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.</li>
<li><b>Model-based payloads:</b> Messages in BAM can be any
<code>Serializable</code> object, letting developers choose
appropriate object models for their messages.</li>
<li><b>Typed, mixin services:</b> 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.</li>
</ul>


</s1>

<s1 title="Quick Start Examples">

<s2 title="Queued Messages">

<p>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.</p>

<p>The sending agent calls <code>message()</code> 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
<code>message()</code> method on the target service to process the
message. As the service processes the message, the client returns from its
<code>message()</code> 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.</p>

<figure src="queue-timing.png"/>

<p>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 <code>ImMessage</code>.</p>

<p>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
<code>service@domain</code> or <code>service@domain/resource</code>.  The
second <code>service@domain/resource</code> is used for dynamic
agent, e.g. a user logged into messaging with a cellphone.</p>

<figure src="bam-queue.png"/>

<p>Writing a BAM client involves the following steps:</p>

<ol>
<li>Create a <code>BamClient</code></li>
<li>Sending messages</li>
</ol>

<p>In the example, the servlet creates a <code>BamClient</code> 
and sends the message.  The special jid syntax "service@" uses the
local domain as a destination.</p>

<example title="Example: TestClient.java">
package example;

import javax.servlet.*;
import com.caucho.bam.BamClient;

public class TestClient extends GenericServlet
{
  private BamClient _client = new BamClient();

  public void service(ServletRequest req, ServletResponse response)
  {
    _client.message("test@", "Hello, world!");
  }
}
</example>

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

<ol>
<li>Implementing <code>BamService</code> (usually by extending <code>SimpleBamService</code>)</li>
<li>Configuring the <code>BamService</code> using <code>&lt;bam-service></code>, which will automatically register the service with the
<code>BamBroker</code>.</li>
<li>Receiving messages by overriding <code>BamStream</code> methods in <code>SimpleBamService</code>.</li>
</ol>

<p>By configuring <code>&lt;bam-service></code>, the service automatically
gains a queuing ability.  The broker will queue the message and spawn a
new thread before calling the service's <code>message</code>, in order
to isolate the receiver from the sender.  Advanced applications can
disable the queue if appropriate.</p>

<example title="Example: LogService.java">
package example;

import com.caucho.bam.SimpleBamService;
import java.io.Serializable;
import java.util.logging.*;

public class LogService extends SimpleBamService
{
  private static final Logger log
    = Logger.getLogger(LogService.class.getName());

  @Override
  public void message(String to, String from, Serializable value)
  {
    log.info(this + " message from=" + from + " value=" + value);
  }
}
</example>

<p>The BAM configuration the service
configured with <a href="resin-ioc.xtp">Resin IoC</a>.</p>

<example title="Example: WEB-INF/resin-web.xml">
&lt;web-app xmlns="http://caucho.com/ns/resin">

    &lt;bam-service name="test" class="example.LogService"/>

&lt;/web-app>
</example>

</s2>

<s2 title="Client queryGet (RPC) example">

<p>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.</p>

<figure src="bam-rpc.png"/>

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

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

<example title="Example: TestClient.java">
package example;

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();
  }
}
</example>

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

<p>For a query, the service must always send a QueryResult message or
a QueryError message with the same <var>id</var> 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.</p>

<figure src="rpc-timing.png"/>

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

<example title="Example: TestService.java">
package example;

import com.caucho.bam.SimpleBamService;
import com.caucho.bam.annotation.QueryGet;

public class TestService extends SimpleBamService
{
  @QueryGet
  public boolean testQueryGet(long id, String to, String from,
                              TestQuery query)
  {
    getBrokerStream().sendQueryResult(id, to, from, "hello response");

    return true;
  }
}
</example>

<p>The configuration for a service now has two components:</p>

<ol>
<li>Any registered <code>BamService</code>, e.g. the TestService</li>
<li>The exposed HMTP service protocol, implemented
with <code>HempServlet</code></li>
</ol>

<p>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.</p>

<example title="Example: WEB-INF/resin-web.xml">
&lt;web-app xmlns="http://caucho.com/ns/resin">

    &lt;bam-service name="test" class="example.TestService"/>

    &lt;servlet-mapping url-pattern="/hmtp"
                     servlet-class="com.caucho.hemp.servlet.HempServlet"/>

&lt;/web-app>
</example>

</s2>

</s1>

<s1 title="Brokered Agent Messaging (BAM)">

<p>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.</p>

<p>Services and clients register one or more agents with
the <code>BamBroker</code> 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.</p>

<figure title="Tic-Tac-Toe Agents" src="tictactoe-game.png"/>

<p>The diagram above has four agents: two agents for the game's players, and
one agent for each logged-in user.  <var>tictactoe@host.com/1</var> is the game's agent
for player #1, and <var>harry@host.com/x</var> 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 <var>harry@host.com/x</var> always
talks to <var>tictactoe@host.com/1</var>, and <var>draco@host.com/y</var>
always talks to <var>tictactoe@host.com/1</var>.</p>

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

<p>Because the game's agents are only created when a game begins, the
tic-tac-toe game has a persistent agent for registration,
<var>tictactoe@host.com</var>.  When Harry logs on, the client will
send a query to <var>tictactoe@host.com</var> 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, <var>tictactoe@host.com/1</var>.</p>

<figure title="Tic-Tac-Toe Registration" src="tictactoe-registration.png"/>

</s1>

<s1 title="Addressing (JIDs)">

<p>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.</p>

<p>The id looks like:</p>

<def title="JID format">
<var>service</var>@<var>domain</var>/<var>resource</var>
</def>

<ul>
<li><var>domain</var> 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.</li>
<li><var>service</var> is the service name within the domain.  In IM
services, each user is represented as a separate service.</li>
<li><var>resource</var> is an ephemeral agent name.  Since each agent needs a
addressable name, the resource identifies each user login or
service agent uniquely.</li>
</ul>

<p>The <var>service</var> and <var>resource</var> are optional.</p>

<deftable title="example jids">
<tr>
  <th>jid</th>
  <th>description</th>
</tr>
<tr>
  <td>ferg@foo.com</td>
  <td>IM user resource</td>
</tr>
<tr>
  <td>ferg@foo.com/xB8</td>
  <td>User login agent, i.e. the BAM address corresponding to a logged
in IM session.</td>
</tr>
<tr>
  <td>batch@foo.com</td>
  <td>Application queuing service (like an EJB message driven bean)</td>
</tr>
<tr>
  <td>mail@foo.com</td>
  <td>Mail notification service</td>
</tr>
<tr>
  <td>tictactoe@foo.com</td>
  <td>tic-tac-toc game manager resource</td>
</tr>
<tr>
  <td>tictactoe@foo.com/1</td>
  <td>player #1 agent of a tic-tac-toe game</td>
</tr>
<tr>
  <td>tictactoe@foo.com/2</td>
  <td>player #2 agent of a tic-tac-toe game</td>
</tr>
<tr>
  <td>tictactoe@foo.com/3</td>
  <td>player #1 agent of a tic-tac-toe game #2</td>
</tr>
<tr>
  <td>tictactoe@foo.com/4</td>
  <td>player #2 agent of a tic-tac-toe game #2</td>
</tr>
<tr>
  <td>myroom@foo.com</td>
  <td>chatroom instance</td>
</tr>
<tr>
  <td>myroom@foo.com/harry</td>
  <td>chatroom nickname for user #1</td>
</tr>
<tr>
  <td>myroom@foo.com/draco</td>
  <td>chatroom nickname for user #2</td>
</tr>
<tr>
  <td>announcements@foo.com</td>
  <td>publish/subscribe resource</td>
</tr>
</deftable>

</s1>

<s1 title="bam-service">

<p>&lt;bam-service> configures a <code>BamService</code> to
listen for messages.  The service is always a single multithreaded
instance like a servlet; it is never pooled.</p>

<p>&lt;bam-service> can be used as a simple queueing service, replacing
JMS queues and ejb-message-bean.  By default the queue is consumed 
with a single thread.  Unlike EJB message driven beans, &lt;bam-service>
uses a single instance like a servlet, not a pool of instances.
</p>

<p>The bean has full access to Resin-IoC capabilities, including
dependency injection, transaction attributes, and aspect interception.
</p>

<deftable title="&lt;bam-service> attributes">
<tr>
  <th>Attribute</th>
  <th>Description</th>
  <th>Default</th>
</tr>
<tr>
  <td>class</td>
  <td>Classname of the BamService bean</td>
  <td>required</td>
</tr>
<tr>
  <td>init</td>
  <td>IoC configuration for the listener bean</td>
  <td></td>
</tr>
<tr>
  <td>name</td>
  <td>The JID of the service, used by clients to send messages to</td>
  <td></td>
</tr>
<tr>
  <td>thread-max</td>
  <td>The number of threads to handle the queue.  If 0, the service
  is not queued, but handles messages directly.</td>
  <td>1</td>
</tr>
<tr>
  <td>uri</td>
  <td>A shortcut name for the service, defined in META-INF/caucho/com.caucho.uri/com.caucho.bam.BamService.</td>
  <td></td>
</tr>
</deftable>

<def title="&lt;bam-service> schema">
element ejb-message-bean {
  (class | uri)
  &amp; init?
  &amp; name?
  &amp; thread-max?
}
</def>

</s1>

<s1 title="Resin Services">

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

<deftable title="Predefined Services">
<tr>
  <th>uri</th>
  <th>description</th>
</tr>
<tr>
  <td>caucho.jms</td>
  <td>forwards messages to a JMS queue</td>
</tr>
<tr>
  <td>caucho.log</td>
  <td>logs messages to java.util.logging</td>
</tr>
<tr>
  <td>caucho.mail</td>
  <td>sends an email with a summary of recent messages</td>
</tr>
<tr>
  <td>caucho.php</td>
  <td>configures a service written in PHP</td>
</tr>
</deftable>

<s2 title="JMS">

<p>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.</p>

<example title="Example: JMS configuration">
&lt;web-app xmlns="http://caucho.com/ns/resin">

  &lt;jms-connection-factory name="jms_cf" uri="resin:"/>
  &lt;jms-queue name="queue" uri="memory:"/>

  &lt;bam-service name="jms" uri="caucho.jms:">
    &lt;init>
      &lt;connection-factory>${jms_cf}&lt;/connection-factory>
      &lt;queue>${queue}&lt;/queue>
    &lt;/init>
  &lt;/bam-service>
  
&lt;/web-app>
</example>

</s2>

<s2 title="Logging">

<p>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.</p>

<deftable title="caucho.log attributes">
<tr>
  <th>attribute</th>
  <th>description</th>
</tr>
<tr>
  <td>name</td>
  <td>logger name</td>
</tr>
<tr>
  <td>level</td>
  <td>logger level</td>
</tr>
</deftable>

<example title="Example: Log configuration">
&lt;web-app xmlns="http://caucho.com/ns/resin">

  &lt;bam-service name="log" uri="caucho.log:">
    &lt;init>
      &lt;name>com.foo.chat&lt;/name>
      &lt;level>info&lt;/level>
    &lt;/init>
  &lt;/bam-service>
  
&lt;/web-app>
</example>

</s2>

<s2 title="Mail">

<p>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.</p>

<deftable title="caucho.mail attributes">
<tr>
  <th>attribute</th>
  <th>description</th>
</tr>
<tr>
  <td>delay-time</td>
  <td>a pause interval to gather groups of messages before sending</td>
</tr>
<tr>
  <td>mail-session</td>
  <td>a javax.mail.Session object</td>
</tr>
<tr>
  <td>properties</td>
  <td>javamail properties</td>
</tr>
<tr>
  <td>subject</td>
  <td>the mail subject</td>
</tr>
<tr>
  <td>to</td>
  <td>a mail destination address</td>
</tr>
</deftable>

<example title="Example: Mail configuration">
&lt;web-app xmlns="http://caucho.com/ns/resin">

  &lt;bam-service name="mail" uri="caucho.mail:">
    &lt;init>
      &lt;to>bam@foo.com&lt;/name>
      &lt;subject>BAM Notification&lt;/subject>
      &lt;properties>
        mail.from=bamservice@foo.com
      &lt;/properties>
    &lt;/init>
  &lt;/bam-service>
  
&lt;/web-app>
</example>

</s2>

<s2 title="PHP">

<p>The php service configures a PHP script as a service handler.</p>

<deftable title="caucho.php attributes">
<tr>
  <th>attribute</th>
  <th>description</th>
</tr>
<tr>
  <td>script</td>
  <td>a path to the PHP script</td>
</tr>
</deftable>

<example title="Example: PHP configuration">
&lt;web-app xmlns="http://caucho.com/ns/resin">

  &lt;bam-service name="php" uri="caucho.php:">
    &lt;init>
      &lt;script>WEB-INF/php/php-service.php&lt;/script>
    &lt;/init>
  &lt;/bam-service>
  
&lt;/web-app>
</example>

<example title="Example: WEB-INF/php/php-service.php">
&lt;?php

bam_message($to, $from, $message)
{
  resin_debug($message);
}

bam_dispatch();
  
?>
</example>

</s2>
  
</s1>

<s1 title="Protocols">

<s2 title="Local (JVM calls)">

<p>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.</p>

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

</s2>

<s2 title="HMTP (Hessian)">

<p>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.</p>

</s2>

<s2 title="XMPP (Jabber)">

<p>BAM is an adaptation of the <a href="http://xmpp.org">XMPP</a> (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.</p>

<p>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.</p>

<p>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
<code>Serializable</code>, 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.</p>

</s2>

</s1>

<s1 title="Packet types">

<p>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.</p>

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

<p>Queries are request-response pairs.  Each request must have a corresponding
response or error.</p>

<p>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.</p>

<s2 title="Message Packets">

<p>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.</p>

<ul>
<li>Message - sends a message to a resource</li>
<li>MessageError - sends a message error to a resource</li>
</ul>

</s2>

<s2 title="Query Packets">

<p>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.</p>

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

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

<ul>
<li>QueryGet - sends an information request</li>
<li>QuerySet - sends an action query </li>
<li>QueryResponse - returns a response</li>
<li>QueryError - returns an error</li>
</ul>

</s2>

<s2 title="Presence Packets">

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

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

</s2>

</s1>

<s1 title="API">

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

<ul>
<li><code>BamBroker</code> - Interface for the hub message routing, and
service/agent registration.</li>
<li><code>BamClient</code> - Client class for sending and receiving
messages calls from a local Java client, implementing
<code>BamConnection</code>.</li>
<li><code>BamConnection</code> - Client interface for sending and
receving messages/rpc calls.</li>
<li><code>BamConnectionFactory</code> - Factory interface for creating
connections to a broker.</li>
<li><code>BamQueryCallback</code> - client API to handle asyncronous RPC
responses.</li>
<li><code>BamService</code> - Interface implemented by all registered
BAM services.</li>
<li><code>BamServiceManager</code> - Optional interface for dynamically
registered services, e.g. an IM user manager.</li>
<li><code>BamStream</code> - Stream interface for all message routing
and filtering.</li>
<li><code>HmtpClient</code> - client class for remote Hessian messaging</li>
<li><code>SimpleBamService</code> - abstract class extended by most
BAM services, providing automatic typed dispatching.</li>
<li><code>XmppClient</code> - client class for remote XMPP (Jabber)</li>
</ul>

<s2 title="Client API">

<s3 title="BamClient">

<p><code>BamClient</code> is the primary client class for
local clients.  The <code>BamClient</code> will automatically create
a connection with the local broker.  Messages are sent using the
<code>BamConnection</code> methods.  Messages are received by
setting a BamStream handler.</p>

<def title="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();
}
</def>

</s3>

<s3 title="BamConnection">

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

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

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

<def title="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();
}
</def>

</s3>

<s3 title="BamConnectionFactory">

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

<def title="BamConnectionFactory">
package com.caucho.bam;

public interface BamConnectionFactory
{
  BamConnection getConnection(String uid, String password);
  
  BamConnection getConnection(String uid, String password, String resourceId);
}
</def>

</s3>

<s3 title="BamQueryCallback">

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

<def title="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);
}
</def>
</s3>

</s2>

<s2 title="Remote Client API">

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

<s3 title="HmtpClient">

<def title="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();
}
</def>
</s3>

</s2>

<s2 title="Protocol(Packet) API">

<s3 title="BamStream">

<p><code>BamStream</code> 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.</p>

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

<p>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).</p>

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

<def title="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);
}
</def>

</s3>

</s2>

<s2 title="Service APIs">

<s3 title="BamBroker">

<p><code>BamBroker</code> 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.
</p>

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

<def title="BamBroker">
package com.caucho.bam;

public interface BamBroker extends BamConnectionFactory
{
  BamStream getBrokerStream();

  void addService(BamService service);
  void removeService(BamService service);

  void addServiceManager(ServiceManager manager);
}
</def>

</s3>

<s3 title="BamService">

<p><code>BamService</code> 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 <code>BamServiceManager</code>.
Most applications will extend the <code>SimpleBamService</code>
instead of implementing <code>BamService</code> directly.</p>

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

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



<def title="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);
}
</def>

</s3>

<s3 title="BamServiceManager">

<p><code>BamServiceManager</code> 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 <code>BamServiceManager</code> will lookup the
appropriate user.</p>

<def title="BamServiceManager">
package com.caucho.bam;

public interface BamServiceManager
{
  public BamService findService(String jid);
}
</def>

</s3>

<s3 title="SimpleBamService">

<def title="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);
}
</def>

</s3>

<s3 title="annotations">

<def title="annotations">
package com.caucho.bam.annotation;

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 {}
</def>

</s3>

</s2>

</s1>

  </body>
</document>
