Print
NanoWar Configuration

NanoContainer Configuration

It is the web application deployer's responsibility to provide the configuration of the various PicoContainer instances used by the web application. There are several ways to do this:

Basic Container Composition 

NanoContainer composition script referenced from web.xml

The simplest (and recommended) way to configure the containers is by referencing a Container script from web.xml as follows:

<context-param>
  <param-name>nanocontainer.groovy</param-name>
  <param-value>/WEB-INF/nanocontainer.groovy</param-value>
</context-param>

The script could look like this:

pico = new org.picocontainer.defaults.DefaultPicoContainer(parent)
if(assemblyScope instanceof javax.servlet.ServletContext) {
  pico.registerComponentImplementation(com.yourdomain.SomethingRequiredGlobally)
} else if(assemblyScope instanceof javax.servlet.http.HttpSession) {
  pico.registerComponentImplementation(com.yourdomain.SomethingRequiredInSessions)
} else if(assemblyScope instanceof javax.servlet.ServletRequest) {
  pico.registerComponentImplementation(com.yourdomain.SomethingRequiredInRequests)
}

Or alternatively, if you use NanoContainer's Groovy Builder:

pico =builder.container(parent:parent) {
  if(assemblyScope instanceof javax.servlet.ServletContext) {
      component(com.yourdomain.SomethingRequiredGlobally)
  } else if(assemblyScope instanceof javax.servlet.http.HttpSession) {
     component(com.yourdomain.SomethingRequiredInSessions)
  } else if(assemblyScope instanceof javax.servlet.ServletRequest) {
     component(com.yourdomain.SomethingRequiredInRequests)
  }} 

The value of the param-name element must start with nanocontainer and the extension must be one of .groovy, .bsh, .js, .py or .xml. The value of the param-value element must be the path to the script from the top of the webapp. You can use any path as long as it starts with a '/' and ends with the same as the param-name.

NanoContainer composition script inlined in web.xml

NanoContainer composition scripts can also be embedded inside web.xml as follows:

<context-param>
  <param-name>nanocontainer.groovy</param-name>
  <param-value><![CDATA[
    pico = new org.picocontainer.defaults.DefaultPicoContainer(parent)
    if(assemblyScope instanceof javax.servlet.ServletContext) {
      pico.registerComponentImplementation(com.yourdomain.SomethingRequiredGlobally)
    } else if(assemblyScope instanceof javax.servlet.http.HttpSession) {
      pico.registerComponentImplementation(com.yourdomain.SomethingRequiredInSessions)
    } else if(assemblyScope instanceof javax.servlet.ServletRequest) {
      pico.registerComponentImplementation(com.yourdomain.SomethingRequiredInRequests)
    }
  ]]</param-value>
</context-param>

The value of the param-name element must start with nanocontainer and the extension must be one of .groovy, .bsh, .js or .py. The value of the param-value element must be a CDATA-embedded script in the corresponding scripting language.

Advanced Container Composition 

Custom Container Composer specified in web.xml

If you don't want to embed a NanoContainer script in web.xml you can do it all in Java:

<context-param>
  <param-name>org.nanocontainer.integrationkit.ContainerComposer</param-name>
  <param-value>com.yourdomain.YourContainerComposer</param-value>
</context-param>

The param-name value must be "org.nanocontainer.integrationkit.ContainerComposer" and the param-value the name of a concrete class that implements org.nanocontainer.integrationkit.ContainerComposer. Then, your container composer might look like the following:

public class YourContainerComposer implements ContainerComposer {
  public void composeContainer(MutablePicoContainer pico, Object assemblyScope) {
    if(assemblyScope instanceof javax.servlet.ServletContext) {
      pico.registerComponentImplementation(com.yourdomain.SomethingRequiredGlobally)
    } else if(assemblyScope instanceof javax.servlet.http.HttpSession) {
      pico.registerComponentImplementation(com.yourdomain.SomethingRequiredInSessions)
    } else if(assemblyScope instanceof javax.servlet.ServletRequest) {
      pico.registerComponentImplementation(com.yourdomain.SomethingRequiredInRequests)
    }
  }
}

Scoped Container composition

NanoWar provides a ScopedContainerComposer which can be used to compose

any set of nanocontainers in the web scopes:

<context-param>
  <param-name>org.nanocontainer.integrationkit.ContainerComposer</param-name>
  <param-value>org.nanocontainer.nanowar.ScopedContainerComposer</param-value>
</context-param>

The ScopedContainerComposer is generic and configurable via an additional optional property

<context-param>  <param-name>org.nanocontainer.integrationkit.ContainerComposer.configuration</param-name>
  <param-value>/path/to/composer/configuration/script</param-value>
</context-param>

The /path/to/composer/configuration/script needs to point to any nanocontainer script which creates a PicoContainer containing an instance of ScopedContainerConfigurator, eg

<container>
    <component-implementation class='org.nanocontainer.nanowar.ScopedContainerConfigurator'>
<parameter><string>org.nanocontainer.script.xml.XMLContainerBuilder</string></parameter>
<parameter><string>nanowar-application.xml,nanowar/application.xml</string></parameter>
<parameter><string>nanowar-session.xml,nanowar/session.xml</string></parameter>
<parameter><string>nanowar-request.xml,nanowar/request.xml</string></parameter>
    </component-implementation>
</container>

The ScopedContainerConfigurator allows to configure the ContainerBuilder used by the composer and the names of the scripts used to configure the scoped containers. Note that you can have as many configuration files per scope as you wish. Simply specify them as comma-separated lists of paths. The composer will process in order each configuration script and add the contents to the scoped container.

If they are not specified, they default to nanowar-application.xml , nanowar-session.xml and nanowar-request.xml in the root of the webapp classpath. Also, the default ContainerComposer is org.nanocontainer.script.xml.XMLContainerBuilder.

XStream Container composition

There is also a simplified ContainerComposer which uses XStream to compose your containers

<context-param>
  <param-name>org.nanocontainer.integrationkit.ContainerComposer</param-name>
  <param-value>org.nanocontainer.nanowar.XStreamContainerComposer</param-value>
</context-param>

This container will set up container hierarchy from tree xml files, which shall be placed in

WEB-INF/classes - nano-application.xml , nano-session.xml and nano-request.xml. See

examples of XML based container configuration in test cases in nanowar project.

Integration with Velocity templating engine

Velocity offers a very fast and lightweight templating engine for web applications as an alternative to JSP. Sometimes it would be nice to have direct access to the container hierarchy from within Velocity templates. This is really easy. Just add a single macro to your global Velocity macro definitions:

## obtain pico component by key
#macro(nano_component $component $key)
    #set($component = $req.getAttribute('nanocontainer.request').getComponentInstance($key))
#end

Then

#nano_component($fooBar 'foo_bar')

will retrieve the component stored with the key "foo_bar" and place it into the Velocity context. This also works nice with NanoWar WebWork.

In order for this to work properly, you must ensure the components you want to access are registered with java.lang.String keys.

Powered by Atlassian Confluence