| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You 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.apache.commons.vfs2.provider; |
| |
| import java.io.InputStream; |
| import java.io.OutputStream; |
| import java.security.cert.Certificate; |
| import java.util.Arrays; |
| import java.util.HashSet; |
| import java.util.Map; |
| import java.util.Set; |
| |
| import org.apache.commons.lang3.ArrayUtils; |
| import org.apache.commons.vfs2.FileChangeEvent; |
| import org.apache.commons.vfs2.FileContentInfo; |
| import org.apache.commons.vfs2.FileListener; |
| import org.apache.commons.vfs2.FileName; |
| import org.apache.commons.vfs2.FileNotFolderException; |
| import org.apache.commons.vfs2.FileObject; |
| import org.apache.commons.vfs2.FileSystemException; |
| import org.apache.commons.vfs2.FileType; |
| import org.apache.commons.vfs2.RandomAccessContent; |
| import org.apache.commons.vfs2.util.RandomAccessMode; |
| import org.apache.commons.vfs2.util.WeakRefFileListener; |
| |
| /** |
| * A file backed by another file. |
| * <p> |
| * TODO - Extract subclass that overlays the children. |
| * </p> |
| * |
| * @param <AFS> A subclass of AbstractFileSystem. |
| */ |
| public class DelegateFileObject<AFS extends AbstractFileSystem> extends AbstractFileObject<AFS> |
| implements FileListener { |
| private FileObject file; |
| private final Set<String> children = new HashSet<>(); |
| private boolean ignoreEvent; |
| |
| public DelegateFileObject(final AbstractFileName name, final AFS fileSystem, final FileObject file) |
| throws FileSystemException { |
| super(name, fileSystem); |
| this.file = file; |
| if (file != null) { |
| WeakRefFileListener.installListener(file, this); |
| } |
| } |
| |
| /** |
| * Get access to the delegated file. |
| * |
| * @return The FileObject. |
| * @since 2.0 |
| */ |
| public FileObject getDelegateFile() { |
| return file; |
| } |
| |
| /** |
| * Adds a child to this file. |
| * |
| * @param baseName The base FileName. |
| * @param type The FileType. |
| * @throws Exception if an error occurs. |
| */ |
| public void attachChild(final FileName baseName, final FileType type) throws Exception { |
| final FileType oldType = doGetType(); |
| if (children.add(baseName.getBaseName())) { |
| childrenChanged(baseName, type); |
| } |
| maybeTypeChanged(oldType); |
| } |
| |
| /** |
| * Attaches or detaches the target file. |
| * |
| * @param file The FileObject. |
| * @throws Exception if an error occurs. |
| */ |
| public void setFile(final FileObject file) throws Exception { |
| final FileType oldType = doGetType(); |
| |
| if (file != null) { |
| WeakRefFileListener.installListener(file, this); |
| } |
| this.file = file; |
| maybeTypeChanged(oldType); |
| } |
| |
| /** |
| * Checks whether the file's type has changed, and fires the appropriate events. |
| * |
| * @param oldType The old FileType. |
| * @throws Exception if an error occurs. |
| */ |
| private void maybeTypeChanged(final FileType oldType) throws Exception { |
| final FileType newType = doGetType(); |
| if (oldType == FileType.IMAGINARY && newType != FileType.IMAGINARY) { |
| handleCreate(newType); |
| } else if (oldType != FileType.IMAGINARY && newType == FileType.IMAGINARY) { |
| handleDelete(); |
| } |
| } |
| |
| /** |
| * Determines the type of the file, returns null if the file does not exist. |
| */ |
| @Override |
| protected FileType doGetType() throws FileSystemException { |
| if (file != null) { |
| return file.getType(); |
| } |
| if (children.isEmpty()) { |
| return FileType.IMAGINARY; |
| } |
| return FileType.FOLDER; |
| } |
| |
| /** |
| * Determines if this file can be read. |
| */ |
| @Override |
| protected boolean doIsReadable() throws FileSystemException { |
| if (file != null) { |
| return file.isReadable(); |
| } |
| return true; |
| } |
| |
| /** |
| * Determines if this file can be written to. |
| */ |
| @Override |
| protected boolean doIsWriteable() throws FileSystemException { |
| if (file != null) { |
| return file.isWriteable(); |
| } |
| return false; |
| } |
| |
| /** |
| * Determines if this file is executable. |
| */ |
| @Override |
| protected boolean doIsExecutable() throws FileSystemException { |
| if (file != null) { |
| return file.isExecutable(); |
| } |
| return false; |
| } |
| |
| /** |
| * Determines if this file is hidden. |
| */ |
| @Override |
| protected boolean doIsHidden() throws FileSystemException { |
| if (file != null) { |
| return file.isHidden(); |
| } |
| return false; |
| } |
| |
| /** |
| * Lists the children of the file. |
| */ |
| @Override |
| protected String[] doListChildren() throws Exception { |
| if (file != null) { |
| final FileObject[] children; |
| |
| try { |
| children = file.getChildren(); |
| } |
| // VFS-210 |
| catch (final FileNotFolderException e) { |
| throw new FileNotFolderException(getName(), e); |
| } |
| |
| return Arrays.stream(children).map(child -> child.getName().getBaseName()).toArray(String[]::new); |
| } |
| return children.toArray(ArrayUtils.EMPTY_STRING_ARRAY); |
| } |
| |
| /** |
| * Creates this file as a folder. |
| */ |
| @Override |
| protected void doCreateFolder() throws Exception { |
| ignoreEvent = true; |
| try { |
| file.createFolder(); |
| } finally { |
| ignoreEvent = false; |
| } |
| } |
| |
| /** |
| * Deletes the file. |
| */ |
| @Override |
| protected void doDelete() throws Exception { |
| ignoreEvent = true; |
| try { |
| file.delete(); |
| } finally { |
| ignoreEvent = false; |
| } |
| } |
| |
| /** |
| * Returns the size of the file content (in bytes). Is only called if {@link #doGetType} returns |
| * {@link FileType#FILE}. |
| */ |
| @Override |
| protected long doGetContentSize() throws Exception { |
| return file.getContent().getSize(); |
| } |
| |
| /** |
| * Returns the attributes of this file. |
| */ |
| @Override |
| protected Map<String, Object> doGetAttributes() throws Exception { |
| return file.getContent().getAttributes(); |
| } |
| |
| /** |
| * Sets an attribute of this file. |
| */ |
| @Override |
| protected void doSetAttribute(final String atttrName, final Object value) throws Exception { |
| file.getContent().setAttribute(atttrName, value); |
| } |
| |
| /** |
| * Returns the certificates of this file. |
| */ |
| @Override |
| protected Certificate[] doGetCertificates() throws Exception { |
| return file.getContent().getCertificates(); |
| } |
| |
| /** |
| * Returns the last-modified time of this file. |
| */ |
| @Override |
| protected long doGetLastModifiedTime() throws Exception { |
| return file.getContent().getLastModifiedTime(); |
| } |
| |
| /** |
| * Sets the last-modified time of this file. |
| * |
| * @since 2.0 |
| */ |
| @Override |
| protected boolean doSetLastModifiedTime(final long modtime) throws Exception { |
| file.getContent().setLastModifiedTime(modtime); |
| return true; |
| } |
| |
| /** |
| * Creates an input stream to read the file content from. |
| */ |
| @Override |
| protected InputStream doGetInputStream(final int bufferSize) throws Exception { |
| return file.getContent().getInputStream(bufferSize); |
| } |
| |
| /** |
| * Creates an output stream to write the file content to. |
| */ |
| @Override |
| protected OutputStream doGetOutputStream(final boolean bAppend) throws Exception { |
| return file.getContent().getOutputStream(bAppend); |
| } |
| |
| /** |
| * Called when a file is created. |
| * |
| * @param event The FileChangeEvent. |
| * @throws Exception if an error occurs. |
| */ |
| @Override |
| public void fileCreated(final FileChangeEvent event) throws Exception { |
| if (event.getFileObject() != file) { |
| return; |
| } |
| if (!ignoreEvent) { |
| handleCreate(file.getType()); |
| } |
| } |
| |
| /** |
| * Called when a file is deleted. |
| * |
| * @param event The FileChangeEvent. |
| * @throws Exception if an error occurs. |
| */ |
| @Override |
| public void fileDeleted(final FileChangeEvent event) throws Exception { |
| if (event.getFileObject() != file) { |
| return; |
| } |
| if (!ignoreEvent) { |
| handleDelete(); |
| } |
| } |
| |
| /** |
| * Called when a file is changed. |
| * <p> |
| * This will only happen if you monitor the file using {@link org.apache.commons.vfs2.FileMonitor}. |
| * </p> |
| * |
| * @param event The FileChangeEvent. |
| * @throws Exception if an error occurs. |
| */ |
| @Override |
| public void fileChanged(final FileChangeEvent event) throws Exception { |
| if (event.getFileObject() != file) { |
| return; |
| } |
| if (!ignoreEvent) { |
| handleChanged(); |
| } |
| } |
| |
| /** |
| * Close the delegated file. |
| * |
| * @throws FileSystemException if an error occurs. |
| */ |
| @Override |
| public void close() throws FileSystemException { |
| super.close(); |
| |
| if (file != null) { |
| file.close(); |
| } |
| } |
| |
| /** |
| * Refresh file information. |
| * |
| * @throws FileSystemException if an error occurs. |
| * @since 2.0 |
| */ |
| @Override |
| public void refresh() throws FileSystemException { |
| super.refresh(); |
| if (file != null) { |
| file.refresh(); |
| } |
| } |
| |
| /** |
| * Return file content info. |
| * |
| * @return the file content info of the delegee. |
| * @throws Exception Any thrown Exception is wrapped in FileSystemException. |
| * @since 2.0 |
| */ |
| protected FileContentInfo doGetContentInfo() throws Exception { |
| return file.getContent().getContentInfo(); |
| } |
| |
| /** |
| * Renames the file. |
| * |
| * @param newFile the new location/name. |
| * @throws Exception Any thrown Exception is wrapped in FileSystemException. |
| * @since 2.0 |
| */ |
| @Override |
| protected void doRename(final FileObject newFile) throws Exception { |
| file.moveTo(((DelegateFileObject) newFile).file); |
| } |
| |
| /** |
| * Removes an attribute of this file. |
| * |
| * @since 2.0 |
| */ |
| @Override |
| protected void doRemoveAttribute(final String atttrName) throws Exception { |
| file.getContent().removeAttribute(atttrName); |
| } |
| |
| /** |
| * Creates access to the file for random i/o. |
| * |
| * @since 2.0 |
| */ |
| @Override |
| protected RandomAccessContent doGetRandomAccessContent(final RandomAccessMode mode) throws Exception { |
| return file.getContent().getRandomAccessContent(mode); |
| } |
| } |