eu.scape_project.planning.manager.FileStorage.java Source code

Java tutorial

Introduction

Here is the source code for eu.scape_project.planning.manager.FileStorage.java

Source

/*******************************************************************************
 * Copyright 2006 - 2012 Vienna University of Technology,
 * Department of Software Technology and Interactive Systems, IFS
 * 
 * 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 eu.scape_project.planning.manager;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.Serializable;
import java.util.UUID;

import javax.annotation.PostConstruct;
import javax.ejb.Stateful;
import javax.inject.Inject;

import org.apache.commons.configuration.Configuration;
import org.slf4j.Logger;

import eu.scape_project.planning.utils.ConfigurationLoader;
import eu.scape_project.planning.utils.FileUtils;

/**
 * A {@link IByteStreamStorage} which stores the data in the file system. The
 * location of the files is defined by {@link #storagePath}
 * 
 * Note: - atm this storage handler shares the same scope as the plan being
 * worked on - it is not defined what happens if multiple threads store data for
 * the same pid This is not be a problem, as a bytestream is always related to
 * one plan(which can only be accessed once at a time) and we do not have
 * multiple threads altering the same bytestream
 * 
 * @author Michael Kraxner
 */
// Do not use @ConversationScoped because the ExperimentRunner is called
// asynchronous and no ConversationScope is available then.
@Stateful
//@SessionScoped
public class FileStorage implements Serializable, IByteStreamStorage {
    private static final long serialVersionUID = -2406172386311143101L;

    @Inject
    private Logger log;

    /**
     * The storage path.
     */
    private String storagePath = null;

    /**
     * File handle to storagePath.
     */
    private File storagePathFile;

    /**
     * will be used as namespace for persistent identifiers, according to
     * {@link https://wiki.duraspace.org/display/FEDORA35/Fedora+Identifiers}.
     */
    private String repositoryName;

    /**
     * Default constructor.
     */
    public FileStorage() {
    }

    /**
     * Initializes class.
     */
    @PostConstruct
    public void init() {
        ConfigurationLoader configurationLoader = new ConfigurationLoader();

        Configuration config = configurationLoader.load();
        storagePath = config.getString("filestorage.path");

        if (storagePath != null) {
            storagePathFile = new File(storagePath);
            if (!storagePathFile.exists()) {
                if (storagePathFile.mkdirs()) {
                    log.info("Storage path created and set to {}.", storagePathFile.getAbsoluteFile());
                } else {
                    log.error("Storage path could not be created.");
                }
            } else {
                log.info("Storage path set to {}.", storagePathFile.getAbsoluteFile());
            }
        } else {
            log.error("Storage path not set.");
        }

        repositoryName = config.getString("filestorage.repository.name");
        if (repositoryName == null) {
            log.error("Repository name not set.");
        }
    }

    @Override
    public String store(String pid, byte[] bytestream) throws StorageException {
        String objectId;
        if (pid == null) {
            // a new object
            objectId = UUID.randomUUID().toString();
            pid = repositoryName + ":" + objectId;
        } else {
            // we ignore the object's namespace
            objectId = pid.substring(pid.indexOf(':') + 1);
        }
        // we try to rename the file, if it already exists
        File file = new File(storagePathFile, objectId);
        File backup = null;
        if (file.exists()) {
            try {
                backup = File.createTempFile(file.getName(), "backup", storagePathFile);
                file.renameTo(backup);
            } catch (IOException e) {
                throw new StorageException("failed to create backup for: " + pid, e);
            }
        }
        try {
            // write data to filesystem
            FileUtils.writeToFile(new ByteArrayInputStream(bytestream), new FileOutputStream(file));
            // data was stored successfully, backup is not needed any more
            if (backup != null) {
                backup.delete();
            }
        } catch (IOException e) {
            // try to restore old file
            if (backup != null) {
                if (backup.renameTo(file)) {
                    backup = null;
                } else {
                    throw new StorageException(
                            "failed to store digital object: " + pid + " and failed to restore backup!");
                }
            }
            throw new StorageException("failed to store digital object: " + pid, e);
        }
        return pid;

    }

    @Override
    public byte[] load(String pid) throws StorageException {
        File file = getFile(pid);
        try {
            return FileUtils.inputStreamToBytes(new FileInputStream(file));
        } catch (IOException e) {
            throw new StorageException("failed to load data for persistent identifier: " + pid);
        }
    }

    @Override
    public void delete(String pid) throws StorageException {
        File file = getFile(pid);
        if (!file.delete()) {
            log.error("failed to delete object: " + pid);
        }
    }

    /**
     * Returns a file for the provided pid.
     * 
     * @param pid
     *            the pid of the object
     * @return the file
     * @throws StorageException
     *             if the pid is empty or the object could not be found
     */
    private File getFile(String pid) throws StorageException {
        if ((pid == null) || (pid.isEmpty())) {
            throw new StorageException("provided persistent identifier is empty");
        }
        String objectId = pid.substring(pid.indexOf(':') + 1);
        File file = new File(storagePathFile, objectId);
        if (file.exists()) {
            return file;
        } else {
            throw new StorageException("no object found for persistent identifier: " + pid);
        }
    }

    // --------------- getter/setter ---------------
    public String getStoragePath() {
        return storagePath;
    }
}