- buy a book
- skim the book in chapter order
- study specific chapters as I need to know their contents
- disregard the chapter's examples because they suck either because they are too simple or inelegant
- unsuccessfully google for better examples
- successfully google for clues
- piece together a simple and elegant example
Spring is funky. I had wanted to use EJB3 for this project but Spring won out. The reasons have little to do with technical merit. From a larger software engineering perspective EJB3 is just too unknown among the in-flight-magazine readers. Ok, that was a dig and childish. Sorry.
For Spring to work on this project I need for it to handle REST, JMS, and RMI simply and elegantly. To this end I have been working on JMS and RMI stuff mostly.
Spring's "JMS template" stuff is very old-school Java. A better approach is to use generics for clean coding and have the configuration done in XML. After some effort I can now code a JMS listener as simply as
public class HelloMessageListener extends MessageListener<String> { @Override public void receive( String message ) { // handle string message } }
And, if your message is more complex the listener's complexity does not change. The generic MessageListener
public abstract class MessageListener<T> implements javax.jms.MessageListener { private MessageConverter<T> messageConverter; @Required public void setMessageConverter( MessageConverter<T> messageConverter ) { this.messageConverter = messageConverter; } @Override public void onMessage( Message jmsMessage ) { T message = messageConverter.fromJMS(jmsMessage); receive( message ); } abstract public void receive( T message ); }
MessageConverter
<bean class="org.springframework.jms.listener.SimpleMessageListenerContainer"> ... <property name="messageListener" ref="helloMessageListener" /> </bean> ... <bean name="helloMessageConverter" class="example.HelloMessageConverter" /> <bean name="helloMessageListener" class="example.HelloMessageListener"> <property name="messageConverter" ref="helloMessageConverter" /> </bean>
For RMI Spring has good POJO support out of the box. What I could not find, however, was support for exporting a POJO as an RMI service that could be called by a non-Spring client. For example, the following client can be run using the standard JDK
import java.rmi.Naming; public class HelloServiceCaller { static public void main( String[] args ) throws Exception { String helloServiceUrl = "rmi://localhost:1199/HelloService"; HelloRemoteService helloService = (HelloRemoteService) Naming.lookup(helloServiceUrl); for ( String input : args ) { String output = helloService.sayHello( input ); System.out.println( input + " -> " + output ); } } }
But if you try to use this against an RMI service exported via Spring's org.springframework.remoting.rmi.RmiServiceExporter it does not work. You get a java.lang.ClassCastException regards org.springframework.remoting.rmi.RmiInvocationWrapper_Stub. Yuck.
However, with a little effort I was able to create an exporter that could export a POJO as a remote service as long as the POJO had methods that correspond to a valid remote interface. For example,
public interface HelloRemoteService extends Remote { public String sayHello( String name ) throws RemoteException; } ... public class HelloService { public String sayHello( String name ) { return "Hello " + name; } }
To remote HelloService I wrote RemoteProxyExporter which is a mixture of Spring, RMI, Proxying, and Reflection.
Now RemoteProxyExporter (and friends) was tricky to write but it took less than a day's effort. As did MessageListener
During Spring's life Java has had many changes of course as to how common problems are solved. For example, how to augment and/or configure a Java object. First we used reflection. When this didn't solve all our needs reflection was augmented with "information" classes (such as BeanInfo). When this was seen as too static for a dynamic world the information classes where replaced/augmented with external declarations encoded in XML. When XML was seem as cumbersome Java 5 added annotations. Spring uses all of this but not consistently. And so often times just understanding how to connect A with B is a nightmare. And googling does not help because the definitive answer for some questions was given in 2009 while others where given in 2004 when Spring 1.0 was released.
The upshot of all this effort is that I will be able to do what I need to do and do it in a way that works for all staff skill levels. And do it simply and elegantly.
I can't wait to dig into pooling!