jueves, 24 de mayo de 2007

Sharing a global Spring application context

One of the best features the Enterprise Edition of Java offers is, without doubt, the modular approach it takes. Mainly it allows an architect to divide a complex application in several modules or components. These are usually a mixture of Web Applications (packed as WARs), Enterprise JavaBeans (packed as JARs) and Message Driven Beans, all wrapped in a EAR (Enterprise Application) file. Even other more esoteric components do exist (for example, Resource Adaptars).

Up until today (with JEE5), the developer had to be very careful when separating the elements, ensuring they could work more or less independently because, unfortunately, the communication between them was lacking (to say the least) in several areas. The API in charge of the handling those communications and offering a common repository to store objects (called JNDI) was slow and, in addition, it lacked some basic functions. With the advent of version 5 things improved considerably as the introduction of Dependency Injection which removed a lot of boilerplate code (like context initialization, unneeded casts) making everything more developer friendly.

Today Spring has become ubiquitous in projects. This adds a new and more powerful IoC container, capable of being embedded inside JEE components and, at the same time, able to work with JNDI (Spring can function as a JNDI context itself). Of course, adding Spring raises the question of having a new type of component, the bean, and how can it interact with the environment. As a matter of fact, once Spring is in the scope it handles nearly everything but there are always areas that the container will rather manage (for example, JTA).

The goal here is to be able to expose Spring beans as services available to the rest of the environment. One possible solution would be to store the bean in the JNDI context so any potential client can look it up. Or better, it can be injected. This can be done easily using the JNDITemplate but suffers from some handicaps: it inherits those of JNDI, it has to be Serializable, it loses advanced capabilites (scoping, transactions, proxying in general), it seems clunky for Spring injection (in other context). All in all, although useful for some purposes, it is not the best solution overall. The ideal we are looking for is a root context, loaded once, parent of the rest of them, that holds singleton beans and exposes them to clients deployed anywhere inside the same application (allegedly in other components). This last sentence is important, JNDI context is global to the application server, our context will be global to each enterprise application.

To achieve it an XML file with all the shared beans has to be created first. Ideally this file will be deployed inside a JAR in the lib directory of the EAR. This way it's just deployed once and available (in the classpath) to each web application or EJB. I said one but in practice two files are needed, the first one includes a reference to the second where the context is actually defined.

<beans ...>
   <bean name="mainApplicationContext"
       class="org.springframework.context.support.ClassPathXmlApplicationContext">
      <constructor-arg>
         <list>
            <value>classpath*:spring/globalContextDefinition.xml</value>
         </list>
      </constructor-arg>
   </bean>
</beans>

Once created it has to be loaded on startup and just once independently of the number of child contexts. To do it we'll use a ContextLoaderListener and two context params.

<context-param>
   <param-name>locatorFactorySelector</param-name>
   <param-value>spring/mainContext.xml</param-value>
</context-param>
<context-param>
   <param-name>parentContextKey</param-name>
   <param-value>mainApplicationContext</param-value>
</context-param>
<listener>
   <listener-class>
      org.springframework.web.context.ContextLoaderListener
   </listener-class>
</listener>

The first param indicates where is the XML that serves as reference located (needs to be in the classpath of the listener), the second which bean defines the parent context.

Just one more thing is needed as the listener expects to find a file called applicationContext.xml in the WEB-INF directory. This file should include the local beans. Normally, in these beans are included those that a web application do not want to share and those that can't be shared (because they depend on the HTTP requests for example). As a caveat, this configuration has to be replicated on every web application although just the first will load the context. Is worth noticing that if using Spring MVC (and so a DispatcherServlet) it's probably best to left the applicationContext.xml void and define the beans in the <servlet-name>-servlet.xml file.

The last step is to be able to reach the context from an EJB, an MDB for example. To do it use the ContextSingletonBeanFactoryLocator:

public class MDB extends AbstractJmsMessageDrivenBean {

   public void setMessageDrivenContext(MessageDrivenContext mdbContext) {
      super.setMessageDrivenContext(mdbContext);
      setBeanFactoryLocator(
          ContextSingletonBeanFactoryLocator.getInstance(
            "classpath*:spring/mainContext.xml"));
      setBeanFactoryLocatorKey("mainApplicationContext");
   }
   ...
}


lunes, 14 de mayo de 2007

Integrating DWR & Spring

As of lately, the DWR mailing list is full of messages from people suffering several problems when trying to tie DWR and Spring. The fact that they try it, it's an unambiguous sign that both technologies can and do play nice together. In fact, it's not unusual to see people from Interface21 (when will you start hiring in Spain!) answering questions there. Bram Smeets has even blogged about all this (several times indeed). But, even with their support, it's not unusual that some topics rise time and again because both technologies deal with complex tasks and have some subtle configuration possibilities. That's the reason that pushed me to make this little guide, offer some clues on how to determine the cause of some of the most common errors anyone can expect to see and, if possible, some workarounds.

Let's start with the basics. The essence of Spring is about dependency injection of plain objects (although it does much more). . The essence of DWR is to expose Java, objects running at the server, in remote (client) contexts. In the end, both have to deal with two concepts: beans and scopes. The most times, our effort is spent configuring both sides and then trying to mix them together. Fortunately, DWR includes the tools to make the task easier.

In the beginning (and it still can be used today), Spring beans were made available to the DWR context using the dwr.xml file. Here's a complete example of doing it. Basically, the <allow> tag includes a creator for each of the beans that should be remoted. Some extra configuration is needed to tell DWR where and how the Spring context can be reached. Several options are possible:
  • Expose the context with a listener (ContextLoaderListener)
  • Indicate the location of the configuration XML
  • Wrapping the servlet
Probably the first option is easier to read and understand for the begginer.

Since version of DWR (and Spring), the developers can opt for using the DWR namespace directly in Spring. This has several advantages:
  • Less files as dwr.xml is not needed anymore
  • Don't need to touch the web.xml file either (if using Spring MVC)
  • More readable and easier to maintain
  • One, unique, repository for configuration (avoid mess)
  • Tightly integrates Spring & DWR
Here's how to use it. First declare the XML schema:

<beans
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns:dwr=”http://www.directwebremoting.org/schema/spring-dwr”
   xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.directwebremoting.org/schema/spring-dwr
       http://www.directwebremoting.org/schema/spring-dwr-2.0.xsd“>

Then add the needed DWR stuff:

<dwr:controller id="dwrController" debug="true" />

<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
   <property name="mappings">
      <props>
         <prop key="/engine.js">dwrController</prop>
         <prop key="/util.js">dwrController</prop>
         <prop key="/interface/**">dwrController</prop>
         <prop key="/call/**">dwrController</prop>
      </props>
   </property>
</bean>

The declare the beans that will be exposed adding a simple tag:

<bean id="aBean" class="package.BeanClass">
   <dwr:remote javascript="RemoteName">
      <dwr:include method="remoteMethod" />
   </dwr:remote>

</bean>

If the bean(s) happen to return objects (unneeded with primitive types or strings) DWR needs to be informed on how to transform them to JSON:

<dwr:configuration>
   <dwr:convert type="bean" class="package.ReturnedBeanClass" />
</dwr:configuration>

This is enough for 90% of the cases a user would need. I haven't looked at signatures (unneded for Java5+) or other advanced functionality (init for example) but everything is available looking at the schema. Take into account that some parts are not targeted to the end user but to developers.

There's one last thing that I would like to consider because it's the origin of 90% of the errors that pop up from time to time: scopes. In DWR, objects can be created with a scope, very similar to the servlet spec (application, session, request and page). In Spring beans are defined as singleton, prototype, request, session, global session or even creating our custom scopes. It's easy to see the cause of the confusion. The problem is aggravated by some circumstances:
  • DWR scope defaults to page, Spring to singleton
  • The schema doesn't have any reference to scopes
  • Spring uses AOP and proxies to implement scoped beans
  • A DWR request is not directly bindded to the Spring context
Let's try to review case by case:
  • Default scopes: The page scope works correctly when backed by singletons or session scoped beans. It does not work for prototype or request scoped beans! Take into account that DWR won't really distinguish prototype and request scoped beans.
  • Schema & scopes: Right now the schema is incomplete and no mappings can be made. That is, if you use this way of configuring, all the Spring remoted beans inherit the page scope (this is an educated guess, the documentation is scarce).
  • Singleton beans: As is well known, Spring shines when working with singletons. As a plus, no proxies are created when working with singleton beans. Whenever DWR ask the application context for the bean, Spring always returns the same instance. A developer should try hard to make all his beans singletons (at least those exposed to DWR). To optimize performance, a singleton bean should actually be mapped to application scope in DWR (so DWR saves trips to Spring).
  • AOP proxies: The trick here is done understanding why AOP proxies are needed and when does Spring create a proxy. It's more or less clear that proxy is created when injecting a scoped bean as a dependency. What people tend to forget is that the beans are in fact injected in DWR, so a proxy is needed even if the bean has no dependencies in the Spring context. So, as a rule of thumb, everytime that a scoped bean needs to be remoted <aop:scoped-proxy/> has to be declared (add <aop:scoped-proxy proxy-target-class="false" /> to ensure JDK proxies are constructed). A subtle error happens when omitting the above declaration because the bean is being already proxied (ie. because of transactions or other interceptors). Don't be fooled, a scoped proxy also has to be created!
  • Prototype beans: There are two possible scenarios. The first one is composed by beans explicitly declared as prototype, the second by lookup-methods. This second case deserves special treatment because CGLIB proxies are a requisite (if using ProxyFactoryBean remember to establish autodetectInterfaces to false). Both types should be mapped to request scope in DWR to ensure a new object is created for each petition.
  • Web scopes in Spring: The most common error is not being able to access the request/session with this type of scoped beans. This usually caused by an incorrect binding of the request to the thread. If using Spring MVC the DispatcherServlet does it automaticall, otherwise a RequestContextListener must be declared (in addition to the DwrSpringServlet). Finally remains the question of the mapping to DWR. For session beans, the default page scope is a good enough candidate, although not optimal performance wise (that's what the session scope would stand for). Request scoped beans should map to DWR's request scope and the request should be bounded. If possible it's probably easier (and will avoid common pitfalls) to use a singleton bean and get the request as a parameter.

miércoles, 2 de mayo de 2007

Internationalization using Aspects & Spring

One of the most common tasks in a web application today is the ability to show text in the language of the user. It’s called internationalization or i18n to abbreviate (the 18 comes from the number of letters involved). It’s so common, in fact, that a lot of technologies provide tools to simplify the labour of the developer. In the Java world, the most common answer to the problem are resource bundles to store the data and JSTL (Java Standard Tag Library) to display it. Here’s what JSTL suggests to deal with messages:


Spring eases the duty a little bit more by providing MessageSources, that is, beans that will load and hold in memory the different resource bundles and offer convenience methods to translate the strings.

If the project at hand is a little bit conventional the properties files, the fmt tags and the different MessageSources (even some for testing) should conform a sufficient mix. But sometimes even more flexibility is needed. Aspects are a good candidate here as i18n is a very cross-cutting concern.

The first question to resolve is where to apply the translations. Is it enough to modify strings or a more generic solution that applies to objects is in order? I will focus in solving the first case and leave the second open. In practice, the same schema works, it’s just a matter of recursion. I can imagine several scenarios where it would be very useful to translate whole objects, for example, when working with DWR requests.

The second question is what can be leveraged from the existing solutions. It’s obvious that an interceptor will be required but may be it can rely on MessageSources to manage the actual effort.

To start we have the usual annotation:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface i18n{ }

At first, it will be used only with Methods but it can be modified later, without difficulty, to annotate fields if the Object approach is needed. The annotation does not declare anything so the accustomed Locale and Resource Bundle have to be obtained somewhere else. The request seems like the best deal with the Locale:

@Bean(name="requestLocaleManager")
public class RequestLocale implements LocaleManager {

   public Locale getCurrentLocale() {
      Locale locale = null;
      ServletRequestAttributes attr = (ServletRequestAttributes)
            RequestContextHolder.currentRequestAttributes();
      if (attr != null) locale = attr.getRequest().getLocale();
      return locale;
   }
}

The code above is a widespread way to access the current request in a Spring environment (Spring MVC). Other options are available, just ensure the class implements the LocaleManager interface as this is what is injected in the interceptor.

@Aspect
public class TranslatorInterceptor {

   private Translator translator;
   private LocaleManager localeManager;

   @Around("@annotation(es.internna.annotations.i18n)")
   public Object translate(ProceedingJoinPoint pjp) throws Throwable {
      String value = (String) pjp.proceed();
      if (value != null) {
         Locale locale = localeManager.getCurrentLocale();
         if (locale == null) locale = Translator.defaultLocale;
         value = translator.translate(value, locale);
      }
      return value;
   }
}

I’ve removed the boring parts of the aspect above but the meat is there. First two beans need to be injected the first will handle the actual translation, the second will provide the expected Locale. The aspect fires when the @i18n is detected, it needs an Around advice because the return value is supplanted. The flow is simple to understand then, it first invokes the intercepted method and stores the returning value, once it has it and if it’s not null it will try to translate it, if it succeeds this will be the value actually returned to the client (whoever is).

The translator code leverages Spring’s capabilities:

public class SpringTranslatorImpl implements Translator {

   private MessageSource messages;

   public String translate(String code, Locale locale) {
      return this.messages.getMessage(code, locale);
   }
}

In the end, it’s just using the same MessageSource as the rest of the system and relying on its competence. It’s obvious to say but to use it just annotate a method

@i18n
public String aMethod() {
   …
   return theStringCode; // this will be intercepted and translated
}

Finally, some little advices to work with whole objects
  • Probably not all the Strings in an object have to be translated (ie. user input)
  • The ones that need to be should be annotated
  • Annotated objects inside should be recursively processed
  • The same annotation (@i18n) can be reused (with minimal changes) on fields
Hope it was useful. I pretend to have the full sources available at Internna’s repository. It will be also submitted to the Spring annotations project and may make its way to a release there sometime.