Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: org/infohazard/maverick/flow/AbstractControllerFactory.java


1   /*
2    * $Id: AbstractControllerFactory.java,v 1.1 2004/06/27 17:42:14 eelco12 Exp $
3    * $Source: /cvsroot/mav/maverick/src/java/org/infohazard/maverick/flow/AbstractControllerFactory.java,v $
4    */
5   
6   package org.infohazard.maverick.flow;
7   
8   import java.util.Map;
9   
10  import javax.servlet.ServletConfig;
11  import javax.servlet.ServletException;
12  
13  import org.infohazard.maverick.util.XML;
14  import org.jdom.Element;
15  
16  /**
17   * Base class for controller factories.
18   * Creates (what appears to be) a singleton controller object appropriate
19   * for the type of controller specified in the XML, including single-use
20   * controllers.  If no controller is specified, a special do-nothing
21   * controller is returned. If you want to use a custom controller factory,
22   * it is advisable to extend from this class and override either the
23   * interface method (createController) or override one or more of the
24   * template methods (getControllerClass, getControllerInstance and
25   * initializeController).
26   *
27   * @author Jeff Schnitzer
28   * @author Eelco Hillenius
29   */
30  public abstract class AbstractControllerFactory implements ControllerFactory
31  {
32    /**
33     * xml attribute of controller class.
34     */
35    protected static final String ATTR_CONTROLLER_CLASS = "class";
36  
37    /**
38     * Dummy controller class.
39     */
40    static class NullController implements ControllerSingleton
41    {
42      /** initialize. */
43      public void init(Element controllerNode) {}
44  
45      /** cmd method impl. */
46      public String go(ControllerContext cctx) throws ServletException
47        { return "NO CONTROLLER DEFINED"; }
48    }
49  
50    /**
51     * dummy controller.
52     */
53    protected static final Controller nullController = new NullController();
54  
55      /**
56       * Initialize: this method does nothing; override to customize.
57       * @see org.infohazard.maverick.flow.ControllerFactory#init(org.jdom.Element, javax.servlet.ServletConfig)
58       */
59      public void init(Element factoryNode, ServletConfig servletCfg) throws ConfigException
60      {
61          // no nada
62      }
63  
64    /**
65     * Creates (what appears to be) a singleton controller object appropriate
66     * for the type of controller specified in the XML, including single-use
67     * controllers. If no controller is specified, a special do-nothing
68     * controller is returned.
69     * @see org.infohazard.maverick.flow.ControllerFactory#createController(org.jdom.Element)
70     */
71    public Controller createController(Element controllerNode) throws ConfigException
72    {
73      if (controllerNode == null) // if no controller is defined, return the dummy impl
74      {
75          return nullController;   
76      }
77  
78      // get the class of the controller node
79      Class controllerClass = getControllerClass(controllerNode);
80      // create the proper instance based on the class
81      Controller controller = getControllerInstance(controllerNode, controllerClass);
82      // initialize the controller based on the implementation
83      initializeController(controllerNode, controller);
84  
85      return controller;
86    }
87  
88    /**
89     * Get the controller class from the configuration.
90     * @param controllerNode the xml node of the controller
91     * @return Class the class from the configuration or null if the controller node was null
92     * @throws ConfigException
93     */
94    protected Class getControllerClass(Element controllerNode) throws ConfigException
95    {
96        if(controllerNode == null) return null;
97  
98      String className = controllerNode.getAttributeValue(ATTR_CONTROLLER_CLASS);
99      if (className == null || className.trim().equals(""))
100     {
101       throw new ConfigException(
102           "Controller element must have " + ATTR_CONTROLLER_CLASS
103         + " attribute:  " + XML.toString(controllerNode));   
104     }
105 
106     Class controllerClass;
107     try
108     {
109       ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
110       if (classLoader == null)
111       {
112         classLoader = AbstractControllerFactory.class.getClassLoader();
113       }
114       controllerClass = classLoader.loadClass(className);
115     }
116     catch (ClassNotFoundException ex) { throw new ConfigException(ex); }
117     return controllerClass;
118   }
119 
120   /**
121    * Create a controller instance (or a decorator) based on the controller class
122    * and the controller node.
123    * @param controllerNode xml node of the controller 
124    * @param controllerClass the class of the controller
125    * @return Controller a controller or a controller decorator
126    * @throws ConfigException
127    */
128   protected Controller getControllerInstance(
129           Element controllerNode,
130           Class controllerClass)
131       throws ConfigException
132   {
133       Controller controller = null;
134     try
135     {
136       if (ControllerSingleton.class.isAssignableFrom(controllerClass))
137       {
138           controller = createSingletonController(controllerNode, controllerClass);
139       }
140       else
141       {
142           controller = createThrowawayController(controllerNode, controllerClass);
143       }
144     }
145     catch (InstantiationException ex) { throw new ConfigException(ex); }
146     catch (IllegalAccessException ex) { throw new ConfigException(ex); }
147 
148     // decorate the controller if needed
149     controller = decorateController(controllerNode, controller);
150       
151       return controller;
152   }
153 
154   /**
155    * If needed, decorate the controller.
156    * @param controllerNode xml node of controller
157    * @param controller the controller instance.
158    * @return Controller the original controller or a decorator
159    * @throws ConfigException
160    */
161   protected Controller decorateController(
162           Element controllerNode,
163           Controller controller)
164       throws ConfigException
165   {
166       Controller decorated = controller;
167     Map params = XML.getParams(controllerNode);
168     if (params != null) // if we have params, create a decorator for the controller
169     {
170         decorated = new ControllerWithParams(controller, params);   
171     }
172     return decorated;
173   }
174 
175   /**
176    * Create a singleton controller instance.
177    * @param controllerNode controller node
178    * @param controllerClass controller class
179    * @return Controller instance
180    * @throws ConfigException
181    * @throws InstantiationException
182    * @throws IllegalAccessException
183    */
184   protected Controller createSingletonController(
185           Element controllerNode,
186           Class controllerClass)
187       throws ConfigException,
188       InstantiationException,
189       IllegalAccessException
190   {
191       return (ControllerSingleton)controllerClass.newInstance();
192   }
193 
194   /**
195    * Create a throwaway controller; this implementation creates
196    * an instance of ThrowawayControllerAdapter.
197    * @param controllerNode controller node
198    * @param controllerClass controller class
199    * @return Controller instance
200    * @throws ConfigException
201    * @throws InstantiationException
202    * @throws IllegalAccessException
203    */
204   protected Controller createThrowawayController(
205           Element controllerNode,
206           Class controllerClass)
207       throws ConfigException,
208       InstantiationException,
209       IllegalAccessException
210   {
211       return new ThrowawayControllerAdapter(controllerClass);
212   }
213 
214   /**
215    * initialize the controller if it needs to be done. This implementation
216    * just looks if the given controller (or embedded controller in case
217    * the given controller is a decorator) is of type ControllerSingleton and,
218    * if it is, it's init method is called.
219    * @param controllerNode the xml node of the controller
220    * @param controller the controller instance
221    * @throws ConfigException
222    */
223   protected void initializeController(
224           Element controllerNode,
225           Controller controller)
226       throws ConfigException
227   {
228       controller = getControllerUndecorated(controller);
229       if(controller instanceof ControllerSingleton)
230       {
231           ((ControllerSingleton)controller).init(controllerNode);
232       }
233       // else do nothing
234   }
235 
236   /**
237    * Get the 'real' controller instance unwrapped.
238    * @param controller the controller or wrapper.
239    * @return Controller the 'real' controller instance unwrapped.
240    */
241   protected Controller getControllerUndecorated(Controller controller)
242   {
243       Controller concreteController = controller;
244       if(controller instanceof ControllerWithParams)
245       {
246           concreteController = ((ControllerWithParams)controller).getDecorated();
247       }
248       return concreteController;
249   }
250 }