org.eclipse.smila.binarystorage.persistence.io.BssIOUtils.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.smila.binarystorage.persistence.io.BssIOUtils.java

Source

/***********************************************************************************************************************
 * Copyright (c) 2008 empolis GmbH and brox IT Solutions GmbH. All rights reserved. This program and the accompanying
 * materials are made available under the terms of the Eclipse Public License v1.0 which accompanies this distribution,
 * and is available at http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors: Marius Cimpean (brox IT Solutions GmbH) - initial creator
 **********************************************************************************************************************/
package org.eclipse.smila.binarystorage.persistence.io;

import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.channels.FileChannel;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.eclipse.smila.binarystorage.BinaryStorageException;
import org.eclipse.smila.binarystorage.config.BinaryStorageConfiguration;

/**
 * Binary Storage Service utility i/o class.
 * 
 * @author mcimpean
 */
public class BssIOUtils {
    /** Binary Storage Service configured root location */
    private static File _root = null;

    /** Constant file size for 64 MB */
    private final static int FILE_SIZE_64MB = 64 * 1024 * 1024;

    /** File size transfer : 64MB - 32KB */
    private final static int FILE_SIZE_TRANSFER = FILE_SIZE_64MB - 32 * 1024;

    /**
     * Binary Storage persistence location initialization.
     * 
     * @param binaryStorageConfig
     */
    public static void init(final BinaryStorageConfiguration binaryStorageConfig) {
        _root = getCanonicalFile(binaryStorageConfig.getPath());
    }

    /**
     * Gets canonical file.
     * 
     * @param filePath
     *          String - file path
     * @return file File
     */
    private static File getCanonicalFile(final String filePath) {
        final File file = new File(filePath);
        try {
            return file.getCanonicalFile();
        } catch (final IOException e) {
            return file.getAbsoluteFile();
        }
    }

    /**
     * Writes input stream to file.
     * 
     * @param path
     * @param stream
     * @throws BinaryStorageException
     */
    public static void writeInputStreamToFile(final String path, final InputStream stream)
            throws BinaryStorageException {

        final File record = mkdirForFileRecord(path);
        if (stream instanceof FileInputStream) {
            try {
                writeCopyByChannels(record.getCanonicalPath(), stream);
            } catch (final IOException ioe) {
                throw new BinaryStorageException(ioe, "Could not write from input stream to record :" + path);
            }
        } else {
            FileOutputStream output = null;
            try {
                output = FileUtils.openOutputStream(record);
                IOUtils.copy(stream, output);
            } catch (final IOException ioe) {
                throw new BinaryStorageException(ioe, "Could not write from input stream to record :" + path);
            } finally {
                IOUtils.closeQuietly(output);
            }
        }
    }

    /**
     * Copies data from input stream into persistence location, by using channels.
     * 
     * @param path
     * @param stream
     * @throws BinaryStorageException
     */
    private static void writeCopyByChannels(final String path, final InputStream stream)
            throws BinaryStorageException {
        FileChannel inChannel = null;
        FileChannel outChannel = null;
        try {
            inChannel = ((FileInputStream) stream).getChannel();
            outChannel = new FileOutputStream(path).getChannel();
            if (inChannel.size() < FILE_SIZE_64MB) {
                outChannel.transferFrom(inChannel, 0, inChannel.size());
            } else {
                // the transferTo() does not transfer files > than 2^31-1 bytes
                final long size = inChannel.size();
                long position = 0;
                while (position < size) {
                    position += inChannel.transferTo(position, FILE_SIZE_TRANSFER, outChannel);
                }
            }
        } catch (final IOException ioe) {
            throw new BinaryStorageException(ioe, "Could not write binary record to :" + path);
        } finally {
            // Close the channels
            closeChannel(inChannel);
            closeChannel(outChannel);
        }
    }

    /**
     * Utility method to close a file channel.
     * 
     * @param channel
     * @throws BinaryStorageException
     */
    private static void closeChannel(final FileChannel channel) throws BinaryStorageException {
        if (channel != null) {
            try {
                channel.close();
            } catch (final IOException exception) {
                throw new BinaryStorageException(exception, "Could not close stream channel.");
            }
        }
    }

    /**
     * Saves array of bytes into file.
     * 
     * @param path
     * @param data
     * @throws BinaryStorageException
     */
    public static void writeByteArrayToFile(final String path, final byte[] data) throws BinaryStorageException {

        final File record = mkdirForFileRecord(path);
        try {
            FileUtils.writeByteArrayToFile(record, data);
        } catch (final IOException ioe) {
            throw new BinaryStorageException(ioe, "Could not write binary record to :" + path);
        }
    }

    /**
     * Make necessary directories for record storing.
     * 
     * @param path
     * @return File record file
     * @throws BinaryStorageException
     */
    private synchronized static File mkdirForFileRecord(final String path) throws BinaryStorageException {
        final File record = getFile(path);
        try {
            if (!isRecordParentRoot(record)) {
                // Hierarchical structure
                FileUtils.forceMkdir(record.getParentFile());
            }
            return record;
        } catch (final IOException ioe) {
            throw new BinaryStorageException(ioe, "Could not write binary record to :" + path);
        }
    }

    /**
     * Check if current record's parent is identically with the binary storage persistence configured-root-location.
     * 
     * @param record
     * @return boolean true in case parent location is identically with root; false otherwise.
     */
    private static boolean isRecordParentRoot(final File record) {
        return record.getParentFile().equals(_root);
    }

    /**
     * Reads a file, filling and return a byte array.
     * 
     * @param path
     * @return byte[]
     * @throws BinaryStorageException
     */
    public static byte[] readFileToByteArray(final String path) throws BinaryStorageException {
        try {
            return FileUtils.readFileToByteArray(getFile(path));
        } catch (final IOException ioe) {
            throw new BinaryStorageException(ioe, "Could not read binary record from :" + path);
        }
    }

    /**
     * Reads a file, filling a byte array.
     * 
     * @throws BinaryStorageException
     */
    public static InputStream readFileToInputStream(final String path) throws BinaryStorageException {
        final File source = getFile(path);
        try {
            return new DataInputStream(new BufferedInputStream(new FileInputStream(source)));
        } catch (final IOException ioe) {
            throw new BinaryStorageException(ioe, "Could not read binary record from :" + path);
        }
    }

    /**
     * Delete file.
     * 
     * @param key
     */
    public static void deleteFile(final String key) {
        FileUtils.deleteQuietly(getFile(key));
        /*
         * note | TM | this needs to be impled in each impl.as this might be specific to each implementation | TM @ Jun 25,
         * 2009
         */
    }

    /**
     * @param key
     * @return
     */
    public static File getFile(final String key) {
        return new File(_root, key);
    }

    /**
     * get file size.
     * 
     * @param key
     * @throws BinaryStorageException
     *           file does not exist
     */
    public static long fetchSize(final String key) throws BinaryStorageException {
        final File file = getFile(key);
        if (file.exists()) {
            return file.length();
        }
        throw new BinaryStorageException("file does not exist: " + key);
    }

    /**
     * Delete empty parent folders.
     * 
     * @param leafFolder
     *          the leaf folder
     */
    public static void deleteEmptyParentFolders(File leafFolder) {
        while (leafFolder != null && !leafFolder.equals(_root)) {
            final String[] elements = leafFolder.list();
            if (elements == null || elements.length > 0) {
                // folder does not exist anymore or is not empty.
                return;
            }
            leafFolder.delete();
            leafFolder = leafFolder.getParentFile();
        }
    }

}