Chico Implementation Notes


Maven module roadmap

The Maven modules for Chico are as follows:

  • The chico.config module contains the Spring configuration extensions that support the property file-based configuration tailoring.
  • The chico.mvc module contains Spring convenience extensions for building MVC-based servlets.

The project's parent POM file has three embedded properties:

  • The chico-version POM property is the master version number for the Chico artifacts.
  • The spring-version POM property gives the version of Spring to be used.
  • The spring-security-version POM property gives the version of SpringSecurity to be used.

Configuration support

The siteTailoring.xml file and other black magic

The siteTailoring.xml file is where Chico defines the beans that perform simple property customizations. If you need to change the way that site-specific tailoring is implemented, this is file is the place to do it.

The file configures two beans to do apply the tailorings in the WEB-INF/classes/*.properties files to main Spring wirings:

  • The "poc" bean uses an enhanced version of the Spring "PropertyOverrideConfigurer" class (see below) to perform whole value replacement of bean property values using replacements defined in a custom site's "overrides.properties" file.
  • The "ppc" bean uses an enhanced version of the Spring "PropertyPlaceholderConfigurer" class (see below) to replace "${...}" placeholders in bean properties, and so on.

The "poc" and "ppc" beans do their stuff on the bean descriptors after they have been read from the Spring wiring files, and before the descriptors are used to instantiate beans. The "order" properties of the "poc" and "ppc" beans specify that property overrides are applied first followed by the replacements.

One of the limitations of Spring wiring files is that there is no direct way expressing conditional wiring; e.g. "if property xyz is 'pqr', create this bean, otherwise that one.". However, we did discover and use one trick that works with Spring 2.5 and 3.0 wiring. For example:

    <alias name="${tripleStore}TypeFactory" alias="typeFactory" />

This defines the id "typeFactory" to be an alias for a bean whose name depends on the "tripleStore" replacement property. If we then declare lazily initialized beans called "sdbTypeFactory", "rdbTypeFactory" and so on, we can switch between different "typeFactory" beans by changing one property substitution parameter.

It is also possible to do more complicated things like this:

    tripleStore=sdb
    sdb.default.db=test
    rdb.default.db=rtest
    tripleStore.default.db=${${tripleStore}.default.db}

However, for reasons that are not obvious, when you declare a bean "parent" using an alias, any placeholders in the alias values do not get substituted. This means that the alias switches won't work in conjunction with Spring property merging in a PropertyBeanFactory declaration. Fortunately, there is an (inelegant) alternative way to do property merging. A PropertyBeanFactory can be also be declared with an "propertiesArray" property, giving an property objects. If this array include a reference to a PropertyBeanFactory bean defined elsewhere in the Spring wirings, the corresponding properties will been merged by this PropertyBeanFactory bean.

The custom PropertyOverrideConfigurer

The standard Spring version of PropertyOverrideConfigurer understands how to substitute placeholders in simple bean properties, aliases and a few other places. However, compound bean property values are beyond its capabilities.

The Chico version of PropertyOverrideConfigurer adds specific support for properties in PropertyBeanFactory bean declarations. Specifically, it will perform placeholder substitution to simple property values in any inline <props> elements used in the bean's "properties" or "propertiesArray" properties. Note that this does not apply to properties defined in external property files and referenced via the bean's "location" or "locations" properties.

The custom PropertyPlaceholderConfigurer

The Chico version of the PropertyPlaceholderConfigurer simply adds a logging statement to log the contents of the effective substitution property set once it has been assembled. This is intended to help diagnose configuration issues in sites where the "siteTailoring.xml" file specifies multiple substitution property files.

The custom ContextLoaderListener

In the previous section, we mentioned that you can implement conditional wiring using an <alias> element with placeholders in the "name" attribute. Another approach that you would imagine would work is this:

    <import name="Danno-${tripleStore}.xml"/>

However, this only works with standard Spring wiring if the parameters to be substituted are defined in the Java system properties. This has the following consequences:

  1. There are some kinds of conditional wiring that cannot be done using aliases; e.g. when the wiring relies on custom XML parsers and doesn't expose bean references.
  2. Putting configuration parameters into the system properties makes them global to all webapps.
  3. Getting the configuration parameters into the system properties entails modifying the Tomcat launch parameters.

As a workaround, Chico provides a custom ContextLoaderListener that inserts properties from a configurable set of properties file into the system properties before starting the Spring wiring process. This works, modulo that it does not address point "2" above.

A better solution would be to change the Spring configuration codebase so that the placeholder expander used for <import> elements could bet get placeholder values from other places. However, the changes required look to be rather intrusive, and we are hesitant to go down this route.

Spring MVC Extensions

BaseController

This abstract class that extends the Spring MVC "AbstractController" class to provide:

  • methods for fetching, validating and converting request parameters,
  • an override for handleRequestInternal that deals with exceptions in a uniform way using the handleRequestException method, and
  • methods for getting a controller logger and the request's Authentication object.