Author: vgritsenko Date: Wed Nov 17 16:15:58 2004 New Revision: 76197 Modified: cocoon/trunk/src/java/org/apache/cocoon/Constants.java cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/DefaultTreeBuilder.java cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/sitemap/SitemapLanguage.java Log: Refactor DefaultTreeBuilder. Make stuff private. Implement separate context object for each pipeline (required for VPCs)
Modified: cocoon/trunk/src/java/org/apache/cocoon/Constants.java ============================================================================== --- cocoon/trunk/src/java/org/apache/cocoon/Constants.java (original) +++ cocoon/trunk/src/java/org/apache/cocoon/Constants.java Wed Nov 17 16:15:58 2004 @@ -24,7 +24,7 @@ * * @author <a href="mailto:[EMAIL PROTECTED]">Stefano Mazzocchi</a> * @author <a href="mailto:[EMAIL PROTECTED]">Peter Royal</a> - * @version CVS $Id: Constants.java,v 1.15 2004/06/11 21:37:04 vgritsenko Exp $ + * @version CVS $Id$ */ public final class Constants { @@ -255,6 +255,19 @@ /** Application <code>Context</code> Key for the current classpath */ public static final String CONTEXT_CLASSPATH = "classpath"; + + + /** Application <code>Context</code> key for the current environment URI */ + public static final String CONTEXT_ENV_URI = "env-uri"; + + /** Application <code>Context</code> key for the current environment prefix */ + public static final String CONTEXT_ENV_PREFIX = "env-prefix"; + + /** Application <code>Context</code> key for the current environment helper */ + public static final String CONTEXT_ENV_HELPER = "env-helper"; + + /** Application <code>Context</code> key prefix for the current sitemap virtual components */ + public static final String CONTEXT_VPC_PREFIX = "vpc-"; /** * Application <code>Context</code> Key for the URL to the configuration file Modified: cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/DefaultTreeBuilder.java ============================================================================== --- cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/DefaultTreeBuilder.java (original) +++ cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/DefaultTreeBuilder.java Wed Nov 17 16:15:58 2004 @@ -39,6 +39,7 @@ import org.apache.cocoon.components.LifecycleHelper; import org.apache.cocoon.components.source.SourceUtil; import org.apache.cocoon.components.treeprocessor.variables.VariableResolverFactory; +import org.apache.cocoon.components.treeprocessor.variables.VariableResolver; import org.apache.cocoon.sitemap.PatternException; import org.apache.cocoon.sitemap.SitemapParameters; import org.apache.excalibur.source.Source; @@ -56,38 +57,62 @@ protected Map attributes = new HashMap(); + //----- lifecycle-related objects ------ + + /** + * This component's avalon context + */ + private Context context; + + /** + * This component's service manager + */ + private ServiceManager manager; + + // ------------------------------------- + /** - * The tree processor that we're building. + * The tree processor that we are building. */ protected ConcreteTreeProcessor processor; - //----- lifecycle-related objects ------ - protected Context context; + /** + * The namespace of configuration for the processor that we are building. + */ + protected String itsNamespace; /** - * The parent component manager. Either the one of the parent processor, or that provided - * by Cocoon in service() + * The context for the processor that we are building + * It is created by [EMAIL PROTECTED] #createContext(Configuration)}. */ - protected ServiceManager ownManager; + private Context itsContext; - // ------------------------------------- + /** + * The service manager for the processor that we are building. + * It is created by [EMAIL PROTECTED] #createServiceManager(Context, Configuration)}. + */ + private ServiceManager itsManager; /** - * Component processor of the parent manager (can be null for the root sitemap) + * Helper object which sets up components in the context + * of the processor that we are building. */ - protected ServiceManager parentProcessorManager; + private LifecycleHelper itsLifecycle; /** - * Component manager created by [EMAIL PROTECTED] #createServiceManager(Configuration)}. + * Selector for ProcessingNodeBuilders which is set up + * in the context of the processor that we are building. */ - protected ServiceManager processorManager; + private ServiceSelector itsBuilders; - /** Selector for ProcessingNodeBuilders */ - protected ServiceSelector builderSelector; + // ------------------------------------- - protected LifecycleHelper lifecycle; + /** + * Component processor of the parent manager + * (can be null for the root sitemap) + */ + protected ServiceManager parentProcessorManager; - protected String namespace; /** Nodes gone through setupNode() that implement Initializable */ private List initializableNodes = new ArrayList(); @@ -116,9 +141,13 @@ * @see org.apache.avalon.framework.service.Serviceable#service(org.apache.avalon.framework.service.ServiceManager) */ public void service(ServiceManager manager) throws ServiceException { - this.ownManager = manager; + this.manager = manager; } + public void initialize() throws Exception { + } + + /** * Get the location of the treebuilder config file. Can be overridden for other versions. * @return @@ -127,51 +156,6 @@ return "resource://org/apache/cocoon/components/treeprocessor/sitemap-language.xml"; } - public void initialize() throws Exception { - // Load the builder config file - SourceResolver resolver = (SourceResolver) this.ownManager.lookup(SourceResolver.ROLE); - String url = getBuilderConfigURL(); - Configuration config; - try { - Source src = resolver.resolveURI(url); - try { - SAXConfigurationHandler handler = new SAXConfigurationHandler(); - SourceUtil.toSAX(this.ownManager, src, null, handler); - config = handler.getConfiguration(); - } finally { - resolver.release(src); - } - } catch (Exception e) { - throw new ConfigurationException("Could not load TreeBuilder configuration from " + url, e); - } finally { - this.ownManager.release(resolver); - } - - // Create the NodeBuilder selector. - CocoonServiceSelector selector = new CocoonServiceSelector() { - protected String getComponentInstanceName() { - return "node"; - } - - protected String getClassAttributeName() { - return "builder"; - } - }; - - // Automagically initialize the selector - LifecycleHelper.setupComponent(selector, - getLogger(), - this.context, - this.ownManager, - config.getChild("nodes", false), - true - ); - - this.builderSelector = selector; - - } - - public void setParentProcessorManager(ServiceManager manager) { this.parentProcessorManager = manager; } @@ -191,23 +175,44 @@ } /** + * Create a context that will be used for all <code>Contextualizable</code> + * <code>ProcessingNodeBuilder</code>s and <code>ProcessingNode</code>s. + * + * <p>The default here is to simply return the context set in + * <code>contextualize()</code>, i.e. the context set by the calling + * <code>TreeProcessor</code>. + * + * <p>Subclasses can redefine this method to create a context local to + * a tree, such as for sitemap's <map:components>. + * + * @return a context + */ + protected Context createContext(Configuration tree) + throws Exception { + return this.context; + } + + /** * Create a service manager that will be used for all <code>Serviceable</code> * <code>ProcessingNodeBuilder</code>s and <code>ProcessingNode</code>s. - * <p> - * The default here is to simply return the manager set by <code>compose()</code>, - * i.e. the component manager set by the calling <code>TreeProcessor</code>. - * <p> - * Subclasses can redefine this method to create a component manager local to a tree, - * such as for sitemap's <map:components>. + * + * <p>The default here is to simply return the manager set in + * <code>compose()</code>, i.e. the component manager set by the calling + * <code>TreeProcessor</code>. + * + * <p>Subclasses can redefine this method to create a service manager local to + * a tree, such as for sitemap's <map:components>. * * @return a component manager */ - protected ServiceManager createServiceManager(Configuration tree) throws Exception { - return this.ownManager; + protected ServiceManager createServiceManager(Context context, Configuration tree) + throws Exception { + return this.manager; } + /* (non-Javadoc) - * @see org.apache.cocoon.components.treeprocessor.TreeBuilder#setProcessor(org.apache.cocoon.components.treeprocessor.ConcreteTreeProcessor) + * @see org.apache.cocoon.components.treeprocessor.TreeBuilder#setProcessor(ConcreteTreeProcessor) */ public void setProcessor(ConcreteTreeProcessor processor) { this.processor = processor; @@ -220,6 +225,7 @@ return this.processor; } + /** * Register a <code>ProcessingNode</code> under a given name. * For example, <code>ResourceNodeBuilder</code> stores here the <code>ProcessingNode</code>s @@ -241,17 +247,16 @@ // FIXME : check namespace String nodeName = config.getName(); - if (this.getLogger().isDebugEnabled()) { + if (getLogger().isDebugEnabled()) { getLogger().debug("Creating node builder for " + nodeName); } ProcessingNodeBuilder builder; try { - builder = (ProcessingNodeBuilder)this.builderSelector.select(nodeName); - - } catch(ServiceException ce) { + builder = (ProcessingNodeBuilder) this.itsBuilders.select(nodeName); + } catch (ServiceException ce) { // Is it because this element is unknown ? - if (this.builderSelector.isSelectable(nodeName)) { + if (this.itsBuilders.isSelectable(nodeName)) { // No : rethrow throw ce; } else { @@ -299,25 +304,63 @@ * Get the namespace URI that builders should use to find their nodes. */ public String getNamespace() { - return this.namespace; + return this.itsNamespace; } /** * Build a processing tree from a <code>Configuration</code>. */ public ProcessingNode build(Configuration tree) throws Exception { + // The namespace used in the whole sitemap is the one of the root element + this.itsNamespace = tree.getNamespace(); - // The namespace use in the whole sitemap is the one of the root element - this.namespace = tree.getNamespace(); - - this.processorManager = createServiceManager(tree); + // Context and manager for the sitemap we build + this.itsContext = createContext(tree); + this.itsManager = createServiceManager(this.itsContext, tree); // Create a helper object to setup components - this.lifecycle = new LifecycleHelper(getLogger(), - this.context, - this.processorManager, - null // configuration - ); + this.itsLifecycle = new LifecycleHelper(getLogger(), + this.itsContext, + this.itsManager, + null /* configuration */); + + // Create & initialize the NodeBuilder selector. + { + CocoonServiceSelector selector = new CocoonServiceSelector() { + protected String getComponentInstanceName() { + return "node"; + } + + protected String getClassAttributeName() { + return "builder"; + } + }; + // Load the builder config file + SourceResolver resolver = (SourceResolver) this.manager.lookup(SourceResolver.ROLE); + String url = getBuilderConfigURL(); + Configuration config; + try { + Source src = resolver.resolveURI(url); + try { + SAXConfigurationHandler handler = new SAXConfigurationHandler(); + SourceUtil.toSAX(this.manager, src, null, handler); + config = handler.getConfiguration(); + } finally { + resolver.release(src); + } + } catch (Exception e) { + throw new ConfigurationException("Could not load TreeBuilder configuration from " + url, e); + } finally { + this.manager.release(resolver); + } + LifecycleHelper.setupComponent(selector, + getLogger(), + this.itsContext, + this.itsManager, + config.getChild("nodes", false), + true); + this.itsBuilders = selector; + } // Calls to getRegisteredNode() are forbidden this.canGetNode = false; @@ -366,7 +409,7 @@ ((AbstractProcessingNode)node).setSitemapExecutor(this.processor.getSitemapExecutor()); } - this.lifecycle.setupComponent(node, false); + this.itsLifecycle.setupComponent(node, false); if (node instanceof ParameterizableProcessingNode) { Map params = getParameters(config); @@ -407,9 +450,7 @@ String name = child.getAttribute("name"); String value = child.getAttribute("value"); try { - params.put( - VariableResolverFactory.getResolver(name, this.processorManager), - VariableResolverFactory.getResolver(value, this.processorManager)); + params.put(resolve(name), resolve(value)); } catch(PatternException pe) { String msg = "Invalid pattern '" + value + "' at " + child.getLocation(); throw new ConfigurationException(msg, pe); @@ -442,42 +483,50 @@ // Check that this type actually exists ServiceSelector selector = null; - try { - selector = (ServiceSelector)this.processorManager.lookup(role + "Selector"); - } catch(ServiceException ce) { + selector = (ServiceSelector) this.itsManager.lookup(role + "Selector"); + } catch (ServiceException e) { throw new ConfigurationException("Cannot get service selector for 'map:" + - statement.getName() + "' at " + statement.getLocation(), - ce - ); + statement.getName() + "' at " + statement.getLocation(), + e); } - this.processorManager.release(selector); + this.itsManager.release(selector); if (!selector.isSelectable(type)) { throw new ConfigurationException("Type '" + type + "' does not exist for 'map:" + - statement.getName() + "' at " + statement.getLocation() - ); + statement.getName() + "' at " + statement.getLocation()); } return type; } + /** + * Resolve expression using its manager + */ + protected VariableResolver resolve (String expression) + throws PatternException { + return VariableResolverFactory.getResolver(expression, this.itsManager); + } + public void recycle() { // Reset all data created during the build this.attributes.clear(); this.canGetNode = false; this.disposableNodes = new ArrayList(); // Must not be cleared as it's used for processor disposal this.initializableNodes.clear(); - this.lifecycle = null; // Created in build() this.linkedBuilders.clear(); - this.namespace = null; // Set in build() this.parentProcessorManager = null; // Set in setParentProcessorManager() - this.processor = null; // Set in setProcessor() - this.processorManager = null; // Set in build() - this.registeredNodes.clear(); + this.processor = null; // Set in setProcessor() + + this.itsNamespace = null; // Set in build() + LifecycleHelper.dispose(this.itsBuilders); + this.itsBuilders = null; // Set in build() + this.itsLifecycle = null; // Set in build() + this.itsManager = null; // Set in build() + this.itsContext = null; // Set in build() - this.lifecycle = null; // Created in build() + this.registeredNodes.clear(); this.initializableNodes.clear(); this.linkedBuilders.clear(); this.canGetNode = false; @@ -487,8 +536,6 @@ } public void dispose() { - LifecycleHelper.dispose(this.builderSelector); - // Don't dispose manager or roles: they are used by the built tree // and thus must live longer than the builder. } Modified: cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/sitemap/SitemapLanguage.java ============================================================================== --- cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/sitemap/SitemapLanguage.java (original) +++ cocoon/trunk/src/java/org/apache/cocoon/components/treeprocessor/sitemap/SitemapLanguage.java Wed Nov 17 16:15:58 2004 @@ -15,20 +15,14 @@ */ package org.apache.cocoon.components.treeprocessor.sitemap; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Map; -import java.util.Set; -import java.util.StringTokenizer; - import org.apache.avalon.framework.configuration.Configuration; import org.apache.avalon.framework.configuration.ConfigurationException; import org.apache.avalon.framework.configuration.DefaultConfiguration; +import org.apache.avalon.framework.context.Context; +import org.apache.avalon.framework.context.DefaultContext; import org.apache.avalon.framework.service.ServiceManager; + +import org.apache.cocoon.Constants; import org.apache.cocoon.acting.Action; import org.apache.cocoon.components.container.CocoonServiceManager; import org.apache.cocoon.components.pipeline.ProcessingPipeline; @@ -36,7 +30,8 @@ import org.apache.cocoon.components.treeprocessor.CategoryNodeBuilder; import org.apache.cocoon.components.treeprocessor.DefaultTreeBuilder; import org.apache.cocoon.components.treeprocessor.ProcessorComponentInfo; -import org.apache.cocoon.components.treeprocessor.variables.VariableResolverFactory; +import org.apache.cocoon.environment.Environment; +import org.apache.cocoon.environment.internal.EnvironmentHelper; import org.apache.cocoon.generation.Generator; import org.apache.cocoon.matching.Matcher; import org.apache.cocoon.reading.Reader; @@ -45,8 +40,19 @@ import org.apache.cocoon.sitemap.PatternException; import org.apache.cocoon.transformation.Transformer; import org.apache.cocoon.util.StringUtils; + import org.apache.regexp.RE; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; +import java.util.StringTokenizer; + /** * The tree builder for the sitemap language. * @@ -63,7 +69,7 @@ * Build a component manager with the contents of the <map:components> element of * the tree. */ - protected ServiceManager createServiceManager(Configuration tree) throws Exception { + protected ServiceManager createServiceManager(Context context, Configuration tree) throws Exception { // Get the map:component node // Don't check namespace here : this will be done by node builders @@ -80,7 +86,7 @@ // Go through the component lifecycle newManager.enableLogging(getLogger()); - newManager.contextualize(this.context); + newManager.contextualize(context); newManager.configure(config); newManager.initialize(); @@ -111,6 +117,17 @@ return newManager; } + protected Context createContext(Configuration tree) throws Exception { + // Create sub-context for this sitemap + DefaultContext newContext = new DefaultContext(super.createContext(tree)); + Environment env = EnvironmentHelper.getCurrentEnvironment(); + newContext.put(Constants.CONTEXT_ENV_URI, env.getURI()); + newContext.put(Constants.CONTEXT_ENV_PREFIX, env.getURIPrefix()); + // FIXME How to get rif of EnvironmentHelper? + newContext.put(Constants.CONTEXT_ENV_HELPER, getProcessor().getWrappingProcessor().getEnvironmentHelper()); + return newContext; + } + /** * Setup the default compnent type for a given role. * @@ -461,16 +478,14 @@ + "\npipeline-hints: (value) [implicit] true"); } - params.put( VariableResolverFactory.getResolver(nameValuePair[0], this.processorManager), - VariableResolverFactory.getResolver("true", this.processorManager)); + params.put(resolve(nameValuePair[0]), resolve("true")); } else { if (getLogger().isDebugEnabled()) { getLogger().debug("pipeline-hints: (name) " + nameValuePair[0] + "\npipeline-hints: (value) " + nameValuePair[1]); } - params.put( VariableResolverFactory.getResolver(nameValuePair[0], this.processorManager), - VariableResolverFactory.getResolver(nameValuePair[1], this.processorManager)); + params.put(resolve(nameValuePair[0]), resolve(nameValuePair[1])); } } catch(PatternException pe) { String msg = "Invalid pattern '" + hintParams + "' at " + statement.getLocation();