Hi Andrew,
Attached is the source code of the transformer I use with cocoon 2.1.10
to post XML to a webservice. You are free to give it a try and modify to
your requirements.
Feel free to change the package name (which is set to
com.franco.pipeline.contenthandler and com.franco.pipeline.transformation).
You will probably wish to change the namespace that it consumes (from
urn:franco.com.au:httppost).
Once you make these changes compile and package into cocoon (or just
drop the class files into WEB-INF/classes directory (which is what I do)
and generate XML (via pipeline) that looks like:
<post:post xmlns:post="urn:franco.com.au:httppost"
url="http://someurl...."> <!-- remember change post namespace -->
<post:request-property name="Content-Type" value="text/xml"/>
<post:message>
/xml to post goes here.../
</post:message>
</post:post>
main cocoon sitemap config looks like:
<map:transformer logger="sitemap.transformer.log" name="httppost"
pool-grow="2" pool-max="16" pool-min="2"
src="com.franco.pipeline.transformation.HTTPPostTransformer"/> <!--
remember to change package name -->
and example usage sitemap match may looks like:
<map:pipeline>
<map:match pattern="*">
<map:select type="request-method">
<map:when test="PUT">
<map:generate type="stream"/>
<map:transform src="xslt/putRequest.xsl" type="xslt-saxon">
<map:parameter name="id" value="{1}"/>
</map:transform>
<map:transform type="httppost"/>
...
</map:when>
</map:select>
<map:serialize type="xml"/>
</map:match>
</map:pipeline>
Hope this is usefull for you.
Regards,
Franco
Andrew Chamberlain wrote:
Hi All,
Just wondering if anyone can help. As part of a service I'm
constructing, I need to send an XML request to an external service by
HTTP Post. For this, I'm looking at using the CInclude transformer,
but all the examples I can find seem to use a parameter to pass the
data, rather than sending it as part of the payload (which the
external service expects).
Has anyone managed to do this, or am I looking at the need for an
external Java class? Any advice/ideas would be much appreciated.
I'm using Cocoon (2.1.10) under JBoss (4.0.5 GA).
Many thanks,
Andy
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]
package com.franco.pipeline.contenthandler;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.ListIterator;
public class StringBufferContentHandler extends DefaultHandler
{
private LinkedList namespaceStack = new LinkedList();
private StringBuffer stringBuffer;
public StringBufferContentHandler(StringBuffer pStringBuffer)
{
this.stringBuffer = pStringBuffer;
}
public void startPrefixMapping(String pPrefix, String pNamespaceURI)
throws SAXException
{
this.namespaceStack.addFirst(
new NamespacePrefixData(pPrefix, pNamespaceURI));
}
public void endPrefixMapping(String pPrefix) throws SAXException
{
// endElement should have removed all the NamespacePrefixDatas
// for the element
}
public void startElement(
String pNamespaceURI,
String pLocalElementName,
String pQualifiedElementName,
Attributes pElementAttributes)
throws SAXException
{
// lets us make sure that the all prefixes
// are associated with an elementName
// if there are any that are free then
// it belongs to the current Element.
ListIterator lListIterator = this.namespaceStack.listIterator();
while (lListIterator.hasNext())
{
NamespacePrefixData lNamespacePrefixData =
(NamespacePrefixData) lListIterator.next();
if (lNamespacePrefixData.qualifiedElementName == null)
{
lNamespacePrefixData.qualifiedElementName =
pQualifiedElementName;
}
else
{
// All the other NamespacePrefixData should have
// element names associated with them
break;
}
}
this.stringBuffer.append("<").append(pQualifiedElementName);
int lNumAttributes = pElementAttributes.getLength();
for (int lAttributeIndex = 0;
lAttributeIndex < lNumAttributes;
lAttributeIndex++)
{
// Check if the attribute is a namespace declaration. Some
// parsers (Xerces) sometimes pass the namespace declaration
// as an attribute. We need to catch this case so that we
// don't end up generating the namespace declaration twice.
String lAttributeQualifiedName =
pElementAttributes.getQName(lAttributeIndex);
if (lAttributeQualifiedName.startsWith("xmlns:")
|| lAttributeQualifiedName.equals("xmlns"))
{
// We have a namespace declaration
String lxmlnsAttributePrefixName =
pElementAttributes.getLocalName(lAttributeIndex);
// Check whether this namespace has been already declared
boolean lFound = false;
ListIterator lNSIterator = this.namespaceStack.listIterator();
while (lNSIterator.hasNext())
{
NamespacePrefixData lNamespacePrefixData =
(NamespacePrefixData) lNSIterator.next();
if (pQualifiedElementName
.equals(lNamespacePrefixData.qualifiedElementName))
{
if (lxmlnsAttributePrefixName
.equals(lNamespacePrefixData.prefix))
{
lFound = true;
break;
}
}
else
{
// All the other NamespacePrefixData should belong
// to a different element
break;
}
}
if (!lFound)
{
this.namespaceStack.addFirst(
new NamespacePrefixData(
lxmlnsAttributePrefixName,
pElementAttributes.getValue(lAttributeIndex),
pQualifiedElementName));
}
}
else
{
// Normal attribute
this.stringBuffer.append(" ");
this.stringBuffer.append(
pElementAttributes.getQName(lAttributeIndex));
this.stringBuffer.append("=\"");
escape(
this.stringBuffer,
pElementAttributes.getValue(lAttributeIndex));
this.stringBuffer.append("\"");
}
}
// This is where we add all the active namespace tags
// We only want to add the prefix once.
HashSet lDefinedPrefixes = new HashSet();
ListIterator lNSIterator = this.namespaceStack.listIterator();
while (lNSIterator.hasNext())
{
NamespacePrefixData lNamespacePrefixData =
(NamespacePrefixData) lNSIterator.next();
if (pQualifiedElementName
.equals(lNamespacePrefixData.qualifiedElementName))
{
// if it is already defined just go to the next one
if (lDefinedPrefixes.contains(lNamespacePrefixData.prefix))
{
continue;
}
lDefinedPrefixes.add(lNamespacePrefixData.prefix);
if ("".equals(lNamespacePrefixData.prefix))
{
// Default namespace
this.stringBuffer.append(" xmlns");
this.stringBuffer.append("=\"");
this.stringBuffer.append(lNamespacePrefixData.namespaceURI);
this.stringBuffer.append("\"");
}
else
{
this.stringBuffer.append(" xmlns:");
this.stringBuffer.append(lNamespacePrefixData.prefix);
this.stringBuffer.append("=\"");
this.stringBuffer.append(lNamespacePrefixData.namespaceURI);
this.stringBuffer.append("\"");
}
}
else
{
// All the other NamespacePrefixData should belong
// to a different element
break;
}
}
this.stringBuffer.append(">");
}
public void endElement(
String pNamespaceURI,
String pLocalElementName,
String pQualifiedElementName)
throws SAXException
{
this.stringBuffer.append("</");
this.stringBuffer.append(pQualifiedElementName);
this.stringBuffer.append(">");
// remove all the namespace prefix pairs for this element
ListIterator lNSIterator = this.namespaceStack.listIterator();
while (lNSIterator.hasNext())
{
NamespacePrefixData lNamespacePrefixData =
(NamespacePrefixData) lNSIterator.next();
if (pQualifiedElementName
.equals(lNamespacePrefixData.qualifiedElementName))
{
lNSIterator.remove();
}
else
{
// All the other NamespacePrefixData should belong
// to a different element
break;
}
}
}
public void characters(char ch[], int start, int len) throws SAXException
{
escape(stringBuffer, ch, start, len);
}
/**
* Copies string into buffer and
* escapes all '<', '&' and '>' chars in the string with
* corresponding entities.
*/
private static void escape(StringBuffer buffer, String s)
{
char[] ch = s.toCharArray();
escape(buffer, ch, 0, ch.length);
}
/**
* Copies characters from the char array into buffer and
* escapes all '<', '&' and '>' chars with corresponding
* entities.
*/
private static void escape(
StringBuffer buffer,
char ch[],
int start,
int len)
{
for (int i = start; i < start + len; i++)
{
switch (ch[i])
{
case '<' :
buffer.append("<");
break;
case '&' :
buffer.append("&");
break;
case '>' :
buffer.append(">");
break;
default :
buffer.append(ch[i]);
break;
}
}
}
/**
* NamespacePrefixData. A helper class that just stores
* prefix, namespace and element information.
*/
class NamespacePrefixData
{
public String prefix;
public String namespaceURI;
public String qualifiedElementName;
NamespacePrefixData(String pPrefix, String pNamespaceURI)
{
this.prefix = pPrefix;
this.namespaceURI = pNamespaceURI;
this.qualifiedElementName = null;
}
NamespacePrefixData(
String pPrefix,
String pNamespaceURI,
String pQualifiedElementName)
{
this.prefix = pPrefix;
this.namespaceURI = pNamespaceURI;
this.qualifiedElementName = pQualifiedElementName;
}
public String toString()
{
return this.prefix + "=" + this.namespaceURI;
}
}
}
package com.franco.pipeline.transformation;
import java.io.IOException;
import java.io.StringReader;
import java.net.URL;
import java.net.URLConnection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import org.apache.avalon.excalibur.pool.Recyclable;
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.component.Composable;
import org.apache.avalon.framework.parameters.Parameters;
import org.apache.cocoon.ProcessingException;
import org.apache.cocoon.environment.SourceResolver;
import org.apache.cocoon.transformation.AbstractTransformer;
import org.apache.excalibur.xml.sax.SAXParser;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.InputSource;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import com.franco.pipeline.contenthandler.StringBufferContentHandler;
/**
* The HTTPPostTransformer posts all markup between the tags to a given URL.
* It consumes the <em>urn:franco.com.au:httppost</em> namespace and
* returns just the xml from the given url. In the case where the website
* returns plain text, the <em>returns-xml</em> attribute of the post
* element should be set to <em>no</em>. This will wrap the text in a
* set of <em>post-result</em> tags.
*/
public class HTTPPostTransformer
extends AbstractTransformer
implements Recyclable, Composable {
public static String STREAM_CHARSET = "UTF-8";
public int READ_BUFFER_SIZE = 2000;
public static String POST_NAMESPACE = "urn:franco.com.au:httppost";
public static String POST_ELEMENT_NAME = "post";
public static String POST_ATTRIBUTE_URL = "url";
public static String POST_ATTRIBUTE_RETURNS_XML = "returns-xml";
public static String POST_RESULT_ELEMENT_NAME = "post-result";
public static String POST_RESULT_PREFIX = "post";
public static String REQUEST_PROPERTY_ELEMENT_NAME = "request-property";
public static String REQUEST_PROPERTY_ATTRIBUTE_NAME = "name";
public static String REQUEST_PROPERTY_ATTRIBUTE_VALUE = "value";
public static String MESSAGE_ELEMENT_NAME = "message";
private ComponentManager manager;
private String targetUrl;
private boolean posting = false;
private SourceResolver resolver;
private StringBufferContentHandler capturePostalContentHandler;
private StringBuffer postalContent;
private Map requestProperties;
private boolean returnsXML = true;
/**
*/
public void setup(
SourceResolver resolver,
Map objectModel,
String source,
Parameters parameters)
throws ProcessingException, SAXException, IOException {
this.refresh();
this.resolver = resolver;
}
/**
*/
public void compose(ComponentManager componentManager)
throws ComponentException {
this.manager = componentManager;
}
/**
*/
public void recycle() {
this.refresh();
super.recycle();
}
public void startElement(
String pNamespace,
String pLocalName,
String pQualifiedName,
Attributes pAttributes)
throws SAXException {
if (pNamespace.equals(POST_NAMESPACE)) {
getLogger().debug("pQualifiedName: " + pQualifiedName);
if (pLocalName.equals(POST_ELEMENT_NAME)) {
this.targetUrl = pAttributes.getValue(POST_ATTRIBUTE_URL);
String lReturnsXML =
pAttributes.getValue(POST_ATTRIBUTE_RETURNS_XML);
this.returnsXML = true;
if (lReturnsXML != null
&& (lReturnsXML.equalsIgnoreCase("no")
|| lReturnsXML.equalsIgnoreCase("false"))) {
this.returnsXML = false;
}
if (getLogger().isDebugEnabled()) {
getLogger().debug(
POST_ATTRIBUTE_URL + ": " + this.targetUrl);
getLogger().debug(
POST_ATTRIBUTE_RETURNS_XML + ": " + this.returnsXML);
}
}
else if (pLocalName.equals(MESSAGE_ELEMENT_NAME)) {
this.posting = true;
} else if (pLocalName.equals(REQUEST_PROPERTY_ELEMENT_NAME)) {
String lPropertyName =
pAttributes.getValue(REQUEST_PROPERTY_ATTRIBUTE_NAME);
String lPropertyValue =
pAttributes.getValue(REQUEST_PROPERTY_ATTRIBUTE_VALUE);
if (getLogger().isDebugEnabled()) {
getLogger().debug(
REQUEST_PROPERTY_ELEMENT_NAME
+ ": "
+ lPropertyName
+ " = "
+ lPropertyValue);
}
this.requestProperties.put(lPropertyName, lPropertyValue);
} else {
String lMessage =
pQualifiedName
+ " is not in the "
+ POST_NAMESPACE
+ " namespace.";
SAXException lSAXException = new SAXException(lMessage);
throw lSAXException;
}
} else if (this.posting) {
this.capturePostalContentHandler.startElement(
pNamespace,
pLocalName,
pQualifiedName,
pAttributes);
} else {
super.startElement(
pNamespace,
pLocalName,
pQualifiedName,
pAttributes);
}
}
public void endElement(
String pNamespace,
String pLocalName,
String pQualifiedName)
throws SAXException {
if (pNamespace.equals(POST_NAMESPACE)) {
if (pLocalName.equals(POST_ELEMENT_NAME)) {
this.refresh();
}
if (pLocalName.equals(MESSAGE_ELEMENT_NAME)) {
this.posting = false;
SAXParser lSAXParser = null;
try {
URL lUrl;
lUrl = new URL(this.targetUrl);
URLConnection lURLConnection;
lURLConnection = lUrl.openConnection();
lURLConnection.setDoOutput(true);
Iterator lRequestPropertyIterator =
this.requestProperties.entrySet().iterator();
while (lRequestPropertyIterator.hasNext()) {
Map.Entry lRequestPropertyEntry =
(Map.Entry) lRequestPropertyIterator.next();
lURLConnection.setRequestProperty(
(String) lRequestPropertyEntry.getKey(),
(String) lRequestPropertyEntry.getValue());
}
if (getLogger().isInfoEnabled()) {
getLogger().info("Sending to " + this.targetUrl);
getLogger().info(this.postalContent.toString());
}
lURLConnection.getOutputStream().write(
this.postalContent.toString().getBytes());
InputSource lInputSource = null;
if (this.returnsXML) {
lInputSource =
new InputSource(lURLConnection.getInputStream());
} else {
// if the returned data is not xml
// let us assume that is is straight boring text
// it should be sufficient in most cases to just
// place tags around it to turn it into xml.
// this may need to be revisited
// TODO run output from the lURLConnection through an encoding
function
byte lByte[] = new byte[READ_BUFFER_SIZE];
StringBuffer lStringBuffer = new StringBuffer();
lStringBuffer.append("<");
lStringBuffer.append(POST_RESULT_PREFIX);
lStringBuffer.append(":");
lStringBuffer.append(POST_RESULT_ELEMENT_NAME);
lStringBuffer.append(" xmlns:");
lStringBuffer.append(POST_RESULT_PREFIX);
lStringBuffer.append("='");
lStringBuffer.append(POST_NAMESPACE);
lStringBuffer.append("'>");
int lByteCount = 0;
while (true) {
lByteCount =
lURLConnection.getInputStream().read(lByte);
if (lByteCount < 0) {
break;
}
lStringBuffer.append(
new String(lByte, 0, lByteCount));
}
lStringBuffer.append("</");
lStringBuffer.append(POST_RESULT_PREFIX);
lStringBuffer.append(":");
lStringBuffer.append(POST_RESULT_ELEMENT_NAME);
lStringBuffer.append(">");
if (getLogger().isInfoEnabled()) {
getLogger().info(
"Receiving from " + this.targetUrl);
getLogger().info(lStringBuffer.toString());
}
lInputSource =
new InputSource(
new StringReader(lStringBuffer.toString()));
}
// we need to filter out the startDocument and endDocument
// calls
FilterContentHandler lFilterContentHandler =
new FilterContentHandler(this);
lSAXParser =
(SAXParser) this.manager.lookup(SAXParser.ROLE);
lSAXParser.parse(lInputSource, lFilterContentHandler);
} catch (Exception lException) {
String lMessage =
"HTTPostTransformer endElement issues: pNamespace["
+ pNamespace
+ "] pQualifiedName ["
+ pQualifiedName
+ "] targetUrl ["
+ this.targetUrl
+ "] postalContent ["
+ this.postalContent.toString()
+ "]";
SAXException lSAXException =
new SAXException(lMessage, lException);
getLogger().error(lMessage, lSAXException);
throw lSAXException;
} finally {
this.manager.release((Component) lSAXParser);
}
}
} else if (this.posting) {
this.capturePostalContentHandler.endElement(
pNamespace,
pLocalName,
pQualifiedName);
} else {
super.endElement(pNamespace, pLocalName, pQualifiedName);
}
}
public void characters(char[] c, int start, int len) throws SAXException {
if (this.posting) {
this.capturePostalContentHandler.characters(c, start, len);
} else {
super.characters(c, start, len);
}
}
public void startPrefixMapping(
String pNamespacePrefix,
String pNamespaceURI)
throws SAXException {
this.capturePostalContentHandler.startPrefixMapping(
pNamespacePrefix,
pNamespaceURI);
super.startPrefixMapping(pNamespacePrefix, pNamespaceURI);
}
public void endPrefixMapping(String pNamespacePrefix) throws SAXException {
this.capturePostalContentHandler.endPrefixMapping(pNamespacePrefix);
super.endPrefixMapping(pNamespacePrefix);
}
private void refresh() {
this.postalContent = new StringBuffer();
this.capturePostalContentHandler =
new StringBufferContentHandler(this.postalContent);
this.targetUrl = null;
this.posting = false;
this.returnsXML = true;
this.requestProperties = new HashMap();
}
/**
* FilterContentHandler removes all start and end documents tags.
*/
class FilterContentHandler implements ContentHandler {
private ContentHandler parentContentHandler = null;
/**
*/
FilterContentHandler(ContentHandler pContentHandler) {
parentContentHandler = pContentHandler;
}
public void characters(char[] ch, int start, int length)
throws SAXException {
parentContentHandler.characters(ch, start, length);
}
public void endDocument() throws SAXException {
// just consume the tag !!!
}
public void endElement(String uri, String localName, String qName)
throws SAXException {
parentContentHandler.endElement(uri, localName, qName);
}
public void endPrefixMapping(String prefix) throws SAXException {
parentContentHandler.endPrefixMapping(prefix);
}
public void ignorableWhitespace(char[] ch, int start, int length)
throws SAXException {
parentContentHandler.ignorableWhitespace(ch, start, length);
}
public void processingInstruction(String target, String data)
throws SAXException {
parentContentHandler.processingInstruction(target, data);
}
public void setDocumentLocator(Locator locator) {
// just ignore it
}
public void skippedEntity(String name) throws SAXException {
parentContentHandler.skippedEntity(name);
}
public void startDocument() throws SAXException {
// just ignore it!!
}
public void startElement(
String uri,
String localName,
String qName,
Attributes atts)
throws SAXException {
parentContentHandler.startElement(uri, localName, qName, atts);
}
public void startPrefixMapping(String prefix, String uri)
throws SAXException {
parentContentHandler.startPrefixMapping(prefix, uri);
}
}
}---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]