![]() | ||||||||||||||||||||||||||||||
streaming hessian/comet servletResin's Comet servlet API enables streaming communication that makes pushing data to the rich clients possible. The API encapsulates of the threading and communications issues between the request threads and the rest of the application. Using Hessian as the communication protocol, we show how to push data to a Flash RIA. Resin's Comet API lets server applications push new data to the client as it becomes available. Flash clients can be used to display continually updated information to the user. ![]() The architecture in the picture uses two HTTP streams to the server application, one for normal client-server requests, and a second unidirectional stream to send updates from the server to the client.
The example updates the Flash application every two seconds with new data. In this case, lines of a Latin text. The components of the Comet/AJAX application look like:
The comet HTTP stream is a sequence of Hessian streaming packets. Because the Flex implementation of Hessian is able to read data progressively, the user will see the updates immediately without waiting for the entire HTTP request to complete. The Flash client receives the objects from the server and executes a method on those objects to get the next line in the text and update them in a List control. The client connects to the service using the HessianStreamingService tag. This tag requires a destination attribute which specifies the URL of the service and a responder attribute which handles data received from the server. In this case, our service is at "comet", which is a relative URL to the location of the Flash SWF file. The responder is the application itself. The responder must implement the mx.rpc.IResponder interface. In our example, we also specify the policyPort attribute. We'll discuss this later in the section about sandboxing. When new data arrives from the service, the responder's result() method is called with the data. In our example, the data is an AddString object on which we call the "execute()" method. This method adds a line to the client state and the state is then reflected in the List control. CometClient.mxml
<?xml version="1.0"?>
<mx:Application
xmlns:mx="http://www.adobe.com/2006/mxml"
implements="mx.rpc.IResponder">
<hessian:HessianStreamingService xmlns:hessian="hessian.mxml.*"
destination="comet" responder="{this}" policyPort="80"/>
<mx:Panel
title="Caucho Hessian Comet Demo"
paddingTop="10" paddingBottom="10" paddingLeft="10" paddingRight="10">
<mx:Script>
<![CDATA[
[Bindable]
private var _state:ClientState = new ClientState();
public function result(data:Object):void
{
var updater:Updater = Updater(data);
updater.update(_state);
}
public function fault(info:Object):void
{
}
]]>
</mx:Script>
<mx:Label text="The following messages have been received from the server:"/>
<mx:List dataProvider="{_state}" width="100%"/>
</mx:Panel>
</mx:Application>
Updater Actionscript Interface
package example {
public interface Updater {
function update(state:ClientState):void;
}
}
AddString Actionscript Object
package example {
public class AddString implements Updater {
private var _value:String;
public function get value():String
{
return _value;
}
public function set value(st:String):void
{
_value = st;
}
public function update(state:ClientState):void
{
state.update(value);
}
}
}
ClientState Actionscript Object
package example {
import mx.collections.ArrayCollection;
public class ClientState extends ArrayCollection {
private var _lines:Array = new Array();
public function update(value:String):void
{
if (value == null)
return;
if (lines.length > 6)
lines.shift();
lines.push(value);
source = lines;
}
public function get lines():Array
{
return _lines;
}
}
}
Flash sandbox issuesThe Flash implementation of Hessian uses sockets directly. Under Flash's security model, sockets are sandboxed to prevent a Flash application from contacting arbitrary ports under 1024, even if they are connecting to the same domain. If your application runs on a server with a port > 1024, then the following steps will not be necessary. Flash allows applications to connect to hosts and ports according to a socket policy file. This policy file is an XML file retrieved from a host that specifies which referring hosts are allowed to access this host and specific ports. The protocol used for retrieving this policy file is not HTTP when using sockets, so it is necessary to configure a special server to handle such requests. Resin provides just such a server and makes it easy to configure. The following code would be added to your resin.conf file in the <server> or <server-default> section: Socket policy file server configuration
<protocol port="80" type="com.caucho.protocols.flash.SocketPolicyProtocol">
<init>
<socket-policy-file>/<path-to>/socketpolicy.xml</socket-policy-file>
</init>
</protocol>
In this example, the server is configured on port 80. In many cases, this will be the same port that you configure your HTTP server. The SocketPolicyProtocol server is intelligent enough that if it receives a request for a policy file using the Flash protocol, it will return the specified policy, but if it receives an HTTP request, it will process as normal. In this case, you will need to remove the <http> tag from your server configuration if it also uses port 80. Note that you may keep the protocol port and HTTP port separate if you like. The socket policy file is retrieved from the file specified by the <socket-policy-file> tag. The following shows the socket policy file used on this server. You will need to customize this file for your own site. Socket policy file used on hessian.caucho.com <cross-domain-policy> <allow-access-from domain="hessian.caucho.com" to-ports="80"/> </cross-domain-policy> Remember when we specified the policyPort on the HessianStreamingService tag in the CometClient.mxml file above? That port corresponds to the port of the socket policy server we configured. Hessian/Flash takes care of contacting the server when this port is specified. The CometController is Resin's thread-safe encapsulation
of control and communication from the application's service to the
Comet servlet. Applications may safely pass the In the example, the com.caucho.servlet.comet.CometController
package com.caucho.servlet.comet;
public interface CometController
{
public boolean wake();
public Object getAttribute(String name);
public void setAttribute(String name, Object value);
public void removeAttribute(String name);
public void close();
}
The comet servlet has three major responsibilities:
Like other servlets, only the comet servlet
may use the Process the initial request: our servlet just calls
Register the Send streaming data:. The example/HessianCometServlet.java
package example;
import java.io.*;
import java.util.*;
import java.util.concurrent.*;
import javax.annotation.*;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.webbeans.In;
import com.caucho.hessian.io.*;
import com.caucho.servlet.comet.*;
public class HessianCometServlet extends GenericCometServlet
{
@In private TimerService _timerService;
private ArrayList<CometState> _itemList
= new ArrayList<CometState>();
@Override
public boolean service(ServletRequest request,
ServletResponse response,
CometController controller)
throws IOException, ServletException
{
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
Hessian2StreamingOutput out =
new Hessian2StreamingOutput(res.getOutputStream());
CometState state = new CometState(controller);
// Add the comet state to the controller
_timerService.addCometState(state);
return true;
}
@Override
public boolean resume(ServletRequest request,
ServletResponse response,
CometController controller)
throws IOException, ServletException
{
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
Hessian2StreamingOutput out =
new Hessian2StreamingOutput(res.getOutputStream());
Object command = controller.getAttribute("comet.command");
out.writeObject(command);
return true;
}
}
The connection can close for a number of reasons. Either the
The sequence of calls for the example looks like the following:
Our Comet Servlet is deployed like any other servlet in resin-web.xml, using a <servlet-mapping> tag: WEB-INF/resin-web.xml
<web-app xmlns="http://caucho.com/ns/resin">
<servlet-mapping url-pattern="/comet"
servlet-class="example.HessianCometServlet"/>
...
</web-app>
Comet Servlet State MachineThe sequence of comet servlet calls looks like the following state
machine. After the initial request, the servlet spends most of its
time suspended, waiting for the ![]() Download the source for this demo
| ||||||||||||||||||||||||||||||