Overview
The NanoContainer Servlet component brings the power of PicoContainer's DependencyInjection to the Java Servlet/web application world. It is the backbone of NanoWar NanoWeb, NanoWar WebWork or any other Java Servlet based web application framework or application that wants to integrate with PicoContainer. It's based on an embedded Container.
(NanoContainer Servlet is not a javax.servlet.Servlet class. It is a reusable component intended to be used within a servlet environment.)
How it works
The NanoContainer Servlet component creates PicoContainer instances at the application, session and request level, using the following hierarchy:

As illustrated in the diagram, a new PicoContainer will be instantiated every time the following happens:
- The web application starts. A new PicoContainer will be created and stored in the ServletContext.
- A new session is created. A new PicoContainer (using the application level one as parent) will be created and stored in the HttpSession.
- A new request is created. A new PicoContainer (using the session level one as parent) will be created and stored in the ServletRequest.
The lifespan of the request level containers will be really short! However, instantiating a PicoContainer is a very light operation.
PicoContainer Configuration with NanoContainer
It is the web application deployer's responsability to provide the configuration of the various PicoContainer instances used by the web application. There are several ways to do this:
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) }
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 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.
Custom Java class 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) } } }
Nanocontainer composition via XStream
You can also use XStream to compose your containers.
<context-param> <param-name>org.nanocontainer.integrationkit.ContainerComposer</param-name> <param-value>org.nanocontainer.servlet.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 xstream based container configuration in test case and from nanocontainer subproject.
Activating NanoContainer in the Web application
In order to activate NanoContainer in the Web application, the following lines also have to be added to web.xml:
<listener> <listener-class>org.nanocontainer.servlet.ServletContainerListener</listener-class> </listener>
This class will receive various events from the Servlet container and do all the magic ![]()
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')
In order for this to work properly, you must ensure the components you want to access are registered with java.lang.String keys.

Comments (1)
Feb 26, 2004
Aslak Hellesøy says:
We should add an example here that illustrates how First class session objects c...We should add an example here that illustrates how First class session objects can be used here. The session containers can contain custom (app-specific) Session objects:
class MyAppSession {
Basket getBasket()
User getUser()
}