You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by th...@apache.org on 2011/09/20 12:26:25 UTC
svn commit: r1173067 - in /jackrabbit/sandbox/microkernel/src:
main/java/org/apache/jackrabbit/mk/fs/ test/java/org/apache/jackrabbit/mk/fs/
Author: thomasm
Date: Tue Sep 20 10:26:24 2011
New Revision: 1173067
URL: http://svn.apache.org/viewvc?rev=1173067&view=rev
Log:
New file system abstraction that is similar to the Java 7 abstraction in the package java.nio.file.
Added:
jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/fs/
jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/fs/FileBase.java
jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/fs/FilePath.java
jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/fs/FilePathDisk.java
jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/fs/FileUtils.java
jackrabbit/sandbox/microkernel/src/test/java/org/apache/jackrabbit/mk/fs/
jackrabbit/sandbox/microkernel/src/test/java/org/apache/jackrabbit/mk/fs/TestFileSystem.java
Added: jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/fs/FileBase.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/fs/FileBase.java?rev=1173067&view=auto
==============================================================================
--- jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/fs/FileBase.java (added)
+++ jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/fs/FileBase.java Tue Sep 20 10:26:24 2011
@@ -0,0 +1,87 @@
+/*
+ * 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.jackrabbit.mk.fs;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.MappedByteBuffer;
+import java.nio.channels.FileChannel;
+import java.nio.channels.FileLock;
+import java.nio.channels.ReadableByteChannel;
+import java.nio.channels.WritableByteChannel;
+
+/**
+ * The base class for file implementations.
+ */
+public abstract class FileBase extends FileChannel {
+
+ public void force(boolean metaData) throws IOException {
+ // ignore
+ }
+
+ public FileLock lock(long position, long size, boolean shared) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ public MappedByteBuffer map(MapMode mode, long position, long size) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ public abstract long position() throws IOException;
+
+ public abstract FileChannel position(long newPosition) throws IOException;
+
+ public abstract int read(ByteBuffer dst) throws IOException;
+
+ public int read(ByteBuffer dst, long position) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ public long read(ByteBuffer[] dsts, int offset, int length) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ public abstract long size() throws IOException;
+
+ public long transferFrom(ReadableByteChannel src, long position, long count) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ public long transferTo(long position, long count, WritableByteChannel target)
+ throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ public abstract FileChannel truncate(long size) throws IOException;
+
+ public FileLock tryLock(long position, long size, boolean shared) throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ public abstract int write(ByteBuffer src) throws IOException;
+
+ public int write(ByteBuffer src, long position) throws IOException {
+ throw new UnsupportedOperationException(); }
+
+ public long write(ByteBuffer[] srcs, int offset, int length) throws IOException {
+ throw new UnsupportedOperationException(); }
+
+ protected void implCloseChannel() throws IOException {
+ // ignore
+ }
+
+}
Added: jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/fs/FilePath.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/fs/FilePath.java?rev=1173067&view=auto
==============================================================================
--- jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/fs/FilePath.java (added)
+++ jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/fs/FilePath.java Tue Sep 20 10:26:24 2011
@@ -0,0 +1,331 @@
+/*
+ * 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.jackrabbit.mk.fs;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.channels.FileChannel;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+import org.apache.jackrabbit.mk.util.StringUtils;
+
+/**
+ * A path to a file. It similar to the Java 7 <code>java.nio.file.Path</code>,
+ * but simpler, and works with older versions of Java. It also implements the
+ * relevant methods found in <code>java.nio.file.FileSystem</code> and
+ * <code>FileSystems</code>
+ */
+public abstract class FilePath {
+
+ private static final FilePath DEFAULT = new FilePathDisk();
+
+ private static Map<String, FilePath> providers;
+
+ /**
+ * The prefix for temporary files.
+ */
+ private static String tempRandom;
+ private static long tempSequence;
+
+ /**
+ * The complete path (which may be absolute or relative, depending on the
+ * file system).
+ */
+ protected String name;
+
+ /**
+ * Get the file path object for the given path.
+ * This method is similar to Java 7 <code>java.nio.file.FileSystem.getPath</code>.
+ * Windows-style '\' is replaced with '/'.
+ *
+ * @param path the path
+ * @return the file path object
+ */
+ public static FilePath get(String path) {
+ path = path.replace('\\', '/');
+ int index = path.indexOf(':');
+ if (index < 2) {
+ // use the default provider if no prefix or
+ // only a single character (drive name)
+ return DEFAULT.getPath(path);
+ }
+ String scheme = path.substring(0, index);
+ registerDefaultProviders();
+ FilePath p = providers.get(scheme);
+ if (p == null) {
+ // provider not found - use the default
+ p = DEFAULT;
+ }
+ return p.getPath(path);
+ }
+
+ private static void registerDefaultProviders() {
+ if (providers == null) {
+ Map<String, FilePath> map = Collections.synchronizedMap(new HashMap<String, FilePath>());
+ for (String c : new String[] {
+ "org.apache.jackrabbit.mk.fs.FilePathDisk"
+ }) {
+ try {
+ FilePath p = (FilePath) Class.forName(c).newInstance();
+ map.put(p.getScheme(), p);
+ } catch (Exception e) {
+ // ignore - the files may be excluded in purpose
+ }
+ }
+ providers = map;
+ }
+ }
+
+ /**
+ * Register a file provider.
+ *
+ * @param provider the file provider
+ */
+ public static void register(FilePath provider) {
+ registerDefaultProviders();
+ providers.put(provider.getScheme(), provider);
+ }
+
+ /**
+ * Unregister a file provider.
+ *
+ * @param provider the file provider
+ */
+ public static void unregister(FilePath provider) {
+ registerDefaultProviders();
+ providers.remove(provider.getScheme());
+ }
+
+ /**
+ * Get the size of a file in bytes
+ *
+ * @return the size in bytes
+ */
+ public abstract long size();
+
+ /**
+ * Rename a file if this is allowed.
+ *
+ * @param newName the new fully qualified file name
+ */
+ public abstract void moveTo(FilePath newName) throws IOException;
+
+ /**
+ * Create a new file.
+ *
+ * @return true if creating was successful
+ */
+ public abstract boolean createFile();
+
+ /**
+ * Checks if a file exists.
+ *
+ * @return true if it exists
+ */
+ public abstract boolean exists();
+
+ /**
+ * Delete a file or directory if it exists.
+ * Directories may only be deleted if they are empty.
+ */
+ public abstract void delete() throws IOException;
+
+ /**
+ * List the files and directories in the given directory.
+ *
+ * @return the list of fully qualified file names
+ */
+ public abstract List<FilePath> newDirectoryStream() throws IOException;
+
+ /**
+ * Normalize a file name.
+ *
+ * @return the normalized file name
+ */
+ public abstract FilePath toRealPath() throws IOException;
+
+ /**
+ * Get the parent directory of a file or directory.
+ *
+ * @return the parent directory name
+ */
+ public abstract FilePath getParent();
+
+ /**
+ * Check if it is a file or a directory.
+ *
+ * @return true if it is a directory
+ */
+ public abstract boolean isDirectory();
+
+ /**
+ * Check if the file name includes a path.
+ *
+ * @return if the file name is absolute
+ */
+ public abstract boolean isAbsolute();
+
+ /**
+ * Get the last modified date of a file
+ *
+ * @return the last modified date
+ */
+ public abstract long lastModified();
+
+ /**
+ * Check if the file is writable.
+ *
+ * @return if the file is writable
+ */
+ public abstract boolean canWrite();
+
+ /**
+ * Create a directory (all required parent directories already exist).
+ */
+ public abstract void createDirectory() throws IOException;
+
+ /**
+ * Get the file or directory name (the last element of the path).
+ *
+ * @return the last element of the path
+ */
+ public String getName() {
+ int idx = Math.max(name.indexOf(':'), name.lastIndexOf('/'));
+ return idx < 0 ? name : name.substring(idx + 1);
+ }
+
+ /**
+ * Create an output stream to write into the file.
+ *
+ * @param append if true, the file will grow, if false, the file will be
+ * truncated first
+ * @return the output stream
+ */
+ public abstract OutputStream newOutputStream(boolean append) throws IOException;
+
+ /**
+ * Open a random access file object.
+ *
+ * @param mode the access mode. Supported are r, rw, rws, rwd
+ * @return the file object
+ */
+ public abstract FileChannel open(String mode) throws IOException;
+
+ /**
+ * Create an input stream to read from the file.
+ *
+ * @return the input stream
+ */
+ public abstract InputStream newInputStream() throws IOException;
+
+ /**
+ * Disable the ability to write.
+ *
+ * @return true if the call was successful
+ */
+ public abstract boolean setReadOnly();
+
+ /**
+ * Create a new temporary file.
+ *
+ * @param suffix the suffix
+ * @param deleteOnExit if the file should be deleted when the virtual
+ * machine exists
+ * @param inTempDir if the file should be stored in the temporary directory
+ * @return the name of the created file
+ */
+ public FilePath createTempFile(String suffix, boolean deleteOnExit, boolean inTempDir) throws IOException {
+ while (true) {
+ FilePath p = getPath(name + getNextTempFileNamePart(false) + suffix);
+ if (p.exists() || !p.createFile()) {
+ // in theory, the random number could collide
+ getNextTempFileNamePart(true);
+ continue;
+ }
+ p.open("rw").close();
+ return p;
+ }
+ }
+
+ /**
+ * Get the next temporary file name part (the part in the middle).
+ *
+ * @param newRandom if the random part of the filename should change
+ * @return the file name part
+ */
+ protected static synchronized String getNextTempFileNamePart(boolean newRandom) {
+ if (newRandom || tempRandom == null) {
+ byte[] prefix = new byte[8];
+ new Random().nextBytes(prefix);
+ tempRandom = StringUtils.convertBytesToHex(prefix) + ".";
+ }
+ return tempRandom + tempSequence++;
+ }
+
+ /**
+ * Get the string representation. The returned string can be used to
+ * construct a new object.
+ *
+ * @return the path as a string
+ */
+ public String toString() {
+ return name;
+ }
+
+ /**
+ * Get the scheme (prefix) for this file provider.
+ * This is similar to <code>java.nio.file.spi.FileSystemProvider.getScheme</code>.
+ *
+ * @return the scheme
+ */
+ public abstract String getScheme();
+
+ /**
+ * Convert a file to a path. This is similar to
+ * <code>java.nio.file.spi.FileSystemProvider.getPath</code>, but may
+ * return an object even if the scheme doesn't match in case of the the
+ * default file provider.
+ *
+ * @param path the path
+ * @return the file path object
+ */
+ public abstract FilePath getPath(String path);
+
+ /**
+ * Get the unwrapped file name (without wrapper prefixes if wrapping /
+ * delegating file systems are used).
+ *
+ * @return the unwrapped path
+ */
+ public FilePath unwrap() {
+ return this;
+ }
+
+ /**
+ * Append an element to the path.
+ * This is similar to <code>java.nio.file.spi.FileSystemProvider.resolve</code>.
+ *
+ * @param other the relative path (might be null)
+ * @return the resolved path
+ */
+ public abstract FilePath resolve(String other);
+
+}
Added: jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/fs/FilePathDisk.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/fs/FilePathDisk.java?rev=1173067&view=auto
==============================================================================
--- jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/fs/FilePathDisk.java (added)
+++ jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/fs/FilePathDisk.java Tue Sep 20 10:26:24 2011
@@ -0,0 +1,429 @@
+/*
+ * 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.jackrabbit.mk.fs;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.RandomAccessFile;
+import java.net.URL;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import java.nio.channels.FileLock;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * This file system stores files on disk.
+ * This is the most common file system.
+ */
+public class FilePathDisk extends FilePath {
+
+ private static final String CLASSPATH_PREFIX = "classpath:";
+ private static final String FILE_SEPARATOR = System.getProperty("file.separator", "/");
+ private static final int MAX_FILE_RETRY = 16;
+
+ public FilePathDisk getPath(String path) {
+ FilePathDisk p = new FilePathDisk();
+ p.name = translateFileName(path);
+ return p;
+ }
+
+ public long size() {
+ return new File(name).length();
+ }
+
+ /**
+ * Translate the file name to the native format. This will replace '\' with
+ * '/' and expand the home directory ('~').
+ *
+ * @param fileName the file name
+ * @return the native file name
+ */
+ protected static String translateFileName(String fileName) {
+ fileName = fileName.replace('\\', '/');
+ return expandUserHomeDirectory(fileName);
+ }
+
+ /**
+ * Expand '~' to the user home directory. It is only be expanded if the '~'
+ * stands alone, or is followed by '/' or '\'.
+ *
+ * @param fileName the file name
+ * @return the native file name
+ */
+ public static String expandUserHomeDirectory(String fileName) {
+ if (fileName == null) {
+ return null;
+ }
+ boolean prefix = false;
+ if (fileName.startsWith("file:")) {
+ prefix = true;
+ fileName = fileName.substring("file:".length());
+ }
+ if (fileName.startsWith("~") && (fileName.length() == 1 || fileName.startsWith("~/") || fileName.startsWith("~\\"))) {
+ String userDir = System.getProperty("user.home", "");
+ fileName = userDir + fileName.substring(1);
+ }
+ return prefix ? "file:" + fileName : fileName;
+ }
+
+ public void moveTo(FilePath newName) throws IOException {
+ File oldFile = new File(name);
+ File newFile = new File(newName.name);
+ if (oldFile.getAbsolutePath().equals(newFile.getAbsolutePath())) {
+ return;
+ }
+ if (!oldFile.exists()) {
+ throw new IOException("Could not rename " +
+ name + " (not found) to " + newName.name);
+ }
+ if (newFile.exists()) {
+ throw new IOException("Could not rename " +
+ name + " to " + newName + " (already exists)");
+ }
+ for (int i = 0; i < MAX_FILE_RETRY; i++) {
+ boolean ok = oldFile.renameTo(newFile);
+ if (ok) {
+ return;
+ }
+ wait(i);
+ }
+ throw new IOException("Could not rename " + name + " to " + newName.name);
+ }
+
+ private static void wait(int i) {
+ if (i == 8) {
+ System.gc();
+ }
+ try {
+ // sleep at most 256 ms
+ long sleep = Math.min(256, i * i);
+ Thread.sleep(sleep);
+ } catch (InterruptedException e) {
+ // ignore
+ }
+ }
+
+ public boolean createFile() {
+ File file = new File(name);
+ for (int i = 0; i < MAX_FILE_RETRY; i++) {
+ try {
+ return file.createNewFile();
+ } catch (IOException e) {
+ // 'access denied' is really a concurrent access problem
+ wait(i);
+ }
+ }
+ return false;
+ }
+
+ public boolean exists() {
+ return new File(name).exists();
+ }
+
+ public void delete() throws IOException {
+ File file = new File(name);
+ for (int i = 0; i < MAX_FILE_RETRY; i++) {
+ boolean ok = file.delete();
+ if (ok || !file.exists()) {
+ return;
+ }
+ wait(i);
+ }
+ throw new IOException("Could not delete " + name);
+ }
+
+ public List<FilePath> newDirectoryStream() throws IOException {
+ ArrayList<FilePath> list = new ArrayList<FilePath>();
+ File f = new File(name);
+ String[] files = f.list();
+ if (files != null) {
+ String base = f.getCanonicalPath();
+ if (!base.endsWith(FILE_SEPARATOR)) {
+ base += FILE_SEPARATOR;
+ }
+ for (int i = 0, len = files.length; i < len; i++) {
+ list.add(getPath(base + files[i]));
+ }
+ }
+ return list;
+ }
+
+ public boolean canWrite() {
+ return canWriteInternal(new File(name));
+ }
+
+ public boolean setReadOnly() {
+ File f = new File(name);
+ return f.setReadOnly();
+ }
+
+ public FilePathDisk toRealPath() throws IOException {
+ String fileName = new File(name).getCanonicalPath();
+ return getPath(fileName);
+ }
+
+ public FilePath getParent() {
+ String p = new File(name).getParent();
+ return p == null ? null : getPath(p);
+ }
+
+ public boolean isDirectory() {
+ return new File(name).isDirectory();
+ }
+
+ public boolean isAbsolute() {
+ return new File(name).isAbsolute();
+ }
+
+ public long lastModified() {
+ return new File(name).lastModified();
+ }
+
+ private static boolean canWriteInternal(File file) {
+ try {
+ if (!file.canWrite()) {
+ return false;
+ }
+ } catch (Exception e) {
+ // workaround for GAE which throws a
+ // java.security.AccessControlException
+ return false;
+ }
+ // File.canWrite() does not respect windows user permissions,
+ // so we must try to open it using the mode "rw".
+ // See also http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4420020
+ RandomAccessFile r = null;
+ try {
+ r = new RandomAccessFile(file, "rw");
+ return true;
+ } catch (FileNotFoundException e) {
+ return false;
+ } finally {
+ if (r != null) {
+ try {
+ r.close();
+ } catch (IOException e) {
+ // ignore
+ }
+ }
+ }
+ }
+
+ public void createDirectory() throws IOException {
+ File f = new File(name);
+ if (!f.exists()) {
+ File dir = new File(name);
+ for (int i = 0; i < MAX_FILE_RETRY; i++) {
+ if ((dir.exists() && dir.isDirectory()) || dir.mkdir()) {
+ return;
+ }
+ wait(i);
+ }
+ throw new IOException("Could not create " + name);
+ }
+ }
+
+ public OutputStream newOutputStream(boolean append) throws IOException {
+ File file = new File(name);
+ File parent = file.getParentFile();
+ if (parent != null) {
+ FileUtils.createDirectories(parent.getAbsolutePath());
+ }
+ FileOutputStream out = new FileOutputStream(name, append);
+ return out;
+ }
+
+ public InputStream newInputStream() throws IOException {
+ if (name.indexOf(':') > 1) {
+ // if the : is in position 1, a windows file access is assumed: C:.. or D:
+ if (name.startsWith(CLASSPATH_PREFIX)) {
+ String fileName = name.substring(CLASSPATH_PREFIX.length());
+ if (!fileName.startsWith("/")) {
+ fileName = "/" + fileName;
+ }
+ InputStream in = getClass().getResourceAsStream(fileName);
+ if (in == null) {
+ Thread.currentThread().getContextClassLoader().getResourceAsStream(fileName);
+ }
+ if (in == null) {
+ throw new FileNotFoundException("resource " + fileName);
+ }
+ return in;
+ }
+ // otherwise an URL is assumed
+ URL url = new URL(name);
+ InputStream in = url.openStream();
+ return in;
+ }
+ FileInputStream in = new FileInputStream(name);
+ return in;
+ }
+
+ /**
+ * Call the garbage collection and run finalization. This close all files that
+ * were not closed, and are no longer referenced.
+ */
+ static void freeMemoryAndFinalize() {
+ Runtime rt = Runtime.getRuntime();
+ long mem = rt.freeMemory();
+ for (int i = 0; i < 16; i++) {
+ rt.gc();
+ long now = rt.freeMemory();
+ rt.runFinalization();
+ if (now == mem) {
+ break;
+ }
+ mem = now;
+ }
+ }
+
+ public FileChannel open(String mode) throws IOException {
+ FileDisk f;
+ try {
+ f = new FileDisk(name, mode);
+ } catch (IOException e) {
+ freeMemoryAndFinalize();
+ try {
+ f = new FileDisk(name, mode);
+ } catch (IOException e2) {
+ throw e;
+ }
+ }
+ return f;
+ }
+
+ public String getScheme() {
+ return "file";
+ }
+
+ public FilePath createTempFile(String suffix, boolean deleteOnExit, boolean inTempDir)
+ throws IOException {
+ String fileName = name + ".";
+ String prefix = new File(fileName).getName();
+ File dir;
+ if (inTempDir) {
+ dir = new File(System.getProperty("java.io.tmpdir", "."));
+ } else {
+ dir = new File(fileName).getAbsoluteFile().getParentFile();
+ }
+ FileUtils.createDirectories(dir.getAbsolutePath());
+ while (true) {
+ File f = new File(dir, prefix + getNextTempFileNamePart(false) + suffix);
+ if (f.exists() || !f.createNewFile()) {
+ // in theory, the random number could collide
+ getNextTempFileNamePart(true);
+ continue;
+ }
+ if (deleteOnExit) {
+ try {
+ f.deleteOnExit();
+ } catch (Throwable e) {
+ // sometimes this throws a NullPointerException
+ // at java.io.DeleteOnExitHook.add(DeleteOnExitHook.java:33)
+ // we can ignore it
+ }
+ }
+ return get(f.getCanonicalPath());
+ }
+ }
+
+
+ /**
+ * Append an element to the path.
+ * This is similar to <code>java.nio.file.spi.FileSystemProvider.resolve</code>.
+ *
+ * @param other the relative path (might be null)
+ * @return the resolved path
+ */
+ public FilePath resolve(String other) {
+ return other == null ? this : getPath(name + "/" + other);
+ }
+
+}
+
+/**
+ * Uses java.io.RandomAccessFile to access a file.
+ */
+class FileDisk extends FileBase {
+
+ private final RandomAccessFile file;
+ private final String name;
+
+ FileDisk(String fileName, String mode) throws FileNotFoundException {
+ this.file = new RandomAccessFile(fileName, mode);
+ this.name = fileName;
+ }
+
+ public void force(boolean metaData) throws IOException {
+ file.getFD().sync();
+ }
+
+ public FileChannel truncate(long newLength) throws IOException {
+ if (newLength < file.length()) {
+ // some implementations actually only support truncate
+ file.setLength(newLength);
+ }
+ return this;
+ }
+
+ public synchronized FileLock tryLock(long position, long size, boolean shared) throws IOException {
+ return file.getChannel().tryLock();
+ }
+
+ public void implCloseChannel() throws IOException {
+ file.close();
+ }
+
+ public long position() throws IOException {
+ return file.getFilePointer();
+ }
+
+ public long size() throws IOException {
+ return file.length();
+ }
+
+ public int read(ByteBuffer dst) throws IOException {
+ int len = file.read(dst.array(), dst.position(), dst.remaining());
+ if (len > 0) {
+ dst.position(dst.position() + len);
+ }
+ return len;
+ }
+
+ public FileChannel position(long pos) throws IOException {
+ file.seek(pos);
+ return this;
+ }
+
+ public int write(ByteBuffer src) throws IOException {
+ int len = src.remaining();
+ file.write(src.array(), src.position(), len);
+ src.position(src.position() + len);
+ return len;
+ }
+
+ public String toString() {
+ return name;
+ }
+
+}
Added: jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/fs/FileUtils.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/fs/FileUtils.java?rev=1173067&view=auto
==============================================================================
--- jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/fs/FileUtils.java (added)
+++ jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/fs/FileUtils.java Tue Sep 20 10:26:24 2011
@@ -0,0 +1,382 @@
+/*
+ * 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.jackrabbit.mk.fs;
+
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.jackrabbit.mk.util.IOUtils;
+
+/**
+ * This utility class contains utility functions that use the file system
+ * abstraction.
+ */
+public class FileUtils {
+
+ /**
+ * Checks if a file exists.
+ * This method is similar to Java 7 <code>java.nio.file.Path.exists</code>.
+ *
+ * @param fileName the file name
+ * @return true if it exists
+ */
+ public static boolean exists(String fileName) {
+ return FilePath.get(fileName).exists();
+ }
+
+ /**
+ * Create a directory (all required parent directories must already exist).
+ * This method is similar to Java 7 <code>java.nio.file.Path.createDirectory</code>.
+ *
+ * @param directoryName the directory name
+ */
+ public static void createDirectory(String directoryName) throws IOException {
+ FilePath.get(directoryName).createDirectory();
+ }
+
+ /**
+ * Create a new file.
+ * This method is similar to Java 7 <code>java.nio.file.Path.createFile</code>, but returns
+ * false instead of throwing a exception if the file already existed.
+ *
+ * @param fileName the file name
+ * @return true if creating was successful
+ */
+ public static boolean createFile(String fileName) {
+ return FilePath.get(fileName).createFile();
+ }
+
+ /**
+ * Delete a file or directory if it exists.
+ * Directories may only be deleted if they are empty.
+ * This method is similar to Java 7 <code>java.nio.file.Path.deleteIfExists</code>.
+ *
+ * @param path the file or directory name
+ */
+ public static void delete(String path) throws IOException {
+ FilePath.get(path).delete();
+ }
+
+ /**
+ * Get the canonical file or directory name.
+ * This method is similar to Java 7 <code>java.nio.file.Path.toRealPath</code>.
+ *
+ * @param fileName the file name
+ * @return the normalized file name
+ */
+ public static String toRealPath(String fileName) throws IOException {
+ return FilePath.get(fileName).toRealPath().toString();
+ }
+
+ /**
+ * Get the parent directory of a file or directory.
+ * This method returns null if there is no parent.
+ * This method is similar to Java 7 <code>java.nio.file.Path.getParent</code>.
+ *
+ * @param fileName the file or directory name
+ * @return the parent directory name
+ */
+ public static String getParent(String fileName) {
+ FilePath p = FilePath.get(fileName).getParent();
+ return p == null ? null : p.toString();
+ }
+
+ /**
+ * Check if the file name includes a path.
+ * This method is similar to Java 7 <code>java.nio.file.Path.isAbsolute</code>.
+ *
+ * @param fileName the file name
+ * @return if the file name is absolute
+ */
+ public static boolean isAbsolute(String fileName) {
+ return FilePath.get(fileName).isAbsolute();
+ }
+
+ /**
+ * Rename a file if this is allowed.
+ * This method is similar to Java 7 <code>java.nio.file.Path.moveTo</code>.
+ *
+ * @param oldName the old fully qualified file name
+ * @param newName the new fully qualified file name
+ */
+ public static void moveTo(String oldName, String newName) throws IOException {
+ FilePath.get(oldName).moveTo(FilePath.get(newName));
+ }
+
+ /**
+ * Get the file or directory name (the last element of the path).
+ * This method is similar to Java 7 <code>java.nio.file.Path.getName</code>.
+ *
+ * @param path the directory and file name
+ * @return just the file name
+ */
+ public static String getName(String path) {
+ return FilePath.get(path).getName();
+ }
+
+ /**
+ * List the files and directories in the given directory.
+ * This method is similar to Java 7 <code>java.nio.file.Path.newDirectoryStream</code>.
+ *
+ * @param path the directory
+ * @return the list of fully qualified file names
+ */
+ public static List<String> newDirectoryStream(String path) throws IOException {
+ List<FilePath> list = FilePath.get(path).newDirectoryStream();
+ int len = list.size();
+ List<String> result = new ArrayList<String>(len);
+ for (int i = 0; i < len; i++) {
+ result.add(list.get(i).toString());
+ }
+ return result;
+ }
+
+ /**
+ * Get the last modified date of a file.
+ * This method is similar to Java 7
+ * <code>java.nio.file.attribute.Attributes.readBasicFileAttributes(file).lastModified().toMillis()</code>
+ *
+ * @param fileName the file name
+ * @return the last modified date
+ */
+ public static long lastModified(String fileName) {
+ return FilePath.get(fileName).lastModified();
+ }
+
+ /**
+ * Get the size of a file in bytes
+ * This method is similar to Java 7
+ * <code>java.nio.file.attribute.Attributes.readBasicFileAttributes(file).size()</code>
+ *
+ * @param fileName the file name
+ * @return the size in bytes
+ */
+ public static long size(String fileName) {
+ return FilePath.get(fileName).size();
+ }
+
+ /**
+ * Check if it is a file or a directory.
+ * <code>java.nio.file.attribute.Attributes.readBasicFileAttributes(file).isDirectory()</code>
+ *
+ * @param fileName the file or directory name
+ * @return true if it is a directory
+ */
+ public static boolean isDirectory(String fileName) {
+ return FilePath.get(fileName).isDirectory();
+ }
+
+ /**
+ * Open a random access file object.
+ * This method is similar to Java 7 <code>java.nio.channels.FileChannel.open</code>.
+ *
+ * @param fileName the file name
+ * @param mode the access mode. Supported are r, rw, rws, rwd
+ * @return the file object
+ */
+ public static FileChannel open(String fileName, String mode) throws IOException {
+ return FilePath.get(fileName).open(mode);
+ }
+
+ /**
+ * Create an input stream to read from the file.
+ * This method is similar to Java 7 <code>java.nio.file.Path.newInputStream</code>.
+ *
+ * @param fileName the file name
+ * @return the input stream
+ */
+ public static InputStream newInputStream(String fileName) throws IOException {
+ return FilePath.get(fileName).newInputStream();
+ }
+
+ /**
+ * Create an output stream to write into the file.
+ * This method is similar to Java 7 <code>java.nio.file.Path.newOutputStream</code>.
+ *
+ * @param fileName the file name
+ * @param append if true, the file will grow, if false, the file will be
+ * truncated first
+ * @return the output stream
+ */
+ public static OutputStream newOutputStream(String fileName, boolean append) throws IOException {
+ return FilePath.get(fileName).newOutputStream(append);
+ }
+
+ /**
+ * Check if the file is writable.
+ * This method is similar to Java 7
+ * <code>java.nio.file.Path.checkAccess(AccessMode.WRITE)</code>
+ *
+ * @param fileName the file name
+ * @return if the file is writable
+ */
+ public static boolean canWrite(String fileName) {
+ return FilePath.get(fileName).canWrite();
+ }
+
+ // special methods =======================================
+
+ /**
+ * Disable the ability to write. The file can still be deleted afterwards.
+ *
+ * @param fileName the file name
+ * @return true if the call was successful
+ */
+ public static boolean setReadOnly(String fileName) {
+ return FilePath.get(fileName).setReadOnly();
+ }
+
+ /**
+ * Get the unwrapped file name (without wrapper prefixes if wrapping /
+ * delegating file systems are used).
+ *
+ * @param fileName the file name
+ * @return the unwrapped
+ */
+ public static String unwrap(String fileName) {
+ return FilePath.get(fileName).unwrap().toString();
+ }
+
+ // utility methods =======================================
+
+ /**
+ * Delete a directory or file and all subdirectories and files.
+ *
+ * @param path the path
+ * @param tryOnly whether errors should be ignored
+ */
+ public static void deleteRecursive(String path, boolean tryOnly) throws IOException {
+ if (exists(path)) {
+ if (isDirectory(path)) {
+ for (String s : newDirectoryStream(path)) {
+ deleteRecursive(s, tryOnly);
+ }
+ }
+ if (tryOnly) {
+ tryDelete(path);
+ } else {
+ delete(path);
+ }
+ }
+ }
+
+ /**
+ * Create the directory and all required parent directories.
+ *
+ * @param dir the directory name
+ */
+ public static void createDirectories(String dir) throws IOException {
+ if (dir != null) {
+ if (exists(dir)) {
+ if (!isDirectory(dir)) {
+ throw new IOException("Could not create directory, " +
+ "because a file with the same name already exists: " + dir);
+ }
+ } else {
+ String parent = getParent(dir);
+ createDirectories(parent);
+ createDirectory(dir);
+ }
+ }
+ }
+
+ /**
+ * Copy a file from one directory to another, or to another file.
+ *
+ * @param original the original file name
+ * @param copy the file name of the copy
+ */
+ public static void copy(String original, String copy) throws IOException {
+ InputStream in = newInputStream(original);
+ try {
+ OutputStream out = newOutputStream(copy, false);
+ try {
+ IOUtils.copy(in, out);
+ } finally {
+ out.close();
+ }
+ } finally {
+ in.close();
+ }
+ }
+
+ /**
+ * Try to delete a file (ignore errors).
+ *
+ * @param fileName the file name
+ * @return true if it worked
+ */
+ public static boolean tryDelete(String fileName) {
+ try {
+ FilePath.get(fileName).delete();
+ return true;
+ } catch (Exception e) {
+ return false;
+ }
+ }
+
+ /**
+ * Create a new temporary file.
+ *
+ * @param prefix the prefix of the file name (including directory name if
+ * required)
+ * @param suffix the suffix
+ * @param deleteOnExit if the file should be deleted when the virtual
+ * machine exists
+ * @param inTempDir if the file should be stored in the temporary directory
+ * @return the name of the created file
+ */
+ public static String createTempFile(String prefix, String suffix, boolean deleteOnExit, boolean inTempDir)
+ throws IOException {
+ return FilePath.get(prefix).createTempFile(suffix, deleteOnExit, inTempDir).toString();
+ }
+
+ /**
+ * Fully read from the file. This will read all remaining bytes,
+ * or throw an EOFException if not successful.
+ *
+ * @param channel the file channel
+ * @param dst the byte buffer
+ */
+ public static void readFully(FileChannel channel, ByteBuffer dst) throws IOException {
+ do {
+ int r = channel.read(dst);
+ if (r < 0) {
+ throw new EOFException();
+ }
+ } while (dst.remaining() > 0);
+ }
+
+ /**
+ * Fully write to the file. This will write all remaining bytes.
+ *
+ * @param channel the file channel
+ * @param src the byte buffer
+ */
+ public static void writeFully(FileChannel channel, ByteBuffer src) throws IOException {
+ do {
+ channel.write(src);
+ } while (src.remaining() > 0);
+ }
+
+
+}
Added: jackrabbit/sandbox/microkernel/src/test/java/org/apache/jackrabbit/mk/fs/TestFileSystem.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/test/java/org/apache/jackrabbit/mk/fs/TestFileSystem.java?rev=1173067&view=auto
==============================================================================
--- jackrabbit/sandbox/microkernel/src/test/java/org/apache/jackrabbit/mk/fs/TestFileSystem.java (added)
+++ jackrabbit/sandbox/microkernel/src/test/java/org/apache/jackrabbit/mk/fs/TestFileSystem.java Tue Sep 20 10:26:24 2011
@@ -0,0 +1,310 @@
+/*
+ * 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.jackrabbit.mk.fs;
+
+import java.io.EOFException;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.RandomAccessFile;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import java.nio.channels.FileLock;
+import java.util.List;
+import java.util.Random;
+import org.apache.jackrabbit.mk.util.IOUtilsTest;
+import junit.framework.TestCase;
+
+/**
+ * Tests various file system.
+ */
+public class TestFileSystem extends TestCase {
+
+ private String getBaseDir() {
+ return "target/temp";
+ }
+
+ public void test() throws Exception {
+ testFileSystem(getBaseDir() + "/fs");
+ }
+
+ public void testClasspath() throws IOException {
+ String resource = getClass().getName().replace('.', '/') + ".class";
+ InputStream in;
+ in = getClass().getResourceAsStream("/" + resource);
+ assertTrue(in != null);
+ in.close();
+ in = getClass().getClassLoader().getResourceAsStream(resource);
+ assertTrue(in != null);
+ in.close();
+ in = FileUtils.newInputStream("classpath:" + resource);
+ assertTrue(in != null);
+ in.close();
+ in = FileUtils.newInputStream("classpath:/" + resource);
+ assertTrue(in != null);
+ in.close();
+ }
+
+ public void testSimpleExpandTruncateSize() throws Exception {
+ String f = getBaseDir() + "/fs/test.data";
+ FileUtils.createDirectories(getBaseDir() + "/fs");
+ FileChannel c = FileUtils.open(f, "rw");
+ c.position(4000);
+ c.write(ByteBuffer.wrap(new byte[1]));
+ FileLock lock = c.tryLock();
+ c.truncate(0);
+ if (lock != null) {
+ lock.release();
+ }
+ c.close();
+ }
+
+ public void testUserHome() throws IOException {
+ String fileName = FileUtils.toRealPath("~/test");
+ String userDir = System.getProperty("user.home").replace('\\', '/');
+ assertTrue(fileName.startsWith(userDir));
+ }
+
+ private void testFileSystem(String fsBase) throws Exception {
+ testSimple(fsBase);
+ testTempFile(fsBase);
+ testRandomAccess(fsBase);
+ }
+
+ private void testSimple(final String fsBase) throws Exception {
+ long time = System.currentTimeMillis();
+ for (String s : FileUtils.newDirectoryStream(fsBase)) {
+ FileUtils.delete(s);
+ }
+ FileUtils.createDirectories(fsBase + "/test");
+ FileUtils.delete(fsBase + "/test");
+ FileUtils.delete(fsBase + "/test2");
+ assertTrue(FileUtils.createFile(fsBase + "/test"));
+ List<FilePath> p = FilePath.get(fsBase).newDirectoryStream();
+ assertEquals(1, p.size());
+ String can = FilePath.get(fsBase + "/test").toRealPath().toString();
+ assertEquals(can, p.get(0).toString());
+ assertTrue(FileUtils.canWrite(fsBase + "/test"));
+ FileChannel channel = FileUtils.open(fsBase + "/test", "rw");
+ byte[] buffer = new byte[10000];
+ Random random = new Random(1);
+ random.nextBytes(buffer);
+ channel.write(ByteBuffer.wrap(buffer));
+ assertEquals(10000, channel.size());
+ channel.position(20000);
+ assertEquals(20000, channel.position());
+ assertEquals(-1, channel.read(ByteBuffer.wrap(buffer, 0, 1)));
+ String path = fsBase + "/test";
+ assertEquals("test", FileUtils.getName(path));
+ can = FilePath.get(fsBase).toRealPath().toString();
+ String can2 = FileUtils.toRealPath(FileUtils.getParent(path));
+ assertEquals(can, can2);
+ FileLock lock = channel.tryLock();
+ if (lock != null) {
+ lock.release();
+ }
+ assertEquals(10000, channel.size());
+ channel.close();
+ assertEquals(10000, FileUtils.size(fsBase + "/test"));
+ channel = FileUtils.open(fsBase + "/test", "r");
+ final byte[] test = new byte[10000];
+ FileUtils.readFully(channel, ByteBuffer.wrap(test, 0, 10000));
+ IOUtilsTest.assertEquals(buffer, test);
+ final FileChannel fc = channel;
+ try {
+ fc.write(ByteBuffer.wrap(test, 0, 10));
+ fail();
+ } catch (IOException e) {
+ // expected
+ }
+ try {
+ fc.truncate(10);
+ fail();
+ } catch (IOException e) {
+ // expected
+ }
+ channel.close();
+ long lastMod = FileUtils.lastModified(fsBase + "/test");
+ if (lastMod < time - 1999) {
+ // at most 2 seconds difference
+ assertEquals(time, lastMod);
+ }
+ assertEquals(10000, FileUtils.size(fsBase + "/test"));
+ List<String> list = FileUtils.newDirectoryStream(fsBase);
+ assertEquals(1, list.size());
+ assertTrue(list.get(0).endsWith("test"));
+ FileUtils.copy(fsBase + "/test", fsBase + "/test3");
+ FileUtils.moveTo(fsBase + "/test3", fsBase + "/test2");
+ assertTrue(!FileUtils.exists(fsBase + "/test3"));
+ assertTrue(FileUtils.exists(fsBase + "/test2"));
+ assertEquals(10000, FileUtils.size(fsBase + "/test2"));
+ byte[] buffer2 = new byte[10000];
+ InputStream in = FileUtils.newInputStream(fsBase + "/test2");
+ int pos = 0;
+ while (true) {
+ int l = in.read(buffer2, pos, Math.min(10000 - pos, 1000));
+ if (l <= 0) {
+ break;
+ }
+ pos += l;
+ }
+ in.close();
+ assertEquals(10000, pos);
+ IOUtilsTest.assertEquals(buffer, buffer2);
+
+ assertTrue(FileUtils.tryDelete(fsBase + "/test2"));
+ FileUtils.delete(fsBase + "/test");
+ if (fsBase.indexOf("memFS:") < 0 && fsBase.indexOf("memLZF:") < 0) {
+ FileUtils.createDirectories(fsBase + "/testDir");
+ assertTrue(FileUtils.isDirectory(fsBase + "/testDir"));
+ if (!fsBase.startsWith("jdbc:")) {
+ FileUtils.deleteRecursive(fsBase + "/testDir", false);
+ assertTrue(!FileUtils.exists(fsBase + "/testDir"));
+ }
+ }
+ }
+
+ private void testRandomAccess(String fsBase) throws Exception {
+ testRandomAccess(fsBase, 1);
+ }
+
+ private void testRandomAccess(String fsBase, int seed) throws Exception {
+ StringBuilder buff = new StringBuilder();
+ String s = FileUtils.createTempFile(fsBase + "/tmp", ".tmp", false, false);
+ File file = new File(getBaseDir() + "/tmp");
+ file.getParentFile().mkdirs();
+ file.delete();
+ RandomAccessFile ra = new RandomAccessFile(file, "rw");
+ FileUtils.delete(s);
+ FileChannel f = FileUtils.open(s, "rw");
+ assertEquals(-1, f.read(ByteBuffer.wrap(new byte[1])));
+ f.force(true);
+ Random random = new Random(seed);
+ int size = 500;
+ try {
+ for (int i = 0; i < size; i++) {
+ trace("op " + i);
+ int pos = random.nextInt(10000);
+ switch(random.nextInt(7)) {
+ case 0: {
+ pos = (int) Math.min(pos, ra.length());
+ trace("seek " + pos);
+ buff.append("seek " + pos + "\n");
+ f.position(pos);
+ ra.seek(pos);
+ break;
+ }
+ case 1: {
+ byte[] buffer = new byte[random.nextInt(1000)];
+ random.nextBytes(buffer);
+ trace("write " + buffer.length);
+ buff.append("write " + buffer.length + "\n");
+ f.write(ByteBuffer.wrap(buffer));
+ ra.write(buffer, 0, buffer.length);
+ break;
+ }
+ case 2: {
+ trace("truncate " + pos);
+ f.truncate(pos);
+ if (pos < ra.length()) {
+ // truncate is supposed to have no effect if the
+ // position is larger than the current size
+ ra.setLength(pos);
+ }
+ assertEquals(ra.getFilePointer(), f.position());
+ buff.append("truncate " + pos + "\n");
+ break;
+ }
+ case 3: {
+ int len = random.nextInt(1000);
+ len = (int) Math.min(len, ra.length() - ra.getFilePointer());
+ byte[] b1 = new byte[len];
+ byte[] b2 = new byte[len];
+ trace("readFully " + len);
+ ra.readFully(b1, 0, len);
+ try {
+ FileUtils.readFully(f, ByteBuffer.wrap(b2, 0, len));
+ } catch (EOFException e) {
+ e.printStackTrace();
+ }
+ buff.append("readFully " + len + "\n");
+ IOUtilsTest.assertEquals(b1, b2);
+ break;
+ }
+ case 4: {
+ trace("getFilePointer " + ra.getFilePointer());
+ buff.append("getFilePointer " + ra.getFilePointer() + "\n");
+ assertEquals(ra.getFilePointer(), f.position());
+ break;
+ }
+ case 5: {
+ trace("length " + ra.length());
+ buff.append("length " + ra.length() + "\n");
+ assertEquals(ra.length(), f.size());
+ break;
+ }
+ case 6: {
+ trace("reopen");
+ buff.append("reopen\n");
+ f.close();
+ ra.close();
+ ra = new RandomAccessFile(file, "rw");
+ f = FileUtils.open(s, "rw");
+ assertEquals(ra.length(), f.size());
+ break;
+ }
+ default:
+ }
+ }
+ } catch (Throwable e) {
+ e.printStackTrace();
+ fail("Exception: " + e + "\n"+ buff.toString());
+ } finally {
+ f.close();
+ ra.close();
+ file.delete();
+ FileUtils.delete(s);
+ }
+ }
+
+ private void trace(String s) {
+ // System.out.println(s);
+ }
+
+ private void testTempFile(String fsBase) throws Exception {
+ int len = 10000;
+ String s = FileUtils.createTempFile(fsBase + "/tmp", ".tmp", false, false);
+ OutputStream out = FileUtils.newOutputStream(s, false);
+ byte[] buffer = new byte[len];
+ out.write(buffer);
+ out.close();
+ out = FileUtils.newOutputStream(s, true);
+ out.write(1);
+ out.close();
+ InputStream in = FileUtils.newInputStream(s);
+ for (int i = 0; i < len; i++) {
+ assertEquals(0, in.read());
+ }
+ assertEquals(1, in.read());
+ assertEquals(-1, in.read());
+ in.close();
+ out.close();
+ FileUtils.delete(s);
+ }
+
+}