Spring 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.

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.

Resources

Application & Source code - ulcspring.zip.

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.