On 28 Sep 2004, at 12:00, Vadim Gritsenko wrote:
Pier Fumagalli wrote:
On 27 Sep 2004, at 23:49, Vadim Gritsenko wrote:
Pier Fumagalli wrote:

Then we could re-create the request by something like:
<incl:include src="proto://whatever">
  <incl:param name="parameterName">value</incl:param>
</incl:include>


Well, if the only thing which troubles you is request, then you can easily do this now with simple:

  <i:include src="cocoon://pipeline?param=value"/>

And be done with it. You won't need any changes in IncludeTransformer at all.
The only problem with it is the encoding of the URL, which I shall do in XSLT, somehow...
Parameters that might contain "weird" characters like "&" or "=" could be troublesome, while if explicitly included in elements, it would make our life easier...

Go ahead, add parameters. We still need to re-create CInclude functionality in order to deprecate it. But, it won't solve caching issue mentioned - I guess I'll tackle it later. JFYI, that's how it looks in CInclude:

     <!-- The following are optional parameters appended to the URI -->
     <cinclude:parameters>
         <cinclude:parameter>
             <cinclude:name>a name</cinclude:name>
             <cinclude:value>a value</cinclude:value>
         </cinclude:parameter>
         <!-- more can follow -->
     </cinclude:parameters>

A bit too verbose... I'd go with your's:

<i:parameter name="name">value</i:parameter>

Done, I'm posting the patch here before applying just to triple-check I'm not f***ing up the whole thing. I mean, it works for me, but do a quick review.

Now, I moved all the inclusion in the EndElement method, and I'm matching parameters in the second format (the easy, non-verbose one). I'm making sure that ALL parameters are nicely URL-encoded, so that we don't have problems down the line, and (in my version), I updated the JavaDOCs quite a lot (including comments and re-indenting of the sources).

        Pier

-- cocoon-2.1/src/blocks/scratchpad/java/org/apache/cocoon/transformation/ IncludeTransformer.java Mon Sep 27 18:56:13 2004
+++ core/sources/local/org/apache/cocoon/transformation/ IncludeTransformer.java Tue Sep 28 14:51:01 2004
@@ -17,6 +17,10 @@

 import java.io.IOException;
 import java.io.Serializable;
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+import java.util.Hashtable;
+import java.util.Iterator;
 import java.util.Map;

import org.apache.avalon.framework.parameters.Parameters;
@@ -28,6 +32,7 @@
import org.apache.cocoon.components.source.SourceUtil;
import org.apache.cocoon.components.source.impl.MultiSourceValidity;
import org.apache.cocoon.environment.SourceResolver;
+import org.apache.cocoon.util.NetUtils;
import org.apache.cocoon.xml.IncludeXMLConsumer;
import org.apache.cocoon.xml.NamespacesTable;
import org.apache.excalibur.source.Source;
@@ -44,8 +49,31 @@
*
* <p>Example:</p>
*
- * <p><code>&lt;incl:include xmlns="http://apache.org/cocoon/include/1.0";
- * src="cocoon://path/to/include"/&gt;</code></p>
+ * <pre>
+ * &lt;incl:include xmlns:incl="http://apache.org/cocoon/include/1.0";
+ * src="cocoon://path/to/include"/&gt;
+ * </pre>
+ *
+ * <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;incl:include xmlns:incl="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>&</code> (amperstand) or <code>=</code> (equals) character, which are
+ * reserved characters in URIs. An example:</p>
+ *
+ * <pre>
+ * &lt;incl:include xmlns:incl="http://apache.org/cocoon/include/1.0";
+ * src="cocoon://path/to/include"&gt;
+ * &lt;incl:parameter name="firstParameterName" value="firstParameterValue"/&gt;
+ * &lt;incl:parameter name="other&amp;Para=Name" value="other=Para&amp;Value"/&gt;
+ * &lt;/incl:include&gt;
+ * </pre>
*
* <p>An interesting feature of this [EMAIL PROTECTED] Transformer} is that it implements the
* [EMAIL PROTECTED] CacheableProcessingComponent} interface and provides full support for
@@ -63,15 +91,41 @@
public class IncludeTransformer extends AbstractTransformer
implements Serviceable, 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 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 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";
+
+ /** <p>The [EMAIL PROTECTED] ServiceManager} instance associated with this instance.</p> */
private ServiceManager m_manager;
+ /** <p>The [EMAIL PROTECTED] SourceResolver} used to resolve included URIs.</p> */
private SourceResolver m_resolver;
+ /** <p>The [EMAIL PROTECTED] SourceValidity} instance associated with this request.</p> */
private MultiSourceValidity m_validity;
+ /** <p>A [EMAIL PROTECTED] NamespacesTable} used to filter namespace declarations.</p> */
private NamespacesTable m_namespaces;

+ /** <p>A [EMAIL PROTECTED] Map} of the parameters to supply to the included source.</p> */
+ private Map x_parameters;
+ /** <p>The source to be included declared in an include element.</p> */
+ private String x_source;
+ /** <p>The current parameter name captured.</p> */
+ private String x_parameter;
+ /** <p>The current parameter value (as a [EMAIL PROTECTED] StringBuffer}).</p> */
+ private StringBuffer x_value;
+
+
/**
* <p>Create a new [EMAIL PROTECTED] IncludeTransformer} instance.</p>
*/
@@ -99,6 +153,8 @@
this.m_resolver = resolver;
this.m_validity = null;
this.m_namespaces = new NamespacesTable();
+ this.x_parameters = new Hashtable();
+ this.x_value = new StringBuffer();
}

     /**
@@ -111,6 +167,8 @@
         this.m_resolver = null;
         this.m_validity = null;
         this.m_namespaces = new NamespacesTable();
+        this.x_parameters = new Hashtable();
+        this.x_value = new StringBuffer();
     }

     /**
@@ -178,39 +236,90 @@
     }

/**
+ * <p>Receive notification of characters.</p>
+ *
+ * @see org.xml.sax.ContentHandler#characters(char[], int, int)
+ */
+ public void characters(char data[], int offset, int length)
+ throws SAXException {
+ /* If we have a parameter value to add to, let's add this chunk */
+ if (this.x_parameter != null) {
+ this.x_value.append(data, offset, length);
+ /* Forward this only if we are not inside an include tag */
+ } else if (this.x_source != null) {
+ super.characters(data, offset, length);
+ }
+ }
+
+ /**
* <p>Receive notification of the start of an element.</p>
*
- * @see org.xml.sax.ContentHandler#startElement(String, String, String, org.xml.sax.Attributes)
+ * @see org.xml.sax.ContentHandler#startElement(String, String, String, Attributes)
*/
public void startElement(String uri, String localName, String qName, Attributes atts)
throws SAXException {
+ /* Check the namespace declaration */
if (NS_URI.equals(uri)) {
+ /* Inclusion will not happen here but when we close this tag */
if (INCLUDE_ELEMENT.equals(localName)) {
- String src = atts.getValue(SRC_ATTRIBUTE);
- Source source = null;
- try {
- source = m_resolver.resolveURI(src);
- if (m_validity != null) {
- m_validity.addSource(source);
+ /* Check before we include (we don't want nested stuff) */
+ if (this.x_source != null) {
+ throw new SAXException("Invalid include nested in another");
}
- SourceUtil.toSAX(m_manager, source, "text/xml",
- new IncludeXMLConsumer(super.contentHandler));
+
+ /* Remember the source we are trying to include */
+ this.x_source = atts.getValue(SRC_ATTRIBUTE);
+ if ((this.x_source == null) || (this.x_source.length() == 0)) {
+ throw new SAXException("Unspecified \"src\" attribute");
}
- catch (IOException e) {
- throw new SAXException(e);
+
+ /* Whatever list of parameters we got before, we wipe it! */
+ this.x_parameters.clear();
+ this.x_value.setLength(0);
+ this.x_parameter = null;
+
+ /* Done with this element */
+ return;
}
- catch (ProcessingException e) {
- throw new SAXException(e);
+
+ /* If this is a parameter, then make sure we prepare. */
+ if (PARAMETER_ELEMENT.equals(localName)) {
+ /* Check if we are in the right context */
+ if (this.x_source == null) {
+ throw new SAXException("Parameter specified outside of include");
}
- finally {
- if (source != null) {
- m_resolver.release(source);
+ if (this.x_parameter != null) {
+ throw new SAXException("Invalid parameter nested in another");
}
+
+ /* Get and process the parameter name */
+ this.x_parameter = atts.getValue(NAME_ATTRIBUTE);
+ if ((this.x_parameter == null) || (this.x_parameter.length() == 0)) {
+ throw new SAXException("Unspecified \"name\" attribute");
}
+
+ /* Make some room for the parameter value */
+ this.x_value.setLength(0);
+ String value = atts.getValue(VALUE_ATTRIBUTE);
+ if (value != null) this.x_value.append(value);
+
+ /* Done with this element */
+ return;
}
- } else {
+
+ /* We don't have a clue of why we got here (wrong element?) */
+ if (this.getLogger().isWarnEnabled()) {
+ this.getLogger().warn("Unknown element \"" + localName + "\"");
+ }
+ return;
+ }
+
+ /* Not our namespace, simply check and pass this element on! */
+ if (this.x_source == null) {
super.startElement(uri, localName, qName, atts);
+ return;
}
+ throw new SAXException("Element <" + qName + "/> invalid inside include");
}

/**
@@ -220,7 +329,78 @@
*/
public void endElement(String uri, String localName, String qName)
throws SAXException {
- if (!NS_URI.equals(uri)) {
+ /* Check the namespace declaration */
+ if (NS_URI.equals(uri)) {
+
+ /* Inclusion will happen here, when we close the include element */
+ if (INCLUDE_ELEMENT.equals(localName)) {
+
+ /* Get the source discovered opening the element and include */
+ Source source = null;
+ try {
+ String encodedSource = NetUtils.parameterize(this.x_source,
+ this.x_parameters);
+ source = m_resolver.resolveURI(encodedSource);
+ if (m_validity != null) m_validity.addSource(source);
+
+ // TODO: remove this debugging code!
+ System.err.println("Including \"" + encodedSource + "\" from \""
+ + source.getURI() + "\" ("
+ + this.x_parameters.size() + ")");
+ Iterator iterator = this.x_parameters.keySet().iterator();
+ while (iterator.hasNext()) {
+ String name = (String) iterator.next();
+ System.err.println("Parameter \"" + name + "\"=\"" + this.x_parameters.get(name) + "\"");
+ }
+ // TODO: remove the above debugging code!
+
+ SourceUtil.toSAX(m_manager, source, "text/xml",
+ new IncludeXMLConsumer(super.contentHandler));
+ } catch (IOException e) {
+ /* Something bad happenend processing a stream */
+ throw new SAXException(e);
+ } catch (ProcessingException e) {
+ /* Something bad happened processing a pipeline */
+ throw new SAXException(e);
+ } finally {
+ /* In any case, make sure we release the source */
+ if (source != null) m_resolver.release(source);
+ }
+
+ /* We are done with the include element */
+ this.x_parameters.clear();
+ this.x_value.setLength(0);
+ this.x_parameter = null;
+ this.x_source = null;
+ return;
+ }
+
+ /* Addition of parameters happens here (so that we can capture chars) */
+ if (PARAMETER_ELEMENT.equals(localName)) {
+ String value = this.x_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.
+ */
+ this.x_parameters.put(URLEncoder.encode(this.x_parameter, ENCODING),
+ URLEncoder.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 */
+ this.x_value.setLength(0);
+ this.x_parameter = null;
+ return;
+ }
+
+ } else {
+ /* This is not our namespace, pass the event on! */
super.endElement(uri, localName, qName);
}
}
@@ -231,8 +411,10 @@
* @see CacheableProcessingComponent#getKey()
*/
public Serializable getKey() {
- // FIXME: In case of including "cocoon://" or other dynamic sources
- // key has to be dynamic.
+ /*
+ * FIXME: In case of including "cocoon://" or other dynamic sources
+ * key has to be dynamic.
+ */
return "I";
}



Attachment: smime.p7s
Description: S/MIME cryptographic signature

Reply via email to