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

org.xmlbeam.DefaultFileIO Maven / Gradle / Ivy

/**
 *  Copyright 2013 Sven Ewald
 *
 *  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.xmlbeam;

import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

import javax.xml.transform.TransformerException;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Document;
import org.xml.sax.SAXException;
import org.xmlbeam.evaluation.CanEvaluate;
import org.xmlbeam.evaluation.DefaultXPathEvaluator;
import org.xmlbeam.evaluation.DocumentResolver;
import org.xmlbeam.evaluation.InvocationContext;
import org.xmlbeam.evaluation.XPathBinder;
import org.xmlbeam.evaluation.XPathEvaluator;
import org.xmlbeam.exceptions.XBDocumentParsingException;
import org.xmlbeam.exceptions.XBException;
import org.xmlbeam.io.FileIO;
import org.xmlbeam.io.StreamOutput;
import org.xmlbeam.types.CloseableMap;
import org.xmlbeam.types.XBAutoMap;
import org.xmlbeam.util.IOHelper;
import org.xmlbeam.util.intern.DOMHelper;

/**
 * @author Sven Ewald
 */
class DefaultFileIO implements CanEvaluate, FileIO {

    private final XBProjector projector;
    private boolean append = false;
    private boolean failIfNotExists = false;
    private final File file;

    /**
     * Constructor for file input.
     *
     * @param xmlProjector
     * @param file
     */
    public DefaultFileIO(final XBProjector xmlProjector, final File file) {
        if (xmlProjector == null) {
            throw new NullPointerException("Parameter xmlProjector must not be null.");
        }
        if (file == null) {
            throw new NullPointerException("Parameter file must not be null.");
        }
        if (file.isDirectory()) {
            throw new IllegalArgumentException("File " + file + " is a directory.");
        }
        this.projector = xmlProjector;
        this.file = file;
    }

    /**
     * Convenient constructor using a filename.
     *
     * @param xmlProjector
     * @param fileName
     */
    public DefaultFileIO(final XBProjector xmlProjector, final String fileName) {
        this(xmlProjector, new File(fileName));
    }

    /**
     * Read a XML document and return a projection to it.
     *
     * @param projectionInterface
     * @return a new projection pointing to the content of the file.
     * @throws IOException
     */
    @Override
    public  T read(final Class projectionInterface) throws IOException {
        try {
            Document document = projector.config().createDocumentBuilder().parse(file);
            return projector.projectDOMNode(document, projectionInterface);
        } catch (SAXException e) {
            throw new XBDocumentParsingException(e);
        }
    }

    /**
     * @param projection
     * @throws IOException
     */
    @Override
    public
    void write(final Object projection) throws IOException {
        FileOutputStream os = new FileOutputStream(file, append);
        new StreamOutput(projector, os).write(projection);
        os.close();
    }

    /**
     * Set whether output should be append to existing file. When this method is not invoked, or
     * invoked with 'false', The file will be replaced on writing operations.
     *
     * @param append
     *            optional parameter, default is true.
     * @return this to provide a fluent API.
     */
    @Override
    public FileIO setAppend(final boolean... append) {
        this.append = (append != null) && ((append.length == 0) || ((append.length > 0) && append[0]));
        return this;
    }

    /**
     * Set whether file should be created if it does not exist. When this method is not invoked, *
     * bind operations will fail if the file does not exist.
     *
     * @return this to provide a fluent API.
     */
    @Override
    public FileIO failIfNotExists(final boolean... failOnFNF) {
        this.failIfNotExists = (failOnFNF != null) && ((failOnFNF.length == 0) || ((failOnFNF.length > 0) && failOnFNF[0]));
        return this;
    }

    /**
     * @param xpath
     * @return evaluator
     * @see org.xmlbeam.evaluation.CanEvaluate#evalXPath(java.lang.String)
     */
    @Override
    public XPathEvaluator evalXPath(final String xpath) {
        return new DefaultXPathEvaluator(projector, new DocumentResolver() {

            @Override
            public Document resolve(final Class... resourceAwareClass) throws IOException {
                FileInputStream fileInputStream = new FileInputStream(file);
                Document doc = IOHelper.loadDocument(projector, fileInputStream);
                fileInputStream.close();
                return doc;
            }

        }, xpath);
    }

    /**
     * @param xpath
     * @return binder
     */
    @Override
    @SuppressWarnings("resource")
    public XPathBinder bindXPath(final String xpath) {
        final Document[] doc = new Document[1];
        return new DefaultXPathBinder(projector, new DocumentResolver() {

            @Override
            public Document resolve(final Class... resourceAwareClass) throws IOException {
                //Document doc;
                if (file.isFile()) {
                    FileInputStream fileInputStream = new FileInputStream(file);
                    doc[0] = IOHelper.loadDocument(projector, fileInputStream);
                    fileInputStream.close();
                } else {
                    if (failIfNotExists) {
                        throw new FileNotFoundException(file.getAbsolutePath());
                    }
                    doc[0] = projector.config().createDocumentBuilder().newDocument();
                }

                return doc[0];
            }

        }, xpath, new Closeable() {

            @Override
            public void close() throws IOException {
                try {
                    FileOutputStream fileOutPutStream = new FileOutputStream(file);
                    DOMHelper.trim(doc[0]);
                    projector.config().createTransformer().transform(new DOMSource(doc[0]), new StreamResult(fileOutPutStream));
                    fileOutPutStream.flush();
                    fileOutPutStream.close();
                } catch (TransformerException e) {
                    throw new XBException("Could not write to file " + file.getAbsolutePath(), e);
                }
            }
        });
    }

    /**
     * @param valueType
     * @return Map bound to file
     * @throws FileNotFoundException
     * @see org.xmlbeam.io.FileIO#bindAsMapOf(java.lang.Class)
     */
    @SuppressWarnings("resource")
    @Override
    public  CloseableMap bindAsMapOf(final Class valueType) throws IOException {
        DefaultXPathBinder.validateEvaluationType(valueType);
        if ((failIfNotExists) && (!file.exists())) {
            throw new FileNotFoundException(file.getAbsolutePath());
        }
        final Document[] document = new Document[1];
        try {
            if (file.exists()) {
                document[0] = projector.config().createDocumentBuilder().parse(file);
            } else {
                document[0] = projector.config().createDocumentBuilder().newDocument();
            }
            InvocationContext invocationContext = new InvocationContext(null, null, null, null, null, valueType, projector);
            return new DefaultFileMap(document[0], invocationContext, new Closeable() {
                final Document doc = document[0];

                @Override
                public void close() throws IOException {
                    try {
                        FileOutputStream fileOutPutStream = new FileOutputStream(file);
                        DOMHelper.trim(doc);
                        projector.config().createTransformer().transform(new DOMSource(doc), new StreamResult(fileOutPutStream));
                        fileOutPutStream.flush();
                        fileOutPutStream.close();
                    } catch (TransformerException e) {
                        throw new XBException("Could not write to file " + file.getAbsolutePath(), e);
                    }
                }
            }, valueType);
        } catch (SAXException e) {
            throw new XBDocumentParsingException(e);
        }
    }

    /**
     * @param valueType
     * @return XBAutoMap for the complete document
     * @throws IOException
     * @see org.xmlbeam.io.FileIO#readAsMapOf(java.lang.Class)
     */
    @Override
    public  XBAutoMap readAsMapOf(final Class valueType) throws IOException {
        DefaultXPathBinder.validateEvaluationType(valueType);
        try {
            Document document = projector.config().createDocumentBuilder().parse(file);
            InvocationContext invocationContext = new InvocationContext(null, null, null, null, null, valueType, projector);
            return new AutoMap(document, invocationContext, valueType);
        } catch (SAXException e) {
            throw new XBDocumentParsingException(e);
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy