/**
* Copyright (C) 2010 Orbeon, Inc.
*
* This program is free software; you can redistribute it and/or modify it under the terms of the
* GNU Lesser General Public License as published by the Free Software Foundation; either version
* 2.1 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* The full text of the license is available at http://www.gnu.org/copyleft/lesser.html
*/
package org.orbeon.oxf.processor.generator;
import org.apache.log4j.Logger;
import org.orbeon.dom.Document;
import org.orbeon.dom.Element;
import org.exolab.castor.mapping.Mapping;
import org.exolab.castor.xml.Marshaller;
import org.orbeon.oxf.common.OXFException;
import org.orbeon.oxf.pipeline.api.*;
import org.orbeon.oxf.processor.*;
import org.orbeon.oxf.processor.impl.DigestState;
import org.orbeon.oxf.processor.impl.DigestTransformerOutputImpl;
import org.orbeon.oxf.util.LoggerFactory;
import org.orbeon.oxf.externalcontext.ExternalContext;
import org.orbeon.oxf.xml.*;
import org.orbeon.oxf.xml.XMLParsing;
import org.orbeon.oxf.xml.dom4j.Dom4jUtils;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.ParserAdapter;
import javax.xml.transform.dom.DOMSource;
import java.io.StringReader;
import java.util.*;
/**
* The Bean generator generates an XML document based on:
*
* o a JavaBean
* o a configuration (config and mapping inputs)
*
* NOTE: This processor is deprecated. Use ScopeGenerator instead.
*/
public class BeanGenerator extends ProcessorImpl {
public static final String BEAN_CONFIG_NAMESPACE_URI = "http://www.orbeon.com/oxf/bean";
public static final String INPUT_MAPPING = "mapping";
private static Logger logger = LoggerFactory.createLogger(BeanGenerator.class);
public BeanGenerator() {
addInputInfo(new ProcessorInputOutputInfo(INPUT_CONFIG, BEAN_CONFIG_NAMESPACE_URI));
addInputInfo(new ProcessorInputOutputInfo(INPUT_MAPPING));
addOutputInfo(new ProcessorInputOutputInfo(OUTPUT_DATA));
}
protected Config getConfig(PipelineContext context) {
return readCacheInputAsObject(context, getInputByName(INPUT_CONFIG),
new CacheableInputReader<Config>() {
public Config read(PipelineContext context, ProcessorInput input) {
Document dom = readInputAsOrbeonDom(context, input);
try {
Config config2 = new Config();
for (Iterator i = XPathUtils.selectNodeIterator(dom, "/config/attribute"); i.hasNext();) {
Element el = (Element) i.next();
config2.addAttribute(el.getTextTrim());
}
for (Iterator i = XPathUtils.selectNodeIterator(dom, "/config/source"); i.hasNext();) {
String s = ((Element) i.next()).getTextTrim();
if (s.equalsIgnoreCase("request"))
config2.addSource(Config.REQUEST);
else if (s.equalsIgnoreCase("session"))
config2.addSource(Config.SESSION);
else
throw new OXFException("Wrong source type: must be either request or session");
}
return config2;
} catch (Exception e) {
throw new OXFException(e);
}
}
});
}
protected Mapping getMapping(PipelineContext context) {
return readCacheInputAsObject(context, getInputByName(INPUT_MAPPING),
new CacheableInputReader<Mapping>() {
public Mapping read(PipelineContext context, ProcessorInput input) {
try {
// TransformerHandler identity = TransformerUtils.getXMLIdentityTransformerHandler();
// Result result = new StreamResult();
// identity.setResult(result);
//
// readInputAsSAX(context, input, identity);
// logger.warn(result.toString());
Document dom = readInputAsOrbeonDom(context, input);
Mapping mapping = new Mapping();
mapping.loadMapping(new InputSource(new StringReader(Dom4jUtils.domToString(dom))));
return mapping;
} catch (Exception e) {
throw new OXFException(e);
}
}
});
}
protected void readBean(PipelineContext context, Config config, Mapping mapping, XMLReceiver xmlReceiver) {
ExternalContext externalContext = (ExternalContext) context.getAttribute(PipelineContext.EXTERNAL_CONTEXT);
if (externalContext == null)
throw new OXFException("Missing external context in BeanGenerator");
try {
xmlReceiver.startDocument();
String rootElementName = "beans";
xmlReceiver.startElement("", rootElementName, rootElementName, SAXUtils.EMPTY_ATTRIBUTES);
// Initialize Castor
ParserAdapter adapter = new ParserAdapter(XMLParsing.newSAXParser(XMLParsing.ParserConfiguration.PLAIN).getParser());
adapter.setContentHandler(xmlReceiver);
Marshaller marshaller = new Marshaller(adapter);
marshaller.setMarshalAsDocument(false);
marshaller.setMapping(mapping);
for (Iterator atts = config.getAttributesIterator(); atts.hasNext();) {
String attName = (String) atts.next();
Object bean = getBean(attName, config.getSourcesIterator(), externalContext);
if (bean == null) {
// Create empty element
if (logger.isInfoEnabled())
logger.info("Bean " + attName + " is null");
xmlReceiver.startElement("", attName, attName, SAXUtils.EMPTY_ATTRIBUTES);
xmlReceiver.endElement("", attName, attName);
} else if (bean instanceof org.w3c.dom.Document) {
// W3C Document: send as-is
TransformerUtils.sourceToSAX(new DOMSource((org.w3c.dom.Document) bean), new EmbeddedDocumentXMLReceiver(xmlReceiver));
} else {
// Serialize with Castor
if (logger.isDebugEnabled())
logger.debug("Serializing bean" + attName + " value=" + bean);
marshaller.setRootElement(attName);
marshaller.marshal(bean);
}
}
xmlReceiver.endElement("", rootElementName, rootElementName);
xmlReceiver.endDocument();
} catch (Exception e) {
throw new OXFException(e);
}
}
public ProcessorOutput createOutput(String name) {
ProcessorOutput output = new DigestTransformerOutputImpl(BeanGenerator.this, name) {
public void readImpl(PipelineContext pipelineContext, XMLReceiver xmlReceiver) {
try {
State state = (State) getFilledOutState(pipelineContext);
state.beanStore.replay(xmlReceiver);
} catch (SAXException e) {
throw new OXFException(e);
}
}
protected byte[] computeDigest(PipelineContext pipelineContext, DigestState digestState) {
if (digestState.digest == null) {
fillOutState(pipelineContext, digestState);
}
return digestState.digest;
}
protected boolean fillOutState(PipelineContext pipelineContext, DigestState digestState) {
State state = (State) digestState;
if (state.beanStore == null) {
state.beanStore = new SAXStore();
final DigestContentHandler digester = new DigestContentHandler();
final TeeXMLReceiver tee = new TeeXMLReceiver(Arrays.asList(state.beanStore, digester));
readBean(pipelineContext, getConfig(pipelineContext), getMapping(pipelineContext), tee);
state.digest = digester.getResult();
}
return true;
}
};
addOutput(name, output);
return output;
}
private Object getBean(String name, Iterator sources, ExternalContext externalContext) {
Object bean = null;
ExternalContext.Request request = externalContext.getRequest();
for (; sources.hasNext();) {
Integer source = (Integer) sources.next();
if (Config.REQUEST.equals(source))
bean = request.getAttributesMap().get(name);
else if (Config.SESSION.equals(source))
bean = externalContext.getSession(true).javaGetAttribute(name);
if (bean != null)
return bean;
}
// If sources is empty, try the request by default
if (bean == null)
return request.getAttributesMap().get(name);
else
return bean;
}
private static class Config {
public static final Integer REQUEST = new Integer(0);
public static final Integer SESSION = new Integer(1);
List attributes;
List sources;
public Config() {
this.attributes = new ArrayList();
this.sources = new ArrayList();
}
public Config(List attributes, List sources) {
this.attributes = attributes;
this.sources = sources;
}
public void addAttribute(String attribute) {
attributes.add(attribute);
}
public void addSource(Integer source) {
if (REQUEST.equals(source) || SESSION.equals(source))
sources.add(source);
else
throw new OXFException("Adding wrong value to source list");
}
public Iterator getAttributesIterator() {
return attributes.iterator();
}
public Iterator getSourcesIterator() {
return sources.iterator();
}
}
public void reset(PipelineContext context) {
setState(context, new State());
}
private static class State extends DigestState {
public SAXStore beanStore;
}
}