cocoon-cvs mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jheym...@apache.org
Subject svn commit: r330548 [59/132] - in /cocoon/whiteboard/maven2/cocoon-flat-layout: ./ cocoon-ajax-block/ cocoon-ajax-block/api/ cocoon-ajax-block/api/src/ cocoon-ajax-block/api/src/main/ cocoon-ajax-block/api/src/main/java/ cocoon-ajax-block/api/src/main/...
Date Thu, 03 Nov 2005 14:00:48 GMT
Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/transformation/IncludeTransformer.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/transformation/IncludeTransformer.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/transformation/IncludeTransformer.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/transformation/IncludeTransformer.java Thu Nov  3 05:41:06 2005
@@ -0,0 +1,1118 @@
+/*
+ * Copyright 1999-2005 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.transformation;
+
+import org.apache.avalon.framework.CascadingRuntimeException;
+import org.apache.avalon.framework.configuration.Configurable;
+import org.apache.avalon.framework.configuration.Configuration;
+import org.apache.avalon.framework.configuration.ConfigurationException;
+import org.apache.avalon.framework.logger.Logger;
+import org.apache.avalon.framework.parameters.Parameters;
+import org.apache.avalon.framework.service.ServiceException;
+import org.apache.avalon.framework.service.ServiceManager;
+import org.apache.avalon.framework.service.Serviceable;
+
+import org.apache.cocoon.ProcessingException;
+import org.apache.cocoon.Processor;
+import org.apache.cocoon.caching.CacheableProcessingComponent;
+import org.apache.cocoon.components.source.SourceUtil;
+import org.apache.cocoon.components.source.impl.MultiSourceValidity;
+import org.apache.cocoon.components.thread.RunnableManager;
+import org.apache.cocoon.environment.Environment;
+import org.apache.cocoon.environment.SourceResolver;
+import org.apache.cocoon.environment.internal.EnvironmentHelper;
+import org.apache.cocoon.transformation.helpers.NOPRecorder;
+import org.apache.cocoon.util.NetUtils;
+import org.apache.cocoon.xml.AbstractXMLPipe;
+import org.apache.cocoon.xml.IncludeXMLConsumer;
+import org.apache.cocoon.xml.NamespacesTable;
+import org.apache.cocoon.xml.SaxBuffer;
+import org.apache.cocoon.xml.XMLConsumer;
+
+import org.apache.excalibur.source.Source;
+import org.apache.excalibur.source.SourceValidity;
+import org.xml.sax.Attributes;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.Locator;
+import org.xml.sax.SAXException;
+import org.xml.sax.ext.LexicalHandler;
+
+import java.io.IOException;
+import java.io.Serializable;
+import java.io.UnsupportedEncodingException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Stack;
+
+/**
+ * <p>A simple transformer including resolvable sources (accessed through
+ * Cocoon's {@link SourceResolver}) from its input.</p>
+ *
+ * <p>Inclusion is triggered by the <code>&lt;include ... /&gt;</code> element
+ * defined in the <code>http://apache.org/cocoon/include/1.0</code> namespace.</p>
+ *
+ * <p>Example:</p>
+ * <pre>
+ * &lt;i:include xmlns:i="http://apache.org/cocoon/include/1.0"
+ *               src="cocoon://path/to/include"/&gt;
+ * </pre>
+ *
+ * <p>An interesting feature of this {@link Transformer} is that it implements the
+ * {@link CacheableProcessingComponent} interface and provides full support for
+ * caching. In other words, if the input given to this transformer has not changed,
+ * and all of the included sources are (cacheable) and still valid, this transformer
+ * will not force a pipeline re-generation like the {@link CIncludeTransformer}.</p>
+ *
+ *
+ * <h3>Relative Source Resolution</h3>
+ * <p>Include sources which are specified using relative URI will be resolved
+ * relative to the source document location. This is consistent with
+ * {@link XIncludeTransformer} behavior, but differs from {@link CIncludeTransformer}.
+ *
+ *
+ * <h3>Parameters Passing</h3>
+ * <p>Parameters to be passed to the included sources can be specified in two ways:
+ * the first one is to encode them onto the source itelf, for example:</p>
+ *
+ * <pre>
+ * &lt;i:include xmlns:i="http://apache.org/cocoon/include/1.0"
+ *               src="cocoon://path/to/include?paramA=valueA&amp;paramB=valueB"/&gt;
+ * </pre>
+ *
+ * <p>Another approach allows the encoding of parameters to be done automatically by
+ * the transformer, so that one can easily pass parameter name or values containing
+ * the <code>&amp;</code> (amperstand) or <code>=</code> (equals) character, which are
+ * reserved characters in URIs. An example:</p>
+ *
+ * <pre>
+ * &lt;i:include xmlns:i="http://apache.org/cocoon/include/1.0"
+ *               src="cocoon://path/to/include"&gt;
+ *   &lt;i:parameter name="firstParameterName" value="firstParameterValue"/&gt;
+ *   &lt;i:parameter name="other&amp;Para=Name" value="other=Para&amp;Value"/&gt;
+ * &lt;/i:include&gt;
+ * </pre>
+ *
+ *
+ * <h3>Fallback Element</h3>
+ * <p>IncludeTransformer allows fallback element to be specified within
+ * include element. XML content of the fallback element will be included instead
+ * of source content if source inclusion caused an exception. Fallback element
+ * can have nested include elements. An example:</p>
+ *
+ * <pre>
+ * &lt;i:include xmlns:i="http://apache.org/cocoon/include/1.0"
+ *               src="cocoon://path/to/include"&gt;
+ *   &lt;i:fallback&gt;
+ *     <strong>The data is temporarily unavailable.</strong>
+ *     We are sorry for the trouble; please try again later.
+ *   &lt;/i:fallback&gt;
+ * &lt;/i:include&gt;
+ * </pre>
+ *
+ *
+ * <h3>Parallel Processing</h3>
+ * <p>Another feature of this {@link Transformer} is that it allows parallel processing
+ * of includes. By setting the optional parameter <code>parallel</code> to true,
+ * the various included contents are processed (included) in parallel threads rather
+ * than in series, in one thread. This parameter can be set in either the transformer
+ * definition (to affect all IncludeTransformer instances):</p>
+ * <pre>
+ *   &lt;parallel&gt;true&lt;/parallel&gt;
+ * </pre>
+ *
+ * <p>or in a pipeline itself (to only affect that instance of the IncludeTransformer):</p>
+ * <pre>
+ *   &lt;map:parameter name="parallel" value="true"/&gt;
+ * </pre>
+ * <p>By default, parallel processing is turned off.</p>
+ *
+ *
+ * <h3>Recursive Processing</h3>
+ * <p>This {@link Transformer} allows recursive processing of includes.
+ * By setting the optional parameter <code>recursive</code> to true,
+ * the various included contents are scanned for include elements, and processed
+ * in the same manner as incoming XML events. This parameter can be set in either
+ * the transformer definition (to affect all IncludeTransformer instances):</p>
+ * <pre>
+ *   &lt;recursive&gt;true&lt;/recursive&gt;
+ * </pre>
+ *
+ * <p>or in a pipeline itself (to only affect that instance of the IncludeTransformer):</p>
+ * <pre>
+ *   &lt;map:parameter name="recursive" value="true"/&gt;
+ * </pre>
+ * <p>This feature is similar to the XInclude processing. By default,
+ * recursive processing is turned off.</p>
+ *
+ *
+ * @cocoon.sitemap.component.documentation
+ * A simple transformer including resolvable sources (accessed through
+ * Cocoon's SourceResolver) from its input.
+ *
+ * @cocoon.sitemap.component.name include
+ * @cocoon.sitemap.component.logger sitemap.transformer.include
+ * @cocoon.sitemap.component.pooling.max 16
+ * @version $Id: IncludeTransformer.java 170053 2005-05-13 16:15:02Z vgritsenko $
+ */
+public class IncludeTransformer extends AbstractTransformer
+                                implements Serviceable, Configurable,
+                                           Transformer, CacheableProcessingComponent {
+
+    /** <p>The namespace URI of the elements recognized by this transformer.</p> */
+    private static final String NS_URI = "http://apache.org/cocoon/include/1.0";
+
+    /** <p>The name of the element triggering inclusion of sources.</p> */
+    private static final String INCLUDE_ELEMENT = "include";
+
+    /** <p>The name of the element defining a fallback content.</p> */
+    private static final String FALLBACK_ELEMENT = "fallback";
+
+    /** <p>The name of the element defining an included subrequest parameter.</p> */
+    private static final String PARAMETER_ELEMENT = "parameter";
+
+    /** <p>The name of the attribute indicating the included source URI.</p> */
+    private static final String SRC_ATTRIBUTE = "src";
+
+    /** <p>The name of the mime type attribute containing the hint for the {@link org.apache.excalibur.xmlizer.XMLizer}.</p> */
+    private static final String MIME_ATTRIBUTE = "mime-type";
+
+    /** <p>The name of the parse attribute indicating type of included source processing: xml or text.</p> */
+    private static final String PARSE_ATTRIBUTE = "parse";
+
+    /** <p>The name of the attribute indicating the parameter name.</p> */
+    private static final String NAME_ATTRIBUTE = "name";
+
+    /** <p>The name of the attribute indicating the parameter name.</p> */
+    private static final String VALUE_ATTRIBUTE = "value";
+
+    /** <p>The encoding to use for parameter names and values.</p> */
+    private static final String ENCODING = "US-ASCII";
+
+    //
+    // Global configuration
+    //
+
+    /** The {@link ServiceManager} instance associated with this instance. */
+    private ServiceManager manager;
+
+    /** Configuration option controlling recursive includes processing */
+    private boolean defaultRecursive;
+
+    /** Configuration option controlling parallel (in multiple threads) includes processing */
+    private boolean defaultParallel;
+
+    /** Configuration option controlling parallel (in multiple threads) includes processing in the recursive includes */
+    private boolean defaultRecursiveParallel;
+
+    /** The name of the thread pool to use (for parallel processing). */
+    private String threadPool;
+
+    /** The default value to be appended to the caching key. */
+    private String defaultKey;
+
+    //
+    // Current configuration
+    //
+
+    /** The {@link SourceResolver} used to resolve included URIs. */
+    private SourceResolver resolver;
+
+    /** The {@link Environment} used within parallel threads */
+    private Environment environment;
+
+    /** The {@link Processor} used within parallel threads */
+    private Processor processor;
+
+    /** The value to be appended to the caching key. */
+    private String key;
+
+    //
+    // Current state
+    //
+
+    /** The {@link SourceValidity} instance associated with this request. */
+    private MultiSourceValidity validity;
+
+    /** A {@link NamespacesTable} used to filter namespace declarations. */
+    private NamespacesTable namespaces;
+
+    /** The {@link IncludeXMLPipe} which is doing all the work */
+    private final IncludeXMLPipe pipe;
+
+    /**
+     * <p>Create a new {@link IncludeTransformer} instance.</p>
+     */
+    public IncludeTransformer() {
+        pipe = new IncludeXMLPipe();
+    }
+
+    /**
+     * <p>Initialize own and {@link #pipe} loggers</p>
+     */
+    public void enableLogging(Logger logger) {
+        super.enableLogging(logger);
+        pipe.enableLogging(logger);
+    }
+
+    /**
+     * <p>Setup the {@link ServiceManager} available for this instance.</p>
+     *
+     * @see Serviceable#service(ServiceManager)
+     */
+    public void service(ServiceManager manager) throws ServiceException {
+        this.manager = manager;
+    }
+
+    /* (non-Javadoc)
+     * @see Configurable#configure(Configuration)
+     */
+    public void configure(Configuration configuration) throws ConfigurationException {
+        /* Read configuration nodes for recursive, parallel, recursive-parallel */
+        this.defaultRecursive = configuration.getChild("recursive").getValueAsBoolean(false);
+        this.defaultParallel = configuration.getChild("parallel").getValueAsBoolean(false);
+        this.defaultRecursiveParallel = configuration.getChild("recursive-parallel").getValueAsBoolean(false);
+        /* Read configuration node for thread pool name */
+        this.threadPool = configuration.getChild("thread-pool").getValue("default");
+        this.defaultKey = configuration.getChild("key").getValue(null);
+    }
+
+    /**
+     * <p>Setup this component instance in the context of its pipeline and
+     * current request.</p>
+     *
+     * @see Serviceable#service(ServiceManager)
+     */
+    public void setup(SourceResolver resolver, Map om, String src, Parameters parameters)
+    throws ProcessingException, SAXException, IOException {
+        /* Read sitemap parameters */
+        this.pipe.recursive = parameters.getParameterAsBoolean("recursive", this.defaultRecursive);
+        this.pipe.parallel = parameters.getParameterAsBoolean("parallel", this.defaultParallel);
+        this.pipe.recursiveParallel = parameters.getParameterAsBoolean("recursive-parallel", this.defaultRecursiveParallel);
+        this.key = parameters.getParameter("key", this.defaultKey);
+
+        /* Init transformer state */
+        if (this.pipe.parallel) {
+            this.environment = EnvironmentHelper.getCurrentEnvironment();
+            this.processor = EnvironmentHelper.getCurrentProcessor();
+        }
+        this.namespaces = new NamespacesTable();
+        this.resolver = resolver;
+        this.validity = null;
+
+        // Set root include pipe as consumer.
+        // Won't use setter methods here - they are overridden
+        super.xmlConsumer = pipe;
+        super.contentHandler = pipe;
+        super.lexicalHandler = pipe;
+    }
+
+    public void setConsumer(XMLConsumer consumer) {
+        pipe.setConsumer(consumer);
+    }
+
+    public void setContentHandler(ContentHandler handler) {
+        pipe.setContentHandler(handler);
+    }
+
+    public void setLexicalHandler(LexicalHandler handler) {
+        pipe.setLexicalHandler(handler);
+    }
+
+    /**
+     * <p>Recycle this component instance.</p>
+     *
+     * @see org.apache.avalon.excalibur.pool.Recyclable#recycle()
+     */
+    public void recycle() {
+        this.namespaces = null;
+        this.validity = null;
+
+        /* Make sure all threads completed their work */
+        this.pipe.recycle();
+
+        // Resolver can be nulled out when all threads completed processing
+        // and released their Sources.
+        this.resolver = null;
+
+        super.recycle();
+    }
+
+
+    /**
+     * <p>Receive notification of the beginning of an XML document.</p>
+     *
+     * @see ContentHandler#startDocument
+     */
+    public void startDocument()
+    throws SAXException {
+        /* Make sure that we have a validity while processing */
+        getValidity();
+
+        super.startDocument();
+    }
+
+    /**
+     * <p>Receive notification of the end of an XML document.</p>
+     *
+     * @see ContentHandler#startDocument()
+     */
+    public void endDocument()
+    throws SAXException {
+        /* Make sure that the validity is "closed" at the end */
+        this.validity.close();
+
+        super.endDocument();
+    }
+
+    /**
+     * <p>Receive notification of the start of a prefix mapping.</p>
+     *
+     * <p>This transformer will remove all prefix mapping declarations for those
+     * prefixes associated with the <code>http://apache.org/cocoon/include/1.0</code>
+     * namespace.</p>
+     *
+     * @see org.xml.sax.ContentHandler#startPrefixMapping(String, String)
+     */
+    public void startPrefixMapping(String prefix, String nsuri)
+    throws SAXException {
+        if (NS_URI.equals(nsuri)) {
+            /* Skipping mapping for the current prefix as it's ours */
+            this.namespaces.addDeclaration(prefix, nsuri);
+        } else {
+            /* Map the current prefix, as we don't know it */
+            super.startPrefixMapping(prefix, nsuri);
+        }
+    }
+
+    /**
+     * <p>Receive notification of the end of a prefix mapping.</p>
+     *
+     * <p>This transformer will remove all prefix mapping declarations for those
+     * prefixes associated with the <code>http://apache.org/cocoon/include/1.0</code>
+     * namespace.</p>
+     *
+     * @see org.xml.sax.ContentHandler#endPrefixMapping(java.lang.String)
+     */
+    public void endPrefixMapping(String prefix)
+    throws SAXException {
+        if (NS_URI.equals(this.namespaces.getUri(prefix))) {
+            /* Skipping unmapping for the current prefix as it's ours */
+            this.namespaces.removeDeclaration(prefix);
+        } else {
+            /* Unmap the current prefix, as we don't know it */
+            super.endPrefixMapping(prefix);
+        }
+    }
+
+    /**
+     * <p>Return the caching key associated with this transformation.</p>
+     *
+     * <p>When including <code>cocoon://</code> sources with dynamic
+     * content depending on environment (request parameters, session attributes,
+     * etc), it makes sense to provide such environment values to the transformer
+     * to be included into the key using <code>key</code> sitemap parameter.</p>
+     *
+     * @see CacheableProcessingComponent#getKey()
+     */
+    public Serializable getKey() {
+        /*
+         * In case of including "cocoon://" or other dynamic sources key
+         * ideally has to include ProcessingPipelineKey of the included
+         * "cocoon://" sources, but it's not possible as at this time
+         * we don't know yet which sources will get included into the
+         * response.
+         *
+         * Hence, javadoc recommends providing key using sitemap parameter.
+         */
+        return key == null? "I": "I" + key;
+    }
+
+    /**
+     * <p>Generate (or return) the {@link SourceValidity} instance used to
+     * possibly validate cached generations.</p>
+     *
+     * @return a <b>non null</b> {@link SourceValidity}.
+     * @see org.apache.cocoon.caching.CacheableProcessingComponent#getValidity()
+     */
+    public SourceValidity getValidity() {
+        if (validity == null) {
+            validity = new MultiSourceValidity(resolver, -1);
+        }
+        return validity;
+    }
+
+    /**
+     * Description of the include element
+     */
+    private class IncludeElement {
+        /** Parameter controlling recursive includes processing */
+        private boolean recursive;
+
+        /** Parameter controlling parallel (in multiple threads) includes processing */
+        private boolean parallel;
+
+        /** Parameter controlling parallel (in multiple threads) includes processing in recursive includes */
+        private boolean recursiveParallel;
+
+        /** The source base URI. */
+        private String base;
+
+        /** The source URI to be included declared in an src attribute of the include element. */
+        private String source;
+
+        /** The flag indicating whether source content has to be parsed into XML or included as text. */
+        private boolean parse;
+
+        /** The mime type hint to the {@link org.apache.excalibur.xmlizer.XMLizer} when parsing the source content. */
+        private String mimeType;
+
+        /** The buffer collecting fallback content. */
+        private SaxBuffer fallback;
+
+        /** A {@link Map} of the parameters to supply to the included source. */
+        private Map parameters;
+
+        /** The current parameter name captured. */
+        private String parameter;
+
+        /** The current parameter value (as a {@link StringBuffer}). */
+        private StringBuffer value;
+
+        /** Create include element */
+        private IncludeElement(String base, boolean parallel, boolean recursive, boolean recursiveParallel) {
+            this.base = base;
+            this.parallel = parallel;
+            this.recursive = recursive;
+            this.recursiveParallel = recursiveParallel;
+        }
+
+        /**
+         * Process element into the buffer.
+         * This can not be shared buffer, as it must be cleaned if fallback is invoked.
+         */
+        public void process(SaxBuffer buffer)
+        throws SAXException {
+            try {
+                process0(buffer, buffer);
+            } catch (SAXException e) {
+                buffer.recycle();
+                if (this.fallback == null) {
+                    throw e;
+                }
+
+                if (getLogger().isInfoEnabled()) {
+                    getLogger().info("Failed to load <" + this.source + ">, using fallback.", e);
+                }
+                // Stream fallback through IncludeXMLPipe
+                this.fallback.toSAX(new IncludeXMLPipe(getLogger(), buffer, buffer,
+                                                       recursive, recursiveParallel? parallel: false, recursiveParallel));
+            }
+        }
+
+        /** Load URI into the provided handlers, process fallback */
+        public void process(ContentHandler contentHandler, LexicalHandler lexicalHandler)
+        throws SAXException {
+            if (this.fallback != null) {
+                SaxBuffer buffer = new SaxBuffer();
+                process(buffer);
+                buffer.toSAX(contentHandler);
+            } else {
+                process0(contentHandler, lexicalHandler);
+            }
+        }
+
+        /** Load URI into the provided handlers. */
+        private void process0(ContentHandler contentHandler, LexicalHandler lexicalHandler)
+        throws SAXException {
+            Source source = null;
+            if (getLogger().isDebugEnabled()) {
+                getLogger().debug("Loading <" + this.source + ">");
+            }
+
+            // Setup this thread's environment
+            try {
+                if (base != null) {
+                    source = resolver.resolveURI(this.source, base, null);
+                } else {
+                    source = resolver.resolveURI(this.source);
+                }
+                if (validity != null) {
+                    synchronized (validity) {
+                        validity.addSource(source);
+                    }
+                }
+
+                // Include source
+                if (this.parse && recursive) {
+                    SourceUtil.toSAX(manager, source, this.mimeType,
+                                     new IncludeXMLPipe(getLogger(), contentHandler, lexicalHandler,
+                                                        recursive, recursiveParallel? parallel: false, recursiveParallel));
+                } else if (this.parse) {
+                    SourceUtil.toSAX(manager, source, this.mimeType,
+                                     new IncludeXMLConsumer(contentHandler, lexicalHandler));
+                } else {
+                    SourceUtil.toCharacters(source, "utf-8",
+                                            contentHandler);
+                }
+
+                if (getLogger().isDebugEnabled()) {
+                    getLogger().debug("Loaded <" + this.source + ">");
+                }
+            } catch (SAXException e) {
+                if (getLogger().isDebugEnabled()) {
+                    getLogger().debug("Failed to load <" + this.source + ">", e);
+                }
+
+                throw e;
+
+            } catch (ProcessingException e) {
+                if (getLogger().isDebugEnabled()) {
+                    getLogger().debug("Failed to load <" + this.source + ">", e);
+                }
+
+                throw new SAXException(e);
+
+            } catch (IOException e) {
+                if (getLogger().isDebugEnabled()) {
+                    getLogger().debug("Failed to load <" + this.source + ">", e);
+                }
+
+                throw new SAXException(e);
+
+            } finally {
+                if (source != null) {
+                    resolver.release(source);
+                }
+            }
+        }
+    }
+
+    /**
+     * XML pipe reacting on the elements in the include namespace.
+     */
+    private class IncludeXMLPipe extends AbstractXMLPipe {
+
+        //
+        // Configuration
+        //
+
+        /** Indicates whether this is root include pipe (owned by transformer) or a nested one */
+        private final boolean root;
+
+        /** Parameter controlling recursive includes processing */
+        private boolean recursive;
+
+        /** Parameter controlling parallel (in multiple threads) includes processing */
+        private boolean parallel;
+
+        /** Parameter controlling parallel (in multiple threads) includes processing in recursive includes */
+        private boolean recursiveParallel;
+
+        //
+        // Current state
+        //
+
+        /** Stack of {@link XMLConsumer}s */
+        private final Stack consumers = new Stack();
+
+        /** Current depth of nested elements in the include namespace */
+        private int depth;
+
+        /** Base URI used for the resolving included sources */
+        private String base;
+
+        /** The source to be included declared in an include element. */
+        private IncludeElement element;
+
+        /** If parallel processing is enabled, then this boolean tells us whether buffering has started yet. */
+        private boolean buffering;
+
+        /**
+         * <p>The IncludeBuffer that is used to buffering events if parallel
+         * processing is turned on.</p>
+         * <p>This object is also used as a lock for the thread counter <code>threads</code>.</p>
+         */
+        private SaxBuffer buffer;
+
+        /** Inclusion threads/tasks counter (if executing in parallel) */
+        private int threads;
+
+        /**
+         * <p>Create a new {@link IncludeXMLPipe} instance.</p>
+         */
+        public IncludeXMLPipe() {
+            root = true;
+        }
+
+        /**
+         * <p>Create a new {@link IncludeXMLPipe} instance.</p>
+         */
+        public IncludeXMLPipe(Logger logger, ContentHandler contentHandler, LexicalHandler lexicalHandler,
+                              boolean recursive, boolean parallel, boolean recursiveParallel) {
+            root = false;
+            enableLogging(logger);
+            setContentHandler(contentHandler);
+            setLexicalHandler(lexicalHandler);
+            this.recursive = recursive;
+            this.parallel = parallel;
+            this.recursiveParallel = recursiveParallel;
+        }
+
+        /**
+         * Finish processing.
+         */
+        public void recycle() {
+            if (this.buffering) {
+                // Wait for threads to complete and release Sources
+                waitForThreads();
+                this.buffering = false;
+                this.buffer = null;
+            }
+            this.threads = 0;
+
+            this.consumers.clear();
+            this.base = null;
+            this.element = null;
+
+            super.recycle();
+        }
+
+        /** Push current consumer into the stack, replace with new one */
+        private void push(XMLConsumer consumer) {
+            this.consumers.push(new Object[]{ super.xmlConsumer, super.contentHandler, super.lexicalHandler });
+            setConsumer(consumer);
+        }
+
+        /** Pop consumer from the stack, replace current one */
+        private void pop() {
+            Object[] consumer = (Object[]) this.consumers.pop();
+            if (consumer[0] != null) {
+                setConsumer((XMLConsumer) consumer[0]);
+            } else {
+                setContentHandler((ContentHandler) consumer[1]);
+                setLexicalHandler((LexicalHandler) consumer[2]);
+            }
+        }
+
+        //
+        // ContentHandler interface
+        //
+
+        public void setDocumentLocator(Locator locator) {
+            try {
+                if (locator != null && locator.getSystemId() != null) {
+                    Source source = resolver.resolveURI(locator.getSystemId());
+                    try {
+                        base = source.getURI();
+                    } finally {
+                        resolver.release(source);
+                    }
+                }
+            } catch (IOException e) {
+                getLogger().warn("Unable to resolve document base URI: <" + locator.getSystemId() + ">");
+            }
+
+            super.setDocumentLocator(locator);
+        }
+
+        /**
+         * <p>Receive notification of the beginning of an XML document.</p>
+         * @see ContentHandler#startDocument
+         */
+        public void startDocument() throws SAXException {
+            if (root) {
+                super.startDocument();
+            }
+        }
+
+        /**
+         * <p>Receive notification of the end of an XML document.</p>
+         * @see ContentHandler#startDocument
+         */
+        public void endDocument() throws SAXException {
+            /* This is the end of the line - process the buffered events */
+            if (this.buffering) {
+                pop();
+                this.buffer.toSAX(super.contentHandler);
+            }
+
+            if (root) {
+                super.endDocument();
+            }
+        }
+
+        /**
+         * <p>Receive notification of the start of an element.</p>
+         * @see ContentHandler#startElement
+         */
+        public void startElement(String uri, String localName, String qName, Attributes atts)
+        throws SAXException {
+
+            /* Check the namespace declaration */
+            if (NS_URI.equals(uri)) {
+
+                /*
+                 * Depth 0: Outside of any include tag
+                 * Depth 1: Must be Inside <include> tag
+                 * Depth 2: Inside <fallback> tag
+                 */
+                depth++;
+
+                /* Inclusion will not happen here but when we close this tag */
+                if (INCLUDE_ELEMENT.equals(localName) && depth == 1) {
+                    /* Check before we include (we don't want nested stuff) */
+                    if (element != null) {
+                        throw new SAXException("Element " + INCLUDE_ELEMENT + " nested in another one.");
+                    }
+                    element = new IncludeElement(this.base, this.parallel, this.recursive, this.recursiveParallel);
+
+                    /* Remember the source we are trying to include */
+                    element.source = atts.getValue(SRC_ATTRIBUTE);
+                    if (element.source == null || element.source.length() == 0) {
+                        throw new SAXException("Attribute '" + SRC_ATTRIBUTE + "' empty or missing.");
+                    }
+
+                    /* Defaults to 'xml' */
+                    String value = atts.getValue(PARSE_ATTRIBUTE);
+                    if (value == null || value.equals("xml")) {
+                        element.parse = true;
+                    } else if (value.equals("text")) {
+                        element.parse = false;
+                    } else {
+                        throw new SAXException("Attribute '" + PARSE_ATTRIBUTE + "' has invalid value.");
+                    }
+
+                    /* Defaults to 'text/xml' */
+                    element.mimeType = atts.getValue(MIME_ATTRIBUTE);
+                    if (!element.parse && element.mimeType != null) {
+                        throw new SAXException("Attribute '" + MIME_ATTRIBUTE + "' can't be specified for text inclusions.");
+                    } else if (element.mimeType == null) {
+                        element.mimeType = "text/xml";
+                    }
+
+                    /* Ignore nested content */
+                    push(new NOPRecorder(){});
+
+                    /* Done with this element */
+                    return;
+                }
+
+                /* If this is a fallback parameter, capture its content. */
+                if (FALLBACK_ELEMENT.equals(localName) && depth == 2) {
+                    /* Check if we are in the right context */
+                    if (element == null) {
+                        throw new SAXException("Element " + FALLBACK_ELEMENT + " specified outside of " + INCLUDE_ELEMENT + ".");
+                    }
+                    if (element.fallback != null) {
+                        throw new SAXException("Duplicate element " + FALLBACK_ELEMENT + ".");
+                    }
+
+                    /* Buffer fallback content */
+                    push(element.fallback = new SaxBuffer());
+
+                    /* Done with this element */
+                    return;
+                }
+
+                /* If this is a parameter, then make sure we prepare. */
+                if (PARAMETER_ELEMENT.equals(localName) && depth == 2) {
+                    /* Check if we are in the right context */
+                    if (element == null) {
+                        throw new SAXException("Element " + PARAMETER_ELEMENT + " specified outside of " + INCLUDE_ELEMENT + ".");
+                    }
+                    if (element.parameter != null) {
+                        throw new SAXException("Element " + PARAMETER_ELEMENT + " nested in another one.");
+                    }
+
+                    /* Get and process the parameter name */
+                    element.parameter = atts.getValue(NAME_ATTRIBUTE);
+                    if (element.parameter == null || element.parameter.length() == 0) {
+                        throw new SAXException("Attribute '" + NAME_ATTRIBUTE + "' empty or missing.");
+                    }
+
+                    /* Make some room for the parameter value */
+                    String value = atts.getValue(VALUE_ATTRIBUTE);
+                    if (value != null) {
+                        element.value = new StringBuffer(value);
+                    }
+
+                    /* Done with this element */
+                    return;
+                }
+
+                /* We don't have a clue of why we got here (wrong element?) */
+                if (depth < 2) {
+                    throw new SAXException("Element '" + localName + "' was not expected here.");
+                }
+            }
+
+            super.startElement(uri, localName, qName, atts);
+        }
+
+        /**
+         * <p>Receive notification of the end of an element.</p>
+         * @see ContentHandler#endElement
+         */
+        public void endElement(String uri, String localName, String qName)
+        throws SAXException {
+            /* Check the namespace declaration */
+            if (NS_URI.equals(uri)) {
+
+                /*
+                 * Depth 0: Outside of any include tag
+                 * Depth 1: Inside <include> tag
+                 * Depth 2: Inside <fallback> tag
+                 */
+                depth--;
+
+                /* Inclusion will happen here, when we close the include element */
+                if (INCLUDE_ELEMENT.equals(localName) && depth == 0) {
+                    /* End ignoring nested content */
+                    pop();
+
+                    /* Get the source discovered opening the element and include */
+                    if (element.parameters != null) {
+                        element.source = NetUtils.parameterize(element.source,
+                                                               element.parameters);
+                        element.parameters = null;
+                    }
+
+                    /* Check for parallel processing */
+                    if (this.parallel) {
+                        if (!this.buffering) {
+                            this.buffering = true;
+                            buffer = new SaxBuffer();
+                            push(buffer);
+                        }
+
+                        /* Process include element in separate thread */
+                        buffer.xmlizable(new IncludeBuffer(element));
+
+                    } else {
+                        /* Process include element inline */
+                        element.process(super.contentHandler, super.lexicalHandler);
+                    }
+
+                    /* We are done with this include element */
+                    this.element = null;
+                    return;
+                }
+
+                if (FALLBACK_ELEMENT.equals(localName) && depth == 1) {
+                    /* End buffering fallback content */
+                    pop();
+
+                    /* Done with this element */
+                    return;
+                }
+
+                /* Addition of parameters happens here (so that we can capture chars) */
+                if (PARAMETER_ELEMENT.equals(localName) && depth == 1) {
+                    String value = (element.value != null? element.value.toString(): "");
+
+                    /* Store the parameter name and value */
+                    try {
+                        /*
+                         * Note: the parameter name and value are URL encoded, so that
+                         * weird characters such as "&" or "=" (have special meaning)
+                         * are passed through flawlessly.
+                         */
+                        if (element.parameters == null) {
+                            element.parameters = new HashMap(5);
+                        }
+                        element.parameters.put(NetUtils.encode(element.parameter, ENCODING),
+                                               NetUtils.encode(value, ENCODING));
+                    } catch (UnsupportedEncodingException e) {
+                        throw new SAXException("Your platform does not support the " +
+                                               ENCODING + " encoding", e);
+                    }
+
+                    /* We are done with this parameter element */
+                    element.value = null;
+                    element.parameter = null;
+                    return;
+                }
+            }
+
+            /* This is not our namespace, pass the event on! */
+            super.endElement(uri, localName, qName);
+        }
+
+        /**
+         * <p>Receive notification of characters.</p>
+         * @see ContentHandler#characters
+         */
+        public void characters(char[] data, int offset, int length)
+        throws SAXException {
+            if (element != null && element.parameter != null) {
+                /* If we have a parameter value to add to, let's add this chunk */
+                if (element.value == null) {
+                    element.value = new StringBuffer();
+                }
+                element.value.append(data, offset, length);
+                return;
+            }
+
+            /* Forward */
+            super.characters(data, offset, length);
+        }
+
+        //
+        // Thread management
+        //
+
+        /**
+         * Increment active threads counter
+         */
+        int incrementThreads() {
+            synchronized (buffer) {
+                return ++threads;
+            }
+        }
+
+        /**
+         * Decrement active threads counter
+         */
+        void decrementThreads() {
+            synchronized (buffer) {
+                if (--threads <= 0) {
+                    buffer.notify();
+                }
+            }
+        }
+
+        /**
+         * Wait till there is no active threads
+         */
+        private void waitForThreads() {
+            synchronized (buffer) {
+                if (threads > 0) {
+                    if (getLogger().isDebugEnabled()) {
+                        getLogger().debug(threads + " threads in progress, waiting");
+                    }
+
+                    try {
+                        buffer.wait();
+                    } catch (InterruptedException ignored) { }
+                    // Don't continue waiting if interrupted.
+                }
+            }
+        }
+
+        /**
+         * Buffer for loading included source in separate thread.
+         * Streaming of the loaded buffer possible only when source is
+         * loaded completely. If loading is not complete, toSAX method
+         * will block.
+         */
+        private class IncludeBuffer extends SaxBuffer
+                                    implements Runnable {
+
+            private IncludeElement element;
+            private int thread;
+            private boolean finished;
+            private SAXException e;
+
+
+            public IncludeBuffer(IncludeElement element) {
+                this.element = element;
+
+                RunnableManager runnable = null;
+                try {
+                    runnable = (RunnableManager) IncludeTransformer.this.manager.lookup(RunnableManager.ROLE);
+                    runnable.execute(IncludeTransformer.this.threadPool, this);
+                } catch (final ServiceException e) {
+                    // In case we failed to spawn a thread
+                    throw new CascadingRuntimeException(e.getMessage(), e);
+                } finally {
+                    IncludeTransformer.this.manager.release(runnable);
+                }
+
+                // Increment active threads counter
+                this.thread = incrementThreads();
+            }
+
+            /**
+             * Load content of the source into this buffer.
+             */
+            public void run() {
+                try {
+                    Source source = null;
+                    if (getLogger().isDebugEnabled()) {
+                        getLogger().debug("Thread #" + thread + " loading <" + element.source + ">");
+                    }
+
+                    // Setup this thread's environment
+                    EnvironmentHelper.enterProcessor(processor, manager, environment);
+                    try {
+                        element.process(this);
+
+                    } catch (SAXException e) {
+                        this.e = e;
+
+                    } finally {
+                        if (source != null) {
+                            resolver.release(source);
+                        }
+                        EnvironmentHelper.leaveProcessor();
+                    }
+                } catch (ProcessingException e) {
+                    /* Unable to set thread's environment */
+                    this.e = new SAXException(e);
+
+                } finally {
+                    synchronized (this) {
+                        this.finished = true;
+                        notify();
+                    }
+
+                    // Make sure that active threads counter is decremented
+                    decrementThreads();
+                }
+
+                if (getLogger().isDebugEnabled()) {
+                    if (this.e == null) {
+                        getLogger().debug("Thread #" + thread + " loaded <" + element.source + ">");
+                    } else {
+                        getLogger().debug("Thread #" + thread + " failed to load <" + element.source + ">", this.e);
+                    }
+                }
+            }
+
+            /**
+             * Stream content of this buffer when it is loaded completely.
+             * This method blocks if loading is not complete.
+             */
+            public void toSAX(ContentHandler contentHandler)
+            throws SAXException {
+                synchronized (this) {
+                    if (!this.finished) {
+                        try {
+                            wait();
+                        } catch (InterruptedException ignored) { }
+                        // Don't continue waiting if interrupted.
+                    }
+                }
+
+                if (this.e != null) {
+                    throw this.e;
+                }
+
+                super.toSAX(contentHandler);
+            }
+        }
+    }
+}

Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/transformation/IncludeTransformer.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/transformation/JPathTransformer.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/transformation/JPathTransformer.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/transformation/JPathTransformer.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/transformation/JPathTransformer.java Thu Nov  3 05:41:06 2005
@@ -0,0 +1,375 @@
+/*
+ * Copyright 1999-2005 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.transformation;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.avalon.framework.activity.Initializable;
+import org.apache.avalon.framework.parameters.Parameters;
+import org.apache.cocoon.ProcessingException;
+import org.apache.cocoon.components.flow.FlowHelper;
+import org.apache.cocoon.components.flow.WebContinuation;
+import org.apache.cocoon.environment.SourceResolver;
+import org.apache.commons.jxpath.JXPathContext;
+import org.apache.regexp.RE;
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.AttributesImpl;
+
+/**
+ * @cocoon.sitemap.component.documentation
+ *  Transformer implementation of the JPath XSP tag library.
+ *
+ * @cocoon.sitemap.component.name   jpath
+ * @cocoon.sitemap.component.logger sitemap.transformer.jpath
+ *
+ *
+ * <p>
+ *  This transformer (so far) supports the following jpath elements:
+ *
+ *   <ul>
+ *     <li>&lt;jpath:value-of select=".."/&gt; element.
+ *     <li>&lt;jpath:continuation/&gt; element.
+ *     <li>&lt;jpath:if test=".."&gt;..&lt;/jpath:if&gt; element.
+ *     <li>jpath:action attribute on all elements that implicitly replaces any
+ *         occurance of the string 'id' with the continuation id (useful when
+ *         writing form action attributes). eg:
+ *         <pre>&lt;form name="myform" jpath:action="../cont/id"&gt;..&lt;/form&gt;</pre>
+ *   </ul>
+ * </p>
+ *
+ * @author <a href="mailto:crafterm@apache.org">Marcus Crafter</a>
+ * @version $Id: JPathTransformer.java 168368 2005-05-05 18:28:46Z vgritsenko $
+ */
+public class JPathTransformer extends AbstractSAXTransformer
+                              implements Initializable {
+
+    /** namespace constant */
+    public static final String JPATH_NAMESPACE_URI  = "http://apache.org/xsp/jpath/1.0";
+
+    /** jpath:action attribute constant */
+    public static final String JPATH_ACTION         = "jpath:action";
+
+    /** jpath:value-of element constant */
+    public static final String JPATH_VALUEOF        = "value-of";
+
+    /** jpath:value-of select attribute constant */
+    public static final String JPATH_VALUEOF_SELECT = "select";
+
+    /** jpath:continuation element constant */
+    public static final String JPATH_CONTINUATION   = "continuation";
+
+    /** jpath:continuation select attribute constant */
+    public static final String JPATH_CONTINUATION_SELECT = "select";
+
+    /** jpath:if element constant */
+    public static final String JPATH_IF             = "if";
+
+    /** jpath generic test attribute */
+    public static final String JPATH_TEST           = "test";
+
+    // web contination
+    private WebContinuation m_kont;
+
+    // regular expression for matching 'id' strings with jpath:action
+    private RE m_re;
+
+    // jxpath context
+    private JXPathContext m_jxpathContext;
+
+    // jpath:value-of variable cache
+    private Map m_cache;
+
+    /**
+     * Constructor. Set namespace.
+     */
+    public JPathTransformer() {
+        super.defaultNamespaceURI = JPATH_NAMESPACE_URI;
+    }
+
+    /**
+     * Initialize this transformer.
+     *
+     * @exception Exception if an error occurs
+     */
+    public void initialize() throws Exception {
+        m_re = new RE("id");
+        m_cache = new HashMap();
+    }
+
+    /**
+     * Setup this transformer
+     *
+     * @param resolver a {@link SourceResolver} instance
+     * @param objectModel the objectModel
+     * @param src <code>src</code> parameter
+     * @param parameters optional parameters
+     * @exception ProcessingException if an error occurs
+     * @exception SAXException if an error occurs
+     * @exception IOException if an error occurs
+     */
+    public void setup(SourceResolver resolver, Map objectModel,
+                      String src, Parameters parameters)
+        throws ProcessingException, SAXException, IOException {
+
+        super.setup(resolver, objectModel, src, parameters);
+
+        // setup the jpath transformer for this thread
+        Object bean = FlowHelper.getContextObject(objectModel);
+        m_kont = FlowHelper.getWebContinuation(objectModel);
+        m_jxpathContext = JXPathContext.newContext(bean);
+    }
+
+    /**
+     * Intercept startElement to ensure all &lt;jpath:action&gt; attributes
+     * are modified.
+     *
+     * @param uri a <code>String</code> value
+     * @param loc a <code>String</code> value
+     * @param raw a <code>String</code> value
+     * @param a an <code>Attributes</code> value
+     * @exception SAXException if an error occurs
+     */
+    public void startElement(String uri, String loc, String raw, Attributes a)
+        throws SAXException {
+
+        AttributesImpl impl = new AttributesImpl(a);
+        checkJPathAction(impl);
+
+        super.startElement(uri, loc, raw, impl);
+    }
+
+    /**
+     * Entry method for all elements in our namespace
+     *
+     * @param uri a <code>String</code> value
+     * @param name a <code>String</code> value
+     * @param raw a <code>String</code> value
+     * @param attr an <code>Attributes</code> value
+     * @exception ProcessingException if an error occurs
+     * @exception IOException if an error occurs
+     * @exception SAXException if an error occurs
+     */
+    public void startTransformingElement(
+        String uri, String name, String raw, Attributes attr
+    )
+        throws ProcessingException ,IOException, SAXException {
+
+        if (JPATH_VALUEOF.equals(name)) {
+            doValueOf(attr);
+        } else if (JPATH_CONTINUATION.equals(name)) {
+            doContinuation(attr);
+        } else if (JPATH_IF.equals(name)) {
+            doIf(attr);
+        } else {
+            super.startTransformingElement(uri, name, raw, attr);
+        }
+    }
+
+    /**
+     * Exit method for all elements in our namespace
+     *
+     * @param uri a <code>String</code> value
+     * @param name a <code>String</code> value
+     * @param raw a <code>String</code> value
+     * @exception ProcessingException if an error occurs
+     * @exception IOException if an error occurs
+     * @exception SAXException if an error occurs
+     */
+    public void endTransformingElement(
+        String uri, String name, String raw
+    )
+        throws ProcessingException, IOException, SAXException {
+
+        if (JPATH_VALUEOF.equals(name) ||
+            JPATH_CONTINUATION.equals(name)) {
+            return; // do nothing
+        } else if (JPATH_IF.equals(name)) {
+            finishIf();
+        } else {
+            super.endTransformingElement(uri, name, raw);
+        }
+    }
+
+    /**
+     * Helper method to check for the existance of an attribute named
+     * jpath:action. If existing the string 'id' is replaced with the
+     * continuation id.
+     *
+     * @param a an {@link AttributesImpl} instance
+     */
+    private void checkJPathAction(final AttributesImpl a) {
+
+        // check for jpath:action attribute
+        int idx = a.getIndex(JPATH_ACTION);
+
+        if (idx != -1 && JPATH_NAMESPACE_URI.equals(a.getURI(idx))) {
+            if (getLogger().isDebugEnabled()) {
+                getLogger().debug("found jpath:action, adjusting");
+            }
+
+            String value = a.getValue(idx);
+
+            // REVISIT(MC): support for continuation level
+            String id = m_kont.getContinuation(0).getId();
+
+            a.removeAttribute(idx);
+            a.addAttribute(
+                "", "action", "action", "CDATA", m_re.subst(value, id)
+            );
+        }
+    }
+
+    /**
+     * Helper method for obtaining the value of a particular variable.
+     *
+     * @param variable variable name
+     * @return variable value as an <code>Object</code>
+     */
+    private Object getValue(final String variable) {
+
+        Object value;
+
+        if (m_cache.containsKey(variable)) {
+            value = m_cache.get(variable);
+        } else {
+            value = JXPathContext.compile(variable).getValue(m_jxpathContext);
+
+            if (value == null) {
+                if (getLogger().isWarnEnabled()) {
+                    final String msg =
+                        "Value for jpath variable '" + variable + "' does not exist";
+                    getLogger().warn(msg);
+                }
+            }
+
+            m_cache.put(variable, value);
+        }
+
+        return value;
+    }
+
+    /**
+     * Helper method to process a &lt;jpath:value-of select="."&gt; tag
+     *
+     * @param a an {@link Attributes} instance
+     * @exception SAXException if a SAX error occurs
+     * @exception ProcessingException if a processing error occurs
+     */
+    private void doValueOf(final Attributes a)
+        throws SAXException, ProcessingException {
+
+        final String select = a.getValue(JPATH_VALUEOF_SELECT);
+
+        if (null != select) {
+            sendTextEvent((String)getValue(select));
+        } else {
+            throw new ProcessingException(
+                "jpath:" + JPATH_VALUEOF + " specified without a select attribute"
+            );
+        }
+    }
+
+    /**
+     * Helper method to process a &lt;jpath:continuation select=""/&gt; element.
+     *
+     * @param a an <code>Attributes</code> value
+     * @exception SAXException if an error occurs
+     */
+    private void doContinuation(final Attributes a)
+        throws SAXException {
+
+        final String level = a.getValue(JPATH_CONTINUATION_SELECT);
+
+        final String id = (level != null)
+            ? m_kont.getContinuation(Integer.decode(level).intValue()).getId()
+            : m_kont.getContinuation(0).getId();
+
+        sendTextEvent(id);
+    }
+
+    /**
+     * Helper method to process a &lt;jpath:if test="..."&gt; element.
+     *
+     * @param a an <code>Attributes</code> value
+     * @exception SAXException if an error occurs
+     */
+    private void doIf(final Attributes a)
+        throws SAXException {
+
+        // handle nested jpath:if statements, if ignoreEventsCount is > 0, then
+        // we are processing a nested jpath:if statement for which the parent
+        // jpath:if test resulted in a false (ie. disallow subelements) result.
+
+        if (ignoreEventsCount > 0) {
+            ++ignoreEventsCount;
+            return;
+        }
+
+        // get the test variable
+        final Object value = getValue(a.getValue(JPATH_TEST));
+
+        final boolean isTrueBoolean =
+            value instanceof Boolean && ((Boolean)value).booleanValue() == true;
+        final boolean isNonNullNonBoolean =
+            value != null && !(value instanceof Boolean);
+
+        if (isTrueBoolean || isNonNullNonBoolean) {
+            // do nothing, allow all subelements
+            if (getLogger().isDebugEnabled()) {
+                getLogger().debug("jpath:if results in allowing subelements");
+            }
+        } else {
+            // disallow all subelements
+            if (getLogger().isDebugEnabled()) {
+                getLogger().debug("jpath:if results in disallowing subelements");
+            }
+            ++ignoreEventsCount;
+        }
+    }
+
+    /**
+     * Helper method to process a &lt;/jpath:if&gt; element.
+     *
+     * @exception SAXException if an error occurs
+     */
+    private void finishIf()
+        throws SAXException {
+
+        // end recording (and dump resulting document fragment) if we've reached
+        // the closing jpath:if tag for which the recording was started.
+        if (ignoreEventsCount > 0) {
+            --ignoreEventsCount;
+        }
+
+        if (getLogger().isDebugEnabled()) {
+            getLogger().debug("jpath:if closed");
+        }
+    }
+
+    /**
+     * Release all held resources.
+     */
+    public void recycle() {
+        m_cache.clear();
+        m_kont = null;
+        m_jxpathContext = null;
+
+        super.recycle();
+    }
+}

Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/transformation/JPathTransformer.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/transformation/LogTransformer.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/transformation/LogTransformer.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/transformation/LogTransformer.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/transformation/LogTransformer.java Thu Nov  3 05:41:06 2005
@@ -0,0 +1,368 @@
+/*
+ * 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.transformation;
+
+import org.apache.avalon.framework.parameters.Parameters;
+import org.apache.cocoon.ProcessingException;
+import org.apache.excalibur.source.Source;
+import org.apache.excalibur.source.SourceException;
+import org.apache.cocoon.components.source.SourceUtil;
+import org.apache.cocoon.environment.SourceResolver;
+import org.xml.sax.Attributes;
+import org.xml.sax.Locator;
+import org.xml.sax.SAXException;
+
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.Date;
+import java.util.Map;
+
+/**
+ * @cocoon.sitemap.component.documentation
+ * The <code>LogTransformer</code> is a class that can be plugged into a pipeline
+ * to print the SAX events which passes thru this transformer in a readable form
+ * to a file.
+ * 
+ * @cocoon.sitemap.component.name  log
+ * @cocoon.sitemap.component.logger sitemap.transformer.log
+ * 
+ * @cocoon.sitemap.component.pooling.max  16
+ *
+ * The <code>LogTransformer</code> is a class that can be plugged into a pipeline
+ * to print the SAX events which passes thru this transformer in a readable form
+ * to a file.
+ * <br>
+ * The file will be specified in a parameter tag in the sitemap pipeline to the
+ * transformer as follows:
+ * <p>
+ * <pre>
+ * &lt;map:transform type="log"&gt;
+ * &nbsp;&nbsp;&lt;map:parameter name="logfile" value="logfile.log"/&gt;
+ * &nbsp;&nbsp;&lt;map:parameter name="append" value="no"/&gt;
+ * &lt;/map:transform&gt;
+ * </pre>
+ * </p>
+ *
+ * Because the log file will be hardcoded into the sitemap this LOGTransformer will
+ * not be thread save!!
+ * <br>
+ * This transformations main purpose is debugging.
+ *
+ * @author <a href="mailto:cziegeler@apache.org">Carsten Ziegeler</a>
+ * @author <a href="mailto:giacomo.pati@pwr.ch">Giacomo Pati</a>
+ *         (PWR Organisation &amp; Entwicklung)
+ * @version CVS $Id: LogTransformer.java 153227 2005-02-10 15:00:57Z cziegeler $
+ *
+ */
+public class LogTransformer
+  extends AbstractTransformer {
+
+    private static String lf = System.getProperty("line.separator", "\n");
+
+    /** log file */
+    private FileWriter logfile;
+
+    /**
+     * Setup
+     */
+    public void setup(SourceResolver resolver, Map objectModel,
+                      String src, Parameters parameters)
+    throws ProcessingException, SAXException, IOException {
+        final boolean append = parameters.getParameterAsBoolean("append", false);
+        final String  logfilename = parameters.getParameter("logfile", null);
+
+        // Check for null, use System.out if logfile is not specified.
+        this.logfile = null;
+        if ( null != logfilename ) {
+            Source source = null;
+            try {
+                source = resolver.resolveURI( logfilename );
+                final String systemId = source.getURI();
+                if ( systemId.startsWith("file:") ) {
+                    this.logfile = new FileWriter(systemId.substring(5), append );
+                } else {
+                    throw new ProcessingException("The logfile parameter must point to a file: " + logfilename);
+                }
+            } catch (SourceException se) {
+                throw SourceUtil.handle(se);
+            } finally {
+                resolver.release( source );
+            }
+        }
+
+        Date date = new Date();
+        StringBuffer logEntry = new StringBuffer();
+        logEntry.append ( "---------------------------- [" );
+        logEntry.append ( date.toString() );
+        logEntry.append ( "] ----------------------------" );
+        this.log("setup", logEntry.toString());
+    }
+
+    /**
+     * Recycle
+     */
+    public void recycle() {
+        super.recycle();
+        try {
+            if (this.logfile != null) logfile.close();
+        } catch (Exception e) {
+            this.getLogger().warn("LogTransformer.recycle()", e);
+        }
+        this.logfile = null;
+    }
+
+    /**
+     * Receive an object for locating the origin of SAX document events.
+     */
+    public void setDocumentLocator(Locator locator) {
+        this.log("setDocumentLocator", locator != null ? "systemid="+locator.getSystemId()+",publicid="+locator.getPublicId() : "(locator is null)");
+        if (super.contentHandler!=null) {
+            super.contentHandler.setDocumentLocator(locator);
+        }
+    }
+
+    /**
+     * Receive notification of the beginning of a document.
+     */
+    public void startDocument()
+    throws SAXException {
+        this.log("startDocument", "");
+        if (super.contentHandler!=null) {
+            super.contentHandler.startDocument();
+        }
+    }
+
+    /**
+     * Receive notification of the end of a document.
+     */
+    public void endDocument()
+    throws SAXException {
+        this.log ("endDocument", "");
+        if (super.contentHandler!=null) {
+            super.contentHandler.endDocument();
+        }
+    }
+
+    /**
+     * Begin the scope of a prefix-URI Namespace mapping.
+     */
+    public void startPrefixMapping(String prefix, String uri)
+    throws SAXException {
+        this.log ("startPrefixMapping", "prefix="+prefix+",uri="+uri);
+        if (super.contentHandler!=null) {
+            super.contentHandler.startPrefixMapping(prefix,uri);
+        }
+    }
+
+    /**
+     * End the scope of a prefix-URI mapping.
+     */
+    public void endPrefixMapping(String prefix)
+    throws SAXException {
+        this.log ("endPrefixMapping", "prefix="+prefix);
+        if (super.contentHandler!=null) {
+            super.contentHandler.endPrefixMapping(prefix);
+        }
+    }
+
+    /**
+     * Receive notification of the beginning of an element.
+     */
+    public void startElement(String uri, String loc, String raw, Attributes a)
+    throws SAXException {
+        this.log ("startElement", "uri="+uri+",local="+loc+",raw="+raw);
+        for (int i = 0; i < a.getLength(); i++) {
+            this.log ("            ", new Integer(i+1).toString()
+                 +". uri="+a.getURI(i)
+                 +",local="+a.getLocalName(i)
+                 +",qname="+a.getQName(i)
+                 +",type="+a.getType(i)
+                 +",value="+a.getValue(i));
+        }
+        if (super.contentHandler!=null) {
+            super.contentHandler.startElement(uri,loc,raw,a);
+        }
+    }
+
+
+    /**
+     * Receive notification of the end of an element.
+     */
+    public void endElement(String uri, String loc, String raw)
+    throws SAXException {
+        this.log ("endElement", "uri="+uri+",local="+loc+",raw="+raw);
+        if (super.contentHandler!=null) {
+            super.contentHandler.endElement(uri,loc,raw);
+        }
+    }
+
+    /**
+     * Receive notification of character data.
+     */
+    public void characters(char ch[], int start, int len)
+    throws SAXException {
+        this.log ("characters", new String(ch,start,len));
+        if (super.contentHandler!=null) {
+            super.contentHandler.characters(ch,start,len);
+        }
+    }
+
+    /**
+     * Receive notification of ignorable whitespace in element content.
+     */
+    public void ignorableWhitespace(char ch[], int start, int len)
+    throws SAXException {
+        this.log ("ignorableWhitespace", new String(ch,start,len));
+        if (super.contentHandler!=null) {
+            super.contentHandler.ignorableWhitespace(ch,start,len);
+        }
+    }
+
+    /**
+     * Receive notification of a processing instruction.
+     */
+    public void processingInstruction(String target, String data)
+    throws SAXException {
+        log ("processingInstruction", "target="+target+",data="+data);
+        if (super.contentHandler!=null) {
+            super.contentHandler.processingInstruction(target,data);
+        }
+    }
+
+    /**
+     * Receive notification of a skipped entity.
+     */
+    public void skippedEntity(String name)
+    throws SAXException {
+        this.log ("skippedEntity", "name="+name);
+        if (super.contentHandler!=null) {
+            super.contentHandler.skippedEntity(name);
+        }
+    }
+
+    /**
+     * Report the start of DTD declarations, if any.
+     */
+    public void startDTD(String name, String publicId, String systemId)
+    throws SAXException {
+        this.log ("startDTD", "name="+name+",publicId="+publicId+",systemId="+systemId);
+        if (super.lexicalHandler!=null) {
+            super.lexicalHandler.startDTD(name,publicId,systemId);
+        }
+    }
+
+    /**
+     * Report the end of DTD declarations.
+     */
+    public void endDTD()
+    throws SAXException {
+        this.log ("endDTD", "");
+        if (super.lexicalHandler!=null) {
+            super.lexicalHandler.endDTD();
+        }
+    }
+
+    /**
+     * Report the beginning of an entity.
+     */
+    public void startEntity(String name)
+    throws SAXException {
+        this.log ("startEntity", "name="+name);
+        if (super.lexicalHandler!=null) {
+            super.lexicalHandler.startEntity(name);
+        }
+    }
+
+    /**
+     * Report the end of an entity.
+     */
+    public void endEntity(String name)
+    throws SAXException {
+        this.log ("endEntity", "name="+name);
+        if (super.lexicalHandler!=null) {
+            super.lexicalHandler.endEntity(name);
+        }
+    }
+
+    /**
+     * Report the start of a CDATA section.
+     */
+    public void startCDATA()
+    throws SAXException {
+        this.log ("startCDATA", "");
+        if (super.lexicalHandler!=null) {
+            super.lexicalHandler.startCDATA();
+        }
+    }
+
+    /**
+     * Report the end of a CDATA section.
+     */
+    public void endCDATA()
+    throws SAXException {
+        this.log ("endCDATA", "");
+        if (super.lexicalHandler!=null) {
+            super.lexicalHandler.endCDATA();
+        }
+    }
+
+    /**
+     * Report an XML comment anywhere in the document.
+     */
+    public void comment(char ch[], int start, int len)
+    throws SAXException {
+        this.log ("comment", new String(ch,start,len));
+        if (super.lexicalHandler!=null) {
+            super.lexicalHandler.comment(ch,start,len);
+        }
+    }
+
+    /**
+     * Report to logfile.
+     */
+    private void log (String location, String description) {
+        final StringBuffer logEntry = new StringBuffer();
+        logEntry.append ( "[" );
+        logEntry.append ( location );
+        logEntry.append ( "] " );
+        logEntry.append ( description );
+        logEntry.append ( lf );
+        final String text = logEntry.toString();
+        if ( this.getLogger().isInfoEnabled() ) {
+            this.getLogger().info( text );
+        }
+        try {
+            if ( null != this.logfile ) {
+                this.logfile.write( text, 0, text.length());
+                this.logfile.flush();
+            } else {
+                System.out.println( text );
+            }
+        }
+        catch(IOException ioe) {
+            this.getLogger().debug("LogTransformer.log", ioe);
+        }
+    }
+
+    /**
+     *  Attempt to close the log file when the class is GC'd
+     */
+    public void destroy() {
+        try {
+            if (this.logfile != null) logfile.close();
+        } catch (Exception e) {getLogger().debug("LogTransformer.destroy()", e);}
+    }
+}

Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/transformation/LogTransformer.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/transformation/ReadDOMSessionTransformer.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/transformation/ReadDOMSessionTransformer.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/transformation/ReadDOMSessionTransformer.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/transformation/ReadDOMSessionTransformer.java Thu Nov  3 05:41:06 2005
@@ -0,0 +1,159 @@
+/*
+ * 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.transformation;
+
+import org.apache.avalon.framework.parameters.Parameters;
+import org.apache.cocoon.ProcessingException;
+import org.apache.cocoon.environment.ObjectModelHelper;
+import org.apache.cocoon.environment.Request;
+import org.apache.cocoon.environment.Session;
+import org.apache.cocoon.environment.SourceResolver;
+import org.apache.cocoon.xml.XMLUtils;
+import org.apache.cocoon.xml.IncludeXMLConsumer;
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+
+import java.io.IOException;
+import java.util.Map;
+
+
+/**
+ * @cocoon.sitemap.component.documentation
+ * With this transformer, an object that is stored in the session, can be inserted
+ * in the SAX stream at a given position, using usual &lt;xsp:expr&gt; rules.
+ * Object can be DOM Node, XMLizable, or any other object supported by &lt;xsp:expr&gt;.
+ * 
+ * @cocoon.sitemap.component.name   readDOMsession
+ * @cocoon.sitemap.component.logger sitemap.transformer.readDOMsession
+ * 
+ * With this transformer, an object that is stored in the session, can be inserted
+ * in the SAX stream at a given position, using usual &lt;xsp:expr&gt; rules.
+ * Object can be DOM Node, XMLizable, or any other object supported by &lt;xsp:expr&gt;.
+ *
+ * Usage in sitemap:
+ * <pre>
+ *    &lt;map:transform type="read-session"&gt;
+ *      &lt;map:parameter name="attribute-name" value="companyInfo"/&gt;
+ *      &lt;map:parameter name="trigger-element" value="company"/&gt;
+ *      &lt;map:parameter name="position" value="after"/&gt;
+ *    &lt;/map:transform&gt;
+ * </pre>
+ *
+ * Where:
+ * <ul>
+ *  <li><b>attribute-name</b> is the name of the object in the session
+ *  <li><b>trigger-element</b> is the element that we need to insert the SAX events
+ *  <li><b>postion</b> is the actual place where the stream will be inserted, ie before, after or in
+ *  the trigger-element
+ * </ul>
+ *
+ * @author <a href="mailto:sven.beauprez@the-ecorp.com">Sven Beauprez</a>
+ * @author <a href="mailto:vgritsenko@apache.org">Vadim Gritsenko</a>
+ * @version CVS $Id: ReadDOMSessionTransformer.java 109638 2004-12-03 06:54:28Z crossley $
+ */
+public class ReadDOMSessionTransformer extends AbstractTransformer  {
+
+    public static final String ATTRIBUTE_NAME = "attribute-name";
+    public static final String TRIGGER_ELEMENT = "trigger-element";
+
+    /*
+      position where the sax events from the dom should be insterted
+      this can be: 'before', 'after' or 'in'
+    */
+    public static final String POSITION = "position";
+
+    Session session;
+    String attributeName;
+    String trigger;
+    String position;
+
+    /** BEGIN SitemapComponent methods **/
+    public void setup(SourceResolver resolver,
+                      Map objectModel,
+                      String source,
+                      Parameters parameters)
+            throws ProcessingException, SAXException, IOException {
+        Request request = ObjectModelHelper.getRequest(objectModel);
+        session = request.getSession(false);
+        if (session != null) {
+            if (getLogger().isDebugEnabled()) {
+                getLogger().debug("Session is available. ID=" + session.getId());
+            }
+            this.attributeName = parameters.getParameter(ATTRIBUTE_NAME, null);
+            if (this.attributeName == null) {
+                // Try old syntax
+                this.attributeName = parameters.getParameter("dom-name", null);
+            }
+
+            this.trigger = parameters.getParameter(TRIGGER_ELEMENT, null);
+            this.position = parameters.getParameter(POSITION, "in");
+            if (getLogger().isDebugEnabled()) {
+                getLogger().debug(ATTRIBUTE_NAME + "=" + attributeName + ", "
+                        + TRIGGER_ELEMENT + "=" + trigger + ", "
+                        + POSITION + "=" + position);
+            }
+        } else {
+            getLogger().warn("No session object: Nothing to do.");
+        }
+    }
+    /** END SitemapComponent methods **/
+
+    /** BEGIN SAX ContentHandler handlers **/
+    public void startElement(String uri, String name, String raw, Attributes attributes)
+            throws SAXException {
+        // Start streaming after certain startelement is encountered
+        if (name.equalsIgnoreCase(trigger)) {
+            getLogger().debug("Trigger encountered");
+            if ("before".equalsIgnoreCase(position))  {
+                stream();
+                super.contentHandler.startElement(uri,name,raw,attributes);
+            } else if ("in".equalsIgnoreCase(position))  {
+                super.contentHandler.startElement(uri,name,raw,attributes);
+                stream();
+            } else if ("after".equalsIgnoreCase(position))  {
+                super.contentHandler.startElement(uri,name,raw,attributes);
+            }
+        } else {
+            super.contentHandler.startElement(uri,name,raw,attributes);
+        }
+    }
+
+    public void endElement(String uri,String name,String raw)
+            throws SAXException  {
+        super.contentHandler.endElement(uri,name,raw);
+        if (name.equalsIgnoreCase(trigger)) {
+            if ("after".equalsIgnoreCase(position))  {
+                stream();
+            }
+        }
+    }
+    /** END SAX ContentHandler handlers **/
+
+    /** own methods **/
+    private void stream() throws SAXException  {
+        if (attributeName != null)  {
+            Object node = session.getAttribute(attributeName);
+            if (node != null)  {
+                getLogger().debug("Start streaming");
+                XMLUtils.valueOf(new IncludeXMLConsumer(super.xmlConsumer), node);
+            } else {
+                getLogger().error("No attribute " + attributeName + " in session");
+            }
+        } else {
+            getLogger().error("No "+ ATTRIBUTE_NAME + " parameter specified");
+        }
+    }
+}

Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/transformation/ReadDOMSessionTransformer.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/transformation/RoleFilterTransformer.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/transformation/RoleFilterTransformer.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/transformation/RoleFilterTransformer.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/transformation/RoleFilterTransformer.java Thu Nov  3 05:41:06 2005
@@ -0,0 +1,162 @@
+/*
+ * 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.transformation;
+
+import org.apache.avalon.framework.parameters.Parameters;
+import org.apache.cocoon.ProcessingException;
+import org.apache.cocoon.environment.ObjectModelHelper;
+import org.apache.cocoon.environment.Request;
+import org.apache.cocoon.environment.SourceResolver;
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.AttributesImpl;
+
+import java.io.IOException;
+import java.util.Map;
+import java.util.StringTokenizer;
+
+/**
+ * @cocoon.sitemap.component.documentation
+ * Filter XML fragments based on a user's role.  This will help in
+ * the development of smart forms that must only show information to
+ * people who are logged in and have the correct role.  The Role is
+ * specified by the Request semantics.  You can specify multiple roles
+ * by using comma delimiting.
+ * 
+ * @cocoon.sitemap.component.name   role-filter
+ * @cocoon.sitemap.component.logger sitemap.transformer.role-filter
+ * 
+ * Filter XML fragments based on a user's role.  This will help in
+ * the development of smart forms that must only show information to
+ * people who are logged in and have the correct role.  The Role is
+ * specified by the Request semantics.  You can specify multiple roles
+ * by using comma delimiting.
+ *
+ * <pre>
+ *   &lt;root xmlns:roles="http://apache.org/cocoon/role-filter/1.0"&gt;
+ *     &lt;textbox name="identifier" roles:restricted="admin,boss"/&gt;
+ *     &lt;textbox name="name" roles:read-only="admin,boss"/&gt;
+ *   &lt;/root&gt;
+ * </pre>
+ *
+ * The previous example will only show the "identifier" textbox for the
+ * roles "admin" and "boss".  It will pass role:read-only="" if the
+ * roles "admin" or "boss" are accessing the page.  That way you can
+ * specify any special processing by testing for the read-only attribute.
+ * This filter does not care about the prefix, only the namespace URI.
+ * That means you can reassign the namespace to another prefix and all
+ * will work as expected.
+ *
+ * @author <a href="mailto:bloritsch@apache.org">Berin Loritsch</a>
+ * @version CVS $Id: RoleFilterTransformer.java 30941 2004-07-29 19:56:58Z vgritsenko $
+ */
+public class RoleFilterTransformer extends FilterTransformer {
+    private final static String URI = "http://apache.org/cocoon/role-filter/1.0";
+    private final static String RESTRICT = "restricted";
+    private final static String VIEW = "read-only";
+    Request request = null;
+
+    public RoleFilterTransformer() {
+    }
+
+    public final void setup(SourceResolver resolver, Map objectModel, String src, Parameters params)
+    throws ProcessingException, SAXException, IOException {
+        super.setup(resolver, objectModel, src, params);
+        this.request = ObjectModelHelper.getRequest(objectModel);
+    }
+
+    /**
+     * Disable caching
+     */
+    public java.io.Serializable getKey() {
+        return null;
+    }
+
+    public final void startElement(String uri, String loc, String raw, Attributes a)
+    throws SAXException {
+        int roleIndex = a.getIndex(RoleFilterTransformer.URI, RoleFilterTransformer.RESTRICT);
+        int viewIndex = a.getIndex(RoleFilterTransformer.URI, RoleFilterTransformer.VIEW);
+        boolean propogate = true;
+        boolean readOnly = false;
+
+        if (roleIndex >= 0) {
+            String roleRestriction = a.getValue(roleIndex);
+            StringTokenizer roles = new StringTokenizer(roleRestriction, ",", false);
+            propogate = false;
+
+            while ((! propogate) && roles.hasMoreTokens()) {
+                if (request.isUserInRole(roles.nextToken())) {
+                    propogate = true;
+                }
+            }
+        }
+
+        if (! propogate) {
+            super.elementName = loc;
+        } else {
+            if (viewIndex >= 0) {
+                String viewRestriction = a.getValue(viewIndex);
+                StringTokenizer roles = new StringTokenizer(viewRestriction, ",", false);
+
+                while ((! readOnly) && roles.hasMoreTokens()) {
+                    if (request.isUserInRole(roles.nextToken())) {
+                        readOnly = true;
+                    }
+                }
+            }
+        }
+
+        super.startElement(uri, loc, raw,
+                this.copyAttributes(a, roleIndex, viewIndex, readOnly));
+    }
+
+    public final void endElement(String uri, String loc, String raw)
+    throws SAXException {
+        super.endElement(uri, loc, raw);
+
+        if (! super.skip) {
+            super.elementName = "";
+        }
+    }
+
+    private final Attributes copyAttributes(final Attributes a, final int role,
+                                            final int view, boolean readOnly) {
+        if (role < 0 && view < 0) {
+            return a;
+        }
+
+        AttributesImpl attr = new AttributesImpl();
+        attr.setAttributes(a);
+        if (role >= 0) {
+            attr.removeAttribute(role);
+        }
+
+        if (view >= 0) {
+            if (readOnly) {
+                attr.setValue(view, "");
+            } else {
+                attr.removeAttribute(view);
+            }
+        }
+
+        return attr;
+    }
+
+    public void recycle() {
+        this.request = null;
+        super.recycle();
+    }
+}

Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/transformation/RoleFilterTransformer.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/transformation/ServiceableTransformer.java
URL: http://svn.apache.org/viewcvs/cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/transformation/ServiceableTransformer.java?rev=330548&view=auto
==============================================================================
--- cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/transformation/ServiceableTransformer.java (added)
+++ cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/transformation/ServiceableTransformer.java Thu Nov  3 05:41:06 2005
@@ -0,0 +1,91 @@
+/*
+ * 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.transformation;
+
+import java.io.IOException;
+import java.util.Map;
+
+import org.apache.avalon.framework.activity.Disposable;
+import org.apache.avalon.framework.parameters.Parameters;
+import org.apache.avalon.framework.service.ServiceException;
+import org.apache.avalon.framework.service.ServiceManager;
+import org.apache.avalon.framework.service.Serviceable;
+import org.apache.cocoon.ProcessingException;
+import org.apache.cocoon.environment.SourceResolver;
+import org.xml.sax.SAXException;
+
+/**
+ * This class can be used as a base class for own transformer implementations
+ * that need to lookup other components.
+ * 
+ * @author <a href="mailto:cziegeler@apache.org">Carsten Ziegeler</a>
+ *         (Apache Software Foundation)
+ * @version CVS $Id: ServiceableTransformer.java 30941 2004-07-29 19:56:58Z vgritsenko $
+ */
+
+public abstract class ServiceableTransformer 
+    extends AbstractTransformer 
+    implements Serviceable, Disposable {
+
+    /** The current <code>SourceResolver</code>. */
+    protected SourceResolver resolver;
+    /** The current <code>Map</code> objectModel. */
+    protected Map objectModel;
+    /** The current <code>Parameters</code>. */
+    protected Parameters parameters;
+    /** The source URI associated with the request or <b>null</b>. */
+    protected String source;
+    /** The ServiceManager */
+    protected ServiceManager manager;
+    
+    /**
+     * Set the <code>SourceResolver</code>, object model <code>Map</code>,
+     * the source and sitemap <code>Parameters</code> used to process the request.
+     */
+    public void setup(SourceResolver resolver, Map objectModel, String src, Parameters par)
+    throws ProcessingException, SAXException, IOException {
+        this.resolver = resolver;
+        this.objectModel = objectModel;
+        this.source = src;
+        this.parameters = par;
+    }
+
+    /**
+     * Recycle the generator by removing references
+     */
+    public void recycle() {
+        super.recycle();
+        this.resolver = null;
+        this.objectModel = null;
+        this.source = null;
+        this.parameters = null;
+    }
+    
+    /* (non-Javadoc)
+     * @see org.apache.avalon.framework.service.Serviceable#service(org.apache.avalon.framework.service.ServiceManager)
+     */
+    public void service(ServiceManager manager) throws ServiceException {
+        this.manager = manager;
+    }
+
+    /* (non-Javadoc)
+     * @see org.apache.avalon.framework.activity.Disposable#dispose()
+     */
+    public void dispose() {
+        this.manager = null;
+    }
+
+}

Propchange: cocoon/whiteboard/maven2/cocoon-flat-layout/cocoon-core/src/main/java/org/apache/cocoon/transformation/ServiceableTransformer.java
------------------------------------------------------------------------------
    svn:eol-style = native



Mime
View raw message