com.thruzero.domain.dsc.fs.FileDataStoreContainer.java Source code

Java tutorial

Introduction

Here is the source code for com.thruzero.domain.dsc.fs.FileDataStoreContainer.java

Source

/*
 *   Copyright 2011-2012 George Norman
 *
 *   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 com.thruzero.domain.dsc.fs;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;

import com.thruzero.common.core.support.ContainerPath;
import com.thruzero.common.core.support.EntityPath;
import com.thruzero.domain.dao.GenericDAO.DAOException;
import com.thruzero.domain.dsc.store.DataStoreContainer;
import com.thruzero.domain.dsc.store.DataStoreException;
import com.thruzero.domain.store.BaseStorePath;

/**
 * A DataStoreContainer that simply manages files within a single directory; it doesn't manage sub-directories or parent directories. Each parent directory and
 * sub-directory is managed by a separate instance of FileDataStoreContainer.
 * <p>
 * All DataStoreContainer objects are managed by {@code GenericDscDAO}, which will flatten and resurrect the Domain Object instances automatically (passed in as
 * instances of DataStoreEntity).
 * 
 * @author George Norman
 */
public class FileDataStoreContainer implements DataStoreContainer {
    /** Absolute path to the directory managed by this FileDataStoreContainer instance. */
    private File containerStore;

    // ------------------------------------------------
    // FileDataStoreEntity
    // ------------------------------------------------

    /**
     * Represents a file in the file system. It uses FileInputStream to get the data to be read or saved.
     */
    public static class FileDataStoreEntity implements DataStoreEntity {
        private File directoryStore;
        private EntityPath entityPath;

        public FileDataStoreEntity(final File directoryStore, final EntityPath entityPath) {
            this.directoryStore = directoryStore;
            this.entityPath = (EntityPath) entityPath.clone();
        }

        @Override
        public InputStream getData() {
            InputStream result;

            try {
                result = new FileInputStream(getFile());
            } catch (FileNotFoundException e) {
                result = null;
            }
            return result;
        }

        @Override
        public EntityPath getEntityPath() {
            return entityPath;
        }

        public File getFile() {
            File directory = new File(directoryStore, entityPath.getContainerPath().getPath());
            File file = new File(directory, entityPath.getEntityName());

            return file;
        }
    }

    // ============================================================
    // FileDataStoreContainer
    // ============================================================

    /**
     * The given baseStorePath and directoryPath are combined to produce an absolute file path to the directory, which is validated to ensure it exists and is a
     * directory. If it's nonexistent and createDirsIfNonExistent is true, then the directory will be created, including all nonexistent parent directories.
     */
    public FileDataStoreContainer(BaseStorePath baseStorePath, ContainerPath containerPath,
            boolean createParentContainersIfNonExistent) {
        this.containerStore = new File(baseStorePath.toString(), containerPath.getPath());

        boolean exists = containerStore.exists();

        // create directory if does not exist
        if (createParentContainersIfNonExistent && !exists) {
            exists = containerStore.mkdirs();
        }

        // assert that the containerStore is a directory
        if (exists && !containerStore.isDirectory()) {
            throw new DAOException(
                    "Error - The directory store is not a directory: " + containerStore.getAbsolutePath());
        }
    }

    /**
     * Return a list of all the {@code DataStoreEntity} instances within this container and if {@code recursive} is true, then return all of the
     * {@code DataStoreEntity} instances within all of the sub containers as well.
     */
    @Override
    public List<? extends DataStoreEntity> getAllEntities(boolean recursive) {
        List<DataStoreEntity> result = new ArrayList<DataStoreEntity>();
        List<EntityPath> paths = getAllEntityPaths(recursive);

        for (EntityPath entityPath : paths) {
            result.add(createDataStoreEntityFrom(entityPath));
        }

        return result;
    }

    @Override
    public List<EntityPath> getAllEntityPaths(boolean recursive) {
        return doGetAllEntityPaths(new ContainerPath(), recursive);
    }

    protected List<EntityPath> doGetAllEntityPaths(ContainerPath childPath, boolean recursive) {
        List<EntityPath> result = new ArrayList<EntityPath>();
        File fromDir = new File(containerStore, childPath.toString().substring(1)); // remove leading "/"
        File[] files = fromDir.listFiles(); // note: could use HierarchicalFileWalker here, but would need to add back the path relative to the containerStore

        if (files != null) {
            for (File file : files) {
                if (file.isFile()) {
                    if (!".DS_Store".equals(file.getName())) { // ignore os x junk.
                        EntityPath id = new EntityPath(childPath.getPath(), file.getName());

                        result.add(id);
                    }
                } else if (recursive) {
                    ContainerPath nextChildPath = new ContainerPath(childPath,
                            file.getName() + ContainerPath.CONTAINER_PATH_SEPARATOR);

                    result.addAll(doGetAllEntityPaths(nextChildPath, recursive));
                }
            }
        }

        return result;
    }

    protected DataStoreEntity createDataStoreEntityFrom(final EntityPath id) {
        return new FileDataStoreEntity(containerStore, id);
    }

    /**
     * Returns a DataStoreEntity that represents the data from the file specified by the given fileName (can have any file extension).
     */
    @Override
    public DataStoreEntity readEntity(final String fileName) {
        return new FileDataStoreEntity(containerStore, new EntityPath(new ContainerPath(), fileName));
    }

    /**
     * Creates a new data file, if nonexistent and then writes the given data to it.
     */
    @Override
    public void saveOrUpdateEntity(String fileName, DataStoreEntity fileData) {
        if (!isExistingEntity(fileName)) {
            // create the file
            createNewEntity(fileName);
        }

        // then, write data to it
        updateEntity(fileName, fileData);
    }

    /**
     * Update an existing data file with the given fileData.
     * 
     * @throws DAOException
     *           if nonexistent.
     */
    @Override
    public void updateEntity(String fileName, DataStoreEntity fileData) {
        File fileToWrite = getFileFor(fileName);

        if (fileToWrite.exists()) {
            byte[] dataAsBytes;
            try {
                dataAsBytes = IOUtils.toByteArray(fileData.getData());
            } catch (IOException e1) {
                throw new DAOException("ERROR: Can't read fileData (to byte array).");
            }

            try {
                FileUtils.writeByteArrayToFile(fileToWrite, dataAsBytes);
            } catch (IOException e) {
                throw new DAOException("Error writing to file: " + fileToWrite.getAbsolutePath(), e);
            }
        } else {
            throw new DAOException(
                    "Error - Can't write to file that doesn't exist: " + fileToWrite.getAbsolutePath());
        }
    }

    /**
     * Create a new data file.
     * 
     * @throws DAOException
     *           if file already exists or could not be created.
     */
    @Override
    public void createNewEntity(String fileName) {
        File fileToCreate = getFileFor(fileName);

        if (fileToCreate.exists()) {
            throw new DAOException(
                    "Error - Can't create a file that already exists: " + fileToCreate.getAbsolutePath());
        } else {
            boolean fileCreated = false;

            try {
                fileCreated = fileToCreate.createNewFile();
            } catch (IOException e) {
                // ignore
            }

            if (!fileCreated) {
                throw new DAOException("Error creating file: " + fileToCreate.getAbsolutePath());
            }
        }
    }

    /**
     * Deletes the file specified by the given fileName.
     * 
     * @throws DAOException
     *           if file is a directory or could not be deleted.
     */
    @Override
    public void deleteEntity(String fileName) {
        File fileToDelete = getFileFor(fileName);

        // assert that the file is not a directory
        if (fileToDelete.isDirectory()) {
            throw new DAOException(
                    "Error - The file name refers to a directory: " + fileToDelete.getAbsolutePath());
        }

        // delete it if it exists
        if (fileToDelete.exists()) {
            if (!fileToDelete.delete()) {
                throw new DAOException("Error - Couldn't delete the file named: " + fileToDelete.getAbsolutePath());
            }
        }
    }

    /**
     * Returns true if the specified file exists in the file system.
     */
    @Override
    public boolean isExistingEntity(String fileName) {
        File fileToCreate = getFileFor(fileName);

        return fileToCreate.exists();
    }

    protected File getFileFor(String fileName) {
        File result = new File(containerStore, fileName);

        return result;
    }

    @Override
    public String getDebugPathInfo(String fileName) {
        return getFileFor(fileName).getAbsolutePath();
    }

    @Override
    public void validate() {
        File parentDirectory = containerStore.getParentFile();
        if (!parentDirectory.exists() && !parentDirectory.getParentFile().exists()) {
            throw new DataStoreException("ERROR: The parent directory for the data store does not exist: '"
                    + parentDirectory.getAbsolutePath() + "'.");
        }
    }

}