dev2dev 首页 > 资源中心 > 技术文章
JMSML:基于XML的标记语言 减少程序编写、监测以及测试的细节
JMSML是一种标记语言,设计和开发它的目的在于,通过在一些简单易用的XML标签隐藏所有的JMS和JMX的Java
API 的复杂性,从而使创建Java消息服务(Java Message
Service,JMS)和Java管理扩展(Java Management
Extensions,JMX)程序的过程更加容易。
JMS
应用:背景 典型的JMS应用程序开发过程包括在JMS提供者应用服务器上配置和管理JMS服务器组件,比如JMSConnectionFactory
和JMSDestination,以及编写使用这些服务器端管理的对象来进行Java消息传递的JMS应用客户端。
JMS应用客户端是利用JMS API编写的Java程序,并且被划分成两类程序:
生产者:负责生成各种各样的JMS消息类型(比如Text, XML, Object,
Stream, Bytes)并且把它们发送到JMS 目的地(消息队列和主题)
消费者:负责从JMS
目的地(消息队列和主题)接收消息,即可以同步接收也可以异步接收。
JMS API是消息生产者和消费者能够使用多种服务质量(qualities of services
,QOS),它们是由底层的JMS实现和JMS提供者(比如事务和认证)提供的。
使用JMS
API来编写消息生产者和消费者包括下面的几个特定步骤,而且需要按照一定顺序执行。这个过程必须对每一个为执行Java消息而编写出来的生产者和消费者重复一遍。
The
JMSML方法 编写JMS应用客户端的JMSML方法不需要编写代码就能够实现。
JMS
API的复杂性被抽象到了一些XML标签中,它们容易使用而且容易记忆。使用JMSML,你可以创建简单的可重用的JMS组件,比如一个"发送者",
"接收者", "发布者",和 "订阅者"。除此之外,JMSML通过使用XML标签,消除了JMS API的复杂性,
使JMS server的管理变得非常简单。JMSML支持为JMS
server的动态配置、管理、以及运行时管理提供服务的所有的JMX操作。
最后,JMSML通过自动验证操作和监测输出,简化了测试。
Java JMS程序是什么样子? 清单1展示了一个利用JMS
API来发送文本消息"Hello World"到一个名为"exampleQueue"的JMS
队列的Java程序,它通过一个非事务支持的(nontransacted)、自动识别的(autoacknowledge)JMSSession使用了一个名为"QueueConnectionFactory"的JMSConnectionFactory(JMS连接工厂)。
JMSML程序是什么样子? 接下来的9行简单的XML代码,来自QueueSend.xml,它和清单1中QueueSend.java的74行代码作用相同。注意:借助默认的属性值,所有其它的Java
JMS API细节都可以被JMSML照顾到。
1
<?xml version="1.0" encoding="UTF-8"?> 2
<!DOCTYPE jmsml PUBLIC "-//BEA Systems Inc//DTD JMSML
Version 1.0 JMSML//EN" "jmsml.dtd"> 3
<jmsml> 4 <operation Class="message"
Type="Text" Name="MyQueueSender" 5
Factory="QueueConnectionFactory" 6
Queue="exampleQueue" 7 Body="Hello World" 8
>Send</operation> 9 </jmsml>
这种情况下,JMSML将会通过一个非事务支持的(nontransacted)、自动识别的(autoacknowledge)JMSSession创建一个QueueSender。
一旦这个操作被执行,"MyQueueSender"对象就能够被重复使用,直到程序停止运行。也就是说?quot;MyQueueSender"能够被用来向不同的消息队列发送不同的消息。
JMSML应用程序 通过前面的代码对比,你很容易就能看出JMSML容易学习和使用,而且在它功能所及的范围之内十分强大。可以在WebLogic
JMS 子系统中使用JMSML来完成下面的任务。
作为WebLogic JMS子系统的一个管理和监测工具。
作为WebLogic JMS应用程序的原型工具。
作为WebLogic JMS子系统的测试工具。
使用JMSML作为测试工具 一旦JMS测试场景被确定,他们能够很容易地被转化成JMSML操作,并且被<scenario>元素包围,从而作为一个测试场景,其中的Verify属性被设置为"false"。该测试程序能够被JMSML执行模型中的某一个所执行。成功执行后,将生成一个和输入的JMSML程序同名的,后缀是.out的输出文件。需要手工验证它的正确性,然后把它保存成一个基准文件(还是和输入的JMSML程序同名,但后缀是.bmk)。
在这之后,无论什么时候执行同样的JMSML程序,如果该组<scenario>元素内的Verify属性被设为"true",JMSML将会把这个输入的JMSML程序当成是一个测试,并且会自动把输出文件与对应的基准文件进行比较,从而进行确认。
如果基准文件和输出文件吻合,那么测试就被宣布为通过,否则,将会被宣布为失败。
例子 测试被JMS管理的对象的动态创建、管理、和监测,以及JMS的消息发送和接收特性。
测试场景:创建一个名为"Warehouse"并且所有属性均为默认值的JMSServer,并且在一个名为"examplesServer"的WebLogic服务器实例上部署它。创建一个名为"orderqueue"的queue
destination,并且使用所有明确定义的默认属性,然后把它添加到名为"Warehouse"的JMSServer上,输入"jms.queue.order"作为它的JNDI。向这个消息队列发送/接收消息,最后,删掉这个名为"orderqueue"的queue
destination和名为"Warehouse" 的JMSServer。
清单2是上面定义的测试场景的JMSML描述。
一个JMSML一旦被编写完成,它就能够在当前的WebLogic服务器实例中运行。当前,JMSML提供了三种不同的运行程序的方法,它们是:
1.独立的命令行客户端 2.用于远程执行的Web浏览器接口 3.IDE
(原型)
java
com.bea.jmsml.commandline.JMSMLClient \ -protocol t3
\ -host localhost \ -port 7001 \ -username
weblogic \ -password weblogic \ -filename
jmstest.xml
该命令行假定执行环境按照如下方式设定:
一个名为"examplesServer"的WebLogic服务器实例正运行在本机,并且在"t3"协议被启动的情况下监听'7001端口。
WebLogic的安全性被设置成允许一个用户名为"weblogic",密码为"weblogic"的用户创建并且访问JMS服务器组件。
一个有效的JMS连接工厂被部署在"examplesServer"上,而且被绑定在JNDI名字"weblogic.examples.jms.QueueConnectionFactory"之上。
清单3中所示的测试程序被保存在"jmsml.dtd"文件所在的当前目录。
成功执行命令后,在标准输出上应该显示下面的消息。
*** jmstest processed ***
\n*** Please see ./jmstest.out for the results ***
这时,当前目录下应该存在一个名为"jmstest.out"的输出文件,其中包含了所有的操作执行结果,如清单3所示。
在这个输出示例中,代码内容用不同的颜色显示,从而标识出操作类别,如下所示: 棕色:JMS接收(在通常模式下成功的发送没有输出) 红色:JMX添加、删除 蓝色:JMX列表(配置信息) 绿色:JMX列表(运行时统计)
一旦手工验证了这个输出的正确性,你就可以通过以下两步轻松地把它变成一个正确的、可重用的WebLogic
JMS测试案例。
1把"jmstest.out"文件重命名为"jmstest.bmk"。 2编辑"jmstest.xml"文件,把<scenario>元素中的Verify属性设为"true"。
当下次执行同样的命令行时,JMSML把"jmstest.xml"当作一个测试案例并且在标准输出上输出测试的通过/失败结果。
这就是全部!不用进行Java编程,我们利用JMSML,快速地为BEA WebLogic
的JMS和JMX特性编写了一个完整的测试案例。这是一个可以运行的例子,就在JMSML的下载包中。
资源
可以从以下网址下载JMSML产品的二进制版本,里面附有技术白皮书: http://dev2dev.bea.com/resourcelibrary/whitepapers/JMSML_WhitePaper.jsp
Listing 1: QueueSend.java
1 import java.util.*; 2 import
javax.naming.*; 3 import javax.jms.*; 4 5
public class QueueSend 6 { 7 public final static
String 8
JNDI_FACTORY="weblogic.jndi.WLInitialContextFactory"; 9
public final static String 10
JMS_FACTORY="QueueConnectionFactory"; 11 public final
static String QUEUE="exampleQueue"; 12 13 private
QueueConnectionFactory qconFactory; 14 private
QueueConnection qcon; 15 private QueueSession
qsession; 16 private QueueSender qsender; 17
private Queue queue; 18 private TextMessage
msg; 19 20 public void init(Context ctx, String
queueName) 21 throws NamingException,
JMSException 22 { 23 qconFactory =
(QueueConnectionFactory) 24
ctx.lookup(JMS_FACTORY); 25 qcon =
qconFactory.createQueueConnection(); 25 qsession =
qcon.createQueueSession(false, 26
Session.AUTO_ACKNOWLEDGE); 27 queue = (Queue)
ctx.lookup(queueName); 28 qsender =
qsession.createSender(queue); 29 msg =
qsession.createTextMessage(); 30 qcon.start(); 31
} 32 33 public void send(String message) 34
throws JMSException 35 { 36
msg.setText(message); 37 qsender.send(msg); 38
} 39 40 public void close() 41 throws
JMSException 42 { 43 qsender.close(); 44
qsession.close(); 45 qcon.close(); 46 } 47
48 /** main() method. 49 * 50 * @param args
WebLogic Server URL 51 * @exception Exception if
operation fails 52 */ 53 public static void
main(String[] args) 54 throws Exception 55 { 56
if (args.length != 1) { 57 System.out.println("Usage:
java QueueSend WebLogicURL"); 58 return; 59
} 60 InitialContext ic =
getInitialContext(args[0]); 61 QueueSend qs = new
QueueSend(); 62 qs.init(ic, QUEUE); 63
qs.send("Hello World") 64 qs.close(); 65
} 66 67 private static InitialContext
getInitialContext(String url) 68 throws
NamingException 69 { 70 Hashtable env = new
Hashtable(); 71
env.put(Context.INITIAL_CONTEXT_FACTORY,
JNDI_FACTORY); 72 env.put(Context.PROVIDER_URL,
url); 73 return new InitialContext(env); 74 }
Listing 2: jmstest.xml
<?xml version="1.0" encoding="UTF-8"
?> <!DOCTYPE jmsml PUBLIC "-//BEA Systems
Inc//DTD JMSML Version 1.0 JMSML//EN"
"jmsml.dtd">
<jmsml>
<scenario Name="Dynamic Queue creation"
Verify="false">
<purpose> To test the dynamic creation of
queue </purpose><expectedresult> JMS
queue destination should be successfully created with
the specified attributes. In order to verify this,
two additional operations are performed as shown
below.
1. Take the statistics information of the JMSServer
"Warehouse", before and after the creation of the
queue destination, to see if the newly created
queue has been added to the current destination count
of the JMSServer "Warehouse".
2. A sender and receiver will be created to send and
receive a text message to and from the newly created
"orderqueue".
If the above two operations are
successful, the test is declared as PASSED. Otherwise
the test is declared as
FAILED. </expectedresult>
<operation
Class="mbean" Type="JMSServer" Name="Warehouse" Targets="examplesServer" >Add</operation>
<operation
Class="mbean" Type="JMSServer" Name="Warehouse" >List</operation>
<operation
Class="mbean" Type="JMSServerRuntime" Name="Warehouse" >List</operation>
<operation Class="mbean"
Type="Queue" Name="orderqueue" JMSServer="Warehouse" JNDIName="jms.queue.order" BytesMaximum="1024000" BytesThresholdHigh="1000000" BytesThresholdLow="4096" MessagesMaximum="100000" MessagesThresholdHigh="90000" MessagesThresholdLow="1000" PriorityOverride="6" TimeToLiveOverride="7200000" DeliveryModeOverride="Persistent" StoreEnabled="default" >Add</operation>
<operation Class="mbean"
Type="Queue" Name="orderqueue" >List</operation>
<operation
Class="mbean"
Type="JMSServerRuntime" Name="Warehouse" >List</operation>
<operation Class="mbean"
Type="DestinationRuntime" Name="orderqueue" >List</operation>
<operation Class="message"
Type="Text" Name="sender" Factory="weblogic.examples.jms.QueueConnectionFactory" Queue="jms.queue.order" Body="Test
message to order queue" >Send</operation>
<operation Class="mbean"
Type="DestinationRuntime" Name="orderqueue" >List</operation>
<operation Class="message"
Type="Text" Mode="Synchronous" Name="receiver" Factory="weblogic.examples.jms.QueueConnectionFactory" Queue="jms.queue.order" >Receive</operation>
<operation Class="mbean"
Type="DestinationRuntime" Name="orderqueue" >List</operation>
<operation Class="mbean"
Type="Queue" Name="orderqueue" >Remove</operation>
<operation Class="mbean"
Type="JMSServerRuntime" Name="Warehouse" >List</operation>
<operation Class="mbean"
Type="JMSServer" Name="Warehouse" >Remove</operation>
</scenario>
</jmsml>
Listing 3: jmstest.out
JMSServer : Warehouse was added
to server : examplesServer ! Name = Warehouse Targets[0] =
examplesServer BytesMaximum =
-1 BytesThresholdHigh = -1 BytesThresholdLow =
-1 MessagesMaximum = -1 MessagesThresholdHigh =
-1 MessagesThresholdLow =
-1 --------------------------------------------- Name =
Warehouse SessionPoolsCurrentCount =
0 SessionPoolsHighCount = 0 SessionPoolsTotalCount
= 0 DestinationsCurrentCount =
0 DestinationsHighCount = 0 DestinationsTotalCount
= 0 MessagesCurrentCount = 0 MessagesHighCount =
0 MessagesPendingCount = 0 MessagesReceivedCount =
0 BytesCurrentCount = 0 BytesHighCount =
0 BytesPendingCount = 0 BytesReceivedCount =
0 --------------------------------------------- Queue Destination : orderqueue was added
to JMSServer : Warehouse ! Name = orderqueue JNDIName =
jms.queue.order JMSServer = Warehouse StoreEnabled
= default Type = Queue BytesMaximum =
1024000 BytesThresholdHigh =
1000000 BytesThresholdLow = 4096 MessagesMaximum =
100000 MessagesThresholdHigh =
90000 MessagesThresholdLow = 1000 PriorityOverride
= 6 TimeToLiveOverride =
7200000 DeliveryModeOverride =
Persistent --------------------------------------------- Name =
Warehouse SessionPoolsCurrentCount =
0 SessionPoolsHighCount = 0 SessionPoolsTotalCount
= 0 DestinationsCurrentCount =
1 DestinationsHighCount = 1 DestinationsTotalCount
= 1 MessagesCurrentCount = 0 MessagesHighCount =
0 MessagesPendingCount = 0 MessagesReceivedCount =
0 BytesCurrentCount = 0 BytesHighCount =
0 BytesPendingCount = 0 BytesReceivedCount =
0 --------------------------------------------- Name = orderqueue ConsumersCurrentCount
= 0 ConsumersHighCount = 0 ConsumersTotalCount =
0 MessagesCurrentCount = 0 MessagesHighCount =
0 MessagesPendingCount = 0 MessagesReceivedCount =
0 BytesCurrentCount = 0 BytesHighCount =
0 BytesPendingCount = 0 BytesReceivedCount =
0 --------------------------------------------- Name = orderqueue ConsumersCurrentCount
= 0 ConsumersHighCount = 0 ConsumersTotalCount =
0 MessagesCurrentCount = 1 MessagesHighCount =
1 MessagesPendingCount = 0 MessagesReceivedCount =
1 BytesCurrentCount = 27 BytesHighCount =
27 BytesPendingCount = 0 BytesReceivedCount =
27 --------------------------------------------- @receiveMessage() : Message Received [0] :
Test message to order queue Name = orderqueue ConsumersCurrentCount
= 1 ConsumersHighCount = 1 ConsumersTotalCount =
1 MessagesCurrentCount = 0 MessagesHighCount =
1 MessagesPendingCount = 0 MessagesReceivedCount =
1 BytesCurrentCount = 0 BytesHighCount =
27 BytesPendingCount = 0 BytesReceivedCount =
27 --------------------------------------------- Queue : orderqueue was removed from
JMSServer : Warehouse
! --------------------------------------------- Name =
Warehouse SessionPoolsCurrentCount =
0 SessionPoolsHighCount = 0 SessionPoolsTotalCount
= 0 DestinationsCurrentCount =
1 DestinationsHighCount = 1 DestinationsTotalCount
= 1 MessagesCurrentCount = 0 MessagesHighCount =
1 MessagesPendingCount = 0 MessagesReceivedCount =
1 BytesCurrentCount = 0 BytesHighCount =
27 BytesPendingCount = 0 BytesReceivedCount =
27 --------------------------------------------- JMSServer : Warehouse was removed from
server : examplesServer !

| 作者简介 |
|
Kathiravan Sengodan具有超过11年的载软件行业经验。目前,他是BEA WebLogic JMS/Messaging组的一名软件工程师。 |
作者其它文章
|