This page follows on from the scopes page
There are only about a million Java web-frameworks for Java. There more recent and sophisticated ones try to do Dependency Injection for 'actions' or 'controllers'.
If you want to use PicoContainer for a web framework, then you're likely to end up with three container levels. The root container would be common to all and known as the application scoped container. Next is a session-scoped one, with the app one marked as its parent. Lastly a request scoped one, with the session one marked as its parent. There are two not-so-subtle varations on how they would be used. One, we poineered with PicoContainer 1.x in 2003, the other inroduced with PicoContainer 2.x in 2007.
You make one instance of the app container. For each new HTTP Session you make a new session level container, and put it into the session itself - refer HttpSession.setAttribute(key,val). For each request, you make a new Request level container and discard it at the end of the request. For as long as it lives, the request level container's parent would be the session container.
There are two downsides of this approach. 1) you have to repeatedly add components to the session and request containers as they are instantiated. 2) the serialization of the session (by Tomcat etc) might cause more things to be serialized than you intend - i.e. the session container refers to the application container.
You make one instance of the app, session and request container on servlet load. For the Application one, you choose Caching as the behavior factory. For the session and request level ones, you choose Storing instead. You wrap the Storing behavior factory instances in HttpSessionStoring and reprogram each http request like so:
public class MyTinyPicoServlet extends HttpServlet {
private MutablePicoContainer appContainer;
private MutablePicoContainer sessionContainer;
private MutablePicoContainer requestContainer;
private HttpSessionStoring sessionStoring;
private HttpSessionStoring requestStoring;
public void init(ServletConfig cfg) throws ServletException {
appContainer = new DefaultPicoContainer(new Caching()); // app scoped components are cached for all users/sessions
Storing storingBehavior1 = new Storing();
sessionContainer = new DefaultPicoContainer(storingBehavior1, appContainer);
sessionStoringAdapter = new HttpSessionStoringAdapter(storingBehavior1, "sessionStore");
Storing storingBehavior2 = new Storing();
requestContainer = new DefaultPicoContainer(storingBehavior2, sessionContainer);
requestStoringAdapter = new HttpSessionStoringAdapter(storingBehavior2, "requestStore");
// populate app, session and request scoped containers.
appContainer.addComponent(HibernateManager.class, MyHibernateManager.class); // all sessions share one HibernateManager
sessionContainer.addComponent(ShoppingCart.class, FifoCart.class); // a new cart per user
requestContainer.addComponent("/addToCart.do", AddToCart.class); // key crudely maps to URL
requestContainer.addComponent("/removeFromCart.do", RemoveFromCart.class);
// etc
}
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
sessionStoringAdapter.retrieveOrCreateStore(req.getSession()); // associate thread with session, for caching (session scoped components)
requestStoringAdapter.resetStore(); // cache components per request (request scoped components)
Action action = (Action) requestContainer.getComponent(req.getPathTranslated());
try {
action.execute(req, resp); // yeah yeah, this is pretty basic
} finally {
sessionStoringAdapter.invalidateStore();
requestStoringAdapter.invalidateStore();
}
// trying to retrieve components from at session or request scopes from here on will result in an UnsupportedOperationException
}
}
The HttpSessionStoring class is not in the core jar, its in the 'gems' one. If you don't want a second jar - copy the class (it's real simple) to your web framework's codebase.
Waffle - hopefully the pinnacle of Java action/controller web-frameworks.