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><include ... /></code> element
+ * defined in the <code>http://apache.org/cocoon/include/1.0</code> namespace.</p>
+ *
+ * <p>Example:</p>
+ * <pre>
+ * <i:include xmlns:i="http://apache.org/cocoon/include/1.0"
+ * src="cocoon://path/to/include"/>
+ * </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>
+ * <i:include xmlns:i="http://apache.org/cocoon/include/1.0"
+ * src="cocoon://path/to/include?paramA=valueA&paramB=valueB"/>
+ * </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>&</code> (amperstand) or <code>=</code> (equals) character, which are
+ * reserved characters in URIs. An example:</p>
+ *
+ * <pre>
+ * <i:include xmlns:i="http://apache.org/cocoon/include/1.0"
+ * src="cocoon://path/to/include">
+ * <i:parameter name="firstParameterName" value="firstParameterValue"/>
+ * <i:parameter name="other&Para=Name" value="other=Para&Value"/>
+ * </i:include>
+ * </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>
+ * <i:include xmlns:i="http://apache.org/cocoon/include/1.0"
+ * src="cocoon://path/to/include">
+ * <i:fallback>
+ * <strong>The data is temporarily unavailable.</strong>
+ * We are sorry for the trouble; please try again later.
+ * </i:fallback>
+ * </i:include>
+ * </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>
+ * <parallel>true</parallel>
+ * </pre>
+ *
+ * <p>or in a pipeline itself (to only affect that instance of the IncludeTransformer):</p>
+ * <pre>
+ * <map:parameter name="parallel" value="true"/>
+ * </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>
+ * <recursive>true</recursive>
+ * </pre>
+ *
+ * <p>or in a pipeline itself (to only affect that instance of the IncludeTransformer):</p>
+ * <pre>
+ * <map:parameter name="recursive" value="true"/>
+ * </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><jpath:value-of select=".."/> element.
+ * <li><jpath:continuation/> element.
+ * <li><jpath:if test="..">..</jpath:if> 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><form name="myform" jpath:action="../cont/id">..</form></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 <jpath:action> 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 <jpath:value-of select="."> 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 <jpath:continuation select=""/> 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 <jpath:if test="..."> 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 </jpath:if> 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>
+ * <map:transform type="log">
+ * <map:parameter name="logfile" value="logfile.log"/>
+ * <map:parameter name="append" value="no"/>
+ * </map:transform>
+ * </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 & 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 <xsp:expr> rules.
+ * Object can be DOM Node, XMLizable, or any other object supported by <xsp:expr>.
+ *
+ * @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 <xsp:expr> rules.
+ * Object can be DOM Node, XMLizable, or any other object supported by <xsp:expr>.
+ *
+ * Usage in sitemap:
+ * <pre>
+ * <map:transform type="read-session">
+ * <map:parameter name="attribute-name" value="companyInfo"/>
+ * <map:parameter name="trigger-element" value="company"/>
+ * <map:parameter name="position" value="after"/>
+ * </map:transform>
+ * </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>
+ * <root xmlns:roles="http://apache.org/cocoon/role-filter/1.0">
+ * <textbox name="identifier" roles:restricted="admin,boss"/>
+ * <textbox name="name" roles:read-only="admin,boss"/>
+ * </root>
+ * </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
|