Java tutorial
/* * 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; } }