/** * 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; } }