package co.codewizards.cloudstore.core.oio;
import static co.codewizards.cloudstore.core.io.StreamUtil.*;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.net.URI;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import co.codewizards.cloudstore.core.io.IInputStream;
import co.codewizards.cloudstore.core.io.IOutputStream;
import co.codewizards.cloudstore.core.util.IOUtil;
/**
* @author Sebastian Schefczyk
*
*/
public class IoFile implements File {
private static final long serialVersionUID = 1L;
private static final Logger logger = LoggerFactory.getLogger(IoFile.class);
protected final java.io.File ioFile;
protected IoFile(final String pathname) {
this.ioFile = new java.io.File(pathname);
// _debug_assert_NioFile();
}
protected IoFile(final File parent, final String child) {
final java.io.File ioParent = parent.getIoFile();
this.ioFile = new java.io.File(ioParent, child);
// _debug_assert_NioFile();
}
protected IoFile(final String parent, final String child) {
this.ioFile = new java.io.File(parent, child);
// _debug_assert_NioFile();
}
protected IoFile(final URI uri) {
this.ioFile = new java.io.File(uri);
// _debug_assert_NioFile();
}
protected IoFile(final java.io.File ioFile) {
this.ioFile = ioFile;
// _debug_assert_NioFile();
}
// private final void _debug_assert_NioFile() {
// if (this.getClass() == IoFile.class)
// throw new IllegalStateException("This should not be an instance of IoFile! " + ioFile);
//
// if (! this.getClass().getSimpleName().equals("NioFile"))
// throw new IllegalStateException("This should be an instance of NioFile! " + ioFile);
// }
@Override
public File getParentFile() {
final java.io.File parentFile = this.ioFile.getParentFile();
return parentFile != null ? new IoFile(parentFile) : null;
}
@Override
public String[] list() {
return this.ioFile.list();
}
@Override
public String[] list(final FilenameFilter filenameFilter) {
return this.ioFile.list(filenameFilter);
}
@Override
public File[] listFiles() {
final java.io.File[] ioFiles = this.ioFile.listFiles();
return IoFileUtil.convert(ioFiles);
}
@Override
public File[] listFiles(final java.io.FileFilter fileFilter) {
final java.io.File[] ioFiles = this.ioFile.listFiles(fileFilter);
return IoFileUtil.convert(ioFiles);
}
@Override
public File[] listFiles(final FileFilter fileFilter) {
final java.io.File[] ioFiles = this.ioFile.listFiles(new FileFilterWrapper(fileFilter));
return IoFileUtil.convert(ioFiles);
}
@Override
public File[] listFiles(final FilenameFilter fileFilter) {
final java.io.File[] ioFiles = this.ioFile.listFiles(fileFilter);
return IoFileUtil.convert(ioFiles);
}
@Override
public File getAbsoluteFile() {
return new IoFile(ioFile.getAbsoluteFile());
}
@Override
public boolean exists() {
return ioFile.exists();
}
@Override
public boolean existsNoFollow() {
return ioFile.exists();
}
@Override
public boolean createNewFile() throws IOException {
return ioFile.createNewFile();
}
@Override
public boolean canExecute() {
return ioFile.canExecute();
}
@Override
public boolean canRead() {
return ioFile.canRead();
}
@Override
public boolean canWrite() {
return ioFile.canWrite();
}
@Override
public boolean setExecutable(final boolean executable) {
return ioFile.setExecutable(executable);
}
@Override
public boolean setExecutable(final boolean executable, final boolean ownerOnly) {
return ioFile.setExecutable(executable, ownerOnly);
}
@Override
public boolean setReadable(final boolean readable) {
return ioFile.setReadable(readable);
}
@Override
public boolean setReadable(final boolean readable, final boolean ownerOnly) {
return ioFile.setReadable(readable, ownerOnly);
}
@Override
public boolean setWritable(final boolean writable) {
return ioFile.setWritable(writable);
}
@Override
public boolean setWritable(final boolean writable, final boolean ownerOnly) {
return ioFile.setWritable(writable, ownerOnly);
}
@Override
public int compareTo(final File otherFile) {
return ioFile.compareTo(otherFile.getIoFile());
}
@Override
public boolean delete() {
return ioFile.delete();
}
@Override
public void deleteOnExit() {
ioFile.deleteOnExit();
}
@Override
public void deleteRecursively() {
IoFileUtil.deleteRecursively(this);
}
@Override
public String getAbsolutePath() {
return ioFile.getAbsolutePath();
}
@Override
public File getCanonicalFile() throws IOException {
return new IoFile(ioFile.getCanonicalFile());
}
@Override
public String getCanonicalPath() throws IOException {
return ioFile.getCanonicalPath();
}
@Override
public long getFreeSpace() {
return ioFile.getFreeSpace();
}
@Override
public long length() {
return ioFile.length();
}
@Override
public boolean isRegularFileNoFollowLinks() {
return this.ioFile.isFile();
}
@Override
public boolean isRegularFileFollowLinks() {
return this.ioFile.isFile();
}
@Override
public boolean isDirectoryNoFollowSymLinks() {
return this.ioFile.isDirectory();
}
@Override
public boolean isDirectoryFollowSymLinks() {
return this.ioFile.isDirectory();
}
@Override
public boolean isSymbolicLink() {
// currently: no support for symlinks in this implementation
return false;
}
@Override
public String readSymbolicLinkToPathString() throws IOException {
throw new IllegalStateException("Impossible operation within this implementation: check use method 'isSymbolicLink' before!");
}
@Override
public long getLastModifiedNoFollow() {
// currently: no support for symlinks in this implementation => cannot do anything about follow/no-follow (that's exactly the reason for the nio-implementation!)
return lastModified();
}
@Override
public boolean renameTo(final File dest) {
return ioFile.renameTo(dest.getIoFile());
}
@Override
public boolean setLastModified(final long lastModified) {
return ioFile.setLastModified(lastModified);
}
@Override
public IOutputStream createOutputStream() throws FileNotFoundException {
return castStream(new FileOutputStream(ioFile));
}
@Override
public IInputStream createInputStream() throws FileNotFoundException {
return castStream(new FileInputStream(ioFile));
}
@Override
public IOutputStream createOutputStream(final boolean append) throws FileNotFoundException {
return castStream(new FileOutputStream(ioFile, append));
}
@Override
public String getName() {
return ioFile.getName();
}
@Override
public void createSymbolicLink(final String targetPath) throws IOException {
throw new IllegalStateException("Impossible operation within this implementation. Check whether symlinks are available here!");
}
@Override
public long lastModified() {
final long result = ioFile.lastModified();
return result;
}
@Override
public boolean isAbsolute() {
return ioFile.isAbsolute();
}
@Override
public String getPath() {
return ioFile.getPath();
}
@Override
public boolean mkdir() {
return ioFile.mkdir();
}
@Override
public boolean mkdirs() {
return ioFile.mkdirs();
}
@Override
public boolean isDirectory() {
return ioFile.isDirectory();
}
@Override
public void move(final File toFile) throws IOException {
if (toFile.exists())
throw new IOException("toFile file did already exists!");
if (!this.ioFile.exists())
throw new IllegalArgumentException("Source file did not exists!");
if (this.ioFile.getCanonicalPath().equals(toFile.getCanonicalPath()))
return; //nothing to do!
final boolean renameTo = this.ioFile.renameTo(toFile.getIoFile());
// we try to do a simple rename, but this won't be successful between partitions or non-empty directories.
if (renameTo)
return;
// 2nd solution: file: copy and delete
if (this.ioFile.isFile()) {
IOUtil.copyFile(this, toFile);
final boolean delete = this.delete();
if (!delete)
throw new IllegalStateException("Problem on moving file from '"
+ this.ioFile.getCanonicalPath() +
"' to " + toFile.getIoFile().getCanonicalPath());
} else if (this.ioFile.isDirectory()) {
/* If empty, but has failed the simple renameTo(), the destination
* is probably on another partition (very unlikely on IOS).
*/
if (this.ioFile.listFiles().length == 0) {
throw new IllegalArgumentException("Should not occure!");
} else { // non-empty directory
/* remark: on IOS should be only one partition available to this app.
* And a copy/delete operation of a non-empty directory could
* last very long; as in Files.move(), this should be prevented.
* Best solution would be to rename recursively, because renaming
* also only works on same partition.
* Assuming there is only on partition, we assume renaming never fails.
* Partition-Detection: Its very hard to detect, whether to files are on the same
* partition, in a OS independent and without java.nio.Files.
* So we just assume one partition because of IOS. */
IoFileUtil.moveRecursively(this, toFile);
}
}
}
@Override
public void copyToCopyAttributes(final File toFile) throws IOException {
if (toFile.exists())
throw new IOException("toFile file did already exists!");
if (!this.ioFile.exists())
throw new IllegalArgumentException("Source file did not exists!");
if (this.ioFile.getCanonicalPath().equals(toFile.getCanonicalPath()))
return; //nothing to do!
if (this.ioFile.isFile()) {
IOUtil.copyFile(this, toFile);
} else {
// java.nio.Files.copy is non-recursive, so must this implementation be!
final boolean mkdir = toFile.mkdir();
if (!mkdir)
throw new IllegalStateException("Problem on moving directory from '"
+ this.ioFile.getCanonicalPath() +
"'! Could not create directory " + toFile.getIoFile().getCanonicalPath());
}
}
@Override
public RandomAccessFile createRandomAccessFile(final String mode) throws FileNotFoundException {
return new RandomAccessFile(ioFile, mode);
}
@Override
public URI toURI() {
return ioFile.toURI();
}
@Override
public boolean isFile() {
return ioFile.isFile();
}
@Override
public void setLastModifiedNoFollow(final long lastModified) {
this.ioFile.setLastModified(lastModified);
}
@Override
public String relativize(final File target) throws IOException {
// return IOUtil.getRelativePath(this, target); // TODO result is different, should have a look; the first shared folder was appended.
return IoFileRelativePathUtil.getRelativePath(this.ioFile, target.getIoFile());
}
@Override
public long getUsableSpace() {
return this.ioFile.getUsableSpace();
}
@Override
public java.io.File getIoFile() {
return ioFile;
}
@Override
public boolean equals(final Object obj) {
if ( !(obj instanceof IoFile) )
return false;
final IoFile ioFile = (IoFile) obj;
return this.ioFile.equals(ioFile.ioFile);
}
@Override
public int hashCode() {
return ioFile.hashCode();
}
@Override
public String toString() {
return this.ioFile.toString();
}
@Override
public File createFile(String ... children) {
return OioFileFactory.createFile(this, children);
}
// private void writeObject(ObjectOutputStream out) throws IOException {
// if (!ioFile.isAbsolute())
// logger.warn("File is not absolute! This may cause w");
//
// out.defaultWriteObject();
// }
//
// private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
//
// }
}