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

org.w3c.cci2.BinaryLargeObjects Maven / Gradle / Ivy

There is a newer version: 2.18.10
Show newest version
/*
 * ====================================================================
 * Project:     openMDX, http://www.openmdx.org/
 * Description: Binary Large Object Factory 
 * Owner:       OMEX AG, Switzerland, http://www.omex.ch
 * ====================================================================
 *
 * This software is published under the BSD license as listed below.
 * 
 * Copyright (c) 2006-2013, OMEX AG, Switzerland
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or
 * without modification, are permitted provided that the following
 * conditions are met:
 * 
 * * Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 * 
 * * Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in
 *   the documentation and/or other materials provided with the
 *   distribution.
 * 
 * * Neither the name of the openMDX team nor the names of its
 *   contributors may be used to endorse or promote products derived
 *   from this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 * 
 * ------------------
 * 
 * This product includes software developed by other organizations as
 * listed in the NOTICE file.
 */
package org.w3c.cci2;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.Serializable;
import java.net.URL;
import java.net.URLConnection;

/**
 * Binary Large Object Factory
 */
public class BinaryLargeObjects {

    /**
     * Constructor
     */
    private BinaryLargeObjects() {
        // To avoid instantiation
    }

    /**
     * Default capacity for stream copy
     */
    private final static int CAPACITY = 10000;

    /**
     * Create a BinaryLargeObject facade for the given byte array
     * 
     * @param source
     * 
     * @return a BinaryLargeObject facade for the given byte array
     */
    public static BinaryLargeObject valueOf(
        byte[] source
    ){
        return new ArrayLargeObject(
            source,
            0,
            source.length
        );
    }

    /**
     * Create a BinaryLargeObject facade for the given byte array
     * 
     * @param source
     * @param offset
     * @param length
     * 
     * @return a BinaryLargeObject facade for the given byte array
     */
    public static BinaryLargeObject valueOf(
        byte[] source,
        int offset,
        int length
    ){
        return new ArrayLargeObject(
            source,
            offset,
            length
        );
    }

    /**
     * Create a BinaryLargeObject facade for the given URL
     * 
     * @param source
     * 
     * @return a BinaryLargeObject facade for the given URL
     */
    public static BinaryLargeObject valueOf(
        URL source
    ){
        return new URLLargeObject(source);
    }
    
    /**
     * Create a BinaryLargeObject facade for the given file
     * 
     * @param source
     * 
     * @return a BinaryLargeObject facade for the given file
     */
    public static BinaryLargeObject valueOf(
        File source
    ){
        return new FileLargeObject(source);
    }

    /**
     * Create a BinaryLargeObject facade for the given stream
     * 
     * @param source
     * 
     * @return a BinaryLargeObject facade for the given stream
     */
    public static BinaryLargeObject valueOf(
        InputStream source
    ){
        return new StreamLargeObject(source);
    }

    /**
     * Create a BinaryLargeObject facade for the given stream
     * 
     * @param source
     * @param length
     * 
     * @return a BinaryLargeObject facade for the given stream
     */
    public static BinaryLargeObject valueOf(
        InputStream source,
        Long length
    ){
        return new StreamLargeObject(source, length);
    }

    /**
     * Create a BinaryLargeObject copy of the given stream
     * 
     * @param source
     * @param length
     * 
     * @return a BinaryLargeObject copy of the given stream
     * 
     * @throws IOException  
     */
    public static BinaryLargeObject copyOf(
        InputStream source,
        Long length
    ) throws IOException {
        ByteArrayOutputStream buffer = length == null ? new ByteArrayOutputStream(
        ) : new ByteArrayOutputStream(
            length.intValue()
        );
        streamCopy(source, 0, buffer);
        return valueOf(buffer.toByteArray());
    }
    
    /**
     * A negative length is converted to null.
     * 
     * @param length
     * 
     * @return the length as object
     */
    public static Long asLength(
        long length
    ){
        return length < 0 ? null : Long.valueOf(length);
    }

    /**
     * Copy an input stream's content to an output stream
     * @param source
     * @param position
     * @param target
     * 
     * @return the number of byte written to the output stream
     * @throws IOException
     */
    public static long streamCopy(
        InputStream source,
        long position,
        OutputStream target
    ) throws IOException {
        byte[] buffer = new byte[CAPACITY];
        if(position != 0l) {
            source.skip(position);
        }
        long count = 0l;
        for(int n; (n = source.read(buffer)) >= 0;){
            count += n;
            target.write(buffer, 0, n);
        }
        return count;
    }

    
    //------------------------------------------------------------------------
    // Class ArrayLargeObject
    //------------------------------------------------------------------------

    /**
     * Array BLOB
     */
    private static class ArrayLargeObject implements BinaryLargeObject, Serializable {

        /**
         * Constructor 
         *
         * @param value
         * @param offset
         * @param length
         */
        ArrayLargeObject(
            final byte[] value,
            final int offset,
            final int length
        ) {
            this.value = value;
            this.offset = offset;
            this.length = length;
        }

        /**
         * Implements Serializable
         */
        private static final long serialVersionUID = 3886030128086687249L;

        private byte[] value;
        private int offset;
        private int length;

        /* (non-Javadoc)
         * @see org.w3c.cci2.BinaryLargeObject#getContent()
         */
        public InputStream getContent() {
            return new ByteArrayInputStream(this.value, this.offset, this.length);
        }

        /* (non-Javadoc)
         * @see org.w3c.cci2.LargeObject#getLength()
         */
        public Long getLength(
        ){
            return Long.valueOf(this.length);
        }

        /* (non-Javadoc)
         * @see org.w3c.cci2.BinaryLargeObject#getContent(java.io.OutputStream, long)
         */
        public void getContent(
            OutputStream stream, 
            long position
        ) throws IOException {
            int offset = this.offset + (int)position;
            int length =  this.length - (int)position;
            if (length < 0) throw new EOFException(
                "Position " + position + " is larger than the objects length " + this.length
            );
            stream.write(this.value, offset, length);
        }

        private void writeObject(
            ObjectOutputStream stream
        ) throws IOException {
            stream.writeLong(this.length);
            stream.write(this.value, this.offset, this.length);
        }
        
        private void readObject(
            ObjectInputStream stream
        ) throws IOException, ClassNotFoundException {
            this.offset = 0;
            this.length = (int)stream.readLong();
            this.value = new byte[this.length];
            stream.read(this.value);
        }

    }
    
    
    //------------------------------------------------------------------------
    // Class AbstractLargeObject
    //------------------------------------------------------------------------

    /**
     * The underlying stream may be retrieved once only
     */
    private static abstract class AbstractLargeObject implements BinaryLargeObject, Serializable {
        
        /**
         * Constructor 
         *
         * @param stream
         */
        protected AbstractLargeObject(
            Long length
        ){
            this.length = length;
        }

        /**
         * Implements Serializable
         */
        private static final long serialVersionUID = -5837819381102619869L;

        private transient byte[] value;
        private transient Long length;

        /**
         * Provide the input stream content
         * 
         * @return the content
         * 
         * @throws IOException
         */
        protected InputStream newContent(
        ) throws IOException {
            return this.value == null ? null : new ByteArrayInputStream(this.value);
        }
        
        /* (non-Javadoc)
         * @see org.w3c.cci2.BinaryLargeObject#getContent(java.io.OutputStream, long)
         */
        public void getContent(
            OutputStream stream, 
            long position
        ) throws IOException {
            Long length = Long.valueOf(
                position + streamCopy(
                    getContent(),
                    position,
                    stream
                )
            );
            this.length = length;
        }

        /* (non-Javadoc)
         * @see org.w3c.cci2.LargeObject#getLength()
         */
        public Long getLength(
        ) throws IOException {
            return this.length;
        }
        
        protected void setLength(
            Long length
        ){
            this.length = length;
        }
        
        private void writeObject(
            ObjectOutputStream stream
        ) throws IOException {
            ByteArrayOutputStream buffer = new ByteArrayOutputStream();
            getContent(buffer, 0);
            stream.writeLong(this.length.longValue());
            buffer.writeTo(stream);
        }
        
        private void readObject(
            ObjectInputStream stream
        ) throws IOException, ClassNotFoundException {
            this.length = Long.valueOf(stream.readLong());
            this.value = new byte[this.length.intValue()];
            stream.read(this.value);
        }
        
    }
    
     
    //------------------------------------------------------------------------
    // Class URLLargeObject
    //------------------------------------------------------------------------

    /**
     * URL BLOB
     */
    private static class URLLargeObject extends AbstractLargeObject {
        
        /**
         * Constructor 
         *
         * @param url
         */
        public URLLargeObject(final URL url) {
            super(null);
            this.url = url;
        }

        /**
         * Implements Serializable
         */
        private static final long serialVersionUID = 3916312441998769493L;

        /**
         * 
         */
        private transient URL url;

        /**
         * 
         */
        private transient URLConnection connection;
        
        /* (non-Javadoc)
         * @see org.w3c.cci2.BinaryLargeObject#getContent()
         */
        public InputStream getContent(
        ) throws IOException {
            return this.url != null ? getConnection().getInputStream() : newContent();
        }

        /* (non-Javadoc)
         * @see org.w3c.cci2.LargeObject#getLength()
         */
        @Override
        public Long getLength(
        ) throws IOException {
            Long length = super.getLength();
            if(length == null) {
                super.setLength(
                    length = asLength(getConnection().getContentLength())
                );
            }
            return length;
        }

        /**
         * Opens the URL connection
         * 
         * @return the URL connection
         * 
         * @throws IOException
         */
        protected URLConnection getConnection() throws IOException{
            if(this.connection == null) {
                this.connection = url.openConnection();
            }
            return this.connection;
        }
        
    }


    //------------------------------------------------------------------------
    // Class FileLargeObject
    //------------------------------------------------------------------------

    /**
     * File BLOB
     */
    private static class FileLargeObject extends AbstractLargeObject {
        
        /**
         * Constructor 
         *
         * @param file
         */
        public FileLargeObject(
            final File file
        ) {
            super(asLength(file.length()));
            this.file = file;
        }

        private transient File file;

        /**
         * Implements Serializable
         */
        private static final long serialVersionUID = -1566865189136279414L;

        /* (non-Javadoc)
         * @see org.w3c.cci2.BinaryLargeObject#getContent()
         */
//      @SuppressWarnings("resource")
        public InputStream getContent(
        ) throws IOException {
            return this.file != null ? new FileInputStream(this.file) : newContent();
        }

    }


    //------------------------------------------------------------------------
    // Class StreamLargeObject
    //------------------------------------------------------------------------

    /**
     * The underlying stream may be retrieved once only
     */
    public static class StreamLargeObject extends AbstractLargeObject {
        
        /**
         * Constructor 
         *
         * @param stream
         */
        public StreamLargeObject(
            final InputStream stream
        ){
            this(stream, getLength(stream));
        }

        /**
         * Constructor 
         *
         * @param stream
         * @param length
         */
        protected StreamLargeObject(
            final InputStream stream,
            final Long length
        ){
            super(length);
            this.stream = stream;
        }
        
        /**
         * Implements Serializable
         */
        private static final long serialVersionUID = -6473575658856881436L;

        /**
         * The stream may be read pnce only
         */
        private transient InputStream stream;

        /**
         * Determine the large objetc's size
         * 
         * @param stream
         * 
         * @return the large objetc's size
         */
        private static Long getLength(
            InputStream stream
        ){
            try {
                return stream instanceof ByteArrayInputStream ? Long.valueOf(stream.available()) : null;
            } catch (IOException exception) {
                return null;
            }
        }
        
        /* (non-Javadoc)
         * @see org.w3c.cci2.BinaryLargeObject#getContent()
         */
        public InputStream getContent(
        ) throws IOException {
            InputStream content;
            if(this.stream == null) {
                content = newContent();
            } else {
                content = this.stream;
                this.stream = null;
            }
            if(content != null) {
                return content;
            }
            throw new IllegalStateException(
                "The stream may be  retrieved once only"
            );
        }

    }
       
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy