org.kie.commons.java.nio.fs.file.SimpleFileSystemProvider.java Source code

Java tutorial

Introduction

Here is the source code for org.kie.commons.java.nio.fs.file.SimpleFileSystemProvider.java

Source

/*
 * Copyright 2012 JBoss Inc
 *
 * 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 org.kie.commons.java.nio.fs.file;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.net.URI;
import java.nio.channels.FileChannel;
import java.util.Iterator;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.concurrent.ExecutorService;

import org.apache.commons.httpclient.URIException;
import org.apache.commons.httpclient.util.URIUtil;
import org.apache.commons.io.FileUtils;
import org.kie.commons.java.nio.IOException;
import org.kie.commons.java.nio.base.BasicFileAttributesImpl;
import org.kie.commons.java.nio.base.ExtendedAttributeView;
import org.kie.commons.java.nio.base.GeneralPathImpl;
import org.kie.commons.java.nio.base.SeekableByteChannelFileBasedImpl;
import org.kie.commons.java.nio.channels.AsynchronousFileChannel;
import org.kie.commons.java.nio.channels.SeekableByteChannel;
import org.kie.commons.java.nio.file.AccessDeniedException;
import org.kie.commons.java.nio.file.AccessMode;
import org.kie.commons.java.nio.file.AtomicMoveNotSupportedException;
import org.kie.commons.java.nio.file.CopyOption;
import org.kie.commons.java.nio.file.DirectoryNotEmptyException;
import org.kie.commons.java.nio.file.DirectoryStream;
import org.kie.commons.java.nio.file.FileAlreadyExistsException;
import org.kie.commons.java.nio.file.FileStore;
import org.kie.commons.java.nio.file.FileSystem;
import org.kie.commons.java.nio.file.FileSystemAlreadyExistsException;
import org.kie.commons.java.nio.file.FileSystemNotFoundException;
import org.kie.commons.java.nio.file.LinkOption;
import org.kie.commons.java.nio.file.NoSuchFileException;
import org.kie.commons.java.nio.file.NotDirectoryException;
import org.kie.commons.java.nio.file.NotLinkException;
import org.kie.commons.java.nio.file.OpenOption;
import org.kie.commons.java.nio.file.Path;
import org.kie.commons.java.nio.file.attribute.BasicFileAttributeView;
import org.kie.commons.java.nio.file.attribute.BasicFileAttributes;
import org.kie.commons.java.nio.file.attribute.FileAttribute;
import org.kie.commons.java.nio.file.attribute.FileAttributeView;
import org.kie.commons.java.nio.file.spi.FileSystemProvider;

import static org.kie.commons.java.nio.file.StandardOpenOption.*;
import static org.kie.commons.validation.Preconditions.*;

public class SimpleFileSystemProvider implements FileSystemProvider {

    private static final String USER_DIR = "user.dir";
    private final BaseSimpleFileSystem fileSystem;
    private boolean isDefault;
    private final OSType osType;
    private final File[] roots;

    enum OSType {
        WINDOWS, UNIX_LIKE;

        public static OSType currentOS() {
            if (System.getProperty("os.name").toLowerCase().indexOf("win") >= 0) {
                return WINDOWS;
            }
            return UNIX_LIKE;
        }
    }

    public SimpleFileSystemProvider() {
        this(File.listRoots(), OSType.currentOS());
    }

    SimpleFileSystemProvider(final File[] roots, final OSType osType) {
        final String defaultPath = System.getProperty(USER_DIR);
        this.osType = checkNotNull("osType", osType);
        this.roots = checkNotNull("roots", roots);
        if (osType == OSType.WINDOWS) {
            this.fileSystem = new SimpleWindowsFileSystem(this, defaultPath);
        } else {
            this.fileSystem = new SimpleUnixFileSystem(this, defaultPath);
        }
    }

    @Override
    public synchronized void forceAsDefault() {
        this.isDefault = true;
    }

    @Override
    public boolean isDefault() {
        return isDefault;
    }

    @Override
    public String getScheme() {
        return "file";
    }

    @Override
    public FileSystem getFileSystem(final URI uri)
            throws IllegalArgumentException, FileSystemNotFoundException, SecurityException {
        return getDefaultFileSystem();
    }

    @Override
    public Path getPath(final URI uri)
            throws IllegalArgumentException, FileSystemNotFoundException, SecurityException {
        checkNotNull("uri", uri);
        checkCondition("uri scheme not supported",
                uri.getScheme().equals(getScheme()) || uri.getScheme().equals("default"));

        try {
            return getDefaultFileSystem().getPath(URIUtil.decode(uri.getPath()));
        } catch (final URIException e) {
            return null;
        }
    }

    @Override
    public FileSystem newFileSystem(final URI uri, final Map<String, ?> env)
            throws IllegalArgumentException, IOException, SecurityException, FileSystemAlreadyExistsException {
        checkNotNull("uri", uri);
        checkNotNull("env", env);
        throw new FileSystemAlreadyExistsException();
    }

    @Override
    public FileSystem newFileSystem(final Path path, final Map<String, ?> env)
            throws IllegalArgumentException, UnsupportedOperationException, IOException, SecurityException {
        checkNotNull("path", path);
        checkNotNull("env", env);
        throw new FileSystemAlreadyExistsException();
    }

    @Override
    public InputStream newInputStream(final Path path, final OpenOption... options)
            throws IllegalArgumentException, NoSuchFileException, IOException, SecurityException {
        checkNotNull("path", path);
        final File file = path.toFile();
        if (!file.exists()) {
            throw new NoSuchFileException(file.toString());
        }
        try {
            return new FileInputStream(path.toFile());
        } catch (FileNotFoundException e) {
            throw new NoSuchFileException(e.getMessage());
        }
    }

    @Override
    public OutputStream newOutputStream(final Path path, final OpenOption... options)
            throws IllegalArgumentException, UnsupportedOperationException, IOException, SecurityException {
        checkNotNull("path", path);
        try {
            return new FileOutputStream(path.toFile());
        } catch (Exception e) {
            throw new IOException(e);
        }
    }

    @Override
    public FileChannel newFileChannel(final Path path, final Set<? extends OpenOption> options,
            final FileAttribute<?>... attrs)
            throws IllegalArgumentException, UnsupportedOperationException, IOException, SecurityException {
        checkNotNull("path", path);
        return ((FileOutputStream) newOutputStream(path)).getChannel();
    }

    @Override
    public AsynchronousFileChannel newAsynchronousFileChannel(final Path path,
            final Set<? extends OpenOption> options, final ExecutorService executor, FileAttribute<?>... attrs)
            throws IllegalArgumentException, UnsupportedOperationException, IOException, SecurityException {
        checkNotNull("path", path);
        throw new UnsupportedOperationException();
    }

    @Override
    public SeekableByteChannel newByteChannel(final Path path, final Set<? extends OpenOption> options,
            final FileAttribute<?>... attrs) throws IllegalArgumentException, UnsupportedOperationException,
            FileAlreadyExistsException, IOException, SecurityException {
        final File file = checkNotNull("path", path).toFile();

        if (file.exists()) {
            if (!(options != null && options.contains(TRUNCATE_EXISTING))) {
                throw new FileAlreadyExistsException(path.toString());
            }
        }

        try {
            return new SeekableByteChannelFileBasedImpl(new RandomAccessFile(file, "rw").getChannel()) {
                @Override
                public void close() throws java.io.IOException {
                    super.close();
                }
            };
        } catch (java.io.IOException e) {
            throw new IOException(e);
        }
    }

    @Override
    public void createDirectory(final Path dir, final FileAttribute<?>... attrs)
            throws UnsupportedOperationException, FileAlreadyExistsException, IOException, SecurityException {
        checkNotNull("dir", dir);
        final Path realDir = dir.toAbsolutePath();
        if (realDir.toFile().exists()) {
            throw new FileAlreadyExistsException(dir.toString());
        }
        realDir.toFile().mkdirs();
    }

    @Override
    public DirectoryStream<Path> newDirectoryStream(final Path dir, final DirectoryStream.Filter<Path> filter)
            throws NotDirectoryException, IOException, SecurityException {
        checkNotNull("filter", filter);
        final File file = checkNotNull("dir", dir).toFile();

        if (!file.isDirectory()) {
            throw new NotDirectoryException(dir.toString());
        }
        final File[] content = file.listFiles();

        if (content == null) {
            throw new NotDirectoryException(dir.toString());
        }

        return new DirectoryStream<Path>() {
            boolean isClosed = false;

            @Override
            public void close() throws IOException {
                if (isClosed) {
                    throw new IOException();
                }
                isClosed = true;
            }

            @Override
            public Iterator<Path> iterator() {
                if (isClosed) {
                    throw new IOException();
                }
                return new Iterator<Path>() {
                    private int i = -1;
                    private Path nextEntry = null;
                    public boolean atEof = false;

                    @Override
                    public boolean hasNext() {
                        if (nextEntry == null && !atEof) {
                            nextEntry = readNextEntry();
                        }
                        return nextEntry != null;
                    }

                    @Override
                    public Path next() {
                        final Path result;
                        if (nextEntry == null && !atEof) {
                            result = readNextEntry();
                        } else {
                            result = nextEntry;
                            nextEntry = null;
                        }
                        if (result == null) {
                            throw new NoSuchElementException();
                        }
                        return result;
                    }

                    private Path readNextEntry() {
                        if (atEof) {
                            return null;
                        }

                        Path result = null;
                        while (true) {
                            i++;
                            if (i >= content.length) {
                                atEof = true;
                                break;
                            }

                            final Path path = GeneralPathImpl.newFromFile(getDefaultFileSystem(), content[i]);
                            if (filter.accept(path)) {
                                result = path;
                                break;
                            }
                        }

                        return result;
                    }

                    @Override
                    public void remove() {
                        throw new UnsupportedOperationException();
                    }
                };
            }
        };
    }

    @Override
    public void createSymbolicLink(final Path link, final Path target, final FileAttribute<?>... attrs)
            throws UnsupportedOperationException, FileAlreadyExistsException, IOException, SecurityException {
        checkNotNull("link", link);
        checkNotNull("target", target);
        checkCondition("link and target can't be same", !link.equals(target));
        checkCondition("target must already exists", target.toFile().exists());

        if (link.toFile().exists()) {
            throw new FileAlreadyExistsException(link.toString());
        }

        throw new UnsupportedOperationException();
    }

    @Override
    public void createLink(final Path link, final Path existing)
            throws UnsupportedOperationException, FileAlreadyExistsException, IOException, SecurityException {
        checkNotNull("link", link);
        checkNotNull("existing", existing);
        checkCondition("existing must already exists", existing.toFile().exists());
        checkCondition("link and target can't be same", !link.equals(existing));

        if (link.toFile().exists()) {
            throw new FileAlreadyExistsException(link.toString());
        }

        throw new UnsupportedOperationException();
    }

    @Override
    public void delete(final Path path)
            throws NoSuchFileException, DirectoryNotEmptyException, IOException, SecurityException {
        checkNotNull("path", path);

        if (!path.toFile().exists()) {
            throw new NoSuchFileException(path.toString());
        }

        deleteIfExists(path);
    }

    @Override
    public boolean deleteIfExists(final Path path)
            throws DirectoryNotEmptyException, IOException, SecurityException {
        checkNotNull("path", path);
        final File file = path.toFile();
        try {
            if (file.isDirectory() && file.list().length > 0) {
                throw new DirectoryNotEmptyException(path.toString());
            }

            return file.delete();
        } finally {
            toGeneralPathImpl(path).clearCache();
        }
    }

    @Override
    public Path readSymbolicLink(final Path link)
            throws UnsupportedOperationException, NotLinkException, IOException, SecurityException {
        checkNotNull("link", link);

        if (!link.toFile().exists()) {
            throw new NotLinkException(link.toString());
        }

        throw new UnsupportedOperationException();
    }

    @Override
    public boolean isSameFile(final Path path, final Path path2) throws IOException, SecurityException {
        checkNotNull("path", path);
        checkNotNull("path2", path2);

        return path.equals(path2);
    }

    @Override
    public boolean isHidden(final Path path) throws IllegalArgumentException, IOException, SecurityException {
        checkNotNull("path", path);

        return path.toFile().isHidden();
    }

    @Override
    public void checkAccess(final Path path, AccessMode... modes) throws UnsupportedOperationException,
            NoSuchFileException, AccessDeniedException, IOException, SecurityException {
        checkNotNull("path", path);
        checkNotNull("modes", modes);

        if (!path.toFile().exists()) {
            throw new NoSuchFileException(path.toString());
        }

        if (path.toFile() != null) {
            for (final AccessMode mode : modes) {
                checkNotNull("mode", mode);
                switch (mode) {
                case READ:
                    if (!path.toFile().canRead()) {
                        throw new AccessDeniedException(path.toString());
                    }
                    break;
                case EXECUTE:
                    if (!path.toFile().canExecute()) {
                        throw new AccessDeniedException(path.toString());
                    }
                    break;
                case WRITE:
                    if (!path.toFile().canWrite()) {
                        throw new AccessDeniedException(path.toString());
                    }
                    break;
                }
            }
        }
    }

    @Override
    public FileStore getFileStore(final Path path) throws IOException, SecurityException {
        checkNotNull("path", path);
        if (osType == OSType.WINDOWS) {
            return new SimpleWindowsFileStore(roots, path);
        }
        return new SimpleUnixFileStore(path);
    }

    @Override
    public <V extends FileAttributeView> V getFileAttributeView(final Path path, final Class<V> type,
            final LinkOption... options) throws NoSuchFileException {

        checkNotNull("path", path);
        checkNotNull("type", type);

        if (!path.toFile().exists()) {
            throw new NoSuchFileException(path.toString());
        }

        final GeneralPathImpl gPath = toGeneralPathImpl(path);

        final V view = gPath.getAttrView(type);

        if (view == null && type == BasicFileAttributeView.class || type == SimpleBasicFileAttributeView.class) {
            final V newView = (V) new SimpleBasicFileAttributeView(gPath);
            gPath.addAttrView(newView);
            return newView;
        }

        return view;
    }

    private ExtendedAttributeView getFileAttributeView(final Path path, final String name,
            final LinkOption... options) {
        final GeneralPathImpl gPath = toGeneralPathImpl(path);

        final ExtendedAttributeView view = gPath.getAttrView(name);

        if (view == null && name.equals("basic")) {
            final SimpleBasicFileAttributeView newView = new SimpleBasicFileAttributeView(gPath);
            gPath.addAttrView(newView);
            return newView;
        }
        return view;
    }

    @Override
    public <A extends BasicFileAttributes> A readAttributes(final Path path, final Class<A> type,
            final LinkOption... options)
            throws NoSuchFileException, UnsupportedOperationException, IOException, SecurityException {
        checkNotNull("path", path);
        checkNotNull("type", type);

        if (!path.toFile().exists()) {
            throw new NoSuchFileException(path.toString());
        }

        if (type == BasicFileAttributesImpl.class || type == BasicFileAttributes.class) {
            final SimpleBasicFileAttributeView view = getFileAttributeView(path, SimpleBasicFileAttributeView.class,
                    options);
            return (A) view.readAttributes();
        }

        return null;
    }

    @Override
    public Map<String, Object> readAttributes(final Path path, final String attributes, final LinkOption... options)
            throws UnsupportedOperationException, IllegalArgumentException, IOException, SecurityException {
        checkNotNull("path", path);
        checkNotEmpty("attributes", attributes);

        final String[] s = split(attributes);
        if (s[0].length() == 0) {
            throw new IllegalArgumentException(attributes);
        }

        final ExtendedAttributeView view = getFileAttributeView(path, s[0], options);
        if (view == null) {
            throw new UnsupportedOperationException("View '" + s[0] + "' not available");
        }
        return view.readAttributes(s[1].split(","));
    }

    @Override
    public void setAttribute(final Path path, final String attribute, final Object value,
            final LinkOption... options) throws UnsupportedOperationException, IllegalArgumentException,
            ClassCastException, IOException, SecurityException {
        checkNotNull("path", path);
        checkNotEmpty("attributes", attribute);

        final String[] s = split(attribute);
        if (s[0].length() == 0) {
            throw new IllegalArgumentException(attribute);
        }
        final ExtendedAttributeView view = getFileAttributeView(path, s[0], options);
        if (view == null) {
            throw new UnsupportedOperationException("View '" + s[0] + "' not available");
        }
        view.setAttribute(attribute, value);
    }

    @Override
    public void copy(final Path source, final Path target, final CopyOption... options)
            throws UnsupportedOperationException, FileAlreadyExistsException, DirectoryNotEmptyException,
            IOException, SecurityException {
        checkNotNull("source", source);
        checkNotNull("target", target);
        checkCondition("source must exist", source.toFile().exists());

        if (target.toFile().exists()) {
            throw new FileAlreadyExistsException(target.toString());
        }
        if (source.toFile().isDirectory() && source.toFile().list().length > 0) {
            throw new DirectoryNotEmptyException(source.toString());
        }

        try {
            if (source.toFile().isDirectory()) {
                FileUtils.copyDirectory(source.toFile(), target.toFile());
            } else {
                FileUtils.copyFile(source.toFile(), target.toFile());
            }
        } catch (java.io.IOException ex) {
            throw new IOException(ex);
        }
    }

    @Override
    public void move(final Path source, final Path target, final CopyOption... options)
            throws DirectoryNotEmptyException, AtomicMoveNotSupportedException, IOException, SecurityException {
        checkNotNull("source", source);
        checkNotNull("target", target);
        checkCondition("source must exist", source.toFile().exists());

        if (target.toFile().exists()) {
            throw new FileAlreadyExistsException(target.toString());
        }

        if (source.toFile().isDirectory() && source.toFile().list().length > 0) {
            throw new DirectoryNotEmptyException(source.toString());
        }

        try {
            if (source.toFile().isDirectory()) {
                FileUtils.moveDirectory(source.toFile(), target.toFile());
            } else {
                FileUtils.moveFile(source.toFile(), target.toFile());
            }
        } catch (java.io.IOException ex) {
            throw new IOException(ex);
        }
    }

    private FileSystem getDefaultFileSystem() {
        return fileSystem;
    }

    private GeneralPathImpl toGeneralPathImpl(final Path path) {
        if (path instanceof GeneralPathImpl) {
            return (GeneralPathImpl) path;
        }
        return GeneralPathImpl.create(fileSystem, path.toString(), false);
    }

    private String[] split(final String attribute) {
        final String[] s = new String[2];
        final int pos = attribute.indexOf(':');
        if (pos == -1) {
            s[0] = "basic";
            s[1] = attribute;
        } else {
            s[0] = attribute.substring(0, pos);
            s[1] = (pos == attribute.length()) ? "" : attribute.substring(pos + 1);
        }
        return s;
    }

}