Build a Java App Server Foundation for Thick-Client Deployment : Page 3
by Stephen Lum
Jun 6, 2006
Page 3 of 3
Now you should expose the stockService bean so that your forthcoming thick client(s) can invoke it. How? I've seen some thick-client-to-app-server architectures that effectively declare a Spring Controller and have the Controller return an XML file (think a Servlet whose response OutputStream is filled with said XML file). I've also seen some that exposed the stockService as a Web service. Neither is wrong, but there are better wayswhich is where Spring Remoting comes in.
Spring Remoting allows you to declare your bean as a service and expose it using a variety of different protocols. Currently, Spring Remoting supports HTTP, Hessian, Burlap, RMI, or a JAX-RPC Web service. Not only that, Spring Remoting enables you to switch between protocols with no required code changes. So if you are building thick clients to deploy in your intranet, you can use RMI. Why RMI over HTTP? Well, how about two-way communication? Using RMI, you can have the server notify clients! By the same token, if you want to deploy your thick app outside of your network and past your firewalls, then you can expose that same service using HTTPagain, this requires no code change.
Now take a look at how you can achieve this:
To expose the stockService over HTTP, you must declare a Spring Bean in the WebApplicationContext. To do so, add the following to springDispatcher-servlet.xml:
<!-- httpInvoker exporter for the StockService -->
<property name="service"><ref bean="stockService"/></property>
This entry exposes the StockService over HTTP using Spring's HttpInvokerServiceExporter. When using Spring's HttpInvokerServiceExporter, you must also define the service and serviceInterface properties. Of additional note, notice that I have not declared a separate URLMappingHandler implementation. So the Web application will use Spring's default BeanNameUrlMappingHandler.
Expose this service over RMI as well. Add the following entry to applicationContext.xml:
Note: Remember, running RMI on Tomcat requires that Tomcat be installed in a directory with no white space. (Click here to read the actual ASF Bugzilla bug. Apache has closed the ticket and is not going to fix it.).
The second entry exposes the same StockService instance over RMI. It's that simple; the only differences being the Spring class you declare is RmiServiceExporter, and you must declare the serviceName property. Also, declare registryPort to 1099, RMI's default port.
Write a quick test now. Create a new source folder under the stocktradeserver node called test. This new folder should reside at the same level as src.
Create a new class called StockServiceImplTest, which extends TestCase. Create a test for the method getStocks(List<String> tickerList) called testGetStocks(), which throws Exception. In this method, you will test both the HTTP and RMI exposures.
Now create an ApplicationContext for your test cases. Create file applicationContext-test.xml under the test directory and add the following:
You're almost ready to test! The last step is to create a beanRefFactory.xml, because you will be using Spring's SingletonBeanFactoryLocator class. Create file beanRefFactory.xml under the test directory and add the following:
Spring recommends SingletonBeanFactoryLocator to grab a reference to your ApplicationContext.
Now, you must also let MyEclipse know about these new application contexts and the dependencies between them. To do this, right click on the stocktradeserver node in Package Explorer, and go back to MyEclipse-Spring. Click Add..., add the beanRefFactory.xml and applicationContext-test.xml files, and then click OK.
Now click the Config Sets tab, and then New. For Name, enter stocktradeserver and check all four application contexts (see Figure 9). Click OK until the Properties window closes.
Figure 9. MyEclipse ConfigSets for StockTradeServer
Now run your tests. In Eclipse, click the toolbar button Deploy MyEclipse J2EE project to Server (see Figure 10).
Make sure the project in the dropdown is stocktradeserver. Click Add, select Tomcat 5 as your server, and then click Finish. When you see a message saying Successfully deployed, click OK (see Figure 11).
Your first test will be through the browser. Open a Web browser and enter the URL: http://localhost:8080/stocktradeserver/service/stockServiceHttpInvoker.
You should get this error. And that's actually a good sign! Why? Don't forget that you are making an HTTP request through the browser for a Java binary .class file. It absolutely should not be able to render. You can also see that HttpInvokerServiceExporter was invoked, meaning that the stockService is exposed over HTTP.
Now run your JUnit test. In Package Explorer, navigate to your StockServiceImplTest class located under the test directory. Once you see the class, right click on it and choose Run As -> JUnit Test (see Figure 13).
java.rmi.ServerException: RemoteException occurred in server thread; nested exception is:
java.rmi.UnmarshalException: error unmarshalling arguments; nested exception is:
java.net.MalformedURLException: no protocol: Files/Apache
... ... ...
Caused by: java.net.MalformedURLException: no protocol: Files/Apache
... ... ...
Remember you can either remove/not invoke the RMI portions, or change Tomcat's location to one without whitespace.
Get Your Thick Client and App Server Talking
This tutorial has shown you how easy it is to expose your service using Spring and RMI. Thick-client-to-app-server communication is easier than it has ever been thanks to Spring Remoting. Spring's flexibility to change the protocol without changing your own code is just superb. As far as I'm concerned, it is better than any other solution out therehand-rolled or otherwise. This protocol swap is particularly convenient if you want your server to push eventssomething that is not feasible using HTTP and Web clients.
Stephen Lum, a senior developer for an investment bank in London, has been programming in Java for more than seven years. He is Sun certified as a Java programmer, Oracle certified as a developer, and also is a CPA.