| <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> |
| <html> |
| <head> |
| <META http-equiv="Content-Type" content="text/html; charset=UTF-8"> |
| <title>Parent Service Manager</title> |
| <link href="http://purl.org/DC/elements/1.0/" rel="schema.DC"> |
| <meta content="Leo Sutic" name="DC.Creator"> |
| <meta content="This document describes how to use a parent service manager in Cocoon." name="DC.Description"> |
| </head> |
| <body> |
| |
| <h1>Parent Service Manager</h1> |
| |
| <p>When using Apache Cocoon it is sometimes neccessary to obtain |
| components from other sources than the <span class="codefrag">user.roles</span> file, |
| or preferable to have a common component manager for several web applications.</p> |
| |
| |
| <p>The pattern chosen for Cocoon is the dynamic loading of a service manager class. |
| The initialization parameter parent-service-manager in web.xml specifies a class |
| that will be loaded, instantiated and used as a parent service manager for |
| Cocoon's serivce manager.</p> |
| |
| |
| <p>The recommended procedure is for the class, when it is initialized, to create a |
| delegate in the form of an <span class="codefrag">CocoonServiceManager</span>, configure it |
| by looking up a <span class="codefrag">Configuration</span> object via JNDI, and delegate any requests to it.</p> |
| |
| |
| <p>In order to provide a way to pass parameters to the parent service manager class |
| (the class specified in parent-service-manager), Cocoon will instantiate the class |
| via the constructor that takes a single <span class="codefrag">String</span> argument, passing |
| anything to the right of the first <span class="codefrag">'/'</span> in the parameter value to the |
| constructor. Subsequently Cocoon examines whether the class implements |
| <span class="codefrag">org.apache.avalon.framework.logger.LogEnabled</span> and/or |
| <span class="codefrag">org.apache.avalon.framework.activity.Initializable</span> and calls |
| <span class="codefrag">setLogger</span> and/or <span class="codefrag">initialize</span>, as appropriate. |
| The instance is then used as a parent service manager. |
| </p> |
| |
| |
| <p>Since that didn't make much sense in itself, let's look at the sample.</p> |
| |
| |
| <p>The goal is to define a component that can give us the time of day and |
| let it be managed by a parent service manager.</p> |
| |
| |
| <p>So, first we need to put a Configuration object into JNDI, and then |
| grab that object, use it to configure an CocoonServiceManager, |
| and pass on any requests to that manager.</p> |
| |
| |
| <h2>Step 1: Creating a configuration object</h2> |
| <p>We'll do this the quick and dirty way. The static initializer of a class |
| will create a Configuration instance with a single role and bind it |
| to <span class="codefrag">org/apache/cocoon/samples/parentcm/ParentCMConfigration</span>. |
| </p> |
| <p>The following code was taken from org/apache/cocoon/samples/parentcm/Configurator.java</p> |
| <pre class="code"> |
| public class Configurator { |
| |
| static { |
| try { |
| // |
| // Create a new role. |
| // |
| DefaultConfiguration config = new DefaultConfiguration("roles", ""); |
| DefaultConfiguration timeComponent = new DefaultConfiguration("role", "roles"); |
| timeComponent.addAttribute("name", Time.ROLE); |
| timeComponent.addAttribute("default-class", TimeComponent.class.getName()); |
| timeComponent.addAttribute("shorthand", "samples-parentcm-time"); |
| config.addChild(timeComponent); |
| |
| // |
| // Bind it - get an initial context. |
| // |
| Hashtable environment = new Hashtable(); |
| environment.put(Context.INITIAL_CONTEXT_FACTORY, |
| MemoryInitialContextFactory.class.getName()); |
| initialContext = new InitialContext(environment); |
| |
| // |
| // Create subcontexts and bind the configuration. |
| // |
| Context ctx = initialContext.createSubcontext("org"); |
| ctx = ctx.createSubcontext("apache"); |
| ctx = ctx.createSubcontext("cocoon"); |
| ctx = ctx.createSubcontext("samples"); |
| ctx = ctx.createSubcontext("parentcm"); |
| ctx.rebind("ParentCMConfiguration", config); |
| } catch (Exception e) { |
| e.printStackTrace(System.err); |
| } |
| } |
| }</pre> |
| <p>To make sure the static initializer runs we make Cocoon force-load the class |
| by making a change to the web.xml file:</p> |
| <pre class="code"> |
| <init-param> |
| <param-name>load-class</param-name> |
| <param-value> |
| <!-- For IBM WebSphere: |
| com.ibm.servlet.classloader.Handler --> |
| |
| <!-- For Database Driver: --> |
| @database-driver@ |
| |
| <!-- For parent ServiceManager sample: |
| This will cause the static initializer to run, |
| and thus the Configuration object to be created |
| and bound. --> |
| org.apache.cocoon.samples.parentcm.Configurator |
| </param-value> |
| </init-param></pre> |
| |
| |
| <h2>Step 2: Write the service manager</h2> |
| <p>Now that the configuration object is sitting there waiting for us, let's craft |
| the component manager. Please see the file org/apache/cocoon/samples/parentcm/ParentServiceManager.java |
| for an example. It is too much to paste in here.</p> |
| |
| |
| <h2>Step 3: Tell Cocoon to use the service manager</h2> |
| <p>Change the web.xml file to:</p> |
| <pre class="code"> |
| <init-param> |
| <param-name>parent-service-manager</param-name> |
| <param-value>org.apache.cocoon.samples.parentcm.ParentServiceManager/(remove this line break) |
| org/apache/cocoon/samples/parentcm/ParentCMConfiguration</param-value> |
| </init-param></pre> |
| <p>Cocoon will now do the following: First, it will split the parameter value at the first slash, |
| in this case ending up with the strings <span class="codefrag">"org.apache.cocoon.samples.parentcm.ParentServiceManager"</span> |
| and <span class="codefrag">"org/apache/cocoon/samples/parentcm/ParentCMConfiguration"</span>. The first string is the |
| class to instantiate. The second is the parameter that will be passed to the constructor.</p> |
| <p>Next, Cocoon loads the component manager class and uses reflection to find a constructor that |
| will accept a single <span class="codefrag">String</span> argument. Upon finding one, it instantiates the |
| class in a manner similar to:</p> |
| <pre class="code"> |
| ServiceManager cm = new |
| org.apache.cocoon.samples.parentcm.ParentServiceManager( |
| "org/apache/cocoon/samples/parentcm/ParentCMConfiguration");</pre> |
| <p> |
| After this Cocoon checks whether the parent service manager class implements <span class="codefrag">Initializable</span> and/or |
| <span class="codefrag">LogEnabled</span>. Since the <span class="codefrag">ParentServiceManager</span> class implements both, Cocoon |
| does the following (with simplification): |
| </p> |
| <pre class="code"> |
| ((LogEnabled) cm).enableLogging(logger); |
| ((Initializable) cm).initialize();</pre> |
| <p>Finally, the instance is used as parent service manager of Cocoon's own service manager.</p> |
| |
| |
| <h2>Step 4: Use the component</h2> |
| <p>Cocoon components can now use the ServiceManager given to them by Cocoon to look up the |
| component managed by the parent service manager:</p> |
| <p>The following code was taken from org/apache/cocoon/samples/parentcm/Generator.java</p> |
| <pre class="code"> |
| public void setup(SourceResolver resolver, Map objectModel, String src, Parameters par) |
| throws ProcessingException, SAXException, IOException { |
| |
| Time timeGiver = null; |
| try { |
| timeGiver = (Time) manager.lookup(Time.ROLE); |
| this.time = timeGiver.getTime (); |
| } catch (ServiceException ce) { |
| throw new ProcessingException ("Could not obtain current time.", ce); |
| } finally { |
| manager.release(timeGiver); |
| } |
| }</pre> |
| |
| |
| <p>And that concludes the tour. A parent service manager was initialized with a configuration |
| obtained via JNDI and its components used by a Cocoon generator.</p> |
| |
| |
| </body> |
| </html> |