Belongs to the following category: Integration,
Purpose
Integrate ULC with Spring. This integration lets ULC applications enjoy dependency injection in a Spring (web-)application context. This approach completely removes the need for service locator patterns in the application code. This integration can host multiple ULC applications, as well as instantiate whole spring application contexts for each client.
Resources
Download the complete source code and compiled jar
here.
This integration has been developed with Spring 1.2. It should also work with Spring 1.1, apart
from the simplified bean xml syntax used below.
How To Use
Setup
This integration uses Spring's MVC framework, namely it exposes ULC as a Spring controller. To use it you need to have a Spring Web Application using the DispatcherServlet. To expose the ULC servlet adapter declare an instance of ULCController and export it through a corresponding handler mapping (in this case a simple BeanNameUrlHandlerMapping):
<bean name="/ulc" class="org.mernst.ulcjava.spring.ULCController"/>
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping"/>
All requests to
http://host:port/context/servlet/ulc will be handled by this controller and forwarded to a private instance of ServletContainerAdapter.
JNLP deployment is performed as usual, only the url changes.
Application Deployment
In the easiest case (only one application, no own context) it is sufficient to declare the ULC application
as a prototype bean in the application context and inject its dependencies. It will be discovered through its type IApplication:
<bean singleton="false" class="org.mernst.ulcjava.Viewer">
<property name="dataSource" ref="dataSource" />
</bean>
Note that the bean definition MUST carry 'singleton="false"', otherwise different clients would
share an application object.
This application is available under
http://host:port/context/servlet/ulc .
If you have multiple applications, you need to distinguish them by name and pass a query parameter
to the controller:
<bean name="app1" singleton="false" class="org.mernst.ulcjava.App1"/>
<bean name="app2" singleton="false" class="org.mernst.ulcjava.App2"/>
are available as:
For more advanced use-cases you may not only want to instantiate the application object but a whole new
application context per client session. This is possible through the ContextApplicationFactoryBean:
<bean name="viewer" class="org.mernst.ulcjava.spring.ContextApplicationFactoryBean">
<property name="contextConfigLocation" value="/WEB-INF/viewer.xml"/>
</bean>
Every new client at
http://host:port/context/servlet/ulc?app=viewer will now receive its
own application context created from /WEB-INF/viewer.xml. That application context is a
child of the main web app context and may use shared services from there. The application object is
resolved from this context, either by type IApplication or explicitly by name, if so configured:
<bean name="viewer" class="org.mernst.ulcjava.spring.ContextApplicationFactoryBean">
<property name="contextConfigLocation" value="/WEB-INF/viewer.xml"/>
<property name="applicationBeanName" value="viewerApplication"/>
</bean>
For reference, viewer.xml might look like this:
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean name="viewerApplication" class="org.mernst.ulcjava.Viewer">
<property name="dataSource" ref="dataSource" />
</bean>
</beans>In this case, the application need not be configured as a prototype bean since a whole new application context is
created for each client.
Implementation
The ULCController wraps the standard ULCServletContainerAdapter servlet and configures it with a special
bootstrap application class: SpringWebULCApplication. Its responsibility is to create the actual application
object via Spring and delegate all further lifecycle callbacks to it. It does so by using the current
application context (exposed by Spring's DispatcherServlet in a request attribute) and the 'app' request
parameter.
Open Issues
This integration only works in a web container (a different implementation for the bootstrap application would
be needed). It supports neither application serialization nor suspension.
Author
Matthias Ernst