All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.crabshue.commons.xproc.XprocRunner Maven / Gradle / Ivy

package com.crabshue.commons.xproc;

import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;

import javax.xml.transform.URIResolver;
import javax.xml.transform.sax.SAXSource;

import org.xml.sax.InputSource;

import com.crabshue.commons.exceptions.ApplicationException;
import com.crabshue.commons.xproc.exceptions.XProcErrorType;
import com.crabshue.commons.xproc.helper.ErrorTranslator;
import com.xmlcalabash.core.XProcConfiguration;
import com.xmlcalabash.core.XProcException;
import com.xmlcalabash.core.XProcMessageListener;
import com.xmlcalabash.core.XProcRuntime;
import com.xmlcalabash.io.ReadablePipe;
import com.xmlcalabash.runtime.XOutput;
import com.xmlcalabash.runtime.XPipeline;
import net.sf.saxon.s9api.DocumentBuilder;
import net.sf.saxon.s9api.ExtensionFunction;
import net.sf.saxon.s9api.Processor;
import net.sf.saxon.s9api.SaxonApiException;
import net.sf.saxon.s9api.XdmNode;

public class XprocRunner {

	final Processor saxon;
	private InputStream xproc;
	private Map inputs;
	private URIResolver resolver;
	private Class listener;

	private XprocRunner(boolean licensed) {
		saxon = new Processor(false);
		inputs = new HashMap<>();
	}

	private XprocRunner() {
		this(false);
	}

	public static XprocRunner of(InputStream xproc) {
		XprocRunner ret = new XprocRunner();
		if (xproc == null) {
			throw new ApplicationException(XProcErrorType.CANNOT_PARSE_INPUT,
					"Pipeline could not be parsed, null object provided");
		}
		ret.xproc = xproc;
		return ret;
	}

	public XprocRunner withExtensionFunction(ExtensionFunction function) {
		saxon.registerExtensionFunction(function);
		return this;
	}

	public XprocRunner withSource(InputStream xml) {
		return this.withInputPort("source", xml);
	}

	public XprocRunner withInputPort(String portName, InputStream xml) {
		this.inputs.put(portName, xml);
		return this;
	}

	public XprocRunner withErrorListener(Class listener) {
		this.listener = listener;
		return this;
	}

	public XprocRunner withUriResolver(URIResolver resolver) {
		this.resolver = resolver;
		return this;
	}

	public  XprocResult run(OutputPortHandler handler) {
		final XProcConfiguration config = new XProcConfiguration(saxon);
		if (listener != null)
			config.errorListener = listener.getName();
		final DocumentBuilder builder = saxon.newDocumentBuilder();
		final XProcRuntime runtime = new XProcRuntime(config);
		if (resolver != null)
			runtime.setURIResolver(resolver);
		// TODO: uncomment if you need to use the  within your pipeline...
		// runtime.setDataStore(new DatawarehouseDataStore(myBase,
		// runtime.getDataStore()));
		try {
			XdmNode pipeline = getNode(builder, xproc);
			final XPipeline xpipeline = runtime.use(pipeline);
			inputs.forEach((port, inputStream) -> {
				xpipeline.writeTo(port, getNode(builder, inputStream));
			});
			xpipeline.run();
			XprocResult ret = new XprocResult<>();

			xpipeline.getOutputs().forEach(port -> {
				final XOutput out = xpipeline.getOutput(port);
				final ReadablePipe outPipe = out.getReader();
				outPipe.canReadSequence(true);
				while (outPipe.moreDocuments()) {
					try {
						ret.add(port, handler.handle(saxon, port, outPipe.read()));
					} catch (SaxonApiException e) {
						throw new ApplicationException(XProcErrorType.XPROC_CANNOT_RETRIEVE_OUTPUT,
								"cannot retrieve the output port", e).addContextValue("port.name", port);
					}
				}
			});
			xpipeline.reset();
			return ret;
		} catch (SaxonApiException e) {
			throw new ApplicationException(XProcErrorType.ERROR_IN_PIPELINE, "cannot process the pipeline", e);
		} catch (XProcException e) {
			throw new ApplicationException(XProcErrorType.XPROC_ERROR, "cannot process the pipeline", e)
					.addContextValue("code", e.getErrorCode())
					.addContextValue("explanation", ErrorTranslator.translate(e.getErrorCode()));
		} finally {
			// FIXME: need to figure out...
			// function.reset();
			runtime.close();
		}
	}

	/**
	 * Transform inputStream into xPipeline compatible node.
	 * 
	 * @param builder
	 * @param inputStream
	 * @return
	 */
	private XdmNode getNode(DocumentBuilder builder, InputStream inputStream) {
		if (inputStream == null) {
			throw new ApplicationException(XProcErrorType.CANNOT_PARSE_INPUT,
					"Input could not be parsed, null object provided");
		}
		try {
			return builder.build(new SAXSource(new InputSource(inputStream)));
		} catch (SaxonApiException e) {
			throw new ApplicationException(XProcErrorType.CANNOT_PARSE_INPUT, "Input could not be parsed", e);
		}
	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy