/**
* 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.xforms.function.xxforms;
import org.orbeon.dom.Document;
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.InitUtils;
import org.orbeon.oxf.pipeline.api.PipelineContext;
import org.orbeon.oxf.pipeline.api.ProcessorDefinition;
import org.orbeon.oxf.processor.DOMSerializer;
import org.orbeon.oxf.processor.Processor;
import org.orbeon.oxf.processor.ProcessorOutput;
import org.orbeon.oxf.resources.URLFactory;
import org.orbeon.oxf.util.PipelineUtils;
import org.orbeon.oxf.xforms.function.XFormsFunction;
import org.orbeon.oxf.xml.TransformerUtils;
import org.orbeon.oxf.xml.XMLConstants;
import org.orbeon.oxf.xml.dom4j.Dom4jUtils;
import org.orbeon.dom.saxon.DocumentWrapper;
import org.orbeon.saxon.expr.Expression;
import org.orbeon.saxon.expr.XPathContext;
import org.orbeon.saxon.om.*;
import org.orbeon.saxon.trans.XPathException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
* xxf:call-xpl() function.
*/
public class XXFormsCallXPL extends XFormsFunction {
public SequenceIterator iterate(XPathContext xpathContext) throws XPathException {
try {
// Get XPL URL
final URL xplURL;
{
Expression xplURIExpression = argument[0];
//xplURL = new URL(((AnyURIValue) xplURIExpression.evaluateItem(xpathContext)).getStringValue());
if (getSystemId() == null)
xplURL = URLFactory.createURL(xplURIExpression.evaluateAsString(xpathContext).toString());
else
xplURL = URLFactory.createURL(getSystemId(), xplURIExpression.evaluateAsString(xpathContext).toString());
}
// Get list of input names
final List<String> inputNames = new ArrayList<String>();
{
final Expression inputNamesExpression = argument[1];
final SequenceIterator i = inputNamesExpression.iterate(xpathContext);
Item currentItem;
while ((currentItem = i.next()) != null) {
inputNames.add(currentItem.getStringValue());
}
}
// Get list of input documents
final List<Item> inputNodeInfos = new ArrayList<Item>();
{
final Expression inputDocumentsExpression = argument[2];
final SequenceIterator i = inputDocumentsExpression.iterate(xpathContext);
Item currentItem;
while ((currentItem = i.next()) != null) {
inputNodeInfos.add(currentItem);
}
}
if (inputNames.size() != inputNodeInfos.size())
throw new OXFException("The length of sequence of input names (" + inputNames.size()
+ ") must be equal to the length of the sequence of input nodes (" + inputNodeInfos.size() + ").");//getDisplayName()
// Get list of output names
final List<String> outputNames = new ArrayList<String>();
{
final Expression inputNamesExpression = argument[3];
final SequenceIterator i = inputNamesExpression.iterate(xpathContext);
Item currentItem;
while ((currentItem = i.next()) != null) {
outputNames.add(currentItem.getStringValue());
}
}
// Create processor definition and processor
Processor processor;
{
ProcessorDefinition processorDefinition = new ProcessorDefinition(QName.get("pipeline", XMLConstants.OXF_PROCESSORS_NAMESPACE));
{
processorDefinition.addInput("config", xplURL.toExternalForm());
Iterator inputNodesIterator = inputNodeInfos.iterator();
for (final String inputName: inputNames) {
final NodeInfo inputNodeInfo = (NodeInfo) inputNodesIterator.next();
if (!(inputNodeInfo.getNodeKind() == org.w3c.dom.Node.ELEMENT_NODE || inputNodeInfo.getNodeKind() == org.w3c.dom.Node.DOCUMENT_NODE))
throw new OXFException("Input node must be a document or element for input name: " + inputName);
// TODO: We should be able to just pass inputNodeInfo to addInput() and avoid the conversions, but that doesn't work!
if (inputNodeInfo instanceof VirtualNode) {
// Get reference to dom4j node
final Element inputElement;
final Node inputNode = (Node) ((VirtualNode) inputNodeInfo).getUnderlyingNode();
if (inputNode instanceof Document)
inputElement = ((Document) inputNode).getRootElement();
else if (inputNode instanceof Element && inputNode.getParent() == null)
inputElement = (Element) inputNode;
else if (inputNode instanceof Element)
inputElement = Dom4jUtils.createDocumentCopyParentNamespaces((Element) inputNode).getRootElement();
else
throw new OXFException("Input node must be a document or element for input name: " + inputName);
processorDefinition.addInput(inputName, inputElement);
} else {
// Copy to dom4j
// final DocumentInfo inputDocumentInfo = TransformerUtils.readTinyTree(inputNodeInfo);
// processorDefinition.addInput(inputName, inputDocumentInfo);
final Document inputDocument = TransformerUtils.tinyTreeToDom4j(inputNodeInfo);
processorDefinition.addInput(inputName, inputDocument.getRootElement());
}
}
}
processor = InitUtils.createProcessor(processorDefinition);
}
final PipelineContext pipelineContext = PipelineContext.get();
processor.reset(pipelineContext);
if (outputNames.size() == 0) {
// Just run the processor
processor.start(pipelineContext);
return EmptyIterator.getInstance();
} else {
// Create all outputs to read
List<ProcessorOutput> outputs = new ArrayList<ProcessorOutput>(outputNames.size());
for (String outputName: outputNames) {
ProcessorOutput output = processor.createOutput(outputName);
outputs.add(output);
}
// Connect all DOM serializers
List<DOMSerializer> domSerializers = new ArrayList<DOMSerializer>(outputNames.size());
for (ProcessorOutput output: outputs) {
DOMSerializer domSerializer = new DOMSerializer();
PipelineUtils.connect(processor, output.getName(), domSerializer, "data");
domSerializers.add(domSerializer);
}
// Read all outputs in sequence
List<DocumentWrapper> results = new ArrayList<DocumentWrapper>(outputNames.size());
for (DOMSerializer domSerializer: domSerializers) {
results.add(new DocumentWrapper((Document) Dom4jUtils.normalizeTextNodes(domSerializer.runGetDocument(pipelineContext)), null,
xpathContext.getConfiguration()));
}
return new ListIterator(results);
}
} catch (XPathException e) {
throw e;
} catch (Exception e) {
throw new OXFException(e);
}
}
}