This post originated from an RSS feed registered with Java Buzz
by Lars Hoss.
Original Post: How I have added IoC to Struts Actions
Feed Title: WoEyE's weblog
Feed URL: http://woeye.highteq.net/xml/weblog/woeye.rss
Feed Description: The personal weblog of WoEyE. Mostly about J2EE and MacOS X.
One of the cool features of WebWork2 is the use of the IoC (Inversion of Control) design pattern. I asked myself wether it would be possible to add IoC to Struts Actions as well and after some meditation I have ended up with a solution which I want to discuss now. The class who is responsible for creating Action instances is RequestProcessor or TilesRequestProcessor if you are using Tiles. If you look at RequestProcessor you will notice the method processActionCreate. As the name suggests this method is responsible for creating the Action instances. Therefore I decided to derive from TilesRequestProcessor and overwrite processActionCreate. Inside the method I use reflection in order to find out wether the action returned by super.processActionCreate(...) implements on of the registered awareable interfaces. In case the action does I call the setter method declared in the interface. The registered awareable interfaces are maintained by a class called ComponentRegistry. This class is designed as a singleton. At last I wrote a Struts plugin that performs the initial registration of the awareable interfaces and their corresponding object instances.
Here's a code snippet from my custom RequestProcessor:
protected Action processActionCreate(HttpServletRequest request, HttpServletResponse response, ActionMapping mapping) throws IOException { Action action = super.processActionCreate(request, response, mapping); // Look for Awareable classes (IoC) and invoke the setters if present ComponentRegistry registry = ComponentRegistry.getSharedInstance(); Set classes = registry.getRegisteredClasses(); Iterator it = classes.iterator(); while (it.hasNext()) { Class awareableIf = (Class)it.next(); if (awareableIf.isAssignableFrom(action.getClass())) { Object instance = registry.findComponent(awareableIf); log.debug("instance for interface [" + awareableIf + "]: " + instance); if (instance != null) { Method[] methods = awareableIf.getMethods(); if (methods.length != 1) throw new IOException("The awareable interface must exactly contain one method"); try { log.debug("Invoking method: " + methods[0]); methods[0].invoke(action, new Object[]{instance}); } catch(Exception ex) { log.error("Could not invoke setter on awareable interface", ex); throw new IOException("Could not invoke setter on awareable interface"); } } } } return action }
As you can see currently the setter of the awareable interface will be called on every request because the action caching is handled inside super.processActionCreate(...) and there's no way to find out if an action was created or reused as far as I know. Therefore you might want to cache the name of the classes whose setter you called.
Now that I have IoC I am looking into Interceptors :-) ...