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

com.day.durbo.DurboInput Maven / Gradle / Ivy

There is a newer version: 6.5.21
Show newest version
/*
 * Copyright 1997-2008 Day Management AG
 * Barfuesserplatz 6, 4001 Basel, Switzerland
 * All Rights Reserved.
 *
 * This software is the confidential and proprietary information of
 * Day Management AG, ("Confidential Information"). You shall not
 * disclose such Confidential Information and shall use it only in
 * accordance with the terms of the license agreement you entered into
 * with Day.
 */
package com.day.durbo;

import java.io.EOFException;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;

import javax.jcr.NamespaceException;
import javax.jcr.PropertyType;
import javax.jcr.RepositoryException;
import javax.jcr.Value;
import javax.jcr.ValueFactory;

import com.day.durbo.impl.DurboInputStream;
import com.day.durbo.io.RegionFileInputStream;

/**
 * The DurboInput class implements a reader on a inputstream that
 * contains durbo-serialized data. {@see DurboOutput} for a more detailed
 * description of this protocol.
 */
public class DurboInput implements DurboConstants, DurboNamespaceResolver {

    /**
     * the 'undefined' property type.
     *
     * @deprecated Use {@link PropertyType#UNDEFINED} instead
     */
    public static final int PROPERTY_TYPE_UNDEFINED = PropertyType.UNDEFINED;

    /**
     * the 'string' property type.
     *
     * @deprecated Use {@link PropertyType#STRING} instead
     */
    public static final int PROPERTY_TYPE_STRING = PropertyType.STRING;

    /**
     * the 'binary' property type.
     *
     * @deprecated Use {@link PropertyType#BINARY} instead
     */
    public static final int PROPERTY_TYPE_BINARY = PropertyType.BINARY;

    /**
     * the 'long' property type.
     *
     * @deprecated Use {@link PropertyType#LONG} instead
     */
    public static final int PROPERTY_TYPE_LONG = PropertyType.LONG;

    /**
     * the 'double' property type.
     *
     * @deprecated Use {@link PropertyType#DOUBLE} instead
     */
    public static final int PROPERTY_TYPE_DOUBLE = PropertyType.DOUBLE;

    /**
     * the 'date' property type.
     *
     * @deprecated Use {@link PropertyType#DATE} instead
     */
    public static final int PROPERTY_TYPE_DATE = PropertyType.DATE;

    /**
     * the 'boolean' property type.
     *
     * @deprecated Use {@link PropertyType#BOOLEAN} instead
     */
    public static final int PROPERTY_TYPE_BOOLEAN = PropertyType.BOOLEAN;

    /**
     * the 'name' property type.
     *
     * @deprecated Use {@link PropertyType#NAME} instead
     */
    public static final int PROPERTY_TYPE_NAME = PropertyType.NAME;

    /**
     * the 'path' property type.
     *
     * @deprecated Use {@link PropertyType#PATH} instead
     */
    public static final int PROPERTY_TYPE_PATH = PropertyType.PATH;

    /**
     * the 'reference' property type.
     *
     * @deprecated Use {@link PropertyType#REFERENCE} instead
     */
    public static final int PROPERTY_TYPE_REFERENCE = PropertyType.REFERENCE;

    /**
     * the input stream to read from
     */
    private DurboInputStream in;

    /**
     * the current version
     */
    private double version = PROTOCOL_VERSION_1;

    /**
     * the encoding
     */
    private String encoding = "";

    /**
     * the content type
     */
    private String contentType = "";

    /**
     * map of namespaces by prefix
     */
    private Map namespaceByPrefix = new HashMap();

    /**
     * map of namespaces by prefix
     */
    private Map namespaceByURI = new HashMap();

    /**
     * Creates a new DurboInput on the specified file. This
     * also reads the header to check if the underlying stream is of the correct
     * format. In difference to the more generic {@link #DurboInput(InputStream)}
     * constructor this operates on a file an can therefor be optimized.
     *
     * @param file underlying file
     * @throws IOException if an I/O error occurs
     */
    public DurboInput(File file) throws IOException {
        this(new RegionFileInputStream(file));
    }

    /**
     * Creates a new DurboInput on the specified input stream. This
     * also reads the header to check if the underlying stream is of the correct
     * format.
     *
     * @param inputStream the input stream
     * @throws IOException if an I/O error occurrs
     */
    public DurboInput(InputStream inputStream) throws IOException {
        in = new DurboInputStream(inputStream);
        namespaceByPrefix.put("", "");
        namespaceByURI.put("", "");

        Element elem = read();
        if (elem == null) {
            throw new IOException("Protocol Header expected.");
        }
        if (!PROTOCOL_HEADER.equals(elem.name())) {
            throw new IOException("Wrong Protocol Header Property: " + elem.name());
        }
        version = ((Property) elem).getValues()[0].getDouble();

        if (version > PROTOCOL_VERSION_2_1) {
            throw new IOException("Wrong Protocol Version: " + elem.getString());
        }
        if (version >= PROTOCOL_VERSION_2) {
            elem = read();
            if (!PROTOCOL_CONTENT_TYPE.equals(elem.name())) {
                throw new IOException("Wrong protocol. " + PROTOCOL_CONTENT_TYPE + " expected.");
            }
            contentType = ((Property) elem).getValues()[0].getString();
            elem = read();
            if (!PROTOCOL_ENCODING.equals(elem.name())) {
                throw new IOException("Wrong protocol. " + PROTOCOL_ENCODING + " expected.");
            }
            encoding = ((Property) elem).getValues()[0].getString();
            if (encoding.equals("zip")) {
                in.enableDecompression();
            }
        }
    }

    public String getEncoding() {
        return encoding;
    }

    public String getContentType() {
        return contentType;
    }

    /**
     * Returns the version
     *
     * @return the version
     */
    public double getVersion() {
        return version;
    }

    /**
     * Reads an element from this input
     *
     * @return an durbo element or null if a end of the input
     * @throws IOException if an I/O error occurs or if the data do not
     *                     match the protocol specification
     */
    public Element read() throws IOException {
        int type = in.readType();
        if (type == -1) {
            return null;
        }
        if ((type & PROPERTY) > 0) {
            String name = in.readString();
            boolean isMulti = (type & MULTIPLE) > 0;
            DurboValue[] values = isMulti ? new DurboValue[in.readInt()] : new DurboValue[1];
            type &= PROPERTY_TYPE_MASK;
            for (int i = 0; i < values.length; i++) {
                switch (type) {
                    case PropertyType.STRING:
                    case PropertyType.LONG:
                    case PropertyType.DOUBLE:
                    case PropertyType.DATE:
                    case PropertyType.BOOLEAN:
                    case PropertyType.NAME:
                    case PropertyType.PATH:
                    case PropertyType.REFERENCE:
                    case PropertyType.WEAKREFERENCE:
                    case PropertyType.DECIMAL:
                    case PropertyType.URI:
                        values[i] = new DurboValue(type, in.readBinary());
                        break;
                    default:
                        if (version >= PROTOCOL_VERSION_2) {
                            throw new IOException("unsupported type: " + type);
                        }
                        type = PropertyType.BINARY;
                        // no break;
                    case PropertyType.BINARY:
                        values[i] = in.readBinaryValue();
                        break;
                }
            }
            return new Property(name, type, isMulti, values);
        } else if (type == NODE_START) {
            return new Node(in.readString());
        } else if (type == NODE_END) {
            return new Node();
        } else if (type == NAMESPACE) {
            String prefix = in.readString();
            String uri = in.readString();
            namespaceByPrefix.put(prefix, uri);
            namespaceByURI.put(uri, prefix);
            return read();
        } else {
            throw new IOException("Unknown element type: " + type);
        }
    }

    /**
     * skips a node
     *
     * @throws IOException if an I/O error occurs
     */
    public void skipNode() throws IOException {
        DurboInput.Element elem;
        while ((elem = read()) != null) {
            if (elem.isNodeStart()) {
                skipNode();
            } else if (elem.isNodeEnd()) {
                return;
            }
        }
        throw new EOFException("Unexpected end of input");
    }


    /**
     * Returns the namespace uri for the given namespace
     *
     * @param prefix the namespace prefix
     * @return the namespace uri
     */
    public String getURI(String prefix) {
        return namespaceByPrefix.get(prefix);
    }

    /**
     * returns the namespace prefix for the given uri
     *
     * @param uri the namespace uri
     * @return the namespace prefix
     * @throws NamespaceException
     */
    public String getPrefix(String uri) throws NamespaceException {
        return namespaceByURI.get(uri);
    }

    public String[] getPrefixes() {
        return namespaceByPrefix.keySet().toArray(new String[namespaceByPrefix.size()]);
    }

    public String[] getURIs() {
        return namespaceByURI.keySet().toArray(new String[namespaceByURI.size()]);
    }

    public class Property extends Element {

        /**
         * the property type
         */
        private final int type;

        /**
         * flag, indicating if the property was multiple
         */
        private final boolean isMultiple;

        /**
         * values
         */
        private final DurboValue[] values;

        public Property(String name, int type, boolean multiple, DurboValue[] values) {
            super(name);
            this.type = type;
            isMultiple = multiple;
            this.values = values;
        }

        public int getType() {
            return type;
        }

        public boolean isMultiple() {
            return isMultiple;
        }

        public DurboValue[] getValues() {
            return values;
        }

        public Value[] getJcrValues(ValueFactory factory)
                throws IOException, RepositoryException {
            Value[] ret = new Value[values.length];
            for (int i = 0; i < ret.length; i++) {
                ret[i] = values[i].toJcrValue(factory);
            }
            return ret;
        }

        public boolean isProperty() {
            return true;
        }

        public boolean isNodeStart() {
            return false;
        }

        public boolean isNodeEnd() {
            return false;
        }

        public String getString() {
            try {
                return (values.length > 0) ? values[0].getString() : "";
            } catch (IOException e) {
                return null;
            }
        }

        public boolean wasBinary() {
            return type == PropertyType.BINARY;
        }

        public boolean wasString() {
            return type != PropertyType.BINARY;
        }

        public long size() {
            return 0;
        }
    }

    public class Node extends Element {
        private final boolean isStart;

        public Node(String name) {
            this(name, true);
        }

        public Node() {
            this(null, false);
        }

        public Node(String name, boolean isNodeStart) {
            super(name);
            isStart = isNodeStart;
        }

        public boolean isProperty() {
            return false;
        }

        public boolean isNodeStart() {
            return isStart;
        }

        public boolean isNodeEnd() {
            return !isStart;
        }


        public String getString() {
            return null;
        }

        public boolean wasBinary() {
            return false;
        }

        public boolean wasString() {
            return false;
        }

        public long size() {
            return 0;
        }
    }

    /**
     * Inner class that represents one element of the Durbo protocol
     */
    abstract public class Element {

        /**
         * the name of this element
         */
        private final String localName;

        /**
         * the namespace prefix
         */
        private final String prefix;

        /**
         * Creates a new element
         * @param name element name
         */
        private Element(String name) {
            if (name == null) {
                this.localName = null;
                this.prefix = null;
            } else {
                int pos = name.indexOf(':');
                if (pos > 0) {
                    this.prefix = name.substring(0, pos);
                    this.localName = name.substring(pos + 1);
                } else {
                    this.prefix = null;
                    this.localName = name;
                }
            }
        }

        /**
         * Returns the name of this element
         *
         * @return the name of this element
         */
        public String name() {
            return prefix == null ? localName : prefix + ":" + localName;
        }

        /**
         * returns the prefix of this element
         *
         * @return the prefix.
         */
        public String prefix() {
            return prefix;
        }

        /**
         * returns the namespace uri for this element
         *
         * @return the namespace uri.
         */
        public String uri() {
            return prefix == null ? null : getURI(prefix);
        }

        /**
         * returns the local name of this element
         *
         * @return the local name.
         */
        public String localName() {
            return localName;
        }

        /**
         * Checks if this element is a property
         *
         * @return true if this element is a property;
         *         false otherwise
         */
        abstract public boolean isProperty();

        /**
         * Checks if this element is a node start
         *
         * @return true if this element is a node start;
         *         false otherwise
         */
        abstract public boolean isNodeStart();

        /**
         * Checks if this element is a node end
         *
         * @return true if this element is a node end; false
         *         otherwise
         */
        abstract public boolean isNodeEnd();

        /**
         * Convenience method
         *
         * @return the string.
         */
        abstract public String getString();

        /**
         * @return the debug representation if this element
         * @deprecated use {@link #getString()} instead.
         */
        public String toString() {
            if (isProperty()) {
                return "Property(" + name() + ")";
            } else if (isNodeStart()) {
                return "NodeStart(" + name() + ")";
            } else {
                return "NodeEnd()";
            }
        }

        /**
         * Checks if this elem is a property and has binary content.
         *
         * @return true if this element has binary content.
         * @deprecated use {@link Property#getType()} instead.
         */
        abstract public boolean wasBinary();

        /**
         * Checks if this elem is a property and has string content.
         *
         * @return true if this element has string content.
         * @deprecated use {@link Property#getType()} instead.
         */
        abstract public boolean wasString();


        /**
         * Returns the size of the this element if it's a property.
         *
         * @return the size of the this element if it's a property.
         * @deprecated use {@link Property#getValues().length()} instead.
         */
        abstract public long size();
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy