BlazeDS, отправка сообщения генерирует исключение IllegalStateException - PullRequest
0 голосов
/ 27 апреля 2018

У меня Flex 3.6 + BlazeDS + Java 1.6 веб-приложение, работающее на Tomcat 6 . Мне нужно, чтобы служба сообщений 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 () соответственно создает и удаляет всплывающее окно, которое содержит индикатор выполнения и помещается на холсте приложения. Всплывающие методы запускают и останавливают поток сообщений:

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 изменены в соответствии с этим руководством .

Проблема : Если я вызываю задание из модуля, индикатор выполнения запускается и останавливается правильно, все работает нормально. Однажды вызвав работу из модуля, если я вызываю другую работу из другого модуля, я всегда получаю следующее исключение:

[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% или более, и это нехорошо. Есть ли способ быстро отправить сообщение?


Решение

Мне удается отправить сообщение с сервера на клиент. без определить пользовательский 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, и я запускаю (и останавливаю) поток с помощью DataManager , когда начинается разработка.

...