Blog from August, 2008

As detailed in my last article I think the current CXF configuration style has it´s problems. To provide people with a short time solution I have described how to use the Camel transport together with Camel´s JMS transport. After my article there was a discussion on the CXF dev mailing list on better JMS support for CXF. The agreement was that CXF should not depend on Camel for JMS and that the JMS config for CXF should be improved.In this article I will propose an alternative configuration style for JMS (and perhaps also other transports). The style is quite similar to Camel´s style and tries to bring the positive aspects of the Camel transports to CXF.

Goals

I have started by defining some goals that are important to achieve for the new configuration and implementation. Of course this is only my opinion. I would be very interested in what goals you would like to see implemented.

Focus more on dependency injection. Do less in the JMSConduit

Allow injection of the ConnectionFactory. So it can be provided directly from a spring bean or via a spring JNDI lookup

Avoid coupling the Conduit to the Client by endpoint name. Instead set the config as property

Allow setting of Transport parameters from the address property of the Client or Endpoint

Support declarative transactions using Springs JMS support (This is mainly an implementation issue)

Client / Endpoint config

The basis will be as before the Client or Endpoint config. This is extended by one new property transportConfig.

In this sample config we reference the bean jmsConf1 as transportConfig. So all settings in this bean will be the defaults. The url after jms:// is implicit set as the parameter targetDestinationName.

Then each parameter from the address overwrites a property of the JMSConfig. So you can define defaults in the JMSConfig and still do special settings for the Endpoint using the URL. Camel has a nice Tool to extract such config info from a string like address and configure a bean with it using reflection. Setting parameters in this way has it´s drawbacks in transports where the parameters are part of the real URL. I am not yet sure how this can be avoided. Setting the parameters from the URL is not absolutely necessary so we should decide if the advantages are worth the trouble.

Transport Config

This is my proposal for a new Config Element of Client and Endpoint named TransportConfig. TransportConfig is a marker interface. The classs JMSConfig implements this interface and contains the special config settings for JMS. Here I only show some few settings. For a complete list we could take a look at the JMSComponent in Camel and see which we need. They also include declarative transactions which we should also try to implement.

I have used the new p Style from spring for the xml sample but it is a normal Bean. The first parameter is a reference to a connection Factory bean. The next two parameters are taken from the Camel JMSComponent as illustration of what we could configure. The last property is for the target JMS Destination. It can be set either as a reference to a bean or as a string. In this case I used the reference to a bean and retrieve the Destination by doing a JNDI lookup. Alternatively I could have set the targetDestination name with a string that defines a queue in the chosen JMS provider.

If you don´t want to use the above described override by using the URL parameters you can also use Springs templating mechanism to support basic configs that are then overriden in some properties. Here is a short sample:

Here the jmsConf2 will have all properties from jmsConf1 and then override some.

Conclusion

I think this new configuration style could be easily built into CXF and would improve the experience for users dramatically. What do you think about it? Are there other ideas how to do a better config for CXF?

Configuring JMS in Apache CXF is possible but not really easy or nice. I have written a Tutorial on the Camel Wiki that shows how to use Apache Camel to provide a better JMS Transport for CXF.

Why not simply use JMS Features of Apache CXF

JMS configuration in Apache CXF is possible but the configuration is not very flexible and quite error prone. In CXF you have to configure a JMSConduit or a JMSDestination for each webservice. The connection between Conduit and the Service proxy is the endpoint name which looks like "{http://service.test\}HelloWorldPort.jms-conduit". As this name is never explicitly configured elsewhere it is quite probable that you misspell the name. If this happens then the JMS Transport just does not work. There is no good error reporting to show you what you did wrong. The next thing is that you have to use JNDI for the connectionFactory and the queue name. This is something that beginners with JMS have many problems with.

Why is using Apache Camel better in the JMS Transport layer

In apache camel you can simply reference the ConnectionFactory as a spring bean. This means you can either define it directly in a spring bean what is the ideal way to start or you can use spring´s JNDI binding to retrieve it from your application server for production use.
The next nice thing is that you can configure all JMS options like Receive Timeout or username / password in a central location, the JMSComponent and then share this config for several services. On the other hand you can easily configure different JMS providers.
The last thing that I do not need right now but is nice to have is that you have the full power of Camel´s routing config. So if you want to do additional things from simply calling the service it is easy.

How to do it

Thanks

Many thanks to Eduard Hildebrandt http://www.family-hildebrandt.com who helped a lot in making this example work by debugging all the problems we initially had and providing patches for the issues.
When I announced this Howto on the camel mailing list James Strachan told me that it is also possible to make your webservices transactional by using Spring declarative transactions. I will write a spearate article that focuses on how to do this.

In this post I will describe how to do contract first in a very simple and efficient way. All people involved in webservice design have the problem what tool to use to describe the webservice interface. Of course there are wsdl editors but you can make many errors in using them and they are normally not very intuitive.

What we would like to have

Ideally I would imagine to have a domain specific language that makes designing the webservice very easy and fail safe. Then there should be an IDE that supports me in writing the DSL. Either with content assist or with a graphical editor. In any case the IDE should check the DSL while it is entered and help me to do the right thing. Some people favor using Model Driven Design tools to do this job but it is quite hard finding good tools and configuring them for the job.

Which tools did I choose and why

I wanted to go some way in the direction of a DSL for webservices but without using a big MDD tool. So I thought about how to have most advantages of a DSL with just Java and the normal Eclipse IDE. So I needed Java code that looks almost like a DSL and a tool to generate the webservice out of it. For the WSDl generation I used Apache CXF with JAXWS and JAXB annotations to describe the webservice. While this setup is quite standard I focused on keeping the syntax as simple as possible.

So how does the DSL look like

To describe a data object I use a java class with just attributes. The Namespace will come from the package name. To make JAXB understand this syntax only one annotation is necessary. Of course some more annotations are necessary if you want to use special fetaures.

Customer datatype

The sample class Customer gives a nice overview which primitive datatypes can be used. Additionally you can create arrays of primitive or class datatypes in this way. The complete example also contains an enumeration definition to show this is possible. I think this code is quite near the DSL I would imagine to describe my services.

Enumeration CustomerType

Shows how enumerations are handled:

NoSuchCustomerException

Defining Exceptions is a little tricky as the default behaviour is to create Exception_Exception classes in the later generated Java code. So we have to use the @WebFault annotation to give the Bean for the data a name that is separate from the Exception name.

Service definition

As you can see only two annotations are necessary here. @WebService marks the interface as a service and @Webparam is necessary as Java will else loose the name of the parameter and the wsdl will contain arg0 instead of the desired name. Using the @WebService annotation you can also customize the port name and service name.

How is the wsdl generated

To generate the wsdl the maven plugin cxf-java2ws-plugin is used. See the pom.xml in the complete example for details.

Let´s take a look at the resulting WSDL

The customer Class is a complex type in xsd. As you can see the Java types have been described as their respective XSD primitive types.

Each element has minOccurs="0" which marks it as optional. This is a good thing as you can add new optional elements and keep compatible. If you do not want this optionality you can use @XmlElement(required=true).

The array of Strings for address is described as maxOccurs="unbounded" so the element may be repeated in the later xml to form the array.

Enumeration customerType

The enumeration customerType is described as a simple type with a restriction:

Fault NoSuchCustomerException

The Exception we defined is generated as a complexType with the defined details and a message for the fault. It is important here that the Element and the Message have different names. We ensure this by using the @Webfault Annotation above. Else the later Java Code generation will produce an ugly Exception name NoSuchCustomerException_Exception.

The wsdl defines a SOAP/HTTP binding by default but can also be used to build services based on JMS as I will show in my next post.

Summary

As you can see the generated WSDL looks quite clean and correctly expresses the service interface we wanted to describe. In most cases where you are not satisfied with what the conversion does you can correct the WSDL using JAX-WS or JAXB annotations. But I recommend to use them sparsly to keep the DSL easy to read.

In the next post I will show ho to build service consumers and providers using the WSDL we just built.