giacomo 01/06/12 07:51:18
Modified: webapp sitemap.xmap
Added: src/org/apache/cocoon/generation StreamGenerator.java
src/org/apache/cocoon/util PostInputStream.java
webapp/docs/samples/stream OrderPage.xml ReadMeAdd.txt
telnet.txt
Log:
Added StreamGenerator and samples
Submitted by: kingadziembowska <[EMAIL PROTECTED]>
Revision Changes Path
1.12 +15 -25 xml-cocoon2/webapp/sitemap.xmap
Index: sitemap.xmap
===================================================================
RCS file: /home/cvs/xml-cocoon2/webapp/sitemap.xmap,v
retrieving revision 1.11
retrieving revision 1.12
diff -u -u -r1.11 -r1.12
--- sitemap.xmap 2001/05/29 20:11:38 1.11
+++ sitemap.xmap 2001/06/12 14:51:16 1.12
@@ -17,6 +17,7 @@
<map:generator name="velocity"
src="org.apache.cocoon.generation.VelocityGenerator"/>
<map:generator name="html"
src="org.apache.cocoon.generation.HTMLGenerator" label="content"/>
<map:generator name="jsp"
src="org.apache.cocoon.generation.JspGenerator"/>
+ <map:generator name="stream"
src="org.apache.cocoon.generation.StreamGenerator"/>
</map:generators>
<map:transformers default="xslt">
@@ -346,31 +347,6 @@
<map:read src="docs/samples/{1}.png" mime-type="image/png"/>
</map:match>
- <!--
- This pipeline is responsable for generating the images for the navigation
- bar. It uses the navimage.xsp to generate an SVG document which contains
- the text for the image from the request URI passed as a parameter. The
- requested language is evaluated by the LangSelect action. The text
- represents a key into the i18n dictionary for all navigation items. At
- the end the generated SVG is serialized as a PNG image.
- This pipeline is fully cachable and thus an image depends only on
- the text id and the laguage used and is generated once for each combination.
- -->
- <map:match type="regexp" pattern="i18n/images/(.*)_(.*)_(.*).png">
- <map:generate type="serverpages" src="docs/samples/i18n/navimages.xsp">
- <map:parameter name="text" value="{1}"/>
- <map:parameter name="lang" value="{2}"/>
- <map:parameter name="kind" value="{3}"/>
- </map:generate>
- <map:transform type="i18n" src="docs/samples/i18n/nav_trans.xml">
- <map:parameter name="lang" value="{2}"/>
- <map:parameter name="default_lang" value="en"/>
- <map:parameter name="available_lang_1" value="en"/>
- <map:parameter name="available_lang_2" value="de"/>
- </map:transform>
- <map:serialize type="svg2png"/>
- </map:match>
-
<!-- =========================== Dynamic ================================ -->
<map:match pattern="xsp/*">
<map:generate type="serverpages" src="docs/samples/xsp/{1}.xsp"/>
@@ -425,6 +401,20 @@
<map:parameter name="view-source" value="docs/samples/session/{1}.xsp"/>
</map:transform>
<map:serialize/>
+ </map:match>
+
+ <!-- ========================== Stream ================================= -->
+ <map:match pattern="request1">
+ <map:generate type="stream">
+ <map:parameter name="form-name" value="Foo"/>
+ </map:generate>
+ <map:serialize type="xml"/>
+ </map:match>
+
+ <map:match pattern="Order">
+ <map:generate src="docs/samples/stream/OrderPage.xml"/>
+ <map:transform src="stylesheets/dynamic-page2html.xsl"/>
+ <map:serialize type="html"/>
</map:match>
<!-- ========================== XSP Sources ============================== -->
1.1
xml-cocoon2/src/org/apache/cocoon/generation/StreamGenerator.java
Index: StreamGenerator.java
===================================================================
/*****************************************************************************
* Copyright (C) The Apache Software Foundation. All rights reserved. *
* ------------------------------------------------------------------------- *
* This software is published under the terms of the Apache Software License *
* version 1.1, a copy of which has been included with this distribution in *
* the LICENSE file. *
*****************************************************************************/
package org.apache.cocoon.generation;
import java.io.StringReader;
import java.io.IOException;
import java.util.Map;
import org.apache.cocoon.Constants;
import org.apache.cocoon.ProcessingException;
import org.apache.cocoon.ResourceNotFoundException;
import org.apache.cocoon.Roles;
import org.apache.cocoon.components.parser.Parser;
import org.apache.cocoon.environment.http.HttpRequest;
import org.apache.cocoon.environment.Source;
import org.apache.cocoon.environment.SourceResolver;
import org.apache.cocoon.util.PostInputStream;
import org.apache.avalon.excalibur.pool.Poolable;
import org.apache.avalon.framework.component.Component;
import org.apache.avalon.framework.component.ComponentException;
import org.apache.avalon.framework.component.ComponentManager;
import org.apache.avalon.framework.parameters.Parameters;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
/**
*
* The <code>StreamGenerator</code> is a class that reads XML from a request
InputStream
* and generates SAX Events.
* For the POST requests with mimetype of application/x-www-form-urlencoded the xml
data is
* expected to be associated with the name specified in the sitemap parameter.
* For the POST requests with mimetypes: text/plain, text/xml, application/xml the
xml data is in the body of teh POST
* request and its length is specified by the value returned by getContentLength()
method.
* The StreamGenerator uses helper org.apache.cocoon.util.PostInputStream class for
InputStream reading operations.
* At the time that Parser is reading the data out of InputStream - Parser has no
knowledge about the length of data to be read.
* The only way to signal to the Parser that all data was read from the InputStream
is to control reading operation - PostInputStream- and to return to
* the requestor -1 when the number of bytes read is equal to the getContentLength()
value.
*
* @author <a href="mailto:[EMAIL PROTECTED]">Kinga Dziembowski</a>
* @version $Revision: 1.1 $ $Date: 2001/06/12 14:51:17 $
*/
public class StreamGenerator extends ComposerGenerator {
public static final String CLASS = StreamGenerator.class.getName();
/** The parameter holding the name associated with the xml data **/
public static final String FORM_NAME = "form-name";
/** The input source */
private InputSource inputSource;
/** The system ID of the input source */
private String systemID;
/**
* Set the current <code>ComponentManager</code> instance used by this
* <code>Composable</code>.
*/
public void compose(ComponentManager manager) {
super.compose(manager);
}
/**
* Recycle this component.
* All instance variables are set to <code>null</code>.
*/
public void recycle() {
super.recycle();
this.inputSource = null;
this.systemID = null;
}
/**
* Setup the stream generator.
*/
public void setup(SourceResolver resolver, Map objectModel, String src,
Parameters par)
throws ProcessingException, SAXException, IOException {
super.setup(resolver, objectModel, src, par);
}
/**
* Generate XML data out of request InputStream.
*/
public void generate() throws IOException, SAXException, ProcessingException {
Parser parser = null;
String parameter = parameters.getParameter(StreamGenerator.FORM_NAME, null);
int len = 0;
try {
HttpRequest request = (HttpRequest)
objectModel.get(Constants.REQUEST_OBJECT);
if
(request.getContentType().equals("application/x-www-form-urlencoded")) {
String sXml = request.getParameter(parameter);
inputSource = new InputSource(new StringReader(sXml));
} else if (request.getContentType().equals("text/plain")
|| request.getContentType().equals("text/xml")
|| request.getContentType().equals("application/xml")) {
len = request.getContentLength();
if (len > 0) {
PostInputStream anStream = new
PostInputStream(request.getInputStream(), len);
inputSource = new InputSource(anStream);
} else {
throw new IOException("getContentLen() == 0");
}
} else {
throw new IOException("Unexpected getContentType(): " +
request.getContentType());
}
}
getLogger().debug("processing stream ContentType= " +
request.getContentType() + "ContentLen= " + len);
parser = (Parser)this.manager.lookup(Roles.PARSER);
parser.setContentHandler(super.contentHandler);
parser.setLexicalHandler(super.lexicalHandler);
parser.parse(this.inputSource);
} catch (IOException e) {
getLogger().error("StreamGenerator.generate()", e);
throw new ResourceNotFoundException("StreamGenerator could not find
resource", e);
} catch (SAXException e) {
getLogger().error("StreamGenerator.generate()", e);
throw(e);
} catch (Exception e){
getLogger().error("Could not get parser", e);
throw new ProcessingException("Exception in
StreamGenerator.generate()",e);
} finally {
if (parser != null) this.manager.release((Component) parser);
}
}
}
1.1 xml-cocoon2/src/org/apache/cocoon/util/PostInputStream.java
Index: PostInputStream.java
===================================================================
/*****************************************************************************
* Copyright (C) The Apache Software Foundation. All rights reserved. *
* ------------------------------------------------------------------------- *
* This software is published under the terms of the Apache Software License *
* version 1.1, a copy of which has been included with this distribution in *
* the LICENSE file. *
*****************************************************************************/
package org.apache.cocoon.util;
import java.io.InputStream;
import java.io.IOException;
/**
* The class PostInputStream is a wrapper for InputStream associated with POST
message.
* It allows to control read operation, restricting the number of bytes read to the
value returned by getContentLen() method.
*
* @author <a href="mailto:[EMAIL PROTECTED]">Kinga Dziembowski</a>
* @version $Id: PostInputStream.java,v 1.1 2001/06/12 14:51:17 giacomo Exp $
*/
public class PostInputStream extends InputStream {
/**
* Class name
*/
public static final String CLASS = PostInputStream.class.getName();
/** The real InputStream object */
private InputStream m_inputStream = null;
/** The length of InputStream */
private int m_contentLen = 0;
/** The number of bytes read */
protected int m_bytesRead = 0;
/**
* Creates a PostInputStream
*/
public PostInputStream() {
super();
}
/**
* Creates a <code>PostInputStream</code> based on a real InputStream object with
the specified
* post message body length. Saves its argument, the input stream
* <code>m_inputStream</code>, for later use.
*
* @param input the underlying input stream.
* @param len the post message body length.
* @exception IllegalArgumentException len <= 0.
*/
public PostInputStream(final InputStream input, final int len) throws
IllegalArgumentException {
super();
init(input, len );
}
/**
* Sets the underlying input stream and contentLen value .
*
* @param inputStream the input stream; can not be null.
* @param len the post message body length.
*
* @throws IllegalArgumentException
*/
protected void init(final InputStream input, final int len) throws
IllegalArgumentException {
if (len <= 0) {
throw new IllegalArgumentException("contentLen <= 0 ");
}
this.m_inputStream = input;
this.m_contentLen = len;
}
/**
* Sets the underlying input stream and contentLen value .
*
* @param inputStream the input stream; can not be null.
* @param len the post message body length.
*
* @throws IOException
*/
public synchronized void setInputStream(final InputStream input, final int len)
throws IOException {
if (m_inputStream != null) {
close();
}
init(input, len);
}
/**
* Returns the underlying input stream.
*
* @return inputStream the underlying InputStream.
*/
public InputStream getInputStream() {
return( m_inputStream );
}
/**
* Returns the post message body length.
*
* @return m_contentLen;
*/
public int getContentLen() {
return( m_contentLen );
}
/**
* Reads the next byte from the input stream. If the end of the stream has been
reached, this method returns -1.
*
* @return the next byte or -1 if at the end of the stream.
*
* @throws IOException
*/
public synchronized int read() throws IOException {
checkOpen();
if (m_bytesRead == m_contentLen) {
return -1;
}
int byt = m_inputStream.read();
if (byt != -1) {
m_bytesRead++;
}
return byt;
}
/**
* Reads bytes from this byte-input stream into the specified byte array,
* starting at the given offset.
*
* <p> This method implements the general contract of the corresponding
* <code>{@link InputStream#read(byte[], int, int) read}</code> method of
* the <code>{@link InputStream}</code> class.
* This method delegetes tre read operation to the underlying InputStream
implementation class but it
* controlls the number of bytes read from the stream.In the remote situation the
underlying InputStream has no knowledge of
* the length of the stream and the notion of the "end" is undefined. This
wrapper class has a knowledge of the
* length of data send by the requestor by the means of contentLength. This
method returns the number of bytes read and
* accumulates the total number of bytes read in m_bytesRead. When the
m_bytesRead is equal to the specified contentLength
* value the method returns returns -1 to signal the end of data.
*
* @param buffer the byte array to read into; can not be null.
* @param offset the starting offset in the byte array.
* @param len the maximum number of bytes to read.
*
* @return the number of bytes read, or <code>-1</code> if the end of
* the stream has been reached.
* @exception IOException if an I/O error occurs.
*/
public synchronized int read(byte[] buffer, int offset, int len) throws
IOException {
checkOpen();
if (m_bytesRead == m_contentLen) {
return -1;
}
int num = m_inputStream.read(buffer, offset, len);
if (num > 0) {
m_bytesRead += num;
}
return num;
}
public synchronized int read(byte[] buffer) throws IOException {
return read( buffer, 0, buffer.length);
}
/**
* Checks to see if this stream is closed; if it is, an IOException is thrown.
*
* @throws IOException
*/
protected void checkOpen() throws IOException {
if (m_inputStream == null) {
throw new IOException("InputStream closed");
}
}
/**
* See the general contract of the <code>skip</code>
* method of <code>InputStream</code>.
* Delegates execution to the underlying InputStream implementation class.
* Checks to see if this stream is closed; if it is, an IOException is thrown.
* @param n the number of bytes to be skipped.
* @return the actual number of bytes skipped.
* @exception IOException if an I/O error occurs.
*/
public synchronized long skip(long n) throws IOException {
checkOpen();
return m_inputStream.skip(n);
}
/**
* Returns the number of bytes available from this input stream that can be read
without the stream blocking.
* Delegates execution to the underlying InputStream implementation class.
* @return available the number of available bytes.
*
* @throws IOException
*/
public synchronized int available() throws IOException {
checkOpen();
return m_inputStream.available();
}
/**
* Tests if this input stream supports the <code>mark</code>
* and <code>reset</code> methods. The <code>markSupported</code>
* method of <code>BufferedInputStream</code> returns
* <code>false</code>.
*
* @return a <code>boolean</code> indicating if this stream type supports
* the <code>mark</code> and <code>reset</code> methods.
* @see java.io.InputStream#mark(int)
* @see java.io.InputStream#reset()
*/
public boolean markSupported() {
return false;
}
/**
* Closes this input stream by closing the underlying stream and marking this one
as closed.
*
* @throws IOException
*/
public synchronized void close() throws IOException {
if (m_inputStream == null) {
return;
}
m_inputStream.close();
m_inputStream = null;
m_contentLen = 0;
m_bytesRead = 0;
}
/**
* Returns a String representation of this.
*
* @return string the String representation of this.
*/
public String toString() {
return getClass().getName() + "[inputStream=" + m_inputStream + ",
contentLen=" + m_contentLen + "bytesRead=" + m_bytesRead + "]";
}
}
1.1 xml-cocoon2/webapp/docs/samples/stream/OrderPage.xml
Index: OrderPage.xml
===================================================================
<page>
<title>B2B processing</title>
<content>
<FORM action="http://localhost:8080/cocoon/request1" id="FORM1" method="post"
name="FORM1">
<para>Input your XML documet here:</para>
<TEXTAREA cols="80" id="TEXTAREA1" name="Foo" rows="60"><?xml
version="1.0"?>
<Orders>
<OrderID>20259</OrderID>
<CustomerID>WWWWWWW</CustomerID>
<EmployeeID>6</EmployeeID>
<OrderDate>2001-05-05 00:00:00</OrderDate>
<RequiredDate>2001-06-05 00:00:00</RequiredDate>
<ShippedDate>2001-06-01 00:00:00</ShippedDate>
<ShipVia>1</ShipVia>
<Freight>11.6100</Freight>
<ShipName>Thoms White</ShipName>
<ShipAddress>Somestr. 48</ShipAddress>
<ShipCity>Munster</ShipCity>
<ShipRegion>West</ShipRegion>
<ShipPostalCode>00000</ShipPostalCode>
<ShipCountry>Germany</ShipCountry>
<OrderDetails>
<OrderID>20259</OrderID>
<ProductID>51</ProductID>
<UnitPrice>42.4000</UnitPrice>
<Quantity>40</Quantity>
<Discount>0.0</Discount>
</OrderDetails>
<OrderDetails>
<OrderID>20259</OrderID>
<ProductID>14</ProductID>
<UnitPrice>18.6000</UnitPrice>
<Quantity>9</Quantity>
<Discount>0.0</Discount>
</OrderDetails>
<OrderDetails>
<OrderID>20259</OrderID>
<ProductID>7</ProductID>
<UnitPrice>12.4000</UnitPrice>
<Quantity>30</Quantity>
<Discount>0.0</Discount>
</OrderDetails>
<Customers>
<CustomerID>WWWWWWW</CustomerID>
<CompanyName>Thomas White</CompanyName>
<ContactName>Karin Black</ContactName>
<ContactTitle>Marketing Manager</ContactTitle>
<Address>Somestr. 48</Address>
<City>Munster</City>
<Region>West</Region>
<PostalCode>00000</PostalCode>
<Country>Germany</Country>
<Phone>xxxx-yyyyyy</Phone>
<Fax>xxxx-yyyyyy</Fax>
</Customers>
</Orders>
</TEXTAREA>
<INPUT id="submit1" name="submit1" type="submit" value="Submit"/>
</FORM>
</content>
</page>
1.1 xml-cocoon2/webapp/docs/samples/stream/ReadMeAdd.txt
Index: ReadMeAdd.txt
===================================================================
Hewlett-Packard Bluestone Cocoon Project
@version@
What is being added?
--------------------
� StreamGenerator
� PostInputStream
StreamGenerator
The StreamGenerator is a class that reads XML from an HttpRequest InputStream and
generates SAX Events. StreamGenerator expects XML data coming as POST message.
For POST requests with mimetype of application/x-www-form-urlencoded, the xml data
expects to be associated with the name specified in the sitemap parameter.
For POST requests with mimetypes: text/plain, text/xml, application/xml the xml data
is in the body of the POST request and its length is specified by the value returned
by getContentLength() method.
PostInputStream
The StreamGenerator uses helper class org.apache.cocoon.util.PostInputStream for
InputStream reading operations. At the time that Parser reads the data out of
InputStream - Parser has no knowledge about the length of data to be read. The only
way to signal to the Parser that all data was read from the InputStream is to control
reading operation - PostInputStream- and to return to the requestor -1 when the
number of bytes read is equal to the getContentLength() value.
Installation Instructions
----------------------------
TO VIEW ABOVE COCOON ELEMENTS "IN ACTION":
Unzip the attached file. The necessary elements will "fall into place" within the
Cocoon code. Compile it using instruction in Cocoon install file. Since the generator
is a generic object, i.e. it can process any stream out of the POST message there are
two ways to see StreamGenerator in action:
1. To invoke URL http://localhost:8080/cocoon/Order
2. To use telnet program to generate POST request
The first option is not a "pure" stream invocation, but it is quick way to observe
desired effects. The result of this invocation is a form containing the XML document
embedded in the textarea of the form. Submission of this form will invoke
StreamGenerator. The testarea name/value par is specified as a parameter in the
sitemap definition for the StreamGenerator. The expected result is the submitted xml
document send back to the browser.
The second or "pure" option of testing StreamGenerator "in action," requires the use
of Telnet program or any other process able to generate correct POST message. The
procedure is:
� To invoke telnet, connect to localhost 8080 and to use content of telnet.txt
file as a post message.
� Here, the Copy-Paste method should be used.
� Remember to hit the enter button twice enter after the contents of the post
are set in telnet.
It is important because Content-len is calculated assuming two "enter" in the end of
http message. Once again, the performed task results in the mirror of the original
document being sent back to the requestor.
The "pure" stream generation can be observed using the telnet utility where you can
invoke a message targeting my processing. Any other method is good (URL object
connection) as long the message is well formed.
Compatibility Issues
------------------------
The attached code was tested and is compatible with the Cocoon codebase ver.2.0a7
taken from CVS Repository 5/26/2001.
The code was tested on Windows 2000 and NT 4.0 using Tomcatt 4.0-b5 and newest
Bluestone HP application server.
1.1 xml-cocoon2/webapp/docs/samples/stream/telnet.txt
Index: telnet.txt
===================================================================
POST /cocoon/request1 HTTP/1.1
Content-Type: text/plain
Content-Length:1513
<?xml version="1.0"?>
<Orders>
<OrderID>20259</OrderID>
<CustomerID>WWWWWWW</CustomerID>
<EmployeeID>6</EmployeeID>
<OrderDate>2001-05-05 00:00:00</OrderDate>
<RequiredDate>2001-06-05 00:00:00</RequiredDate>
<ShippedDate>2001-06-01 00:00:00</ShippedDate>
<ShipVia>1</ShipVia>
<Freight>11.6100</Freight>
<ShipName>Thoms White</ShipName>
<ShipAddress>Somestr. 48</ShipAddress>
<ShipCity>Munster</ShipCity>
<ShipRegion>West</ShipRegion>
<ShipPostalCode>00000</ShipPostalCode>
<ShipCountry>Germany</ShipCountry>
<OrderDetails>
<OrderID>20259</OrderID>
<ProductID>51</ProductID>
<UnitPrice>42.4000</UnitPrice>
<Quantity>40</Quantity>
<Discount>0.0</Discount>
</OrderDetails>
<OrderDetails>
<OrderID>20259</OrderID>
<ProductID>14</ProductID>
<UnitPrice>18.6000</UnitPrice>
<Quantity>9</Quantity>
<Discount>0.0</Discount>
</OrderDetails>
<OrderDetails>
<OrderID>20259</OrderID>
<ProductID>7</ProductID>
<UnitPrice>12.4000</UnitPrice>
<Quantity>30</Quantity>
<Discount>0.0</Discount>
</OrderDetails>
<Customers>
<CustomerID>WWWWWWW</CustomerID>
<CompanyName>Thomas White</CompanyName>
<ContactName>Karin Black</ContactName>
<ContactTitle>Marketing Manager</ContactTitle>
<Address>Somestr. 48</Address>
<City>Munster</City>
<Region>West</Region>
<PostalCode>00000</PostalCode>
<Country>Germany</Country>
<Phone>xxxx-yyyyyy</Phone>
<Fax>xxxx-yyyyyy</Fax>
</Customers>
</Orders>
----------------------------------------------------------------------
In case of troubles, e-mail: [EMAIL PROTECTED]
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]