The attached html doc contains a proposal for a URL syntax to be used by
the Call object to pass JMS'isms down to the transport layer.  Among
other things, this removes the necessity to call setTransport() in the
client code in order to enable the JMS transport.  The details of the
why and the how are included in the proposal.  Feel free to critique, or
pass it along to your own resident JMS experts to have at it.
Dave

-- 
Sonic Software - Backbone of the Extended Enterprise
--
David Chappell <[EMAIL PROTECTED]> Office: (781)999-7099
Mobile: (617)510-6566
Vice President and Chief Technology Evangelist, Sonic Software
co-author,"Java Web Services", (O'Reilly 2002)
"The Java Message Service", (O'Reilly 2000)
"Professional ebXML Foundations", (Wrox 2001)
--
Title: JMS URL Syntax

JMS URL Syntax For the Apache Axis Project

 

<author: Dave Chappell   [EMAIL PROTECTED]>

<author: Ray Chun           [EMAIL PROTECTED]>

<author: Jaime Meritt      [EMAIL PROTECTED] >

 

Summary

This is a proposal to define a URL syntax for use by the JMS transport layer in Axis.  The JMS URL syntax will allow a vendor-neutral way of specifying JMS specific details, like Topic and Queue destinations, without having to code them specifically into the client application, or pass them from a command line. 

 

Backgrounder

When one uses the JMS transport layer, it is hidden underneath the client API of Axis.  Axis implements the JAX-RPC API. JAX-RPC (and Axis) provides multiple models for constructing both static and dynamic invocations of a service.   There are 2 flavors of dynamic invocation using the Call and Stub interface, and a static model using a WSDL2Java stub generation.  Both the Call and Stub interfaces allow the use of application-specific properties that get passed down to the handlers, including the transport handler.

 

Currently the model in 1.0 Axis is to specify the JMS specific properties from the command line, or in a properties file.  The client application then obtains these and places the JMS specific properties into the Call object by calling the setProperty() method.   The properties are then passed on to the transport handler, where they are extracted and used to perform the appropriate actions in JMS nomenclature.  Examples of JMS specific properties are location of a ConnectionFactory object, the name of a JMS destination, the type of destination (topic or queue), username and password, and message delivery options such as persistence.

 

Example:

 

Service  service = new Service(new XMLStringProvider(wsdd));

 

// create the JMS transport

JMSTransport transport = new JMSTransport(connectorMap, cfMap);

 

// create a new Call object

Call     call    = (Call) service.createCall();

 

// populate the call object.  In this case it’s a method

// invocation with a description of the parameter list and

// the return type.

call.setOperationName( new QName("urn:xmltoday-delayed-quotes",       

                                       “getQuote") );

call.addParameter( "symbol",

                   XMLType.XSD_STRING,

                   ParameterMode.IN );

call.setReturnType( XMLType.XSD_FLOAT );

 

 

// set the transport object

call.setTransport(transport);

 

// set some properties.  These will get passed down into the

// handlers, including the transport handler.

call.setUsername(username );

call.setPassword(password );

call.setProperty(JMSConstants.WAIT_FOR_RESPONSE, Boolean.FALSE);

call.setProperty(JMSConstants.PRIORITY, new Integer(5));

call.setProperty(JMSConstants.DELIVERY_MODE,

new Integer(javax.jms.DeliveryMode.PERSISTENT));

call.setProperty(JMSConstants.TIME_TO_LIVE, new Long(20000));

 

call.setProperty(JMSConstants.DESTINATION, destination);

 

...

 

// invoke the call

res = (Float) call.invoke(...);

 

 

While the current model works well, the ease of plugging in the JMS transport can be made much more tenable by being able to specify everything in a URL encoding.  The goal is to eliminate the need to do anything special in the client application.

 

URL Syntax

Rather than inventing a rigid syntax, it is desirable to use a URL-encoded query string in accordance with RFC-1738.  The intent is to specify a minimal syntax, allowing for the most flexibility for different JMS providers. 

Proposed syntax:  jms:<vendor-uri>:*

The vendor-uri dictates how the remainder of the URL is encoded.  If the vendor-uri is omitted, then secondary lookup of the ‘connectionfactory’ and ‘destination’ properties is performed using JNDI.

 

Examples

Using Sonic:

With a host and port: jms:<vendor-uri>://host:port/domain?etc…

1. jms:sonicmq://localhost:2506/queue?destination=SampleQ1

With a slightly modified syntax: jms:<vendor-uri>:<domain>:*

2. jms:sonicmq:queue://localhost:2506?destination=SampleQ1

3. jms:sonicmq:queue;brokerurl1=url1;brokerurl2=url2;destination=SampleQ1

 

Using JNDI:

1. jms:jndi-uri://queue/MyQCF/MyQ?jmspriority=5&…

2. jms:jndi-uri://ldap.somewhere.com/queue?initialcontextfactory=icf& connectionfactory=MyCF&..

3. jms::queue;connectionfactory=MyQCF;destination=MyQ;…

 

Alternative syntax:  jms://<vendor-uri>/any…

Again, omitting a vendor-uri and thus specifying the URL with “jms:///…” will by default use JNDI as the secondary lookup.

 

Examples

1. jms://sonicmq/queue?brokerurl=localhost:2506&destination=SampleQ1&…

2. jms:///queue?connectionfactory=MyQCF&destination=MyQ&…

3. jms:///queue/MyQCF/MyQ?jmspriority=5...

 

The connection factory and destination are string properties that may map to a JNDI lookup name.  If the JMS provider supports direct instantiation of a CF class, or a named destination, then that is allowable as well.  As far as the client application is concerned, the CF and destination are just string properties, and the underlying implementation of the transport can decide whether or not to use JNDI.

 

JMS Properties

Properties that appear in the query string may be overridden by explicitly setting the property via call.setProperty(..).  For instance, the username and password, though optional parameters in the query string, will likely be specified using the call object’s setUsername() and setPassword() methods.

 

In the short term, the scope of what can be set in the query-string is limited to the perspective of  a JMS sender.  The following table illustrates the possible settings in the query string.  Depending on the syntax chosen, some properties may be set implicitly in the URL (for instance, the domain in ‘jms:queue:jndi-uri…’ is specified without a property key).

 

Property Name

Example Value

Comments

InitialContextFactory

“com.sun.jndi.fscontext.RefFSContextFactory”

“com.sun.jndi.ldap.LdapCtxFactory”

If the secondary lookup is JNDI

JNDIURL

“file:///JNDIStore”

“ldap://localhost:123”

“”

ConnectionFactory

“MyCF”, “com.JMSVendor.TopicConnectionFactory”

May be JNDI lookup name or fully qualified class name

Host

“localhost”

May be required by CF

Port

“2506”

“”

Destination

“MyQueue”

May be JNDI lookup name or direct destination name

DestinationType or Domain

“Topic” or “Queue”

Indicates the type of connection factory and destination

ReplyToDestination

“ReplyToQueue”

May be JNDI lookup name or direct destination name

Username

 

Required in JMS to establish a Connection object

Password

 

Required in JMS to establish a Connection object

DeliveryMode

“Persistent”, “non-persistent”

 

TTL

“10000”

Time-to-live in milliseconds.

Priority

0 – 9, in accordance with JMS spec

Message priority

WAIT_FOR_RESPONSE

“Yes”

Can be used in conjunction with  call.setTimeout()?

 

In the not-too-distant future, we will have asynchronous callback support and client notification in the client engine and the client API.  When this is enabled, we will need to be able to specify a listener and listener traits in the query-string.   This is likely to change as we evolve the API.  The following table lists the possible values:

 

Property Name

Example Value

Comments

 

 

 

ListenerAction

“Subscribe”,”Unsubscribe”,

”Open”,”Close”,”Retrieve”,

“Acknowledge”

The existence of the ListenerAction indicates that a listener should be created, destroyed, or retrieved from.  “Acknowledge” is a special case for CLIENT_ACKNOWLEDGE mode.

DurableSuscriptionName

 

Required to uniquely identify a durable subscription.  Specifying this obviates the need to have a separate “durable” setting.

AcknowledgeMode

“Client”,”Auto”,”DUPS_OK”

 

 

 

 

 

 

 

 

The use of a URL to specify properties of a listener is unusual in that not all things have a parallel on the send side.  In the send scenario, there is only one action to consider—send.  From the receiver’s perspective, there are separate steps beyond creating a listener like deleting a durable subscription (Unsubscribe), and explicit acknowledgement of receipt for CLIENT_ACKNOWLEDGE and DUPS_OK mode.  An empty Call object could be created with just the URL containing the action.  The action could be performed using Call.invoke().  In the case of “ListenerAction=Unsubscribe” this would not actually invoke anything.  It would simply be a command to tell the transport layer to unsubscribe.  When we enhance the API for client we will have a more direct way to do this.

 

Example: URL-based JMS transport

Service  service = new Service(new XMLStringProvider(wsdd));

 

// create a new Call object

Call     call    = (Call) service.createCall();

 

// populate the call object.  In this case it’s a method

// invocation with a description of the parameter list and

// the return type.

call.setOperationName( new QName("urn:xmltoday-delayed-quotes",      

                                 “getQuote") );

call.addParameter( "symbol",

                   XMLType.XSD_STRING,

                   ParameterMode.IN );

call.setReturnType( XMLType.XSD_FLOAT );

 

// set the jms url

String sampleJmsUrl = “jms:sonicmq://localhost:2506?

                      “destination=SampleQ1” +

                      “&deliverymode=persistent” +

                      “&priority=5” +

    “&timetolive=10000”;

call.setTargetEndpointAddress(new java.net.URL(sampleJmsUrl));

 

// setting properties explicitly is still supported

// these override properties specified in the url

call.setUsername(username );

call.setPassword(password );

call.setProperty(JMSConstants.TIME_TO_LIVE, new Long(20000));

 

...

 

// invoke the call

res = (Float) call.invoke(...);

     

 

Note that the call to set the JMSTransport is no longer required, as the appropriate transport will be selected based on the protocol specified in the endpoint address.

 

Issues:

 

-         Lifecycle.  With references to JMSTransport no longer necessary, how will the client application dictate lifecycle?  Via commands passed in with the send?

-         How does one check the JMSRedelivered property on receipt of a message?  JMS properties table in call object?

Futures:

 

-         Transaction support

 

 

begin:vcard 
n:Chappell;Dave
tel;cell:617-510-6566
tel;work:781-999-7099
x-mozilla-html:FALSE
url:www.sonicsoftware.com
org:Sonic Software Corp.    <BR><BR><A HREF="http://www.sonicsoftware.com/products/sonicxq.htm";>Read about SonicXQ</A> - the first product to deliver <br>on the promise of the enterprise service bus.<BR><BR><A HREF="http://www.sonicsoftware.com";><IMG BORDER="0" SRC="http://www.sonicsoftware.com/media/email_signatures/schulte_quote_logo2.gif";></A>
adr:;;14 Oak Park;Bedford;MA;01730;USA
version:2.1
email;internet:[EMAIL PROTECTED]
title:vice president & chief technology evangelist<a href="http://www.oreillynet.com/weblogs/author/207";>[weblog]</a>
fn:Dave Chappell
end:vcard

Reply via email to