/*
blizzy's Backup - Easy to use personal file backup application
Copyright (C) 2011-2012 Maik Schreiber
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program 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 for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.blizzy.backup.vfs;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.attribute.FileTime;
import java.util.HashSet;
import java.util.Set;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.vfs2.FileContent;
import org.apache.commons.vfs2.FileObject;
import org.apache.commons.vfs2.FileSystemException;
import org.apache.commons.vfs2.FileType;
public abstract class RemoteFileOrFolder<L extends RemoteLocation> implements IFolder, IFile {
private static final int BUFFER_SIZE = 128 * 1024;
private String file;
private L location;
private FileObject fileObject;
private FileContent fileContent;
private Boolean isFolder;
public RemoteFileOrFolder(String file, L location) {
this.file = file;
this.location = location;
}
@Override
public String getName() {
return StringUtils.substringAfterLast(file, "/"); //$NON-NLS-1$
}
@Override
public String getAbsolutePath() {
return location.getProtocol() + "://" + location.getHost() + file; //$NON-NLS-1$
}
@Override
public IFolder getParentFolder() {
if (!file.equals("/")) { //$NON-NLS-1$
String parentFolder = StringUtils.substringBeforeLast(file, "/"); //$NON-NLS-1$
if (StringUtils.isBlank(parentFolder)) {
parentFolder = "/"; //$NON-NLS-1$
}
return getFolder(parentFolder);
}
return null;
}
protected abstract IFolder getFolder(String folder);
protected L getLocation() {
return location;
}
@Override
public boolean isHidden() {
return getName().startsWith("."); //$NON-NLS-1$
}
@Override
public FileTime getCreationTime() {
return null;
}
@Override
public FileTime getLastModificationTime() throws IOException {
FileContent content = getFileContent();
try {
long lastModifiedTime = content.getLastModifiedTime();
return FileTime.fromMillis(lastModifiedTime);
} catch (FileSystemException e) {
return null;
}
}
private FileObject getFileObject() throws IOException {
if (fileObject == null) {
IAction<FileObject> action = new IAction<FileObject>() {
@Override
public FileObject run() throws IOException {
return location.resolveFile(file);
}
@Override
public boolean canRetry(IOException e) {
return location.canRetryAction(e);
}
};
fileObject = new ActionRunner<>(action, RemoteLocation.MAX_TRIES, location).run();
}
return fileObject;
}
private FileContent getFileContent() throws IOException {
if (fileContent == null) {
final FileObject fileObject = getFileObject();
IAction<FileContent> action = new IAction<FileContent>() {
@Override
public FileContent run() throws IOException {
return fileObject.getContent();
}
@Override
public boolean canRetry(IOException e) {
return location.canRetryAction(e);
}
};
fileContent = new ActionRunner<>(action, RemoteLocation.MAX_TRIES, location).run();
}
return fileContent;
}
@Override
public boolean isFolder() throws IOException {
if (isFolder == null) {
isFolder = Boolean.valueOf(getFileObject().getType().equals(FileType.FOLDER));
}
return isFolder.booleanValue();
}
public void setIsFolder() {
isFolder = Boolean.TRUE;
}
@Override
public void copy(final IOutputStreamProvider outputStreamProvider) throws IOException {
final FileContent fileContent = getFileContent();
IAction<Void> action = new IAction<Void>() {
@Override
public Void run() throws IOException {
InputStream in = null;
OutputStream out = null;
try {
in = new BufferedInputStream(fileContent.getInputStream(), BUFFER_SIZE);
out = outputStreamProvider.getOutputStream();
IOUtils.copy(in, out);
} finally {
IOUtils.closeQuietly(in);
IOUtils.closeQuietly(out);
}
return null;
}
@Override
public boolean canRetry(IOException e) {
return location.canRetryAction(e);
}
};
new ActionRunner<>(action, RemoteLocation.MAX_TRIES, location).run();
}
@Override
public long getLength() throws IOException {
return getFileContent().getSize();
}
@Override
public Set<IFileSystemEntry> list() throws IOException {
final FileObject fileObject = getFileObject();
IAction<Set<IFileSystemEntry>> action = new IAction<Set<IFileSystemEntry>>() {
@Override
public Set<IFileSystemEntry> run() throws IOException {
Set<IFileSystemEntry> result = new HashSet<>();
for (FileObject child : fileObject.getChildren()) {
result.add(getFileOrFolder(file + "/" + child.getName().getBaseName())); //$NON-NLS-1$
}
return result;
}
@Override
public boolean canRetry(IOException e) {
return location.canRetryAction(e);
}
};
return new ActionRunner<>(action, RemoteLocation.MAX_TRIES, location).run();
}
protected abstract IFolder getFileOrFolder(String file);
@Override
public int hashCode() {
return file.hashCode();
}
@Override
public boolean equals(Object o) {
if (o == this) {
return true;
} else if ((o != null) && o.getClass().equals(getClass())) {
RemoteFileOrFolder<?> other = (RemoteFileOrFolder<?>) o;
return other.file.equals(file);
}
return false;
}
}