I have Flex 3.6 + BlazeDS + Java 1.6 webapp running on Tomcat 6. I need the BlazeDS pushing message service from server to client to create a deterministic progress bar when some elaboration are invoked by user from flex front end.
Then I have n module built as follows:
public static const JOBN:String = "JOBN";
private var _dm:DataManager;
public function init():void {
_dm = new DataManager;
}
private function btnN_OnClick(event:MouseEvent):void {
_dm.addEventListener(JOBN, onJobNResult);
_dm.jobN();
}
private function onJobNResult(dataEvent:MyEvent):void {
var resN:int = dataEvent.result as int;
_dm.removeEventListener(JOBN, onJobNResult);
}
and a DataManager built as follows:
public static const JOBN:String = "JOBN";
public function DataManager() {
var loCs:ChannelSet = new ChannelSet();
loCs.addChannel(new AMFChannel("canale", "messagebroker/amf"));
_service = new RemoteObject("dataManager");
_service.channelSet = loCs;
}
public function jobN():void {
var token:AsyncToken = _service.jobN();
token.addResponder(new AsyncResponder(jobNOnResult,jobNOnFault));
runProgressBar();
}
private function jobNOnFault(event:FaultEvent,token:Object):void {
var _fail:String = "Error";
}
private function jobNOnResult(event:ResultEvent,token:Object):void {
var jobNResult:int = event.result as int;
dispatchEvent(new MyEvent(JOBN,jobNResult));
stopProgressBar();
}
the runProgressBar() and stopProgressBar() method respectively create and remove a PopUp which contains the progress bar and is placed on the app canvas. The popup methods starts and stop the pushing message thread:
private function init():void {
start();
}
private function start():void {
var msg:AsyncMessage = new AsyncMessage();
msg.body = "START";
producer.send(msg);
consumer.subscribe();
}
private function stop():void {
var msg:AsyncMessage = new AsyncMessage();
msg.body = "STOP";
producer.send(msg);
}
private function messageHandler(message:IMessage):void {
values = message.body as String;
value = (int) (values.substr(0, values.lastIndexOf(";")));
max = (int) (values.substr(values.indexOf(";")+1,values.length));
if (value == -1) {
value = 0;
increaseProgress(max,max);
stop();
} else {
increaseProgress(value, max);
}
}
private function ack(event:MessageAckEvent):void {
if ( (event != null) && (event.message.body != null) ) {
values = event.message.body as String;
}
}
private function increaseProgress(num:int, max:int):void {
trace(num+" "+max);
prgBar.setProgress(num, max);
}
Java class that sends data:
public class ProgressMessSender extends ServiceAdapter {
private ProgressDataSender thread;
public void startMessaging() {
if (thread == null) {
thread = new ProgressDataSender();
thread.start();
}
}
public void stop() {
thread.running = false;
MsgConstant.ProgValues = 0;
MsgConstant.MaxValues = -2;
thread = null;
}
@Override
public Object invoke(Message message) {
if (message.getBody().equals("STOP")) {
stop();
} else if (message.getBody().equals("START")) {
startMessaging();
}
return null;
}
public class ProgressDataSender extends Thread {
public volatile boolean running = true;
private Message createTestMessage() {
AsyncMessage msg = new AsyncMessage();
msg.setDestination("RandomDataPush");
msg.setClientId(UUIDUtils.createUUID());
msg.setMessageId(UUIDUtils.createUUID());
msg.setBody(MsgConstant.ProgValues+";"+MsgConstant.MaxValues);
return msg;
}
public void run() {
while(running) {
sendMessageToClients(createTestMessage());
secondsToSleep(5);
}
}
public void sendMessageToClients(Message msg) {
((MessageService) getDestination().getService()).pushMessageToClients(msg, false);
}
private void secondsToSleep(int seconds) {
try{
Thread.sleep(seconds * 10);
}catch(InterruptedException e){
System.out.println("TestServiceAdapter Interrupted while sending messages");
e.printStackTrace();
}
}
}
}
MsgConstant.MaxValues and MsgConstant.ProgValues are static variables that are respectively setted and increased in job classes. The configuration BlazeDS files messaging-config.xml and services-config.xml are modified according to this guide.
Problem is: If I invoke a job from a module the progress bar starts and stops correctly, all works fine. Once invoked a job from a module if I invoke another job from another module I always get the follow exception:
[BlazeDS]Unexpected error encountered in Message Broker servlet
java.lang.IllegalStateException
at org.apache.catalina.connector.ResponseFacade.sendError(ResponseFacade.java:421)
at flex.messaging.endpoints.BaseStreamingHTTPEndpoint.handleFlexClientStreamingOpenRequest(BaseStreamingHTTPEndpoint.java:764)
at flex.messaging.endpoints.BaseStreamingHTTPEndpoint.serviceStreamingRequest(BaseStreamingHTTPEndpoint.java:1055)
at flex.messaging.endpoints.BaseStreamingHTTPEndpoint.service(BaseStreamingHTTPEndpoint.java:460)
at flex.messaging.MessageBrokerServlet.service(MessageBrokerServlet.java:353)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:723)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:293)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:861)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:620)
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489)
at java.lang.Thread.run(Unknown Source)
I have searched the web but I can't find a working solution and I have no idea how to solve this.
Simpler question.. I have tried another way to push message without extends ServiceAdapter :
messaging-config.xml:
<adapters>
<adapter-definition id="actionscript" class="flex.messaging.services.messaging.adapters.ActionScriptAdapter" default="true" />
</adapters>
<destination id="feed">
<properties>
<network>
<session-timeout>0</session-timeout>
</network>
<server>
<message-time-to-live>0</message-time-to-live>
<durable>false</durable>
</server>
</properties>
</destination>
services-config.xml is the same as the first question:
<channel-definition id="my-streaming-amf" class="mx.messaging.channels.StreamingAMFChannel">
<endpoint url="http://localhost:8080/ProgressBar2/messagebroker/streamingamf" class="flex.messaging.endpoints.StreamingAMFEndpoint"/>
<properties>
<!-- you don't need to set all these properties, this is just what we set, included for illustration, only -->
<idle-timeout-minutes>0</idle-timeout-minutes>
<max-streaming-clients>10</max-streaming-clients>
<server-to-client-heartbeat-millis>5000</server-to-client-heartbeat-millis>
<user-agent-settings>
<user-agent match-on="Safari" kickstart-bytes="2048" max-streaming-connections-per-session="10"/>
<user-agent match-on="MSIE" kickstart-bytes="2048" max-streaming-connections-per-session="15"/>
<user-agent match-on="Firefox" kickstart-bytes="2048" max-streaming-connections-per-session="10"/>
</user-agent-settings>
</properties>
</channel-definition>
and class that push the message:
private Message createTestMessage() {
AsyncMessage msg = new AsyncMessage();
msg.setDestination("feed");
msg.setClientId(clientID);
msg.setMessageId(UUIDUtils.createUUID());
msg.setBody(MsgConstant.ProgValues+";"+MsgConstant.MaxValues);
msgBroker.routeMessageToService(msg, null);
System.out.println("CREATE MESSAGE FOR CLIENT: "+msg.getBody().toString());
return msg;
}
public void run() {
while(running) {
createTestMessage();
secondsToSleep(1);
}
}
private void secondsToSleep(int seconds) {
try{
Thread.sleep(seconds * 100);
}catch(InterruptedException e){
System.out.println("TestServiceAdapter Interrupted while sending messages");
e.printStackTrace();
}
}
And this way works better than the first but the method msgBroker.routeMessageToService() send message (or block of messages) to the client every tot second and progress bar increase from 10% to 50% or more in a while and it's not good. Is there a way to send message quickly?
Solution
I manage to push message from server to client without define a custom SeviceAdapter (the Thread inside class extends ServiceAdapter starts at application startup and I don't know how avoid this) as follow:
messaging-config.xml
<default-channels>
<channel ref="my-streaming-amf"/>
<channel ref="my-polling-amf"/>
</default-channels>
<destination id="dest">
<properties>
<network>
<session-timeout>0</session-timeout>
</network>
<server>
<message-time-to-live>0</message-time-to-live>
<durable>false</durable>
</server>
</properties>
</destination>
services-config.xml
<channel-definition id="my-amf" class="mx.messaging.channels.AMFChannel">
<endpoint url="http://localhost:8080/ProgressBar2/messagebroker/amf" class="flex.messaging.endpoints.AMFEndpoint"/>
<properties>
<polling-enabled>false</polling-enabled>
<polling-interval-millis>4</polling-interval-millis>
</properties>
</channel-definition>
<channel-definition id="my-polling-amf" class="mx.messaging.channels.AMFChannel">
<endpoint url="http://localhost:8080/ProgressBar2/messagebroker/amfpolling" class="flex.messaging.endpoints.AMFEndpoint"/>
<properties>
<polling-enabled>false</polling-enabled>
<polling-interval-seconds>4</polling-interval-seconds>
</properties>
</channel-definition>
<!-- definito per il push di dati asincroni da java a flex -->
<channel-definition id="my-streaming-amf" class="mx.messaging.channels.StreamingAMFChannel">
<endpoint url="http://localhost:8080/ProgressBar2/messagebroker/streamingamf" class="flex.messaging.endpoints.StreamingAMFEndpoint"/>
<properties>
<!-- you don't need to set all these properties, this is just what we set, included for illustration, only -->
<idle-timeout-minutes>0</idle-timeout-minutes>
<max-streaming-clients>10</max-streaming-clients>
<server-to-client-heartbeat-millis>5000</server-to-client-heartbeat-millis>
<user-agent-settings>
<user-agent match-on="Safari" kickstart-bytes="2048" max-streaming-connections-per-session="10"/>
<user-agent match-on="MSIE" kickstart-bytes="2048" max-streaming-connections-per-session="15"/>
<user-agent match-on="Firefox" kickstart-bytes="2048" max-streaming-connections-per-session="10"/>
</user-agent-settings>
</properties>
</channel-definition>
java class extends Thread that send messages:
MessageBroker msgBroker = MessageBroker.getMessageBroker(null);
public Message createTestMessage() {
AsyncMessage msg = new AsyncMessage();
msg.setDestination("feed");
msg.setClientId(UUIDUtils.createUUID());
msg.setMessageId(UUIDUtils.createUUID());
msg.setBody(MsgConstant.ProgValues+";"+MsgConstant.MaxValues);
msgBroker.routeMessageToService(msg, null);
return msg;
}
public void run() {
while(running) {
sendMessageToClients(createTestMessage());
secondsToSleep(1);
}
}
public void sendMessageToClients(Message msg) {
MessageService service = (MessageService) msgBroker.getService("message-service");
service.pushMessageToClients(msg, false);
}
Than I define a tag consumer inside .mxml and I start (and stop) thread by DataManager when elaboration starts.