/*
* Copyright (c) 2002-2009 Juwi MacMillan Group GmbH (JuwiMM)
* Bockhorn 1, 29664 Walsrode, Germany
* All rights reserved.
*
* This software is the confidential and proprietary information of JuwiMM
* ("Confidential Information"). You shall not disclose such
* Confidential Information and shall use it only in accordance with the
* terms of the license agreement you entered into with JuwiMM.
*/
package org.tizzit.cocoon.generic.generation;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StringReader;
import java.util.Map;
import org.apache.avalon.framework.parameters.ParameterException;
import org.apache.avalon.framework.parameters.Parameters;
import org.apache.cocoon.ProcessingException;
import org.apache.cocoon.components.source.util.SourceUtil;
import org.apache.cocoon.core.xml.SAXParser;
import org.apache.cocoon.environment.ObjectModelHelper;
import org.apache.cocoon.environment.Request;
import org.apache.cocoon.environment.SourceResolver;
import org.apache.cocoon.generation.AbstractGenerator;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.excalibur.source.Source;
import org.apache.excalibur.source.SourceException;
import org.tizzit.cocoon.generic.helper.ParameterHelper;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
/**
* Generates the value of the <code>content</code> parameter or the input stream into SAX events.
* The <code>content</code> parameter has a higher priority and will be used, if the value is not null or empty!
*
* <h5>Configuration:</h5>
* <pre> <bean class="org.tizzit.cocoon.generic.generation.XMLRequestParserGenerator" name="org.apache.cocoon.generation.Generator/XMLRequestParserGenerator" scope="prototype">
* <property name="parser" ref="org.apache.cocoon.core.xml.SAXParser" />
* </bean></pre>
*
* <h5>Usage:</h5>
* <pre> <map:generate type="XMLRequestParserGenerator" /></pre>
*
* <h5>Usage with src attribute:</h5>
* <pre> <map:generate type="XMLRequestParserGenerator" src="cocoon://yourPipelineOrFile">
* <map:parameter name="forceUseSrcAttribute" value="true" /> <-- Possible values: true / yes / false / no -->
* </map:generate></pre>
*
* <h5>Parameters</h5>
* <ul>
* <li>
* INGOING (pipeline)<br/>
* <b>optional:</b>
* <ul>
* <li><b>forceUseSrcAttribute</b> - default: <code>false</code> - Set this parameter to <code>true</code> or <code>yes</code>. to provide a source with the <code>src</code> attribute.</li>
* <li><b>encoding</b> - default: <code>org.apache.cocoon.containerencoding</code> - fallback on errors: <code>UTF-8</code> - Overrides the Cocoon container encoding.</li>
* </ul>
* </li>
* <li>
* INGOING (request)<br/>
* <ul>
* <li><b>content</b> - XMl content, which will be converted into SAX events. The generator tries to convert the input stream into SAX events, if this parameter is empty or null!</li>
* </ul>
* </li>
* </ul>
*
* @author <a href="mailto:eduard.siebert@juwimm.com">Eduard Siebert</a>
* company Juwi MacMillan Group GmbH, Walsrode, Germany
* @version $Id$
* @since tizzit-cocoon-components 02.11.2009
*/
public class XMLRequestParserGenerator extends AbstractGenerator {
private static final Log log = LogFactory.getLog(XMLRequestParserGenerator.class);
private static final String PARAM_NAME_CONTENT = "content";
private static final String PARAM_NAME_ENCODING = "encoding";
private static final String PARAM_NAME_FORCE_USE_SRC_ATTRIBUTE = "forceUseSrcAttribute";
/**
* The encoding.
* <p>
* A parameter could be used, to set the encoding <code><map:parameter name="encoding" value="UTF-8"/></code>.<br/>
* Default value: <code>org.apache.cocoon.containerencoding</code>.<br/>
* Fallback value if an error occurred: <code>UTF-8</code>
* </p>
* <p>
* <b>Please make sure, that you use the same encoding in your tidy.properties (<code>char-encoding=utf8</code>).</b>
* </p>
*/
private String defaultEncoding = "UTF-8";
private boolean forceUseSrcAttribute = false;
private Source cocoonSource = null;
private Request request = null;
/** The SAX Parser. */
protected SAXParser parser;
/* (non-Javadoc)
* @see org.apache.cocoon.generation.AbstractGenerator#setup(org.apache.cocoon.environment.SourceResolver, java.util.Map, java.lang.String, org.apache.avalon.framework.parameters.Parameters)
*/
@SuppressWarnings("unchecked")
@Override
public void setup(SourceResolver resolver, Map objectModel, String src, Parameters par) throws ProcessingException, SAXException, IOException {
if (log.isDebugEnabled()) log.debug("setup() -> begin");
super.setup(resolver, objectModel, src, par);
this.request = ObjectModelHelper.getRequest(objectModel);
try {
this.forceUseSrcAttribute = ParameterHelper.booleanValue(par.getParameter(PARAM_NAME_FORCE_USE_SRC_ATTRIBUTE));
if (this.forceUseSrcAttribute) {
try {
this.cocoonSource = super.resolver.resolveURI(this.source);
} catch (SourceException se) {
throw SourceUtil.handle("Error during resolving of '" + this.source + "'.", se);
}
if (log.isDebugEnabled()) {
log.debug("Source " + super.source + " resolved to " + this.cocoonSource.getURI());
}
}
} catch (ParameterException exe) {
}
try {
this.defaultEncoding = par.getParameter(PARAM_NAME_ENCODING);
} catch (Exception exe) {
}
if (log.isDebugEnabled()) log.debug("setup() -> end");
}
/* (non-Javadoc)
* @see org.apache.cocoon.generation.Generator#generate()
*/
public void generate() throws IOException, SAXException, ProcessingException {
if (log.isDebugEnabled()) log.debug("generate() -> begin");
if (this.forceUseSrcAttribute) {
try {
SourceUtil.parse(this.parser, this.cocoonSource, super.xmlConsumer);
} catch (SAXException e) {
SourceUtil.handleSAXException(this.cocoonSource.getURI(), e);
}
} else {
String content = this.request.getParameter(PARAM_NAME_CONTENT);
if (StringUtils.isNotBlank(content)) {
if (log.isDebugEnabled()) log.debug("Found '" + PARAM_NAME_CONTENT + "' parameter. Parsing the value: \n" + content);
InputSource inputSource = new InputSource(new StringReader(content));
this.parser.parse(inputSource, this.contentHandler);
} else {
if (log.isDebugEnabled()) log.debug("Parameter '" + PARAM_NAME_CONTENT + "' is null or empty! Parsing the input stream...");
InputStream is = this.request.getInputStream();
int contentLength = 0;
try {
contentLength = Integer.parseInt(this.request.getHeader("Content-Length"));
} catch (Exception exe) {
log.warn("Could not parse Content-Length:" + exe.getMessage());
}
try {
if (is != null && contentLength > 0) {
InputSource inputSource = new InputSource(new InputStreamReader(is, this.defaultEncoding));
this.parser.parse(inputSource, this.contentHandler);
} else {
this.printErrorAsXML("Parameter '" + PARAM_NAME_CONTENT + "' and the input stream are null or empty! Please fill at least one of it!");
}
} catch (IOException exe) {
throw exe;
} catch (SAXException exe) {
throw exe;
} finally {
if (is != null) {
IOUtils.closeQuietly(is);
is = null;
}
}
}
}
if (log.isDebugEnabled()) log.debug("generate() -> end");
}
private void printErrorAsXML(String msg) throws IOException, SAXException {
if (log.isDebugEnabled()) log.debug("printErrorAsXML() -> begin");
log.warn(msg);
String error = "<error>";
error += msg;
error += "</error>";
InputSource inputSource = new InputSource(new StringReader(error));
this.parser.parse(inputSource, this.contentHandler);
if (log.isDebugEnabled()) log.debug("printErrorAsXML() -> end");
}
/**
* @param parser the parser to set
*/
public void setParser(SAXParser parser) {
this.parser = parser;
}
/* (non-Javadoc)
* @see org.apache.cocoon.generation.AbstractGenerator#recycle()
*/
@Override
public void recycle() {
super.recycle();
if (this.cocoonSource != null) {
super.resolver.release(this.cocoonSource);
this.cocoonSource = null;
}
}
/**
* @param defaultEncoding the defaultEncoding to set
*/
public void setDefaultEncoding(String defaultEncoding) {
this.defaultEncoding = defaultEncoding;
}
}