/** * Copyright (C) 2004 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; import org.apache.log4j.Logger; import org.orbeon.dom.Element; import org.orbeon.dom.Node; import org.orbeon.dom.QName; import org.orbeon.oxf.common.OXFException; import org.orbeon.oxf.pipeline.api.PipelineContext; import org.orbeon.oxf.processor.generator.DOMGenerator; import org.orbeon.oxf.util.LoggerFactory; import org.orbeon.oxf.util.PipelineUtils; import org.orbeon.oxf.util.StringUtils; import org.orbeon.oxf.xml.XPathUtils; import org.orbeon.oxf.xml.dom4j.Dom4jUtils; import java.util.Iterator; public class XMLProcessorRegistry extends ProcessorImpl { static private Logger logger = LoggerFactory.createLogger(XMLProcessorRegistry.class); public static final String PROCESSOR_REGISTRY_CONFIG_NAMESPACE_URI = "http://www.orbeon.com/oxf/processor/processor-registry-config"; public XMLProcessorRegistry() { addInputInfo(new ProcessorInputOutputInfo(INPUT_CONFIG, PROCESSOR_REGISTRY_CONFIG_NAMESPACE_URI)); } public void start(final PipelineContext ctxt) { try { final Node cfg = readInputAsOrbeonDom(ctxt, INPUT_CONFIG); for (Iterator i = XPathUtils.selectNodeIterator(cfg, "/processors//processor"); i.hasNext();) { // support multiple nesting levels Element processorElement = (Element) i.next(); // Extract processor name final QName processorQName = extractProcessorQName(processorElement); final String processorURI = extractProcessorURI(processorElement);// [BACKWARD COMPATIBILITY] if (processorQName == null && processorURI == null) throw new OXFException("Missing or empty processor name!"); if (processorQName != null) logger.debug("Binding name: " + Dom4jUtils.qNameToExplodedQName(processorQName)); if (processorURI != null) logger.debug("Binding name: " + processorURI); // Defined as a class Node classDef = XPathUtils.selectSingleNode(processorElement, "class"); if (classDef != null) { final String className = XPathUtils.selectStringValueNormalize(classDef, "@name"); if (logger.isDebugEnabled()) logger.debug("To class: " + className); final String defaultName = (processorQName != null) ? Dom4jUtils.qNameToExplodedQName(processorQName) : processorURI; final QName defaultQName = (processorQName != null) ? processorQName : QName.get(processorURI); ProcessorFactory processorFactory = new ProcessorFactory() { public Processor createInstance() { try { Processor processor = (Processor) Class.forName(className).newInstance(); processor.setName(defaultQName); return processor; } catch (ClassNotFoundException e) { throw new OXFException("Cannot load processor '" + defaultName + "' because the class implementing this processor ('" + className + "') cannot be found"); } catch (NoClassDefFoundError e) { throw new OXFException("Cannot load processor '" + defaultName + "' because it needs a class that cannot be loaded: '" + e.getMessage() + "'"); } catch (Exception e) { throw new OXFException(e); } } }; if (processorQName != null) ProcessorFactoryRegistry.bind(processorQName, processorFactory); if (processorURI != null) ProcessorFactoryRegistry.bind(processorURI, processorFactory); } // Defined based on an other processor (instantiation) final Element instantiationDef = (Element) XPathUtils.selectSingleNode(processorElement, "instantiation"); if (instantiationDef != null) { ProcessorFactory processorFactory = new ProcessorFactory() { public Processor createInstance() { try { // Find base processor final QName processorQName = extractProcessorQName(instantiationDef); final String processorURI = extractProcessorURI(instantiationDef);// [BACKWARD COMPATIBILITY] if (processorQName == null && processorURI == null) throw new OXFException("Missing or empty processor name!"); if (processorQName != null) logger.debug("Binding name: " + Dom4jUtils.qNameToExplodedQName(processorQName)); if (processorURI != null) logger.debug("Binding name: " + processorURI); final QName defaultQName = (processorQName != null) ? processorQName : QName.get(processorURI); Processor baseProcessor = ((processorQName != null) ? ProcessorFactoryRegistry.lookup(processorQName) : ProcessorFactoryRegistry.lookup(processorURI)).createInstance(); // Override the name - can this have unexpected consequences? baseProcessor.setName(defaultQName); for (Iterator j = XPathUtils.selectNodeIterator(instantiationDef, "input"); j.hasNext();) { final Element inputElement = (Element) j.next(); final String name = XPathUtils.selectStringValueNormalize(inputElement, "@name"); final String href = XPathUtils.selectStringValueNormalize(inputElement, "@href"); if (href != null) { // Connect to URL generator Processor urlGenerator = PipelineUtils.createURLGenerator(href); PipelineUtils.connect(urlGenerator, OUTPUT_DATA, baseProcessor, name); } else { final ProcessorInput processorConfigInput = getInputByName(INPUT_CONFIG); final Object processorConfigValidity = getInputValidity(ctxt, processorConfigInput); // We must have some XML in the <input> tag final Element childElement = (Element) inputElement.elements().get(0); final String sid = Dom4jUtils.makeSystemId(childElement); final DOMGenerator domGenerator = PipelineUtils.createDOMGenerator (childElement, "input from registry", processorConfigValidity, sid); PipelineUtils.connect(domGenerator, OUTPUT_DATA, baseProcessor, name); } } return baseProcessor; } catch (Exception e) { throw new OXFException(e); } } }; if (processorQName != null) ProcessorFactoryRegistry.bind(processorQName, processorFactory); if (processorURI != null) ProcessorFactoryRegistry.bind(processorURI, processorFactory); } } } catch (Exception e) { throw new OXFException(e); } } public static QName extractProcessorQName(Element processorElement) { return Dom4jUtils.extractAttributeValueQName(processorElement, "name"); } public static String extractProcessorURI(Element processorElement) { // [BACKWARD COMPATIBILITY] Extract URI String uri = XPathUtils.selectStringValueNormalize(processorElement, "@uri"); if (uri == null || StringUtils.trimAllToEmpty(uri).length() == 0) return null; else return StringUtils.trimAllToEmpty(uri); } }