doGetAttributes() throws Exception {
return Collections.emptyMap();
}
/**
* Returns the certificates used to sign this file. Is only called if {@link #doGetType} does not return
* {@link FileType#IMAGINARY}.
*
* This implementation always returns null.
*
* @return The certificates used to sign the file.
* @throws Exception if an error occurs.
*/
protected Certificate[] doGetCertificates() throws Exception {
return null;
}
/**
* Returns the size of the file content (in bytes). Is only called if {@link #doGetType} returns
* {@link FileType#FILE}.
*
* @return The size of the file in bytes.
* @throws Exception if an error occurs.
*/
protected abstract long doGetContentSize() throws Exception;
/**
* Creates an input stream to read the file content from. Is only called if {@link #doGetType} returns
* {@link FileType#FILE}.
*
* It is guaranteed that there are no open output streams for this file when this method is called.
*
* The returned stream does not have to be buffered.
*
* @return An InputStream to read the file content.
* @throws Exception if an error occurs.
*/
protected abstract InputStream doGetInputStream() throws Exception;
/**
* Returns the last modified time of this file. Is only called if {@link #doGetType} does not return
* {@link FileType#IMAGINARY}.
*
* This implementation throws an exception.
*
* @return The last modification time.
* @throws Exception if an error occurs.
*/
protected long doGetLastModifiedTime() throws Exception {
throw new FileSystemException("vfs.provider/get-last-modified-not-supported.error");
}
/**
* Creates an output stream to write the file content to. Is only called if:
*
* - {@link #doIsWriteable} returns true.
*
- {@link #doGetType} returns {@link FileType#FILE}, or {@link #doGetType} returns {@link FileType#IMAGINARY},
* and the file's parent exists and is a folder.
*
* It is guaranteed that there are no open stream (input or output) for this file when this method is called.
*
* The returned stream does not have to be buffered.
*
* This implementation throws an exception.
*
* @param bAppend true if the file should be appended to, false if it should be overwritten.
* @return An OutputStream to write to the file.
* @throws Exception if an error occurs.
*/
protected OutputStream doGetOutputStream(final boolean bAppend) throws Exception {
throw new FileSystemException("vfs.provider/write-not-supported.error");
}
/**
* Creates access to the file for random i/o. Is only called if {@link #doGetType} returns {@link FileType#FILE}.
*
* It is guaranteed that there are no open output streams for this file when this method is called.
*
* @param mode The mode to access the file.
* @return The RandomAccessContext.
* @throws Exception if an error occurs.
*/
protected RandomAccessContent doGetRandomAccessContent(final RandomAccessMode mode) throws Exception {
throw new FileSystemException("vfs.provider/random-access-not-supported.error");
}
/**
* Determines the type of this file. Must not return null. The return value of this method is cached, so the
* implementation can be expensive.
*
* @return the type of the file.
* @throws Exception if an error occurs.
*/
protected abstract FileType doGetType() throws Exception;
/**
* Determines if this file is executable. Is only called if {@link #doGetType} does not return
* {@link FileType#IMAGINARY}.
*
* This implementation always returns false.
*
* @return true if the file is executable, false otherwise.
* @throws Exception if an error occurs.
*/
protected boolean doIsExecutable() throws Exception {
return false;
}
/**
* Determines if this file is hidden. Is only called if {@link #doGetType} does not return
* {@link FileType#IMAGINARY}.
*
* This implementation always returns false.
*
* @return true if the file is hidden, false otherwise.
* @throws Exception if an error occurs.
*/
protected boolean doIsHidden() throws Exception {
return false;
}
/**
* Determines if this file can be read. Is only called if {@link #doGetType} does not return
* {@link FileType#IMAGINARY}.
*
* This implementation always returns true.
*
* @return true if the file is readable, false otherwise.
* @throws Exception if an error occurs.
*/
protected boolean doIsReadable() throws Exception {
return true;
}
/**
* Checks if this fileObject is the same file as {@code destFile} just with a different name. E.g. for case
* insensitive filesystems like windows.
*
* @param destFile The file to compare to.
* @return true if the FileObjects are the same.
* @throws FileSystemException if an error occurs.
*/
protected boolean doIsSameFile(final FileObject destFile) throws FileSystemException {
return false;
}
/**
* Determines if this file can be written to. Is only called if {@link #doGetType} does not return
* {@link FileType#IMAGINARY}.
*
* This implementation always returns true.
*
* @return true if the file is writable.
* @throws Exception if an error occurs.
*/
protected boolean doIsWriteable() throws Exception {
return true;
}
/**
* Lists the children of this file. Is only called if {@link #doGetType} returns {@link FileType#FOLDER}. The return
* value of this method is cached, so the implementation can be expensive.
*
* @return a possible empty String array if the file is a directory or null or an exception if the file is not a
* directory or can't be read.
* @throws Exception if an error occurs.
*/
protected abstract String[] doListChildren() throws Exception;
/**
* Lists the children of this file.
*
* Is only called if {@link #doGetType} returns {@link FileType#FOLDER}.
*
* The return value of this method is cached, so the implementation can be expensive.
* Other than {@code doListChildren} you could return FileObject's to e.g. reinitialize the type of the file.
*
* (Introduced for Webdav: "permission denied on resource" during getType())
*
* @return The children of this FileObject.
* @throws Exception if an error occurs.
*/
protected FileObject[] doListChildrenResolved() throws Exception {
return null;
}
/**
* Removes an attribute of this file.
*
* Is only called if {@link #doGetType} does not return {@link FileType#IMAGINARY}.
*
* This implementation throws an exception.
*
* @param attrName The name of the attribute to remove.
* @throws Exception if an error occurs.
* @since 2.0
*/
protected void doRemoveAttribute(final String attrName) throws Exception {
throw new FileSystemException("vfs.provider/remove-attribute-not-supported.error");
}
/**
* Renames the file.
*
* Is only called when:
*
* - {@link #doIsWriteable} returns true.
*
*
* This implementation throws an exception.
*
* @param newFile A FileObject with the new file name.
* @throws Exception if an error occurs.
*/
protected void doRename(final FileObject newFile) throws Exception {
throw new FileSystemException("vfs.provider/rename-not-supported.error");
}
/**
* Sets an attribute of this file.
*
* Is only called if {@link #doGetType} does not return {@link FileType#IMAGINARY}.
*
* This implementation throws an exception.
*
* @param attrName The attribute name.
* @param value The value to be associated with the attribute name.
* @throws Exception if an error occurs.
*/
protected void doSetAttribute(final String attrName, final Object value) throws Exception {
throw new FileSystemException("vfs.provider/set-attribute-not-supported.error");
}
/**
* Make the file executable.
*
* Only called if {@link #doGetType} does not return {@link FileType#IMAGINARY}.
*
* This implementation returns false.
*
* @param executable True to allow access, false to disallow.
* @param ownerOnly If {@code true}, the permission applies only to the owner; otherwise, it applies to everybody.
* @return true if the operation succeeded.
* @throws Exception Any Exception thrown is wrapped in FileSystemException.
* @see #setExecutable(boolean, boolean)
* @since 2.1
*/
protected boolean doSetExecutable(final boolean executable, final boolean ownerOnly) throws Exception {
return false;
}
/**
* Sets the last modified time of this file.
*
* Is only called if {@link #doGetType} does not return {@link FileType#IMAGINARY}.
*
* This implementation throws an exception.
*
* @param modtime The last modification time.
* @return true if the time was set.
* @throws Exception Any Exception thrown is wrapped in FileSystemException.
*/
protected boolean doSetLastModifiedTime(final long modtime) throws Exception {
throw new FileSystemException("vfs.provider/set-last-modified-not-supported.error");
}
/**
* Make the file or folder readable.
*
* Only called if {@link #doGetType} does not return {@link FileType#IMAGINARY}.
*
* This implementation returns false.
*
* @param readable True to allow access, false to disallow
* @param ownerOnly If {@code true}, the permission applies only to the owner; otherwise, it applies to everybody.
* @return true if the operation succeeded
* @throws Exception Any Exception thrown is wrapped in FileSystemException.
* @see #setReadable(boolean, boolean)
* @since 2.1
*/
protected boolean doSetReadable(final boolean readable, final boolean ownerOnly) throws Exception {
return false;
}
/**
* Make the file or folder writeable.
*
* Only called if {@link #doGetType} does not return {@link FileType#IMAGINARY}.
*
* @param writable True to allow access, false to disallow
* @param ownerOnly If {@code true}, the permission applies only to the owner; otherwise, it applies to everybody.
* @return true if the operation succeeded
* @throws Exception Any Exception thrown is wrapped in FileSystemException.
* @see #setWritable(boolean, boolean)
* @since 2.1
*/
protected boolean doSetWritable(final boolean writable, final boolean ownerOnly) throws Exception {
return false;
}
/**
* Called when the output stream for this file is closed.
*
* @throws Exception if an error occurs.
*/
protected void endOutput() throws Exception {
if (getType() == FileType.IMAGINARY) {
// File was created
handleCreate(FileType.FILE);
} else {
// File has changed
onChange();
}
}
/**
* Determines if the file exists.
*
* @return true if the file exists, false otherwise,
* @throws FileSystemException if an error occurs.
*/
@Override
public boolean exists() throws FileSystemException {
return getType() != FileType.IMAGINARY;
}
private FileName[] extractNames(final FileObject[] objects) {
if (objects == null) {
return null;
}
final FileName[] names = new FileName[objects.length];
for (int iterObjects = 0; iterObjects < objects.length; iterObjects++) {
names[iterObjects] = objects[iterObjects].getName();
}
return names;
}
@Override
protected void finalize() throws Throwable {
fs.fileObjectDestroyed(this);
super.finalize();
}
/**
* Finds the set of matching descendants of this file, in depthwise order.
*
* @param selector The FileSelector.
* @return list of files or null if the base file (this object) do not exist
* @throws FileSystemException if an error occurs.
*/
@Override
public FileObject[] findFiles(final FileSelector selector) throws FileSystemException {
final List list = this.listFiles(selector);
return list == null ? null : list.toArray(new FileObject[list.size()]);
}
/**
* Traverses the descendants of this file, and builds a list of selected files.
*
* @param selector The FileSelector.
* @param depthwise if true files are added after their descendants, before otherwise.
* @param selected A List of the located FileObjects.
* @throws FileSystemException if an error occurs.
*/
@Override
public void findFiles(final FileSelector selector, final boolean depthwise, final List selected)
throws FileSystemException {
try {
if (exists()) {
// Traverse starting at this file
final DefaultFileSelectorInfo info = new DefaultFileSelectorInfo();
info.setBaseFolder(this);
info.setDepth(0);
info.setFile(this);
traverse(info, selector, depthwise, selected);
}
} catch (final Exception e) {
throw new FileSystemException("vfs.provider/find-files.error", fileName, e);
}
}
/**
* Returns the file system this file belongs to.
*
* @return The FileSystem this file is associated with.
*/
protected AFS getAbstractFileSystem() {
return fs;
}
/**
* Returns a child of this file.
*
* @param name The name of the child to locate.
* @return The FileObject for the file or null if the child does not exist.
* @throws FileSystemException if an error occurs.
*/
@Override
public FileObject getChild(final String name) throws FileSystemException {
// TODO - use a hashtable when there are a large number of children
final FileObject[] children = getChildren();
for (final FileObject element : children) {
final FileName child = element.getName();
// TODO - use a comparator to compare names
if (child.getBaseName().equals(name)) {
return resolveFile(child);
}
}
return null;
}
/**
* Returns the children of the file.
*
* @return an array of FileObjects, one per child.
* @throws FileSystemException if an error occurs.
*/
@Override
public FileObject[] getChildren() throws FileSystemException {
synchronized (fs) {
// VFS-210
if (!fs.hasCapability(Capability.LIST_CHILDREN)) {
throw new FileNotFolderException(fileName);
}
/*
* VFS-210 if (!getType().hasChildren()) { throw new
* FileSystemException("vfs.provider/list-children-not-folder.error", name); }
*/
attach();
// Use cached info, if present
if (children != null) {
return resolveFiles(children);
}
// allow the filesystem to return resolved children. e.g. prefill type for webdav
FileObject[] childrenObjects;
try {
childrenObjects = doListChildrenResolved();
children = extractNames(childrenObjects);
} catch (final FileSystemException exc) {
// VFS-210
throw exc;
} catch (final Exception exc) {
throw new FileSystemException("vfs.provider/list-children.error", exc, fileName);
}
if (childrenObjects != null) {
return childrenObjects;
}
// List the children
final String[] files;
try {
files = doListChildren();
} catch (final FileSystemException exc) {
// VFS-210
throw exc;
} catch (final Exception exc) {
throw new FileSystemException("vfs.provider/list-children.error", exc, fileName);
}
if (files == null) {
// VFS-210
// honor the new doListChildren contract
// return null;
throw new FileNotFolderException(fileName);
} else if (files.length == 0) {
// No children
children = EMPTY_FILE_ARRAY;
} else {
// Create file objects for the children
final FileName[] cache = new FileName[files.length];
for (int i = 0; i < files.length; i++) {
final String file = files[i];
cache[i] = fs.getFileSystemManager().resolveName(fileName, file, NameScope.CHILD);
}
// VFS-285: only assign the children filenames after all of them have been
// resolved successfully to prevent an inconsistent internal state
children = cache;
}
return resolveFiles(children);
}
}
/**
* Returns the file's content.
*
* @return the FileContent for this FileObject.
* @throws FileSystemException if an error occurs.
*/
@Override
public FileContent getContent() throws FileSystemException {
synchronized (fs) {
attach();
if (content == null) {
content = doCreateFileContent();
}
return content;
}
}
/**
* Creates the FileContentInfo factory.
*
* @return The FileContentInfoFactory.
*/
protected FileContentInfoFactory getFileContentInfoFactory() {
return fs.getFileSystemManager().getFileContentInfoFactory();
}
/**
* @return FileOperations interface that provides access to the operations API.
* @throws FileSystemException if an error occurs.
*/
@Override
public FileOperations getFileOperations() throws FileSystemException {
if (operations == null) {
operations = new DefaultFileOperations(this);
}
return operations;
}
/**
* Returns the file system this file belongs to.
*
* @return The FileSystem this file is associated with.
*/
@Override
public FileSystem getFileSystem() {
return fs;
}
/**
* Returns an input stream to use to read the content of the file.
*
* @return The InputStream to access this file's content.
* @throws FileSystemException if an error occurs.
*/
public InputStream getInputStream() throws FileSystemException {
/*
* VFS-210 if (!getType().hasContent()) { throw new FileSystemException("vfs.provider/read-not-file.error",
* name); } if (!isReadable()) { throw new FileSystemException("vfs.provider/read-not-readable.error", name); }
*/
// Get the raw input stream
try {
return doGetInputStream();
} catch (final org.apache.commons.vfs2.FileNotFoundException exc) {
throw new org.apache.commons.vfs2.FileNotFoundException(fileName, exc);
} catch (final FileNotFoundException exc) {
throw new org.apache.commons.vfs2.FileNotFoundException(fileName, exc);
} catch (final FileSystemException exc) {
throw exc;
} catch (final Exception exc) {
throw new FileSystemException("vfs.provider/read.error", fileName, exc);
}
}
/**
* Returns the name of the file.
*
* @return The FileName, never {@code null}.
*/
@Override
public FileName getName() {
return fileName;
}
/**
* Returns the receiver as a URI String for public display, like, without a password.
*
* @return A URI String without a password, never {@code null}.
*/
@Override
public String getPublicURIString() {
return fileName.getFriendlyURI();
}
/**
* Prepares this file for writing. Makes sure it is either a file, or its parent folder exists. Returns an output
* stream to use to write the content of the file to.
*
* @return An OutputStream where the new contents of the file can be written.
* @throws FileSystemException if an error occurs.
*/
public OutputStream getOutputStream() throws FileSystemException {
return getOutputStream(false);
}
/**
* Prepares this file for writing. Makes sure it is either a file, or its parent folder exists. Returns an output
* stream to use to write the content of the file to.
*
* @param bAppend true when append to the file.
* Note: If the underlying filesystem does not support appending, a FileSystemException is thrown.
* @return An OutputStream where the new contents of the file can be written.
* @throws FileSystemException if an error occurs; for example:
* bAppend is true, and the underlying FileSystem does not support it
*/
public OutputStream getOutputStream(final boolean bAppend) throws FileSystemException {
/*
* VFS-210 if (getType() != FileType.IMAGINARY && !getType().hasContent()) { throw new
* FileSystemException("vfs.provider/write-not-file.error", name); } if (!isWriteable()) { throw new
* FileSystemException("vfs.provider/write-read-only.error", name); }
*/
if (bAppend && !fs.hasCapability(Capability.APPEND_CONTENT)) {
throw new FileSystemException("vfs.provider/write-append-not-supported.error", fileName);
}
if (getType() == FileType.IMAGINARY) {
// Does not exist - make sure parent does
final FileObject parent = getParent();
if (parent != null) {
parent.createFolder();
}
}
// Get the raw output stream
try {
return doGetOutputStream(bAppend);
} catch (final RuntimeException re) {
throw re;
} catch (final Exception exc) {
throw new FileSystemException("vfs.provider/write.error", exc, fileName);
}
}
/**
* Returns the parent of the file.
*
* @return the parent FileObject.
* @throws FileSystemException if an error occurs.
*/
@Override
public FileObject getParent() throws FileSystemException {
if (this.compareTo(fs.getRoot()) == 0) // equals is not implemented :-/
{
if (fs.getParentLayer() == null) {
// Root file has no parent
return null;
}
// Return the parent of the parent layer
return fs.getParentLayer().getParent();
}
synchronized (fs) {
// Locate the parent of this file
if (parent == null) {
final FileName name = fileName.getParent();
if (name == null) {
return null;
}
parent = fs.resolveFile(name);
}
return parent;
}
}
/**
* Returns an input/output stream to use to read and write the content of the file in and random manner.
*
* @param mode The RandomAccessMode.
* @return The RandomAccessContent.
* @throws FileSystemException if an error occurs.
*/
public RandomAccessContent getRandomAccessContent(final RandomAccessMode mode) throws FileSystemException {
/*
* VFS-210 if (!getType().hasContent()) { throw new FileSystemException("vfs.provider/read-not-file.error",
* name); }
*/
if (mode.requestRead()) {
if (!fs.hasCapability(Capability.RANDOM_ACCESS_READ)) {
throw new FileSystemException("vfs.provider/random-access-read-not-supported.error");
}
if (!isReadable()) {
throw new FileSystemException("vfs.provider/read-not-readable.error", fileName);
}
}
if (mode.requestWrite()) {
if (!fs.hasCapability(Capability.RANDOM_ACCESS_WRITE)) {
throw new FileSystemException("vfs.provider/random-access-write-not-supported.error");
}
if (!isWriteable()) {
throw new FileSystemException("vfs.provider/write-read-only.error", fileName);
}
}
// Get the raw input stream
try {
return doGetRandomAccessContent(mode);
} catch (final Exception exc) {
throw new FileSystemException("vfs.provider/random-access.error", fileName, exc);
}
}
/**
* Returns the file's type.
*
* @return The FileType.
* @throws FileSystemException if an error occurs.
*/
@Override
public FileType getType() throws FileSystemException {
synchronized (fs) {
attach();
// VFS-210: get the type only if requested for
try {
if (type == null) {
setFileType(doGetType());
}
if (type == null) {
setFileType(FileType.IMAGINARY);
}
} catch (final Exception e) {
throw new FileSystemException("vfs.provider/get-type.error", e, fileName);
}
return type;
}
}
/**
* Returns a URL representation of the file.
*
* @return The URL representation of the file.
* @throws FileSystemException if an error occurs.
*/
@Override
public URL getURL() throws FileSystemException {
try {
return AccessController.doPrivileged(new PrivilegedExceptionAction() {
@Override
public URL run() throws MalformedURLException {
final StringBuilder buf = new StringBuilder();
final String scheme = UriParser.extractScheme(fileName.getURI(), buf);
return new URL(scheme, "", -1, buf.toString(),
new DefaultURLStreamHandler(fs.getContext(), fs.getFileSystemOptions()));
}
});
} catch (final PrivilegedActionException e) {
throw new FileSystemException("vfs.provider/get-url.error", fileName, e.getException());
}
}
/**
* Called when this file is changed.
*
* This will only happen if you monitor the file using {@link org.apache.commons.vfs2.FileMonitor}.
*
* @throws Exception if an error occurs.
*/
protected void handleChanged() throws Exception {
// Notify the file system
fs.fireFileChanged(this);
}
/**
* Called when this file is created. Updates cached info and notifies the parent and file system.
*
* @param newType The type of the file.
* @throws Exception if an error occurs.
*/
protected void handleCreate(final FileType newType) throws Exception {
synchronized (fs) {
if (attached) {
// Fix up state
injectType(newType);
removeChildrenCache();
// Notify subclass
onChange();
}
// Notify parent that its child list may no longer be valid
notifyParent(this.getName(), newType);
// Notify the file system
fs.fireFileCreated(this);
}
}
/**
* Called when this file is deleted. Updates cached info and notifies subclasses, parent and file system.
*
* @throws Exception if an error occurs.
*/
protected void handleDelete() throws Exception {
synchronized (fs) {
if (attached) {
// Fix up state
injectType(FileType.IMAGINARY);
removeChildrenCache();
// Notify subclass
onChange();
}
// Notify parent that its child list may no longer be valid
notifyParent(this.getName(), FileType.IMAGINARY);
// Notify the file system
fs.fireFileDeleted(this);
}
}
/**
* This method is meant to add an object where this object holds a strong reference then. E.g. a archive-filesystem
* creates a list of all children and they shouldn't get garbage collected until the container is garbage collected
*
* @param strongRef The Object to add.
*/
// TODO should this be a FileObject?
public void holdObject(final Object strongRef) {
if (objects == null) {
objects = new ArrayList<>(INITIAL_LIST_SIZE);
}
objects.add(strongRef);
}
protected void injectType(final FileType fileType) {
setFileType(fileType);
}
/**
* Check if the internal state is "attached".
*
* @return true if this is the case
*/
@Override
public boolean isAttached() {
return attached;
}
/**
* Check if the content stream is open.
*
* @return true if this is the case
*/
@Override
public boolean isContentOpen() {
if (content == null) {
return false;
}
return content.isOpen();
}
/**
* Determines if this file is executable.
*
* @return {@code true} if this file is executable, {@code false} if not.
* @throws FileSystemException On error determining if this file exists.
*/
@Override
public boolean isExecutable() throws FileSystemException {
try {
return exists() ? doIsExecutable() : false;
} catch (final Exception exc) {
throw new FileSystemException("vfs.provider/check-is-executable.error", fileName, exc);
}
}
/**
* Checks if this file is a regular file by using its file type.
*
* @return true if this file is a regular file.
* @throws FileSystemException if an error occurs.
* @see #getType()
* @see FileType#FILE
*/
@Override
public boolean isFile() throws FileSystemException {
// Use equals instead of == to avoid any class loader worries.
return FileType.FILE.equals(this.getType());
}
/**
* Checks if this file is a folder by using its file type.
*
* @return true if this file is a regular file.
* @throws FileSystemException if an error occurs.
* @see #getType()
* @see FileType#FOLDER
*/
@Override
public boolean isFolder() throws FileSystemException {
// Use equals instead of == to avoid any class loader worries.
return FileType.FOLDER.equals(this.getType());
}
/**
* Determines if this file can be read.
*
* @return true if the file is a hidden file, false otherwise.
* @throws FileSystemException if an error occurs.
*/
@Override
public boolean isHidden() throws FileSystemException {
try {
return exists() ? doIsHidden() : false;
} catch (final Exception exc) {
throw new FileSystemException("vfs.provider/check-is-hidden.error", fileName, exc);
}
}
/**
* Determines if this file can be read.
*
* @return true if the file can be read, false otherwise.
* @throws FileSystemException if an error occurs.
*/
@Override
public boolean isReadable() throws FileSystemException {
try {
return exists() ? doIsReadable() : false;
} catch (final Exception exc) {
throw new FileSystemException("vfs.provider/check-is-readable.error", fileName, exc);
}
}
/**
* Checks if this fileObject is the same file as {@code destFile} just with a different name. E.g. for case
* insensitive filesystems like windows.
*
* @param destFile The file to compare to.
* @return true if the FileObjects are the same.
* @throws FileSystemException if an error occurs.
*/
protected boolean isSameFile(final FileObject destFile) throws FileSystemException {
attach();
return doIsSameFile(destFile);
}
/**
* Determines if this file can be written to.
*
* @return true if the file can be written to, false otherwise.
* @throws FileSystemException if an error occurs.
*/
@Override
public boolean isWriteable() throws FileSystemException {
try {
if (exists()) {
return doIsWriteable();
}
final FileObject parent = getParent();
if (parent != null) {
return parent.isWriteable();
}
return true;
} catch (final Exception exc) {
throw new FileSystemException("vfs.provider/check-is-writeable.error", fileName, exc);
}
}
/**
* Returns an iterator over a set of all FileObject in this file object.
*
* @return an Iterator.
*/
@Override
public Iterator iterator() {
try {
return listFiles(Selectors.SELECT_ALL).iterator();
} catch (final FileSystemException e) {
throw new IllegalStateException(e);
}
}
/**
* Lists the set of matching descendants of this file, in depthwise order.
*
* @param selector The FileSelector.
* @return list of files or null if the base file (this object) do not exist or the {@code selector} is null
* @throws FileSystemException if an error occurs.
*/
public List listFiles(final FileSelector selector) throws FileSystemException {
if (!exists() || selector == null) {
return null;
}
final ArrayList list = new ArrayList<>();
this.findFiles(selector, true, list);
return list;
}
/**
* Moves (rename) the file to another one.
*
* @param destFile The target FileObject.
* @throws FileSystemException if an error occurs.
*/
@Override
public void moveTo(final FileObject destFile) throws FileSystemException {
if (canRenameTo(destFile)) {
if (!getParent().isWriteable()) {
throw new FileSystemException("vfs.provider/rename-parent-read-only.error", getName(),
getParent().getName());
}
} else {
if (!isWriteable()) {
throw new FileSystemException("vfs.provider/rename-read-only.error", getName());
}
}
if (destFile.exists() && !isSameFile(destFile)) {
destFile.deleteAll();
// throw new FileSystemException("vfs.provider/rename-dest-exists.error", destFile.getName());
}
if (canRenameTo(destFile)) {
// issue rename on same filesystem
try {
attach();
// remember type to avoid attach
final FileType srcType = getType();
doRename(destFile);
FileObjectUtils.getAbstractFileObject(destFile).handleCreate(srcType);
destFile.close(); // now the destFile is no longer imaginary. force reattach.
handleDelete(); // fire delete-events. This file-object (src) is like deleted.
} catch (final RuntimeException re) {
throw re;
} catch (final Exception exc) {
throw new FileSystemException("vfs.provider/rename.error", exc, getName(), destFile.getName());
}
} else {
// different fs - do the copy/delete stuff
destFile.copyFrom(this, Selectors.SELECT_SELF);
if ((destFile.getType().hasContent()
&& destFile.getFileSystem().hasCapability(Capability.SET_LAST_MODIFIED_FILE)
|| destFile.getType().hasChildren()
&& destFile.getFileSystem().hasCapability(Capability.SET_LAST_MODIFIED_FOLDER))
&& fs.hasCapability(Capability.GET_LAST_MODIFIED)) {
destFile.getContent().setLastModifiedTime(this.getContent().getLastModifiedTime());
}
deleteSelf();
}
}
/**
* will be called after this file-object closed all its streams.
*/
protected void notifyAllStreamsClosed() {
}
/**
* Notify the parent of a change to its children, when a child is created or deleted.
*
* @param childName The name of the child.
* @param newType The type of the child.
* @throws Exception if an error occurs.
*/
private void notifyParent(final FileName childName, final FileType newType) throws Exception {
if (parent == null) {
final FileName parentName = fileName.getParent();
if (parentName != null) {
// Locate the parent, if it is cached
parent = fs.getFileFromCache(parentName);
}
}
if (parent != null) {
FileObjectUtils.getAbstractFileObject(parent).childrenChanged(childName, newType);
}
}
/**
* Called when the type or content of this file changes.
*
* This implementation does nothing.
*
* @throws Exception if an error occurs.
*/
protected void onChange() throws Exception {
}
/**
* Called when the children of this file change. Allows subclasses to refresh any cached information about the
* children of this file.
*
* This implementation does nothing.
*
* @param child The name of the child that changed.
* @param newType The type of the file.
* @throws Exception if an error occurs.
*/
protected void onChildrenChanged(final FileName child, final FileType newType) throws Exception {
}
/**
* This will prepare the fileObject to get resynchronized with the underlying filesystem if required.
*
* @throws FileSystemException if an error occurs.
*/
@Override
public void refresh() throws FileSystemException {
// Detach from the file
try {
detach();
} catch (final Exception e) {
throw new FileSystemException("vfs.provider/resync.error", fileName, e);
}
}
private void removeChildrenCache() {
children = null;
}
private FileObject resolveFile(final FileName child) throws FileSystemException {
return fs.resolveFile(child);
}
/**
* Finds a file, relative to this file.
*
* @param path The path of the file to locate. Can either be a relative path, which is resolved relative to this
* file, or an absolute path, which is resolved relative to the file system that contains this file.
* @return The FileObject.
* @throws FileSystemException if an error occurs.
*/
@Override
public FileObject resolveFile(final String path) throws FileSystemException {
final FileName otherName = fs.getFileSystemManager().resolveName(fileName, path);
return fs.resolveFile(otherName);
}
/**
* Returns a child by name.
*
* @param name The name of the child to locate.
* @param scope the NameScope.
* @return The FileObject for the file or null if the child does not exist.
* @throws FileSystemException if an error occurs.
*/
@Override
public FileObject resolveFile(final String name, final NameScope scope) throws FileSystemException {
// return fs.resolveFile(this.name.resolveName(name, scope));
return fs.resolveFile(fs.getFileSystemManager().resolveName(this.fileName, name, scope));
}
private FileObject[] resolveFiles(final FileName[] children) throws FileSystemException {
if (children == null) {
return null;
}
final FileObject[] objects = new FileObject[children.length];
for (int iterChildren = 0; iterChildren < children.length; iterChildren++) {
objects[iterChildren] = resolveFile(children[iterChildren]);
}
return objects;
}
@Override
public boolean setExecutable(final boolean readable, final boolean ownerOnly) throws FileSystemException {
try {
return exists() ? doSetExecutable(readable, ownerOnly) : false;
} catch (final Exception exc) {
throw new FileSystemException("vfs.provider/set-executable.error", fileName, exc);
}
}
private void setFileType(final FileType type) {
if (type != null && type != FileType.IMAGINARY) {
try {
fileName.setType(type);
} catch (final FileSystemException e) {
throw new RuntimeException(e.getMessage());
}
}
this.type = type;
}
@Override
public boolean setReadable(final boolean readable, final boolean ownerOnly) throws FileSystemException {
try {
return exists() ? doSetReadable(readable, ownerOnly) : false;
} catch (final Exception exc) {
throw new FileSystemException("vfs.provider/set-readable.error", fileName, exc);
}
}
// --- OPERATIONS ---
@Override
public boolean setWritable(final boolean readable, final boolean ownerOnly) throws FileSystemException {
try {
return exists() ? doSetWritable(readable, ownerOnly) : false;
} catch (final Exception exc) {
throw new FileSystemException("vfs.provider/set-writeable.error", fileName, exc);
}
}
/**
* Returns the URI as a String.
*
* @return Returns the URI as a String.
*/
@Override
public String toString() {
return fileName.getURI();
}
}