Simplified BlazeDS and JMS
发布时间:2020-12-15 01:23:50 所属栏目:百科 来源:网络整理
导读:I've been using Flex for some time now,and finally got around to trying out BlazeDS. What really peaked my interest was it's claim to publish and consume JMS messages from both topics and queues. The one area in web development that I alwa
I've been using Flex for some time now,and finally got around to trying out
BlazeDS. What really peaked my interest was it's claim to publish and consume JMS messages from both topics and queues.
The one area in web development that I always struggle with is asynchronous messaging from the server to clients over HTTP. I'm pleased to announce that I got a simple application up and running. The goal of this post is to share the example and lessons learned in order to save others some of the problems I ran into. My project had a few main goals:
Before I get into the example code,a few things I ran into:
The example contains 5 main files:
The image to the right shows the file locations in the final WAR layout. web.xml The web.xml file is pretty basic. The main 2 things to point out are the HttpFlexSession listener and the MessageBrokerServlet. The servlet loads up you services,so it is passed the location of the services-config.xml file inside the WAR file. <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE web-app PUBLIC "-//Sun Microsystems,Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd"> <web-app> <display-name>BlazeDS</display-name> <description>BlazeDS Application</description> <!-- Http Flex Session attribute and binding listener support --> <listener> <listener-class>flex.messaging.HttpFlexSession</listener-class> </listener> <!-- MessageBroker Servlet --> <servlet> <servlet-name>MessageBrokerServlet</servlet-name> <display-name>MessageBrokerServlet</display-name> <servlet-class>flex.messaging.MessageBrokerServlet</servlet-class> <init-param> <param-name>services.configuration.file</param-name> <param-value>/WEB-INF/flex/services-config.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>MessageBrokerServlet</servlet-name> <url-pattern>/messagebroker/*</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>index.html</welcome-file> <welcome-file>index.htm</welcome-file> <welcome-file>index.jsp</welcome-file> </welcome-file-list> </web-app> context.xml The context.xml file is for Tomcat. You can read more about it in the Tomcat documentation. The key take away is the "name" attribute is the JNDI name that has to match the jndi name used in the messaging-config.xml file. <?xml version="1.0" encoding="UTF-8"?> <Context path="/BlazeTest"> <Resource name="jms/flex/TopicConnectionFactory" type="org.apache.activemq.ActiveMQConnectionFactory" description="JMS Connection Factory" factory="org.apache.activemq.jndi.JNDIReferenceFactory" brokerURL="tcp://localhost:61616" brokerName="myBroker"/> <Resource name="jms/messageTopic" type="org.apache.activemq.command.ActiveMQTopic" description="a simple topic" factory="org.apache.activemq.jndi.JNDIReferenceFactory" physicalName="messageTopic"/> </Context> services-config.xml The services-config.xml file is used by BlazeDS. It is first used when you go to compile the mxml file. When you deploy the war file to Tomcat,this file is also loaded up by the MessageBrokerServlet. During compilation,you pass it in like this using the relative path to it from your mxml file. ~/java_libraries/flex3/bin/mxmlc -services=WEB-INF/flex/services-config.xml test.mxml My current file turns on logging which can help during resolve messaging problems like jndi resources not being found. This file loads in the messaging-config.xml file which is described below. The channels determine how the client will talk to the server. The endpoint has to match the servlet-mapping url-pattern contained in the web.xml. Since the servlet is grabbing /messagebroker/* and my application is deployed under BlazeTest,the endpoint becomes: http://localhost:8080/BlazeTest/messagebroker/amf The "amf" on the end of the URL can be called anything--it's what distinguishes one channel url from another channel url. Here,I am only using one channel. <?xml version="1.0" encoding="UTF-8"?> <services-config> <services> <service-include file-path="messaging-config.xml" /> </services> <security/> <channels> <channel-definition id="my-amf" class="mx.messaging.channels.AMFChannel"> <endpoint url="http://localhost:8080/BlazeTest/messagebroker/amf" class="flex.messaging.endpoints.AMFEndpoint"/> </channel-definition> </channels> <logging> <target class="flex.messaging.log.ConsoleTarget" level="Debug"> <properties> <prefix>[BlazeDS] </prefix> <includeDate>false</includeDate> <includeTime>false</includeTime> <includeLevel>false</includeLevel> <includeCategory>false</includeCategory> </properties> <filters> <pattern>Endpoint.*</pattern> <pattern>Service.*</pattern> <pattern>Configuration</pattern> </filters> </target> </logging> </services-config> messaging-config.xml This file stores the JMS services and tells BlazeDS where to get the JMS ConnectionFactory and Topics from the JNDI lookup. The part here that caused be a little problem was making sure the connection-factory and destination-jndi-name values had the correct JNDI name Tomcat expected. Also,note the destination id value. When you set up the consumer or producer in the mxml file,you don't tell it what Topic or Queue to connect to,you tell it what destination to connect to. This makes sense,since the mx:Producer and mx:Consumer attribute is called "destination",but it did throw me for a little loop. <?xml version="1.0" encoding="UTF-8"?>
<service id="message-service" class="flex.messaging.services.MessageService">
<adapters>
<adapter-definition id="actionscript" class="flex.messaging.services.messaging.adapters.ActionScriptAdapter" default="true" />
<adapter-definition id="jms" class="flex.messaging.services.messaging.adapters.JMSAdapter"/>
</adapters>
<default-channels>
<channel ref="my-amf"/>
</default-channels>
<destination id="message-destination">
<properties>
<jms>
<destination-type>Topic</destination-type>
<message-type>javax.jms.TextMessage</message-type>
<connection-factory>java:comp/env/jms/flex/TopicConnectionFactory</connection-factory>
<destination-jndi-name>java:comp/env/jms/messageTopic</destination-jndi-name>
<delivery-mode>NON_PERSISTENT</delivery-mode>
<message-priority>DEFAULT_PRIORITY</message-priority>
<acknowledge-mode>AUTO_ACKNOWLEDGE</acknowledge-mode>
<initial-context-environment>
<property>
<name>Context.INITIAL_CONTEXT_FACTORY</name>
<value>org.apache.activemq.jndi.ActiveMQInitialContextFactory</value>
</property>
<property>
<name>Context.PROVIDER_URL</name>
<value>tcp://localhost:61616</value>
</property>
</initial-context-environment>
</jms>
</properties>
<channels>
<channel ref="my-amf"/>
</channels>
<adapter ref="jms"/>
</destination>
</service>
test.mxml The test.mxml is the final file. It's the GUI code. The file gets compiled into a swf file as I showed up above. My version uses mx:Producer and mx:Consumer mxml tags,though you can also instantiate these using Actionscript if you'd like. I prefer to write as little script as possible. The main key in this file was that I had to subscribe the consumer to it's destination before it would consume messages. Everything else is pretty simple,and you can see how easy it is to get a client sending and receiving messages to the server-side JMS broker over HTTP. This is why I like Flex! <?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx='http://www.adobe.com/2006/mxml' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' backgroundGradientColors="[0xcfe4ff,0xffffff]" paddingTop="5" paddingLeft="5" paddingRight="5" paddingBottom="0" applicationComplete="logon()"> <mx:Script> <![CDATA[ import mx.rpc.events.FaultEvent; import mx.messaging.*; import mx.messaging.messages.*; import mx.messaging.events.*; import mx.controls.Alert; private function messageHandler(event:MessageEvent):void { receiveTextArea.text = event.message.body + "n" + receiveTextArea.text; } private function acknowledgeHandler(event:MessageAckEvent):void{ } private function faultHandler(event:MessageFaultEvent):void { Alert.show('Fault!','Alert Box',mx.controls.Alert.OK); } private function logon():void { consumer.subscribe(); } private function sendMessage():void { var message:AsyncMessage = new AsyncMessage(); message.body = sendTextArea.text; producer.send(message); sendTextArea.text=""; } ]]> </mx:Script> <mx:Producer id="producer" destination="message-destination" acknowledge="acknowledgeHandler(event);" fault=" faultHandler(event)"/> <mx:Consumer id="consumer" destination="message-destination" message="messageHandler(event)" acknowledge="acknowledgeHandler(event);" fault=" faultHandler(event)"/> <mx:HBox> <mx:TextInput id="sendTextArea"/> <mx:Button label="Send" click="sendMessage();"/> </mx:HBox> <mx:TextArea id="receiveTextArea" width="50%" height="200"/> </mx:Application>The client app looks something like this: In Conclusion,BlazeDS is an extremely simple way to use JMS with remote Flex clients over HTTP connections. The back-end configuation is somewhat complex,but mostly boilerplate and not too bad once you piece it together. I haven't "stress" tested the messaging yet,or done very complex messaging to be able to say how robust and scalable it is,but so far,It does live up to it's claims. Best of all,I can now do asynchronous messaging to remote clients without writing code. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |