bam.xtp
来自「RESIN 3.2 最新源码」· XTP 代码 · 共 1,259 行 · 第 1/3 页
XTP
1,259 行
<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 theJabber 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 thebroker. The streaming architecture allows for filters, queuing, translators,and routing for sophisticated applications.</li><li><b>Federated addressing:</b> BAM requests are addressablelike email or Jabber IM messages, so applications log on once to theirlocal broker, and send messages to any service in the BAMnetwork.</li><li><b>Model-based payloads:</b> Messages in BAM can be any<code>Serializable</code> object, letting developers chooseappropriate object models for their messages.</li><li><b>Typed, mixin services:</b> Since messages are typed, servicesare designed around a mixin architecture. Each set of messagesprovides a sub-service. So a single service address might providechat, pub/sub and custom query capabilities just by providing handlersfor 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 andimportant use of BAM. Typical applications include message queuing,chat text, game updates, Atom/RSS updates, pub/sub messaging, andevent notification for administration consoles. In out example, aservlet sends a message to an internal logging service.</p><p>The sending agent calls <code>message()</code> to send a messagewith 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 themessage. As the service processes the message, the client returns from its<code>message()</code> call and continues processing. If a new messagearrives for the service, the broker will queue the message until the serviceis ready to process it. The queue isolates the producing thread fromthe service, improving response time and even allowing to be processedon 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 theservice, either a custom Java model bean, or an XML string, or adefined protocol message, like a Jabber IM message. This flexibilitylets services define messages appropriate to the application, andavoids tying the service into knots trying to conform to a restrictedencoding like SOAP. If remoting is used, the remoting protocol mightrestrict the possible messages. HMTP (Hessian) will allow anyserializable object, while XMPP (Jabber) is restricted to XMLand <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>. Thesecond <code>service@domain/resource</code> is used for dynamicagent, 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 thelocal 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><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><bam-service></code>, the service automaticallygains a queuing ability. The broker will queue the message and spawn anew thread before calling the service's <code>message</code>, in orderto isolate the receiver from the sender. Advanced applications candisable 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 serviceconfigured with <a href="resin-ioc.xtp">Resin IoC</a>.</p><example title="Example: WEB-INF/resin-web.xml"><web-app xmlns="http://caucho.com/ns/resin"> <bam-service name="test" class="example.LogService"/></web-app></example></s2><s2 title="Client queryGet (RPC) example"><p>Remote calls in BAM can query or update a service based on thetype of the query message. Since the query is typed, a servicecan be defined by the set of query types it understands and evenmixin multiple capabilities, like implementing both a chat and apub/sub service. In this example, we just query a service for somebasic information.</p><figure src="bam-rpc.png"/><p>We'll use a remote client to show how BAM can be used as a remoteservice 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 wireprotocol. For local messages, we coulduse <code>BamClient</code> instead. Once the connection isestablished, the remaining code is identical.</p><p>When you create a <code>HmtpClient</code>, you'll send it the URLof the HMTP service, then call <code>connect()</code> and <code>login</code>to authenticate. The <code>login()</code> method will register anagent 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 thequery to see if it understands the query class. To simplify thequery dispatching, <code>SimpleBamService</code> introspects themethods looking for <code>@QueryGet</code> annotations and creating amap of query types, in this case <code>TestQuery</code>.</p><p>For a query, the service must always send a QueryResult message ora QueryError message with the same <var>id</var> back to the callerto match responses to the calls. If the service understands the query,it will send a result message and return true. If it does notunderstand the query, it will return false, which tells the broker tosend 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 beunordered and start from either direction. The <var>id</var> turnsthis unordered mess into a coherent request-response pattern forRPC-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, implementedwith <code>HempServlet</code></li></ol><p>The BAM service itself does not know or care that it's being calledremotely. The remote HMTP servlet exists only so the remote clientcan login to the local broker.</p><example title="Example: WEB-INF/resin-web.xml"><web-app xmlns="http://caucho.com/ns/resin"> <bam-service name="test" class="example.TestService"/> <servlet-mapping url-pattern="/hmtp" servlet-class="com.caucho.hemp.servlet.HempServlet"/></web-app></example></s2></s1><s1 title="Brokered Agent Messaging (BAM)"><p>Applications using BAM will generally follow a Brokered AgentMessaging pattern, a hub-and-spoke messaging topology wherethe agents act as dynamic services, joining and detaching from the brokeras the application progresses.</p><p>Services and clients register one or more agents withthe <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: onefor 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, andone agent for each logged-in user. <var>tictactoe@host.com/1</var> is the game's agentfor player #1, and <var>harry@host.com/x</var> is Harry's agent for hisflash client. In the tic-tac-toe game, each user's agent talks to thematching game player, so <var>harry@host.com/x</var> alwaystalks 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 thenew 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 willunregister its agents.</p><p>Because the game's agents are only created when a game begins, thetic-tac-toe game has a persistent agent for registration,<var>tictactoe@host.com</var>. When Harry logs on, the client willsend a query to <var>tictactoe@host.com</var> asking for a new game. As soonas Draco asks for a match, the registration server will create a newgame instance and tell Harry's client the name of hisplayer 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), whichlook and act like extended email addresses. Because IM applications canhave multiple connections for the same user, each address has anoptional 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 federatedarchitecture, not a strict client-server architecture.</li><li><var>service</var> is the service name within the domain. In IMservices, each user is represented as a separate service.</li><li><var>resource</var> is an ephemeral agent name. Since each agent needs aaddressable name, the resource identifies each user login orservice 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 loggedin 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><bam-service> configures a <code>BamService</code> to
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?