blob: 6582f1d31d429c9c14a66e4de81a2bac93d2c547 [file] [log] [blame]
<!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">
&lt;init-param&gt;
&lt;param-name&gt;load-class&lt;/param-name&gt;
&lt;param-value&gt;
&lt;!-- For IBM WebSphere:
com.ibm.servlet.classloader.Handler --&gt;
&lt;!-- For Database Driver: --&gt;
@database-driver@
&lt;!-- For parent ServiceManager sample:
This will cause the static initializer to run,
and thus the Configuration object to be created
and bound. --&gt;
org.apache.cocoon.samples.parentcm.Configurator
&lt;/param-value&gt;
&lt;/init-param&gt;</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">
&lt;init-param&gt;
&lt;param-name&gt;parent-service-manager&lt;/param-name&gt;
&lt;param-value&gt;org.apache.cocoon.samples.parentcm.ParentServiceManager/(remove this line break)
org/apache/cocoon/samples/parentcm/ParentCMConfiguration&lt;/param-value&gt;
&lt;/init-param&gt;</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>