Package org.jnode.fs.spi

Source Code of org.jnode.fs.spi.AbstractFileSystem

/*
* $Id$
*
* Copyright (C) 2003-2014 JNode.org
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; If not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.jnode.fs.spi;

import java.io.IOException;
import java.util.HashMap;

import org.apache.log4j.Logger;
import org.jnode.driver.ApiNotFoundException;
import org.jnode.driver.Device;
import org.jnode.driver.block.BlockDeviceAPI;
import org.jnode.driver.block.FSBlockDeviceAPI;
import org.jnode.fs.FSDirectory;
import org.jnode.fs.FSEntry;
import org.jnode.fs.FSFile;
import org.jnode.fs.FileSystem;
import org.jnode.fs.FileSystemException;
import org.jnode.fs.FileSystemType;

/**
* This class provide a basic implementation of {@link FileSystem} interface.
*
* @author Fabien DUMINY
*/
public abstract class AbstractFileSystem<T extends FSEntry> implements FileSystem<T> {
    /** My logger */
    private static final Logger log = Logger.getLogger(AbstractFileSystem.class);
    /** The device that contains the file system */
    private final Device device;
    /** API of the block device */
    private final BlockDeviceAPI api;
    /** Type of the file system */
    private final FileSystemType<? extends FileSystem<T>> type;
    /** Root enntry of the file system */
    private T rootEntry;
    /** The file system is read-only */
    private boolean readOnly;
    /** The file system is closed */
    private boolean closed;
    /** The cache of files */
    private HashMap<FSEntry, FSFile> files = new HashMap<FSEntry, FSFile>();
    /** The cache of directory */
    private HashMap<FSEntry, FSDirectory> directories = new HashMap<FSEntry, FSDirectory>();

    /**
     * Construct an AbstractFileSystem in specified readOnly mode
     *
     * @param device device contains file system. This paramter is mandatory.
     * @param readOnly file system should be read-only.
     *
     * @throws FileSystemException device is null or device has no {@link BlockDeviceAPI} defined.
     */
    public AbstractFileSystem(Device device, boolean readOnly,
            FileSystemType<? extends FileSystem<T>> type) throws FileSystemException {
        if (device == null)
            throw new FileSystemException("Device cannot be null.");

        this.device = device;

        try {
            api = device.getAPI(BlockDeviceAPI.class);
        } catch (ApiNotFoundException e) {
            throw new FileSystemException("Device is not a partition!", e);
        }

        this.closed = false;
        this.readOnly = readOnly;
        this.type = type;
    }

    /**
     * @see org.jnode.fs.FileSystem#getDevice()
     */
    public final Device getDevice() {
        return device;
    }

    /**
     * @see org.jnode.fs.FileSystem#getType()
     */
    public final FileSystemType<? extends FileSystem<T>> getType() {
        return type;
    }

    /**
     * @see org.jnode.fs.FileSystem#getRootEntry()
     */
    public T getRootEntry() throws IOException {
        if (isClosed())
            throw new IOException("FileSystem is closed");

        if (rootEntry == null) {
            rootEntry = createRootEntry();
        }
        return rootEntry;
    }

    /**
     * @see org.jnode.fs.FileSystem#close()
     */
    public void close() throws IOException {
        if (!closed) {
            if (!readOnly) {
                flush();
            }
            api.flush();
            files.clear();
            directories.clear();
            rootEntry = null;
            files = null;
            directories = null;
            closed = true;
        }
    }

    /**
     * Save any cached data (files, directories, ...) to the device.
     *
     * @throws IOException if error occurs during write of datas on the device.
     */
    public void flush() throws IOException {
        flushFiles();
        flushDirectories();
    }

    /**
     * Returns block device api.
     *
     * @return {@link BlockDeviceAPI}.
     */
    public final BlockDeviceAPI getApi() {
        return api;
    }

    /**
     * Return file system block device api.
     *
     * @return {@link BlockDeviceAPI}
     *
     * @throws ApiNotFoundException if no api found for this file system device.
     */
    public final FSBlockDeviceAPI getFSApi() throws ApiNotFoundException {
        return device.getAPI(FSBlockDeviceAPI.class);
    }

    /*
     * (non-Javadoc)
     * @see org.jnode.fs.FileSystem#isClosed()
     */
    public final boolean isClosed() {
        return closed;
    }

    /**
     * Returns <tt>true</tt> if file system is read-only.
     *
     * @return <tt>true</tt> if file system is read-only.
     */
    public final boolean isReadOnly() {
        return readOnly;
    }

    /**
     * Sets file system as a read-only file system.
     *
     * @param readOnly <tt>true</tt> if file system should be treated as a read-only file system.
     */
    protected final void setReadOnly(boolean readOnly) {
        this.readOnly = readOnly;
    }

    /**
     * Gets the file for the given entry.
     *
     * @param entry
     *
     * @return the {@link FSFile} associated with entry.
     *
     * @throws IOException if file system is closed.
     */
    public final synchronized FSFile getFile(FSEntry entry) throws IOException {
        if (isClosed())
            throw new IOException("FileSystem is closed");

        FSFile file = files.get(entry);
        if (file == null) {
            file = createFile(entry);
            files.put(entry, file);
        }
        return file;
    }

    /**
     * Creates a new file from the entry
     *
     * @param entry
     * @return a new {@link FSFile}
     *
     * @throws IOException
     */
    protected abstract FSFile createFile(FSEntry entry) throws IOException;

    /**
     * Save all unsaved files from entry cache.
     *
     * @throws IOException if error occurs during write of datas on the device.
     */
    private final void flushFiles() throws IOException {
        log.info("flushing files ...");
        for (FSFile f : files.values()) {
            if (log.isDebugEnabled()) {
                log.debug("flush: flushing file " + f);
            }
            f.flush();
        }
    }

    /**
     * Gets the file for the given entry.
     *
     * @param entry
     *
     * @return the {@link FSDirectory} associated with this entry
     *
     * @throws IOException
     */
    public final synchronized FSDirectory getDirectory(FSEntry entry) throws IOException {
        if (isClosed())
            throw new IOException("FileSystem is closed");

        FSDirectory dir = directories.get(entry);
        if (dir == null) {
            dir = createDirectory(entry);
            directories.put(entry, dir);
        }
        return dir;
    }

    /**
     * Creates a new directory from the entry
     *
     * @param entry
     * @return a new {@link FSDirectory}
     *
     * @throws IOException
     */
    protected abstract FSDirectory createDirectory(FSEntry entry) throws IOException;

    /**
     * Save all unsaved files from entry cache.
     */
    private final void flushDirectories() {
        log.info("flushing directories ...");
        for (FSDirectory d : directories.values()) {
            if (log.isDebugEnabled()) {
                log.debug("flush: flushing directory " + d);
            }
            //TODO: uncomment this line
            //d.flush();
        }
    }

    /**
     * Creates a new root entry
     *
     * @return {@link FSEntry} representing the new created root entry.
     *
     * @throws IOException file system doesn't allow to create a new root entry.
     */
    protected abstract T createRootEntry() throws IOException;
}
TOP

Related Classes of org.jnode.fs.spi.AbstractFileSystem

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.