BlazeDS, Push-Nachricht generiert eine IllegalStateException

Ich habe Flex 3.6 + BlazeDS + Java 1.6 webapp auf Tomcat 6 ausgeführt. Ich brauche den BlazeDS-Pushing-Nachrichtendienst von Server zu Client, um eine deterministische Fortschrittsleiste zu erstellen, wenn der Flex-Front-End-Benutzer eine ausführliche Bearbeitung anfordert.

Dann habe ich n Modul wie folgt aufgebaut:

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);
}

und einen DataManager, der wie folgt aufgebaut ist:

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

Die Methoden runProgressBar() und stopProgressBar() erstellen bzw. entfernen ein PopUp, das die Fortschrittsleiste enthält und ist auf der App-Leinwand platziert. Die Popup-Methoden starten und stoppen den Pushing-Nachrichtenthread:

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-Klasse, die Daten sendet:

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)

Ich habe im Internet gesucht, finde aber keine funktionierende Lösung und weiß nicht, wie ich das lösen soll.


Einfachere Frage .. Ich habe eine andere Möglichkeit zum Senden von Nachrichten ohne ServiceAdapter ausprobiert:

messaging-config.xml:


    


 
     
        
            0 
         
        
            <message-time-to-live>0<\/message-time-to-live> 
            <durable>false<\/durable> 
         
     

services-config.xml entspricht der ersten Frage:


        
        
             <!-- you don't need to set all these properties, this is just what we set, included for illustration, only -->
            0
            10
                5000
            
                  
                 
                
            
        

und Klasse, die die Nachricht drücken:

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

Und dieser Weg funktioniert besser als der erste, aber die Methode msgBroker.routeMessageToService() sendet jede Sekunde eine Nachricht (oder einen Block von Nachrichten) an den Client und der Fortschrittsbalken steigt in einer Weile von 10% auf 50% oder mehr, und das ist nicht gut. Gibt es eine Möglichkeit, Nachrichten schnell zu senden?


Lösung

Ich schaffe es, eine Nachricht vom Server an den Client zu senden, ohne einen benutzerdefinierten SeviceAdapter zu definieren (die Klasse Thread innerhalb der Klasse erweitert ServiceAdapter beginnt beim Start der Anwendung und ich weiß nicht, wie Sie dies vermeiden können):

messaging-config.xml


    
    




     
        
            0 
         
        
            <message-time-to-live>0<\/message-time-to-live> 
            <durable>false<\/durable> 
        
    

services-config.xml


        
        
            false
            4
        
    


        
        
            false
            4
        
    

    <!-- definito per il push di dati asincroni da java a flex -->

        
        
             <!-- you don't need to set all these properties, this is just what we set, included for illustration, only -->
            0
            10
                5000
            
                  
                 
                
            
        

Java-Klasse erweitert Thread, der Nachrichten sendet:

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);
}

Dann definiere ich ein Tag Consumer in .mxml und starte (und stoppe) einen Thread mit DataManager , wenn die Ausarbeitung beginnt.

1
ru