我在 Tomcat 6 上运行 Flex 3.6 + BlazeDS + Java 1.6 webapp。我需要BlazeDS从服务器推送消息服务,以便在用户从flex前端调用某些详细信息时创建确定性进度条。
然后我有如下构建的n模块:
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);
}
和构建如下的DataManager:
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();
}
runProgressBar() 和 stopProgressBar() 方法分别创建和删除包含进度的PopUp栏和放置在应用程序画布上。弹出方法启动和停止推送消息线程:
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类:
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 和 MsgConstant.ProgValues 是在作业类中分别设置和增加的静态变量。配置BlazeDS文件 messaging-config.xml 和 services-config.xml 将根据此{{ 3}}
问题 : 如果我从模块调用作业,进度条正确启动和停止,一切正常。一旦从模块中调用了一个作业,如果我从另一个模块调用另一个作业,我总会得到以下异常:
[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)
我在网上搜索过,但我找不到可行的解决方案,而且我不知道如何解决这个问题。
更简单的问题..我尝试了另一种方式来推送消息而不扩展 ServiceAdapter :
消息-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与第一个问题相同:
<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>
和推送消息的类:
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();
}
}
这种方式比第一种方式更好,但方法msgBroker.routeMessageToService()每隔一秒向客户端发送一条消息(或消息块),进度条在一段时间内从10%增加到50%或更多#39;不好。有没有办法快速发送消息?
我设法将消息从服务器推送到客户端没有定义自定义SeviceAdapter(类内部的Thread扩展ServiceAdapter在应用程序启动时启动,我不知道如何避免这种情况)如下所示:
消息-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>
服务-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类扩展发送消息的线程:
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);
}
我在.mxml中定义了一个标签 consumer ,并在精心设计开始时通过 DataManager 启动(并停止)线程。