com.netspective.commons.xml.ParseContext.java Source code

Java tutorial

Introduction

Here is the source code for com.netspective.commons.xml.ParseContext.java

Source

/*
 * Copyright (c) 2000-2004 Netspective Communications LLC. All rights reserved.
 *
 * Netspective Communications LLC ("Netspective") permits redistribution, modification and use of this file in source
 * and binary form ("The Software") under the Netspective Source License ("NSL" or "The License"). The following
 * conditions are provided as a summary of the NSL but the NSL remains the canonical license and must be accepted
 * before using The Software. Any use of The Software indicates agreement with the NSL.
 *
 * 1. Each copy or derived work of The Software must preserve the copyright notice and this notice unmodified.
 *
 * 2. Redistribution of The Software is allowed in object code form only (as Java .class files or a .jar file
 *    containing the .class files) and only as part of an application that uses The Software as part of its primary
 *    functionality. No distribution of the package is allowed as part of a software development kit, other library,
 *    or development tool without written consent of Netspective. Any modified form of The Software is bound by these
 *    same restrictions.
 *
 * 3. Redistributions of The Software in any form must include an unmodified copy of The License, normally in a plain
 *    ASCII text file unless otherwise agreed to, in writing, by Netspective.
 *
 * 4. The names "Netspective", "Axiom", "Commons", "Junxion", and "Sparx" are trademarks of Netspective and may not be
 *    used to endorse or appear in products derived from The Software without written consent of Netspective.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" WITHOUT A WARRANTY OF ANY KIND. ALL EXPRESS OR IMPLIED REPRESENTATIONS AND
 * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT,
 * ARE HEREBY DISCLAIMED.
 *
 * NETSPECTIVE AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE OR ANY THIRD PARTY AS A
 * RESULT OF USING OR DISTRIBUTING THE SOFTWARE. IN NO EVENT WILL NETSPECTIVE OR ITS LICENSORS BE LIABLE FOR ANY LOST
 * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER
 * CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THE SOFTWARE, EVEN
 * IF IT HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
 */
package com.netspective.commons.xml;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.OptionBuilder;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.commons.cli.PosixParser;
import org.apache.commons.lang.StringUtils;
import org.xml.sax.InputSource;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;

import com.netspective.commons.io.FileTracker;
import com.netspective.commons.io.InputSourceTracker;
import com.netspective.commons.io.Resource;
import com.netspective.commons.io.URLTracker;
import com.netspective.commons.xml.template.TemplateCatalog;

public class ParseContext {
    private static final String TRANSFORM_INSTRUCTION = "transform";
    private static SAXParserFactory parserFactory;
    private static CommandLineParser CLPARSER = new PosixParser();
    private static Options TRANSFORM_OPTIONS = new Options();

    static {
        Option styleSheetOption = OptionBuilder.withLongOpt("xslt").withArgName("style-sheet").hasArg()
                .withValueSeparator(',').withDescription("XSLT style-sheet file").create("s");
        Option resourceOption = OptionBuilder.withLongOpt("resource").create("r");
        TRANSFORM_OPTIONS.addOption(styleSheetOption);
        TRANSFORM_OPTIONS.addOption(resourceOption);
    }

    private TemplateCatalog templateCatalog;
    private ParseContext parentPC;
    private String sourceText;
    private File sourceFile;
    private FileInputStream activeFileInputStream;
    private Resource sourceResource;
    private ZipFile sourceJarFile;
    private ZipEntry sourceJarEntry;

    private InputSourceTracker parentSrcTracker;
    private InputSourceTracker inputSrcTracker;
    private InputSource inputSource;
    private XMLReader parser;
    private Locator locator;
    private boolean throwErrorException;
    private List errors;
    private List warnings;
    private Source[] transformSources;

    public ParseContext(ParseContext parentPC, String text) throws ParserConfigurationException, SAXException {
        this.parentPC = parentPC;
        if (parentPC != null)
            setParentSrcTracker(parentPC.getInputSrcTracker());
        init(createInputSource(text));
    }

    public ParseContext(ParseContext parentPC, File srcFile)
            throws ParserConfigurationException, SAXException, FileNotFoundException {
        this.parentPC = parentPC;
        if (parentPC != null)
            setParentSrcTracker(parentPC.getInputSrcTracker());
        init(createInputSource(srcFile));
    }

    public ParseContext(ParseContext parentPC, Resource resource)
            throws ParserConfigurationException, SAXException, IOException {
        this.parentPC = parentPC;
        if (parentPC != null)
            setParentSrcTracker(parentPC.getInputSrcTracker());
        init(createInputSource(resource));
    }

    public ParseContext(ParseContext parentPC, File jarFile, ZipEntry jarFileEntry)
            throws ParserConfigurationException, SAXException, FileNotFoundException, IOException {
        this.parentPC = parentPC;
        if (parentPC != null)
            setParentSrcTracker(parentPC.getInputSrcTracker());
        init(createInputSource(jarFile, jarFileEntry));
    }

    public ParseContext getParentPC() {
        return parentPC;
    }

    public InputSourceTracker getParentSrcTracker() {
        return parentSrcTracker;
    }

    public void setParentSrcTracker(InputSourceTracker parentSrcTracker) {
        this.parentSrcTracker = parentSrcTracker;
    }

    public TemplateCatalog getTemplateCatalog() {
        if (templateCatalog == null && parentPC != null)
            return parentPC.getTemplateCatalog();

        return templateCatalog;
    }

    public void setTemplateCatalog(TemplateCatalog templateCatalog) {
        this.templateCatalog = templateCatalog;
    }

    public String getTransformInstruction() {
        return TRANSFORM_INSTRUCTION;
    }

    public InputSource createInputSource(String text) {
        this.sourceText = text;
        InputSource is = new InputSource(new StringReader(text));
        is.setSystemId("text://");
        return is;
    }

    public InputSource createInputSource(File srcFile) throws FileNotFoundException {
        String uri = "file:" + srcFile.getAbsolutePath().replace('\\', '/');
        for (int index = uri.indexOf('#'); index != -1; index = uri.indexOf('#')) {
            uri = uri.substring(0, index) + "%23" + uri.substring(index + 1);
        }

        activeFileInputStream = new FileInputStream(srcFile);
        BufferedInputStream inputStream = new BufferedInputStream(activeFileInputStream);
        InputSource inputSource = new InputSource(inputStream);
        inputSource.setSystemId(uri);

        this.inputSrcTracker = new FileTracker();
        ((FileTracker) this.inputSrcTracker).setFile(srcFile);
        if (parentSrcTracker != null)
            this.inputSrcTracker.setParent(parentSrcTracker);
        this.sourceFile = srcFile;

        return inputSource;
    }

    public InputSource createInputSource(Resource resource) throws IOException {
        this.sourceResource = resource;

        InputStream stream = resource.getResourceAsStream();
        if (stream != null) {
            InputSource inputSource = new InputSource(stream);
            inputSource.setSystemId(resource.getSystemId());

            this.inputSrcTracker = new URLTracker();
            ((URLTracker) this.inputSrcTracker).setUrl(resource.getResource());
            if (parentSrcTracker != null)
                this.inputSrcTracker.setParent(parentSrcTracker);

            return inputSource;
        } else
            throw new IOException("Resource '" + resource.getSystemId() + "' not found. ClassPath is "
                    + System.getProperty("java.class.path") + ".");
    }

    public InputSource createInputSource(File jarFile, ZipEntry jarFileEntry)
            throws FileNotFoundException, IOException {
        this.sourceFile = jarFile;
        this.sourceJarEntry = jarFileEntry;
        this.sourceJarFile = new ZipFile(jarFile);

        InputStream stream = sourceJarFile.getInputStream(jarFileEntry);
        if (stream != null) {
            InputSource inputSource = new InputSource(stream);
            inputSource.setSystemId(sourceJarFile.getName() + "!" + jarFileEntry.getName());

            this.inputSrcTracker = new FileTracker();
            ((FileTracker) this.inputSrcTracker).setFile(jarFile);
            if (parentSrcTracker != null)
                this.inputSrcTracker.setParent(parentSrcTracker);

            return inputSource;
        } else
            throw new FileNotFoundException("Zip entry '" + jarFileEntry.getName() + "' not found in zip file '"
                    + jarFile.getAbsolutePath() + "'.");
    }

    public void init(InputSource inputSource) throws ParserConfigurationException, SAXException {
        this.inputSource = inputSource;
        this.errors = new ArrayList();
        this.warnings = new ArrayList();

        if (inputSource.getSystemId() == null)
            throw new ParserConfigurationException("Please set the system id.");

        SAXParser saxParser = getParserFactory().newSAXParser();
        parser = saxParser.getXMLReader();
    }

    public boolean prepareTransformInstruction(String instructionParams) {
        CommandLine cmd = null;
        try {
            cmd = CLPARSER.parse(TRANSFORM_OPTIONS, StringUtils.split(instructionParams));
        } catch (ParseException e) {
            errors.add("Unable to process transformation command <?" + TRANSFORM_INSTRUCTION + " "
                    + instructionParams + "?>: " + e.toString());
            return false;
        }

        if (!cmd.hasOption('s')) {
            errors.add("No style-sheet options specified for <?" + TRANSFORM_INSTRUCTION + " " + instructionParams
                    + "?> PI.");
            HelpFormatter formatter = new HelpFormatter();
            formatter.printHelp(TRANSFORM_INSTRUCTION, TRANSFORM_OPTIONS);
            return false;
        }

        boolean isResource = cmd.hasOption("r");
        List sources = new ArrayList();
        String[] styleSheets = cmd.getOptionValues('s');
        for (int i = 0; i < styleSheets.length; i++) {
            if (isResource) {
                InputStream stream = getClass().getClassLoader().getResourceAsStream(styleSheets[i].trim());
                if (stream == null)
                    errors.add("Error in <?" + TRANSFORM_INSTRUCTION + " " + instructionParams + "?>, stylesheet '"
                            + styleSheets[i].trim() + "' not found as a resource in ClassLoader "
                            + getClass().getClassLoader());
                else {
                    sources.add(new StreamSource(stream));
                }
            } else {
                File sourceFile = resolveFile(styleSheets[i].trim());
                try {
                    if (inputSrcTracker != null) {
                        FileTracker preProcessor = new FileTracker();
                        preProcessor.setFile(sourceFile);
                        inputSrcTracker.addPreProcessor(preProcessor);
                    }
                    sources.add(new StreamSource(new FileInputStream(sourceFile)));
                } catch (FileNotFoundException e) {
                    errors.add("Error in <?" + TRANSFORM_INSTRUCTION + " " + instructionParams + "?>, stylesheet '"
                            + sourceFile.getAbsolutePath() + "': " + e.toString());
                    continue;
                }
            }
        }

        if (sources.size() == 0)
            return false;

        transformSources = (Source[]) sources.toArray(new Source[sources.size()]);
        return true;
    }

    public InputSource recreateInputSource() throws FileNotFoundException, IOException {
        if (sourceFile != null && sourceJarEntry == null)
            return createInputSource(sourceFile);

        if (sourceText != null)
            return createInputSource(sourceText);

        if (sourceResource != null)
            return createInputSource(sourceResource);

        if (sourceFile != null && sourceJarEntry != null)
            return createInputSource(sourceFile, sourceJarEntry);

        return null;
    }

    public void closeInputSource() throws IOException {
        if (inputSource.getCharacterStream() != null) {
            try {
                inputSource.getCharacterStream().close();
            } catch (IOException ioe) {
                // ignore this
            }
        }
        if (inputSource.getByteStream() != null) {
            try {
                inputSource.getByteStream().close();
            } catch (IOException ioe) {
                // ignore this
            }
        }

        if (activeFileInputStream != null) {
            activeFileInputStream.close();
            activeFileInputStream = null;
        }

        if (sourceJarFile != null)
            sourceJarFile.close();
    }

    public void doExternalTransformations() throws TransformerConfigurationException, TransformerException,
            ParserConfigurationException, SAXException, IOException {
        // re-create the input source because the original stream is already closed
        InputSource inputSource = recreateInputSource();

        Source activeSource = inputSource.getByteStream() != null ? new StreamSource(inputSource.getByteStream())
                : new StreamSource(inputSource.getCharacterStream());
        activeSource.setSystemId(inputSource.getSystemId());

        Writer activeResultBuffer = new StringWriter();
        Result activeResult = new StreamResult(activeResultBuffer);
        activeResult.setSystemId(activeResultBuffer.getClass().getName());

        TransformerFactory factory = TransformerFactory.newInstance();
        int lastTransformer = transformSources.length - 1;
        for (int i = 0; i <= lastTransformer; i++) {
            Transformer transformer = factory.newTransformer(transformSources[i]);
            transformer.transform(activeSource, activeResult);

            if (i < lastTransformer) {
                activeSource = new StreamSource(new StringReader(activeResultBuffer.toString()));
                activeResultBuffer = new StringWriter();
                activeResult = new StreamResult(activeResultBuffer);
            }
        }

        // now that all the transformations have been performed, we want to reset our input source to the final
        // transformation
        init(createInputSource(activeResultBuffer.toString()));
    }

    private static SAXParserFactory getParserFactory() {
        if (parserFactory == null)
            parserFactory = SAXParserFactory.newInstance();

        return parserFactory;
    }

    public File resolveFile(String src) {
        File file = new File(src);
        if (file.isAbsolute())
            return file;
        else
            return inputSrcTracker != null && inputSrcTracker instanceof FileTracker
                    ? new File(((FileTracker) inputSrcTracker).getFile().getParent(), src)
                    : file;
    }

    public void setThrowErrorException(boolean throwErrorException) {
        this.throwErrorException = throwErrorException;
    }

    public InputSourceTracker getInputSrcTracker() {
        return inputSrcTracker;
    }

    public InputSource getInputSource() {
        return inputSource;
    }

    public XMLReader getParser() {
        return parser;
    }

    public Locator getLocator() {
        return locator;
    }

    public void setLocator(Locator locator) {
        this.locator = locator;
    }

    public boolean isThrowErrorException() {
        return throwErrorException;
    }

    public void addError(Throwable t) {
        errors.add(t);
    }

    public void addError(String message) {
        this.errors.add(message);
    }

    public void addWarning(String message) {
        this.warnings.add(message);
    }

    public void addErrors(List errors) {
        this.errors.addAll(errors);
    }

    public List getErrors() {
        return errors;
    }

    public List getWarnings() {
        return warnings;
    }
}