sylvain 2004/06/05 01:18:50
Modified: . status.xml
src/java/org/apache/cocoon/components/treeprocessor
DefaultTreeBuilder.java TreeBuilder.java
TreeProcessor.java
src/java/org/apache/cocoon/components/treeprocessor/sitemap
MountNodeBuilder.java
Added: src/java/org/apache/cocoon/components/treeprocessor
ConcreteTreeProcessor.java
Log:
Fix bug# 27249 : refactor TreeProcessor to avoid constant sitemap reloading
if its modification date is in the future and occasional ECM-related exceptions
when a sitemap is reloaded
Revision Changes Path
1.352 +6 -1 cocoon-2.1/status.xml
Index: status.xml
===================================================================
RCS file: /home/cvs/cocoon-2.1/status.xml,v
retrieving revision 1.351
retrieving revision 1.352
diff -u -r1.351 -r1.352
--- status.xml 4 Jun 2004 09:55:16 -0000 1.351
+++ status.xml 5 Jun 2004 08:18:50 -0000 1.352
@@ -205,6 +205,11 @@
<changes>
<release version="@version@" date="@date@">
+ <action dev="SW" type="fix" fixes-bug="27249">
+ Refactor TreeProcessor to avoid constant reloading of sitemap if its
modification
+ date is in the future and occasional ECM-related exceptions when a
sitemap is
+ reloaded.
+ </action>
<action dev="BD" type="add" due-to="Stavros Kounis" fixes-bug="28834">
Tour block: added Java shapes sample.
</action>
1.9 +4 -4
cocoon-2.1/src/java/org/apache/cocoon/components/treeprocessor/DefaultTreeBuilder.java
Index: DefaultTreeBuilder.java
===================================================================
RCS file:
/home/cvs/cocoon-2.1/src/java/org/apache/cocoon/components/treeprocessor/DefaultTreeBuilder.java,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -r1.8 -r1.9
--- DefaultTreeBuilder.java 8 Mar 2004 12:07:39 -0000 1.8
+++ DefaultTreeBuilder.java 5 Jun 2004 08:18:50 -0000 1.9
@@ -63,7 +63,7 @@
/**
* The tree processor that we're building.
*/
- protected TreeProcessor processor;
+ protected ConcreteTreeProcessor processor;
//----- lifecycle-related objects ------
protected Context context;
@@ -237,11 +237,11 @@
return selector;
}
- public void setProcessor(TreeProcessor processor) {
+ public void setProcessor(ConcreteTreeProcessor processor) {
this.processor = processor;
}
- public TreeProcessor getProcessor() {
+ public ConcreteTreeProcessor getProcessor() {
return this.processor;
}
1.5 +3 -3
cocoon-2.1/src/java/org/apache/cocoon/components/treeprocessor/TreeBuilder.java
Index: TreeBuilder.java
===================================================================
RCS file:
/home/cvs/cocoon-2.1/src/java/org/apache/cocoon/components/treeprocessor/TreeBuilder.java,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- TreeBuilder.java 5 Mar 2004 13:02:51 -0000 1.4
+++ TreeBuilder.java 5 Jun 2004 08:18:50 -0000 1.5
@@ -31,9 +31,9 @@
public interface TreeBuilder extends Component {
- void setProcessor(TreeProcessor processor);
+ void setProcessor(ConcreteTreeProcessor processor);
- TreeProcessor getProcessor();
+ ConcreteTreeProcessor getProcessor();
/**
* Returns the language that is being built (e.g. "sitemap").
1.34 +61 -287
cocoon-2.1/src/java/org/apache/cocoon/components/treeprocessor/TreeProcessor.java
Index: TreeProcessor.java
===================================================================
RCS file:
/home/cvs/cocoon-2.1/src/java/org/apache/cocoon/components/treeprocessor/TreeProcessor.java,v
retrieving revision 1.33
retrieving revision 1.34
diff -u -r1.33 -r1.34
--- TreeProcessor.java 4 Jun 2004 13:35:05 -0000 1.33
+++ TreeProcessor.java 5 Jun 2004 08:18:50 -0000 1.34
@@ -15,11 +15,6 @@
*/
package org.apache.cocoon.components.treeprocessor;
-import java.io.IOException;
-import java.net.MalformedURLException;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
import java.util.Map;
import org.apache.avalon.excalibur.component.RoleManageable;
@@ -39,12 +34,8 @@
import org.apache.avalon.framework.context.ContextException;
import org.apache.avalon.framework.context.Contextualizable;
import org.apache.avalon.framework.logger.AbstractLogEnabled;
-import org.apache.avalon.framework.logger.Logger;
-import org.apache.avalon.framework.service.ServiceManager;
import org.apache.avalon.framework.thread.ThreadSafe;
-import org.apache.cocoon.ProcessingException;
import org.apache.cocoon.Processor;
-import org.apache.cocoon.components.ChainedConfiguration;
import org.apache.cocoon.components.ContextHelper;
import org.apache.cocoon.components.ExtendedComponentSelector;
import org.apache.cocoon.components.LifecycleHelper;
@@ -52,11 +43,7 @@
import org.apache.cocoon.components.source.SourceUtil;
import org.apache.cocoon.components.source.impl.DelayedRefreshSourceWrapper;
import org.apache.cocoon.environment.Environment;
-import org.apache.cocoon.environment.ForwardRedirector;
-import org.apache.cocoon.environment.Redirector;
import org.apache.cocoon.environment.internal.EnvironmentHelper;
-import org.apache.cocoon.environment.wrapper.EnvironmentWrapper;
-import org.apache.cocoon.environment.wrapper.MutableEnvironmentFacade;
import org.apache.excalibur.source.Source;
import org.apache.excalibur.source.SourceResolver;
@@ -101,12 +88,6 @@
/** Selector of TreeBuilders, the hint is the language name */
protected ExtendedComponentSelector builderSelector;
- /** The root node of the processing tree */
- protected ProcessingNode rootNode;
-
- /** The list of processing nodes that should be disposed when disposing
this processor */
- protected List disposableNodes;
-
/** Last modification time */
protected long lastModified = 0;
@@ -125,23 +106,14 @@
/** Check for reload? */
protected boolean checkReload;
- /** The component configurations from the sitemap (if any) */
- protected Configuration componentConfigurations;
-
- /** The different sitemap component configurations */
- protected Map sitemapComponentConfigurations;
-
- /** The component manager for the sitemap */
- protected ComponentManager sitemapComponentManager;
-
- /** A service manager wrapper */
- protected ServiceManager serviceManager;
-
/** The source resolver */
protected SourceResolver resolver;
/** The environment helper */
private EnvironmentHelper environmentHelper;
+
+ /** The actual processor (package-private as needs to be accessed by
ConcreteTreeProcessor) */
+ ConcreteTreeProcessor concreteProcessor;
/**
* Create a TreeProcessor.
@@ -175,7 +147,7 @@
this.lastModifiedDelay = parent.lastModifiedDelay;
// We have our own CM
- this.manager = parent.sitemapComponentManager;
+ this.manager = parent.concreteProcessor.sitemapComponentManager;
this.resolver =
(SourceResolver)this.manager.lookup(SourceResolver.ROLE);
this.environmentHelper = new
EnvironmentHelper(parent.environmentHelper);
// Setup environment helper
@@ -198,31 +170,19 @@
return new TreeProcessor(this, delayedSource, checkReload, prefix);
}
- /* (non-Javadoc)
- * @see
org.apache.avalon.framework.context.Contextualizable#contextualize(org.apache.avalon.framework.context.Context)
- */
public void contextualize(Context context) throws ContextException {
this.context = context;
}
- /* (non-Javadoc)
- * @see
org.apache.avalon.framework.component.Composable#compose(org.apache.avalon.framework.component.ComponentManager)
- */
public void compose(ComponentManager manager) throws ComponentException {
this.manager = manager;
this.resolver =
(SourceResolver)this.manager.lookup(SourceResolver.ROLE);
}
- /* (non-Javadoc)
- * @see
org.apache.avalon.excalibur.component.RoleManageable#setRoleManager(org.apache.avalon.excalibur.component.RoleManager)
- */
public void setRoleManager(RoleManager rm) {
this.roleManager = rm;
}
- /* (non-Javadoc)
- * @see org.apache.avalon.framework.activity.Initializable#initialize()
- */
public void initialize() throws Exception {
// setup the environment helper
if (this.environmentHelper == null ) {
@@ -301,95 +261,12 @@
* ConnectionResetException If the connection was reset
*/
public boolean process(Environment environment) throws Exception {
- InvokeContext context = new InvokeContext();
-
- context.enableLogging(getLogger());
-
- try {
- return process(environment, context);
- } finally {
- context.dispose();
- }
+
+ setupConcreteProcessor(environment);
+
+ return this.concreteProcessor.process(environment);
}
- /**
- * Do the actual processing, be it producing the response or just
building the pipeline
- * @param environment
- * @param context
- * @return true if the pipeline was successfully built, false otherwise.
- * @throws Exception
- */
- protected boolean process(Environment environment, InvokeContext context)
- throws Exception {
-
- // first, check for sitemap changes
- if (this.rootNode == null ||
- (this.checkReload && this.source.getLastModified() >
this.lastModified)) {
- setupRootNode(environment);
- }
-
- // and now process
- EnvironmentHelper.enterProcessor(this, this.serviceManager,
environment);
-
- final Redirector oldRedirector = context.getRedirector();
-
- // Build a redirector
- TreeProcessorRedirector redirector = new
TreeProcessorRedirector(environment, context);
- setupLogger(redirector);
- context.setRedirector(redirector);
-
- try {
- boolean success = this.rootNode.invoke(environment, context);
-
- return success;
-
- } finally {
- EnvironmentHelper.leaveProcessor();
- // Restore old redirector
- context.setRedirector(oldRedirector);
- }
- }
-
- private boolean handleCocoonRedirect(String uri, Environment
environment, InvokeContext context) throws Exception {
-
- // Build an environment wrapper
- // If the current env is a facade, change the delegate and continue
processing the facade, since
- // we may have other redirects that will in turn also change the
facade delegate
-
- MutableEnvironmentFacade facade = environment instanceof
MutableEnvironmentFacade ?
- ((MutableEnvironmentFacade)environment) : null;
-
- if (facade != null) {
- // Consider the facade delegate (the real environment)
- environment = facade.getDelegate();
- }
-
- // test if this is a call from flow
- boolean isRedirect =
(environment.getObjectModel().remove("cocoon:forward") == null);
- Environment newEnv = new ForwardEnvironmentWrapper(environment, uri,
getLogger());
- if ( isRedirect ) {
- ((ForwardEnvironmentWrapper)newEnv).setInternalRedirect(true);
- }
-
- if (facade != null) {
- // Change the facade delegate
- facade.setDelegate((EnvironmentWrapper)newEnv);
- newEnv = facade;
- }
-
- // Get the processor that should process this request
- TreeProcessor processor;
- if ( newEnv.getURIPrefix().equals("") ) {
- processor = (TreeProcessor)getRootProcessor();
- } else {
- processor = this;
- }
-
- // Process the redirect
-// No more reset since with TreeProcessorRedirector, we need to pop values
from the redirect location
-// context.reset();
- return processor.process(newEnv, context);
- }
/**
* Process the given <code>Environment</code> to assemble
@@ -398,19 +275,10 @@
*/
public InternalPipelineDescription buildPipeline(Environment environment)
throws Exception {
- InvokeContext context = new InvokeContext( true );
-
- context.enableLogging(getLogger());
- context.setLastProcessor(this);
- try {
- if ( process(environment, context) ) {
- return context.getInternalPipelineDescription(environment);
- } else {
- return null;
- }
- } finally {
- context.dispose();
- }
+
+ setupConcreteProcessor(environment);
+
+ return this.concreteProcessor.buildPipeline(environment);
}
/* (non-Javadoc)
@@ -429,54 +297,14 @@
* Set the sitemap component configurations
*/
public void setComponentConfigurations(Configuration
componentConfigurations) {
- this.componentConfigurations = componentConfigurations;
- this.sitemapComponentConfigurations = null;
+
this.concreteProcessor.setComponentConfigurations(componentConfigurations);
}
/* (non-Javadoc)
* @see org.apache.cocoon.Processor#getComponentConfigurations()
*/
public Map getComponentConfigurations() {
- // do we have the sitemap configurations prepared for this processor?
- if ( null == this.sitemapComponentConfigurations ) {
-
- synchronized (this) {
-
- if ( this.sitemapComponentConfigurations == null ) {
- // do we have configurations?
- final Configuration[] childs =
(this.componentConfigurations == null
- ? null
- :
this.componentConfigurations.getChildren());
-
- if ( null != childs ) {
-
- if ( null == this.parent ) {
- this.sitemapComponentConfigurations = new
HashMap(12);
- } else {
- // copy all configurations from parent
- this.sitemapComponentConfigurations = new
HashMap(this.parent.getComponentConfigurations());
- }
-
- // and now check for new configurations
- for(int m = 0; m < childs.length; m++) {
-
- final String r =
this.roleManager.getRoleForName(childs[m].getName());
- this.sitemapComponentConfigurations.put(r, new
ChainedConfiguration(childs[m],
-
(ChainedConfiguration)this.sitemapComponentConfigurations.get(r)));
- }
- } else {
- // we don't have configurations
- if ( null == this.parent ) {
- this.sitemapComponentConfigurations =
Collections.EMPTY_MAP;
- } else {
- // use configuration from parent
- this.sitemapComponentConfigurations =
this.parent.getComponentConfigurations();
- }
- }
- }
- }
- }
- return this.sitemapComponentConfigurations;
+ return this.concreteProcessor.getComponentConfigurations();
}
/* (non-Javadoc)
@@ -497,29 +325,37 @@
return this.environmentHelper;
}
- protected synchronized void setupRootNode(Environment env) throws
Exception {
+ private void setupConcreteProcessor(Environment env) throws Exception {
+ // first, check for sitemap changes
+ if (this.concreteProcessor == null ||
+ (this.checkReload && this.source.getLastModified() !=
this.lastModified)) {
+ buildConcreteProcessor(env);
+ }
+ }
+
+ private synchronized void buildConcreteProcessor(Environment env) throws
Exception {
// Now that we entered the synchronized area, recheck what's already
// been checked in process().
- if (this.rootNode != null && source.getLastModified() <=
this.lastModified) {
+ if (this.concreteProcessor != null && source.getLastModified() ==
this.lastModified) {
// Nothing changed
return;
}
long startTime = System.currentTimeMillis();
- // Dispose the previous tree, if any
- disposeTree();
-
// Get a builder
TreeBuilder builder =
(TreeBuilder)this.builderSelector.select(this.language);
- ProcessingNode root;
+ ConcreteTreeProcessor newProcessor = new ConcreteTreeProcessor(this);
+ long newLastModified;
+ this.setupLogger(newProcessor);
+ //FIXME (SW): why do we need to enterProcessor here?
EnvironmentHelper.enterProcessor(this, new
ComponentManagerWrapper(this.manager), env);
try {
if (builder instanceof Recomposable) {
((Recomposable)builder).recompose(this.manager);
}
- builder.setProcessor(this);
+ builder.setProcessor(newProcessor);
if (this.fileName == null) {
this.fileName = builder.getFileName();
}
@@ -527,116 +363,54 @@
if (this.source == null) {
this.source = new
DelayedRefreshSourceWrapper(this.resolver.resolveURI(this.fileName),
lastModifiedDelay);
}
- root = builder.build(this.source);
-
- this.sitemapComponentManager =
builder.getSitemapComponentManager();
- this.serviceManager = new
ComponentManagerWrapper(this.sitemapComponentManager);
- this.disposableNodes = builder.getDisposableNodes();
+ newLastModified = this.source.getLastModified();
+
+ ProcessingNode root = builder.build(this.source);
+
+
newProcessor.setProcessorData(builder.getSitemapComponentManager(), root,
builder.getDisposableNodes());
} finally {
EnvironmentHelper.leaveProcessor();
this.builderSelector.release(builder);
}
- this.lastModified = System.currentTimeMillis();
-
if (getLogger().isDebugEnabled()) {
double time = (this.lastModified - startTime) / 1000.0;
getLogger().debug("TreeProcessor built in " + time + " secs from
" + source.getURI());
}
- // Finished
- this.rootNode = root;
- }
+ // Switch to the new processor (ensure it's never temporarily null)
+ ConcreteTreeProcessor oldProcessor = this.concreteProcessor;
- public void dispose() {
- disposeTree();
- if (this.parent == null) {
- // root processor : dispose the builder selector
- this.builderSelector.dispose();
- }
- if ( this.manager != null ) {
- if ( this.source != null ) {
- this.resolver.release(this.source.getSource());
- this.source = null;
- }
- this.manager.release(this.resolver);
- this.resolver = null;
- this.manager = null;
- }
- }
+ this.concreteProcessor = newProcessor;
+ this.lastModified = newLastModified;
- /**
- * Dispose all nodes in the tree that are disposable
- */
- protected void disposeTree() {
- if (this.disposableNodes != null) {
- // we must dispose the nodes in reverse order
- // otherwise selector nodes are freed before the components node
- for(int i=this.disposableNodes.size()-1; i>-1; i--) {
- ((Disposable)disposableNodes.get(i)).dispose();
- }
- this.disposableNodes = null;
+ // Dispose the old processor, if any
+ if (oldProcessor != null) {
+ oldProcessor.markForDisposal();
}
}
-
- private class TreeProcessorRedirector extends ForwardRedirector {
-
- private InvokeContext context;
- public TreeProcessorRedirector(Environment env, InvokeContext
context) {
- super(env);
- this.context = context;
- }
-
- protected void cocoonRedirect(String uri) throws IOException,
ProcessingException {
- try {
- TreeProcessor.this.handleCocoonRedirect(uri, this.env,
this.context);
- } catch(IOException ioe) {
- throw ioe;
- } catch(ProcessingException pe) {
- throw pe;
- } catch(RuntimeException re) {
- throw re;
- } catch(Exception ex) {
- throw new ProcessingException(ex);
- }
- }
- }
-
- /**
- * Local extension of EnvironmentWrapper to propagate otherwise blocked
- * methods to the actual environment.
- */
- private static final class ForwardEnvironmentWrapper extends
EnvironmentWrapper {
-
- public ForwardEnvironmentWrapper(Environment env,
- String uri, Logger logger) throws MalformedURLException {
- super(env, uri, logger);
- }
- public void setStatus(int statusCode) {
- environment.setStatus(statusCode);
- }
-
- public void setContentLength(int length) {
- environment.setContentLength(length);
- }
-
- public void setContentType(String contentType) {
- environment.setContentType(contentType);
- }
-
- public String getContentType() {
- return environment.getContentType();
- }
-
- public boolean isResponseModified(long lastModified) {
- return environment.isResponseModified(lastModified);
- }
-
- public void setResponseIsNotModified() {
- environment.setResponseIsNotModified();
+ public void dispose() {
+ // Dispose the concrete processor. No need to check for existing
requests, as there
+ // are none when a TreeProcessor is disposed.
+ if (this.concreteProcessor != null) {
+ this.concreteProcessor.dispose();
}
- }
+ if (this.parent == null) {
+ // root processor : dispose the builder selector
+ this.builderSelector.dispose();
+ }
+
+ if ( this.manager != null ) {
+ if ( this.source != null ) {
+ this.resolver.release(this.source.getSource());
+ this.source = null;
+ }
+ this.manager.release(this.resolver);
+ this.resolver = null;
+ this.manager = null;
+ }
+ }
}
1.1
cocoon-2.1/src/java/org/apache/cocoon/components/treeprocessor/ConcreteTreeProcessor.java
Index: ConcreteTreeProcessor.java
===================================================================
/*
* Copyright 1999-2004 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.cocoon.components.treeprocessor;
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.avalon.framework.activity.Disposable;
import org.apache.avalon.framework.component.ComponentManager;
import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.logger.AbstractLogEnabled;
import org.apache.avalon.framework.logger.Logger;
import org.apache.avalon.framework.service.ServiceManager;
import org.apache.cocoon.ProcessingException;
import org.apache.cocoon.Processor;
import org.apache.cocoon.components.ChainedConfiguration;
import org.apache.cocoon.components.container.ComponentManagerWrapper;
import org.apache.cocoon.environment.Environment;
import org.apache.cocoon.environment.ForwardRedirector;
import org.apache.cocoon.environment.Redirector;
import org.apache.cocoon.environment.SourceResolver;
import org.apache.cocoon.environment.internal.EnvironmentHelper;
import org.apache.cocoon.environment.wrapper.EnvironmentWrapper;
import org.apache.cocoon.environment.wrapper.MutableEnvironmentFacade;
/**
* The concrete implementation of [EMAIL PROTECTED] Processor}, containing
the evaluation tree and associated
* data such as component manager.
*
* @version CVS $Id: ConcreteTreeProcessor.java,v 1.1 2004/06/05 08:18:50
sylvain Exp $
*/
public class ConcreteTreeProcessor extends AbstractLogEnabled implements
Processor {
/** The processor that wraps us */
private TreeProcessor wrappingProcessor;
/** Component manager defined by the <map:components> of this
sitemap */
ComponentManager sitemapComponentManager;
private ServiceManager serviceManager;
/** Processing nodes that need to be disposed with this processor */
private List disposableNodes;
/** Root node of the processing tree */
private ProcessingNode rootNode;
private Map sitemapComponentConfigurations;
private Configuration componentConfigurations;
/** Number of simultaneous uses of this processor (either by concurrent
request or by internal requests) */
private int requestCount;
/** Builds a concrete processig, given the wrapping processor */
public ConcreteTreeProcessor(TreeProcessor wrappingProcessor) {
this.wrappingProcessor = wrappingProcessor;
}
/** Set the processor data, result of the treebuilder job */
public void setProcessorData(ComponentManager manager, ProcessingNode
rootNode, List disposableNodes) {
if (this.sitemapComponentManager != null) {
throw new IllegalStateException("setProcessorData() can
only be called once");
}
this.sitemapComponentManager = manager;
this.serviceManager = new ComponentManagerWrapper(manager);
this.rootNode = rootNode;
this.disposableNodes = disposableNodes;
}
/** Set the sitemap component configurations (called as part of the
tree building process) */
public void setComponentConfigurations(Configuration
componentConfigurations) {
this.componentConfigurations = componentConfigurations;
this.sitemapComponentConfigurations = null;
}
/**
* Get the sitemap component configurations
* @since 2.1
*/
public Map getComponentConfigurations() {
// do we have the sitemap configurations prepared for this processor?
if ( null == this.sitemapComponentConfigurations ) {
synchronized (this) {
if ( this.sitemapComponentConfigurations == null ) {
// do we have configurations?
final Configuration[] childs =
(this.componentConfigurations == null
? null
:
this.componentConfigurations.getChildren());
if ( null != childs ) {
if ( null == this.wrappingProcessor.parent ) {
this.sitemapComponentConfigurations = new
HashMap(12);
} else {
// copy all configurations from parent
this.sitemapComponentConfigurations = new HashMap(
this.wrappingProcessor.parent.getComponentConfigurations());
}
// and now check for new configurations
for(int m = 0; m < childs.length; m++) {
final String r =
this.wrappingProcessor.roleManager.getRoleForName(childs[m].getName());
this.sitemapComponentConfigurations.put(r, new
ChainedConfiguration(childs[m],
(ChainedConfiguration)this.sitemapComponentConfigurations.get(r)));
}
} else {
// we don't have configurations
if ( null == this.wrappingProcessor.parent ) {
this.sitemapComponentConfigurations =
Collections.EMPTY_MAP;
} else {
// use configuration from parent
this.sitemapComponentConfigurations =
this.wrappingProcessor.parent.getComponentConfigurations();
}
}
}
}
}
return this.sitemapComponentConfigurations; }
/**
* Mark this processor as needing to be disposed. Actual call to [EMAIL
PROTECTED] #dispose()} will occur when
* all request processings on this processor will be terminated.
*/
public void markForDisposal() {
// Decrement the request count (negative number means dispose)
synchronized(this) {
this.requestCount--;
}
if (this.requestCount < 0) {
// No more users : dispose right now
dispose();
}
}
public TreeProcessor getWrappingProcessor() {
return this.wrappingProcessor;
}
public Processor getRootProcessor() {
return this.wrappingProcessor.getRootProcessor();
}
/**
* Process the given <code>Environment</code> producing the output.
* @return If the processing is successfull <code>true</code> is returned.
* If not match is found in the sitemap <code>false</code>
* is returned.
* @throws org.apache.cocoon.ResourceNotFoundException If a sitemap
component tries
* to access a resource which can not
* be found, e.g. the generator
* ConnectionResetException If the connection was reset
*/
public boolean process(Environment environment) throws Exception {
InvokeContext context = new InvokeContext();
context.enableLogging(getLogger());
try {
return process(environment, context);
} finally {
context.dispose();
}
}
/**
* Process the given <code>Environment</code> to assemble
* a <code>ProcessingPipeline</code>.
* @since 2.1
*/
public InternalPipelineDescription buildPipeline(Environment environment)
throws Exception {
InvokeContext context = new InvokeContext( true );
context.enableLogging(getLogger());
context.setLastProcessor(this);
try {
if ( process(environment, context) ) {
return context.getInternalPipelineDescription(environment);
} else {
return null;
}
} finally {
context.dispose();
}
}
/**
* Do the actual processing, be it producing the response or just
building the pipeline
* @param environment
* @param context
* @return true if the pipeline was successfully built, false otherwise.
* @throws Exception
*/
protected boolean process(Environment environment, InvokeContext context)
throws Exception {
// Increment the concurrent requests count
synchronized(this) {
requestCount++;
}
try {
// and now process
EnvironmentHelper.enterProcessor(this, this.serviceManager,
environment);
final Redirector oldRedirector = context.getRedirector();
// Build a redirector
TreeProcessorRedirector redirector = new
TreeProcessorRedirector(environment, context);
setupLogger(redirector);
context.setRedirector(redirector);
try {
boolean success = this.rootNode.invoke(environment,
context);
return success;
} finally {
EnvironmentHelper.leaveProcessor();
// Restore old redirector
context.setRedirector(oldRedirector);
}
} finally {
// Decrement the concurrent request count
synchronized(this) {
requestCount--;
}
if(requestCount < 0) {
// Marked for disposal and no more concurrent
requests.
dispose();
}
}
}
private boolean handleCocoonRedirect(String uri, Environment environment,
InvokeContext context) throws Exception {
// Build an environment wrapper
// If the current env is a facade, change the delegate and continue
processing the facade, since
// we may have other redirects that will in turn also change the
facade delegate
MutableEnvironmentFacade facade = environment instanceof
MutableEnvironmentFacade ?
((MutableEnvironmentFacade)environment) : null;
if (facade != null) {
// Consider the facade delegate (the real environment)
environment = facade.getDelegate();
}
// test if this is a call from flow
boolean isRedirect =
(environment.getObjectModel().remove("cocoon:forward") == null);
Environment newEnv = new ForwardEnvironmentWrapper(environment, uri,
getLogger());
if ( isRedirect ) {
((ForwardEnvironmentWrapper)newEnv).setInternalRedirect(true);
}
if (facade != null) {
// Change the facade delegate
facade.setDelegate((EnvironmentWrapper)newEnv);
newEnv = facade;
}
// Get the processor that should process this request
ConcreteTreeProcessor processor;
if ( newEnv.getURIPrefix().equals("") ) {
processor = ((TreeProcessor)getRootProcessor()).concreteProcessor;
} else {
processor = this;
}
// Process the redirect
// No more reset since with TreeProcessorRedirector, we need to pop values
from the redirect location
// context.reset();
return processor.process(newEnv, context);
}
public void dispose() {
if (this.disposableNodes != null) {
// we must dispose the nodes in reverse order
// otherwise selector nodes are freed before the components node
for(int i=this.disposableNodes.size()-1; i>-1; i--) {
((Disposable)disposableNodes.get(i)).dispose();
}
this.disposableNodes = null;
}
// Ensure it won't be used anymore
this.rootNode = null;
}
private class TreeProcessorRedirector extends ForwardRedirector {
private InvokeContext context;
public TreeProcessorRedirector(Environment env, InvokeContext
context) {
super(env);
this.context = context;
}
protected void cocoonRedirect(String uri) throws IOException,
ProcessingException {
try {
ConcreteTreeProcessor.this.handleCocoonRedirect(uri,
this.env, this.context);
} catch(IOException ioe) {
throw ioe;
} catch(ProcessingException pe) {
throw pe;
} catch(RuntimeException re) {
throw re;
} catch(Exception ex) {
throw new ProcessingException(ex);
}
}
}
/**
* Local extension of EnvironmentWrapper to propagate otherwise blocked
* methods to the actual environment.
*/
private static final class ForwardEnvironmentWrapper extends
EnvironmentWrapper {
public ForwardEnvironmentWrapper(Environment env,
String uri, Logger logger) throws MalformedURLException {
super(env, uri, logger);
}
public void setStatus(int statusCode) {
environment.setStatus(statusCode);
}
public void setContentLength(int length) {
environment.setContentLength(length);
}
public void setContentType(String contentType) {
environment.setContentType(contentType);
}
public String getContentType() {
return environment.getContentType();
}
public boolean isResponseModified(long lastModified) {
return environment.isResponseModified(lastModified);
}
public void setResponseIsNotModified() {
environment.setResponseIsNotModified();
}
}
public SourceResolver getSourceResolver() {
return wrappingProcessor.getSourceResolver();
}
public String getContext() {
return wrappingProcessor.getContext();
}
}
1.4 +2 -2
cocoon-2.1/src/java/org/apache/cocoon/components/treeprocessor/sitemap/MountNodeBuilder.java
Index: MountNodeBuilder.java
===================================================================
RCS file:
/home/cvs/cocoon-2.1/src/java/org/apache/cocoon/components/treeprocessor/sitemap/MountNodeBuilder.java,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- MountNodeBuilder.java 25 May 2004 07:28:25 -0000 1.3
+++ MountNodeBuilder.java 5 Jun 2004 08:18:50 -0000 1.4
@@ -39,7 +39,7 @@
MountNode node = new MountNode(
VariableResolverFactory.getResolver(config.getAttribute("uri-prefix"), manager),
VariableResolverFactory.getResolver(config.getAttribute("src"),
manager),
- this.treeBuilder.getProcessor(),
+ this.treeBuilder.getProcessor().getWrappingProcessor(),
config.getAttributeAsBoolean("check-reload", true)
);
return (this.treeBuilder.setupNode(node, config));