/* * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Sun designates this * particular file as subject to the "Classpath" exception as provided * by Sun in the LICENSE file that accompanied this code. * * This code 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 General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, * CA 95054 USA or visit www.sun.com if you need additional information or * have any questions. */ package java.nio.file.spi; import java.nio.file.*; import static java.nio.file.StandardOpenOption.*; import java.nio.file.attribute.*; import java.nio.channels.*; import java.nio.ByteBuffer; import java.io.*; import java.util.*; /** * Base implementation class for a {@code Path}. * *
This class is intended to be extended by provider implementors. It * implements, or provides default implementations for several of the methods * defined by the {@code Path} class. It implements the {@link #copyTo copyTo} * and {@link #moveTo moveTo} methods for the case that the source and target * are not associated with the same provider. * * @since 1.7 */ public abstract class AbstractPath extends Path { /** * Initializes a new instance of this class. */ protected AbstractPath() { } /** * Deletes the file referenced by this object. * *
This method invokes the {@link #delete(boolean) delete(boolean)} * method with a parameter of {@code true}. It may be overridden where * required. * * @throws NoSuchFileException {@inheritDoc} * @throws DirectoryNotEmptyException {@inheritDoc} * @throws IOException {@inheritDoc} * @throws SecurityException {@inheritDoc} */ @Override public void delete() throws IOException { delete(true); } /** * Creates a new and empty file, failing if the file already exists. * *
This method invokes the {@link #newByteChannel(Set,FileAttribute[])
* newByteChannel(Set,FileAttribute...)} method to create the file. It may be
* overridden where required.
*
* @throws IllegalArgumentException {@inheritDoc}
* @throws FileAlreadyExistsException {@inheritDoc}
* @throws IOException {@inheritDoc}
* @throws SecurityException {@inheritDoc}
*/
@Override
public Path createFile(FileAttribute>... attrs)
throws IOException
{
EnumSet This method invokes the {@link #newByteChannel(Set,FileAttribute[])
* newByteChannel(Set,FileAttribute...)} method to open or create the file.
* It may be overridden where required.
*
* @throws IllegalArgumentException {@inheritDoc}
* @throws FileAlreadyExistsException {@inheritDoc}
* @throws IOException {@inheritDoc}
* @throws SecurityException {@inheritDoc}
*/
@Override
public SeekableByteChannel newByteChannel(OpenOption... options)
throws IOException
{
Set This method returns an {@code InputStream} that is constructed by
* invoking the {@link java.nio.channels.Channels#newInputStream
* Channels.newInputStream} method. It may be overridden where a more
* efficient implementation is available.
*
* @throws IOException {@inheritDoc}
* @throws SecurityException {@inheritDoc}
*/
@Override
public InputStream newInputStream() throws IOException {
return Channels.newInputStream(newByteChannel());
}
// opts must be modifiable
private OutputStream implNewOutputStream(Set This method returns an {@code OutputStream} that is constructed by
* invoking the {@link java.nio.channels.Channels#newOutputStream
* Channels.newOutputStream} method. It may be overridden where a more
* efficient implementation is available.
*
* @throws IllegalArgumentException {@inheritDoc}
* @throws IOException {@inheritDoc}
* @throws SecurityException {@inheritDoc}
*/
@Override
public OutputStream newOutputStream(OpenOption... options) throws IOException {
int len = options.length;
Set This method returns an {@code OutputStream} that is constructed by
* invoking the {@link java.nio.channels.Channels#newOutputStream
* Channels.newOutputStream} method. It may be overridden where a more
* efficient implementation is available.
*
* @throws IllegalArgumentException {@inheritDoc}
* @throws IOException {@inheritDoc}
* @throws SecurityException {@inheritDoc}
*/
@Override
public OutputStream newOutputStream(Set extends OpenOption> options,
FileAttribute>... attrs)
throws IOException
{
Set This method invokes the {@link
* #newDirectoryStream(java.nio.file.DirectoryStream.Filter)
* newDirectoryStream(Filter)} method with a filter that accept all entries.
* It may be overridden where required.
*
* @throws NotDirectoryException {@inheritDoc}
* @throws IOException {@inheritDoc}
* @throws SecurityException {@inheritDoc}
*/
@Override
public DirectoryStream This method constructs a {@link PathMatcher} by invoking the
* file system's {@link java.nio.file.FileSystem#getPathMatcher
* getPathMatcher} method. This method may be overridden where a more
* efficient implementation is available.
*
* @throws java.util.regex.PatternSyntaxException {@inheritDoc}
* @throws UnsupportedOperationException {@inheritDoc}
* @throws NotDirectoryException {@inheritDoc}
* @throws IOException {@inheritDoc}
* @throws SecurityException {@inheritDoc}
*/
@Override
public DirectoryStream This method invokes the {@link #checkAccess checkAccess} method to
* check if the file exists. It may be overridden where a more efficient
* implementation is available.
*/
@Override
public boolean exists() {
try {
checkAccess();
return true;
} catch (IOException x) {
// unable to determine if file exists
}
return false;
}
/**
* Tests whether the file located by this path does not exist.
*
* This method invokes the {@link #checkAccess checkAccess} method to
* check if the file exists. It may be overridden where a more efficient
* implementation is available.
*/
@Override
public boolean notExists() {
try {
checkAccess();
return false;
} catch (NoSuchFileException x) {
// file confirmed not to exist
return true;
} catch (IOException x) {
return false;
}
}
/**
* Registers the file located by this path with a watch service.
*
* This method invokes the {@link #register(WatchService,WatchEvent.Kind[],WatchEvent.Modifier[])
* register(WatchService,WatchEvent.Kind[],WatchEvent.Modifier...)}
* method to register the file. It may be overridden where required.
*/
@Override
public WatchKey register(WatchService watcher, WatchEvent.Kind>... events)
throws IOException
{
return register(watcher, events, NO_MODIFIERS);
}
private static final WatchEvent.Modifier[] NO_MODIFIERS = new WatchEvent.Modifier[0];
/**
* Copy the file located by this path to a target location.
*
* This method is invoked by the {@link #copyTo copyTo} method for
* the case that this {@code Path} and the target {@code Path} are
* associated with the same provider.
*
* @param target
* The target location
* @param options
* Options specifying how the copy should be done
*
* @throws IllegalArgumentException
* If an invalid option is specified
* @throws FileAlreadyExistsException
* The target file exists and cannot be replaced because the
* {@code REPLACE_EXISTING} option is not specified, or the target
* file is a non-empty directory (optional specific exception)
* @throws IOException
* If an I/O error occurs
* @throws SecurityException
* In the case of the default provider, and a security manager is
* installed, the {@link SecurityManager#checkRead(String) checkRead}
* method is invoked to check read access to the source file, the
* {@link SecurityManager#checkWrite(String) checkWrite} is invoked
* to check write access to the target file. If a symbolic link is
* copied the security manager is invoked to check {@link
* LinkPermission}{@code ("symbolic")}.
*/
protected abstract void implCopyTo(Path target, CopyOption... options)
throws IOException;
/**
* Move the file located by this path to a target location.
*
* This method is invoked by the {@link #moveTo moveTo} method for
* the case that this {@code Path} and the target {@code Path} are
* associated with the same provider.
*
* @param target
* The target location
* @param options
* Options specifying how the move should be done
*
* @throws IllegalArgumentException
* If an invalid option is specified
* @throws FileAlreadyExistsException
* The target file exists and cannot be replaced because the
* {@code REPLACE_EXISTING} option is not specified, or the target
* file is a non-empty directory
* @throws AtomicMoveNotSupportedException
* The options array contains the {@code ATOMIC_MOVE} option but
* the file cannot be moved as an atomic file system operation.
* @throws IOException
* If an I/O error occurs
* @throws SecurityException
* In the case of the default provider, and a security manager is
* installed, the {@link SecurityManager#checkWrite(String) checkWrite}
* method is invoked to check write access to both the source and
* target file.
*/
protected abstract void implMoveTo(Path target, CopyOption... options)
throws IOException;
/**
* Copy the file located by this path to a target location.
*
* If this path is associated with the same {@link FileSystemProvider
* provider} as the {@code target} then the {@link #implCopyTo implCopyTo}
* method is invoked to copy the file. Otherwise, this method attempts to
* copy the file to the target location in a manner that may be less
* efficient than would be the case that target is associated with the same
* provider as this path.
*
* @throws IllegalArgumentException {@inheritDoc}
* @throws FileAlreadyExistsException {@inheritDoc}
* @throws IOException {@inheritDoc}
* @throws SecurityException {@inheritDoc}
*/
@Override
public final Path copyTo(Path target, CopyOption... options)
throws IOException
{
if ((getFileSystem().provider() == target.getFileSystem().provider())) {
implCopyTo(target, options);
} else {
xProviderCopyTo(target, options);
}
return target;
}
/**
* Move or rename the file located by this path to a target location.
*
* If this path is associated with the same {@link FileSystemProvider
* provider} as the {@code target} then the {@link #implCopyTo implMoveTo}
* method is invoked to move the file. Otherwise, this method attempts to
* copy the file to the target location and delete the source file. This
* implementation may be less efficient than would be the case that
* target is associated with the same provider as this path.
*
* @throws IllegalArgumentException {@inheritDoc}
* @throws FileAlreadyExistsException {@inheritDoc}
* @throws IOException {@inheritDoc}
* @throws SecurityException {@inheritDoc}
*/
@Override
public final Path moveTo(Path target, CopyOption... options)
throws IOException
{
if ((getFileSystem().provider() == target.getFileSystem().provider())) {
implMoveTo(target, options);
} else {
// different providers so copy + delete
xProviderCopyTo(target, convertMoveToCopyOptions(options));
delete(false);
}
return target;
}
/**
* Converts the given array of options for moving a file to options suitable
* for copying the file when a move is implemented as copy + delete.
*/
private static CopyOption[] convertMoveToCopyOptions(CopyOption... options)
throws AtomicMoveNotSupportedException
{
int len = options.length;
CopyOption[] newOptions = new CopyOption[len+2];
for (int i=0; i