org.callimachusproject.xproc.Pipeline.java Source code

Java tutorial

Introduction

Here is the source code for org.callimachusproject.xproc.Pipeline.java

Source

/*
 * Copyright (c) 2013 3 Round Stones Inc., Some Rights Reserved
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */
package org.callimachusproject.xproc;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.Enumeration;

import javax.xml.parsers.ParserConfigurationException;

import net.sf.saxon.s9api.SaxonApiException;
import net.sf.saxon.s9api.XdmNode;

import org.apache.http.client.HttpClient;
import org.callimachusproject.fluid.FluidType;
import org.callimachusproject.server.exceptions.InternalServerError;
import org.callimachusproject.xml.CloseableEntityResolver;
import org.callimachusproject.xml.CloseableURIResolver;
import org.callimachusproject.xml.DocumentFactory;
import org.callimachusproject.xml.XdmNodeFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.SAXException;

import com.xmlcalabash.core.XProcConfiguration;
import com.xmlcalabash.core.XProcConstants;
import com.xmlcalabash.core.XProcException;
import com.xmlcalabash.core.XProcRuntime;
import com.xmlcalabash.runtime.XPipeline;
import com.xmlcalabash.util.Base64;

public class Pipeline {
    private static final String XPROC_STEP = XProcConstants.c_data.getNamespaceURI();
    private static final String DATA = XProcConstants.c_data.getLocalName();
    private static final int bufSize = 912 * 8; // A multiple of 3, 4, and 75 for base64 line breaking

    private final HttpClient client;
    private final XProcConfiguration config;
    private final XdmNodeFactory resolver;
    private final String systemId;
    private final XdmNode pipeline;

    Pipeline(String systemId, HttpClient client) {
        assert systemId != null;
        this.systemId = systemId;
        this.client = client;
        this.config = null;
        this.resolver = null;
        this.pipeline = null;
    }

    Pipeline(InputStream in, String systemId, HttpClient client) throws SAXException, IOException {
        this.systemId = systemId;
        this.client = client;
        this.config = new XProcConfiguration("he", false);
        this.resolver = new XdmNodeFactory(config.getProcessor(), client);
        loadConfig(resolver, config);
        this.pipeline = resolver.parse(systemId, in);
    }

    Pipeline(Reader in, String systemId, HttpClient client) throws SAXException, IOException {
        this.systemId = systemId;
        this.client = client;
        this.config = new XProcConfiguration("he", false);
        this.resolver = new XdmNodeFactory(config.getProcessor(), client);
        loadConfig(resolver, config);
        this.pipeline = resolver.parse(systemId, in);
    }

    @Override
    public String toString() {
        if (systemId != null)
            return systemId;
        return super.toString();
    }

    public String getSystemId() {
        return systemId;
    }

    public Pipe pipe() throws SAXException, IOException {
        XProcConfiguration config = this.config;
        XdmNodeFactory resolver = this.resolver;
        if (config == null) {
            config = new XProcConfiguration("he", false);
            resolver = new XdmNodeFactory(config.getProcessor(), client);
            loadConfig(resolver, config);
        }
        return pipeSource(null, resolver, config);
    }

    public Pipe pipeStreamOf(InputStream source, String systemId, String media)
            throws SAXException, IOException, XProcException, ParserConfigurationException {
        XProcConfiguration config = this.config;
        XdmNodeFactory resolver = this.resolver;
        if (config == null) {
            config = new XProcConfiguration("he", false);
            resolver = new XdmNodeFactory(config.getProcessor(), client);
            loadConfig(resolver, config);
        }
        XdmNode xml = parse(systemId, source, media, config);
        return pipeSource(xml, resolver, config);
    }

    public Pipe pipeStream(InputStream source, String systemId) throws SAXException, IOException, XProcException {
        XProcConfiguration config = this.config;
        XdmNodeFactory resolver = this.resolver;
        if (config == null) {
            config = new XProcConfiguration("he", false);
            resolver = new XdmNodeFactory(config.getProcessor(), client);
            loadConfig(resolver, config);
        }
        XdmNode xml = resolver.parse(systemId, source);
        return pipeSource(xml, resolver, config);
    }

    public Pipe pipeReader(Reader reader, String systemId) throws SAXException, IOException, XProcException {
        XProcConfiguration config = this.config;
        XdmNodeFactory resolver = this.resolver;
        if (config == null) {
            config = new XProcConfiguration("he", false);
            resolver = new XdmNodeFactory(config.getProcessor(), client);
            loadConfig(resolver, config);
        }
        XdmNode xml = resolver.parse(systemId, reader);
        return pipeSource(xml, resolver, config);
    }

    private Pipe pipeSource(XdmNode source, XdmNodeFactory resolver, XProcConfiguration config)
            throws SAXException, IOException {
        Pipe pipe = null;
        XProcRuntime runtime = new XProcRuntime(config);
        try {
            CloseableURIResolver uriResolver = new CloseableURIResolver(resolver);
            CloseableEntityResolver entityResolver = new CloseableEntityResolver(resolver);
            runtime.setURIResolver(uriResolver);
            runtime.setEntityResolver(entityResolver);
            runtime.getResolver().setUnderlyingModuleURIResolver(resolver);
            runtime.getResolver().setUnderlyingUnparsedTextURIResolver(resolver);
            runtime.setHttpClient(client);
            XdmNode doc = this.pipeline;
            if (doc == null) {
                doc = resolver.parse(systemId);
            }
            if (doc == null)
                throw new InternalServerError("Missing pipeline: " + systemId);
            XPipeline xpipeline = runtime.use(doc);
            if (source != null) {
                xpipeline.writeTo("source", source);
            }
            return pipe = new Pipe(runtime, uriResolver, entityResolver, xpipeline, systemId);
        } catch (SaxonApiException e) {
            throw new SAXException(e);
        } finally {
            if (pipe == null) {
                runtime.setHttpClient(null);
                runtime.close();
            }
        }
    }

    private void loadConfig(XdmNodeFactory resolver, XProcConfiguration config) throws IOException {
        ClassLoader cl = getClass().getClassLoader();
        Enumeration<URL> resources = cl.getResources("META-INF/xmlcalabash.xml");
        while (resources.hasMoreElements()) {
            try {
                URL puri = resources.nextElement();
                InputStream in = puri.openStream();
                config.parse(resolver.parse(puri.toExternalForm(), in));
            } catch (SAXException sae) {
                throw new XProcException(sae);
            }
        }
    }

    private XdmNode parse(String systemId, InputStream source, String media, XProcConfiguration config)
            throws IOException, SAXException, ParserConfigurationException {
        if (source == null && media == null)
            return null;
        try {
            FluidType type = new FluidType(InputStream.class, media);
            if (type.isXML())
                return resolver.parse(systemId, source);
            Document doc = DocumentFactory.newInstance().newDocument();
            if (systemId != null) {
                doc.setDocumentURI(systemId);
            }
            Element data = doc.createElementNS(XPROC_STEP, DATA);
            data.setAttribute("content-type", media);
            if (type.isText()) {
                Charset charset = type.getCharset();
                if (charset == null) {
                    charset = Charset.forName("UTF-8");
                }
                if (source != null) {
                    appendText(new InputStreamReader(source, charset), doc, data);
                }
            } else if (source != null) {
                data.setAttribute("encoding", "base64");
                appendBase64(source, doc, data);
            }

            doc.appendChild(data);
            return config.getProcessor().newDocumentBuilder().wrap(doc);
        } finally {
            if (source != null) {
                source.close();
            }
        }
    }

    private void appendText(InputStreamReader reader, Document doc, Element data) throws IOException {
        char buf[] = new char[bufSize];
        int len = reader.read(buf, 0, bufSize);
        while (len >= 0) {
            data.appendChild(doc.createTextNode(new String(buf, 0, len)));
            len = reader.read(buf, 0, bufSize);
        }
    }

    private void appendBase64(InputStream source, Document doc, Element data) throws IOException {
        byte bytes[] = new byte[bufSize];
        int pos = 0;
        int readLen = bufSize;
        int len = source.read(bytes, 0, bufSize);
        while (len >= 0) {
            pos += len;
            readLen -= len;
            if (readLen == 0) {
                data.appendChild(doc.createTextNode(Base64.encodeBytes(bytes)));
                pos = 0;
                readLen = bufSize;
            }

            len = source.read(bytes, pos, readLen);
        }

        if (pos > 0) {
            byte lastBytes[] = new byte[pos];
            System.arraycopy(bytes, 0, lastBytes, 0, pos);
            data.appendChild(doc.createTextNode(Base64.encodeBytes(lastBytes)));
        }
    }

}