You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by rm...@apache.org on 2014/11/25 16:21:19 UTC
svn commit: r1641632 [1/2] - in /lucene/dev/trunk/lucene:
core/src/test/org/apache/lucene/mockfile/ test-framework/
test-framework/src/java/org/apache/lucene/mockfile/
test-framework/src/java/org/apache/lucene/util/
Author: rmuir
Date: Tue Nov 25 15:21:18 2014
New Revision: 1641632
URL: http://svn.apache.org/r1641632
Log:
LUCENE-6072: use mockfilesystem in tests
Added:
lucene/dev/trunk/lucene/core/src/test/org/apache/lucene/mockfile/
lucene/dev/trunk/lucene/core/src/test/org/apache/lucene/mockfile/TestMockFilesystems.java (with props)
lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/mockfile/
lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/mockfile/DisableFsyncFS.java (with props)
lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/mockfile/FilterAsynchronousFileChannel.java (with props)
lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/mockfile/FilterDirectoryStream.java (with props)
lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/mockfile/FilterFileChannel.java (with props)
lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/mockfile/FilterFileStore.java (with props)
lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/mockfile/FilterFileSystem.java (with props)
lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/mockfile/FilterFileSystemProvider.java (with props)
lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/mockfile/FilterInputStream2.java (with props)
lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/mockfile/FilterOutputStream2.java (with props)
lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/mockfile/FilterPath.java (with props)
lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/mockfile/FilterSecureDirectoryStream.java (with props)
lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/mockfile/FilterSeekableByteChannel.java (with props)
lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/mockfile/HandleTrackingFS.java (with props)
lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/mockfile/LeakFS.java (with props)
lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/mockfile/VerboseFS.java (with props)
lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/mockfile/WindowsFS.java (with props)
lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/mockfile/package.html (with props)
Modified:
lucene/dev/trunk/lucene/test-framework/build.xml
lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/util/TestRuleTemporaryFilesCleanup.java
Added: lucene/dev/trunk/lucene/core/src/test/org/apache/lucene/mockfile/TestMockFilesystems.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/core/src/test/org/apache/lucene/mockfile/TestMockFilesystems.java?rev=1641632&view=auto
==============================================================================
--- lucene/dev/trunk/lucene/core/src/test/org/apache/lucene/mockfile/TestMockFilesystems.java (added)
+++ lucene/dev/trunk/lucene/core/src/test/org/apache/lucene/mockfile/TestMockFilesystems.java Tue Nov 25 15:21:18 2014
@@ -0,0 +1,205 @@
+package org.apache.lucene.mockfile;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URI;
+import java.nio.channels.AsynchronousFileChannel;
+import java.nio.channels.FileChannel;
+import java.nio.channels.SeekableByteChannel;
+import java.nio.file.FileSystem;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.StandardCopyOption;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.apache.lucene.util.InfoStream;
+import org.apache.lucene.util.LuceneTestCase;
+
+public class TestMockFilesystems extends LuceneTestCase {
+
+ public void testLeakInputStream() throws IOException {
+ Path dir = FilterPath.unwrap(createTempDir());
+ FileSystem fs = new LeakFS(dir.getFileSystem()).getFileSystem(URI.create("file:///"));
+ Path wrapped = new FilterPath(dir, fs);
+
+ OutputStream file = Files.newOutputStream(wrapped.resolve("stillopen"));
+ file.write(5);
+ file.close();
+ InputStream leak = Files.newInputStream(wrapped.resolve("stillopen"));
+ try {
+ fs.close();
+ fail("should have gotten exception");
+ } catch (Exception e) {
+ assertTrue(e.getMessage().contains("file handle leaks"));
+ }
+ leak.close();
+ }
+
+ public void testLeakOutputStream() throws IOException {
+ Path dir = FilterPath.unwrap(createTempDir());
+ FileSystem fs = new LeakFS(dir.getFileSystem()).getFileSystem(URI.create("file:///"));
+ Path wrapped = new FilterPath(dir, fs);
+
+ OutputStream leak = Files.newOutputStream(wrapped.resolve("leaky"));
+ try {
+ fs.close();
+ fail("should have gotten exception");
+ } catch (Exception e) {
+ assertTrue(e.getMessage().contains("file handle leaks"));
+ }
+ leak.close();
+ }
+
+ public void testLeakFileChannel() throws IOException {
+ Path dir = FilterPath.unwrap(createTempDir());
+ FileSystem fs = new LeakFS(dir.getFileSystem()).getFileSystem(URI.create("file:///"));
+ Path wrapped = new FilterPath(dir, fs);
+
+ OutputStream file = Files.newOutputStream(wrapped.resolve("stillopen"));
+ file.write(5);
+ file.close();
+ FileChannel leak = FileChannel.open(wrapped.resolve("stillopen"));
+ try {
+ fs.close();
+ fail("should have gotten exception");
+ } catch (Exception e) {
+ assertTrue(e.getMessage().contains("file handle leaks"));
+ }
+ leak.close();
+ }
+
+ public void testLeakAsyncFileChannel() throws IOException {
+ Path dir = FilterPath.unwrap(createTempDir());
+ FileSystem fs = new LeakFS(dir.getFileSystem()).getFileSystem(URI.create("file:///"));
+ Path wrapped = new FilterPath(dir, fs);
+
+ OutputStream file = Files.newOutputStream(wrapped.resolve("stillopen"));
+ file.write(5);
+ file.close();
+ AsynchronousFileChannel leak = AsynchronousFileChannel.open(wrapped.resolve("stillopen"));
+ try {
+ fs.close();
+ fail("should have gotten exception");
+ } catch (Exception e) {
+ assertTrue(e.getMessage().contains("file handle leaks"));
+ }
+ leak.close();
+ }
+
+ public void testLeakByteChannel() throws IOException {
+ Path dir = FilterPath.unwrap(createTempDir());
+ FileSystem fs = new LeakFS(dir.getFileSystem()).getFileSystem(URI.create("file:///"));
+ Path wrapped = new FilterPath(dir, fs);
+
+ OutputStream file = Files.newOutputStream(wrapped.resolve("stillopen"));
+ file.write(5);
+ file.close();
+ SeekableByteChannel leak = Files.newByteChannel(wrapped.resolve("stillopen"));
+ try {
+ fs.close();
+ fail("should have gotten exception");
+ } catch (Exception e) {
+ assertTrue(e.getMessage().contains("file handle leaks"));
+ }
+ leak.close();
+ }
+
+ public void testDeleteOpenFile() throws IOException {
+ Path dir = FilterPath.unwrap(createTempDir());
+ FileSystem fs = new WindowsFS(dir.getFileSystem()).getFileSystem(URI.create("file:///"));
+ Path wrapped = new FilterPath(dir, fs);
+
+ OutputStream file = Files.newOutputStream(wrapped.resolve("stillopen"));
+ file.write(5);
+ file.close();
+ InputStream is = Files.newInputStream(wrapped.resolve("stillopen"));
+ try {
+ Files.delete(wrapped.resolve("stillopen"));
+ fail("should have gotten exception");
+ } catch (IOException e) {
+ assertTrue(e.getMessage().contains("access denied"));
+ }
+ is.close();
+ }
+
+ public void testDeleteIfExistsOpenFile() throws IOException {
+ Path dir = FilterPath.unwrap(createTempDir());
+ FileSystem fs = new WindowsFS(dir.getFileSystem()).getFileSystem(URI.create("file:///"));
+ Path wrapped = new FilterPath(dir, fs);
+
+ OutputStream file = Files.newOutputStream(wrapped.resolve("stillopen"));
+ file.write(5);
+ file.close();
+ InputStream is = Files.newInputStream(wrapped.resolve("stillopen"));
+ try {
+ Files.deleteIfExists(wrapped.resolve("stillopen"));
+ fail("should have gotten exception");
+ } catch (IOException e) {
+ assertTrue(e.getMessage().contains("access denied"));
+ }
+ is.close();
+ }
+
+ public void testRenameOpenFile() throws IOException {
+ Path dir = FilterPath.unwrap(createTempDir());
+ FileSystem fs = new WindowsFS(dir.getFileSystem()).getFileSystem(URI.create("file:///"));
+ Path wrapped = new FilterPath(dir, fs);
+
+ OutputStream file = Files.newOutputStream(wrapped.resolve("stillopen"));
+ file.write(5);
+ file.close();
+ InputStream is = Files.newInputStream(wrapped.resolve("stillopen"));
+ try {
+ Files.move(wrapped.resolve("stillopen"), wrapped.resolve("target"), StandardCopyOption.ATOMIC_MOVE);
+ fail("should have gotten exception");
+ } catch (IOException e) {
+ assertTrue(e.getMessage().contains("access denied"));
+ }
+ is.close();
+ }
+
+ public void testVerboseWrite() throws IOException {
+ Path dir = FilterPath.unwrap(createTempDir());
+ final AtomicBoolean seenMessage = new AtomicBoolean(false);
+ InfoStream testStream = new InfoStream() {
+ @Override
+ public void close() throws IOException {}
+
+ @Override
+ public void message(String component, String message) {
+ if ("FS".equals(component) && message.startsWith("newOutputStream")) {
+ seenMessage.set(true);
+ }
+ }
+
+ @Override
+ public boolean isEnabled(String component) {
+ return true;
+ }
+ };
+ FileSystem fs = new VerboseFS(dir.getFileSystem(), testStream).getFileSystem(URI.create("file:///"));
+ Path wrapped = new FilterPath(dir, fs);
+
+ OutputStream file = Files.newOutputStream(wrapped.resolve("output"));
+ assertTrue(seenMessage.get());
+ file.close();
+ }
+}
Modified: lucene/dev/trunk/lucene/test-framework/build.xml
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/test-framework/build.xml?rev=1641632&r1=1641631&r2=1641632&view=diff
==============================================================================
--- lucene/dev/trunk/lucene/test-framework/build.xml (original)
+++ lucene/dev/trunk/lucene/test-framework/build.xml Tue Nov 25 15:21:18 2014
@@ -22,6 +22,11 @@
<property name="build.dir" location="../build/test-framework"/>
+ <!-- file is part of the API -->
+ <property name="forbidden-base-excludes" value="
+ org/apache/lucene/mockfile/FilterPath.class
+ "/>
+
<import file="../common-build.xml"/>
<path id="classpath">
Added: lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/mockfile/DisableFsyncFS.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/mockfile/DisableFsyncFS.java?rev=1641632&view=auto
==============================================================================
--- lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/mockfile/DisableFsyncFS.java (added)
+++ lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/mockfile/DisableFsyncFS.java Tue Nov 25 15:21:18 2014
@@ -0,0 +1,59 @@
+package org.apache.lucene.mockfile;
+
+import java.io.IOException;
+import java.nio.channels.AsynchronousFileChannel;
+import java.nio.channels.FileChannel;
+import java.nio.file.FileSystem;
+import java.nio.file.OpenOption;
+import java.nio.file.Path;
+import java.nio.file.attribute.FileAttribute;
+import java.util.Set;
+import java.util.concurrent.ExecutorService;
+
+/*
+ * 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.
+ */
+
+/**
+ * Disables actual calls to fsync.
+ * <p>
+ * All other filesystem operations are passed thru as normal.
+ */
+public class DisableFsyncFS extends FilterFileSystemProvider {
+
+ /**
+ * Create a new instance, wrapping {@code delegate}.
+ */
+ public DisableFsyncFS(FileSystem delegate) {
+ super("disablefsync://", delegate);
+ }
+
+ @Override
+ public FileChannel newFileChannel(Path path, Set<? extends OpenOption> options, FileAttribute<?>... attrs) throws IOException {
+ return new FilterFileChannel(super.newFileChannel(path, options, attrs)) {
+ @Override
+ public void force(boolean metaData) throws IOException {}
+ };
+ }
+
+ @Override
+ public AsynchronousFileChannel newAsynchronousFileChannel(Path path, Set<? extends OpenOption> options, ExecutorService executor, FileAttribute<?>... attrs) throws IOException {
+ return new FilterAsynchronousFileChannel(super.newAsynchronousFileChannel(path, options, executor, attrs)) {
+ @Override
+ public void force(boolean metaData) throws IOException {}
+ };
+ }
+}
Added: lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/mockfile/FilterAsynchronousFileChannel.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/mockfile/FilterAsynchronousFileChannel.java?rev=1641632&view=auto
==============================================================================
--- lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/mockfile/FilterAsynchronousFileChannel.java (added)
+++ lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/mockfile/FilterAsynchronousFileChannel.java Tue Nov 25 15:21:18 2014
@@ -0,0 +1,112 @@
+package org.apache.lucene.mockfile;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.AsynchronousFileChannel;
+import java.nio.channels.CompletionHandler;
+import java.nio.channels.FileLock;
+import java.util.Objects;
+import java.util.concurrent.Future;
+
+/**
+ * A {@code FilterAsynchronousFileChannel} contains another
+ * {@code AsynchronousFileChannel}, which it uses as its basic
+ * source of data, possibly transforming the data along the
+ * way or providing additional functionality.
+ */
+public class FilterAsynchronousFileChannel extends AsynchronousFileChannel {
+
+ /**
+ * The underlying {@code AsynchronousFileChannel} instance.
+ */
+ protected final AsynchronousFileChannel delegate;
+
+ /**
+ * Construct a {@code FilterAsynchronousFileChannel} based on
+ * the specified base channel.
+ * <p>
+ * Note that base channel is closed if this channel is closed.
+ * @param delegate specified base channel.
+ */
+ public FilterAsynchronousFileChannel(AsynchronousFileChannel delegate) {
+ this.delegate = Objects.requireNonNull(delegate);
+ }
+
+ @Override
+ public void close() throws IOException {
+ delegate.close();
+ }
+
+ @Override
+ public boolean isOpen() {
+ return delegate.isOpen();
+ }
+
+ @Override
+ public long size() throws IOException {
+ return delegate.size();
+ }
+
+ @Override
+ public AsynchronousFileChannel truncate(long size) throws IOException {
+ delegate.truncate(size);
+ return this;
+ }
+
+ @Override
+ public void force(boolean metaData) throws IOException {
+ delegate.force(metaData);
+ }
+
+ @Override
+ public <A> void lock(long position, long size, boolean shared, A attachment, CompletionHandler<FileLock,? super A> handler) {
+ delegate.lock(position, size, shared, attachment, handler);
+ }
+
+ @Override
+ public Future<FileLock> lock(long position, long size, boolean shared) {
+ return delegate.lock(position, size, shared);
+ }
+
+ @Override
+ public FileLock tryLock(long position, long size, boolean shared) throws IOException {
+ return delegate.tryLock(position, size, shared);
+ }
+
+ @Override
+ public <A> void read(ByteBuffer dst, long position, A attachment, CompletionHandler<Integer,? super A> handler) {
+ delegate.read(dst, position, attachment, handler);
+ }
+
+ @Override
+ public Future<Integer> read(ByteBuffer dst, long position) {
+ return delegate.read(dst, position);
+ }
+
+ @Override
+ public <A> void write(ByteBuffer src, long position, A attachment, CompletionHandler<Integer,? super A> handler) {
+ delegate.write(src, position, attachment, handler);
+ }
+
+ @Override
+ public Future<Integer> write(ByteBuffer src, long position) {
+ return delegate.write(src, position);
+ }
+}
Added: lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/mockfile/FilterDirectoryStream.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/mockfile/FilterDirectoryStream.java?rev=1641632&view=auto
==============================================================================
--- lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/mockfile/FilterDirectoryStream.java (added)
+++ lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/mockfile/FilterDirectoryStream.java Tue Nov 25 15:21:18 2014
@@ -0,0 +1,58 @@
+package org.apache.lucene.mockfile;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.nio.file.DirectoryStream;
+import java.util.Iterator;
+import java.util.Objects;
+
+/**
+ * A {@code FilterDirectoryStream} contains another
+ * {@code DirectoryStream}, which it uses as its basic
+ * source of data, possibly transforming the data along the
+ * way or providing additional functionality.
+ */
+public class FilterDirectoryStream<T> implements DirectoryStream<T> {
+
+ /**
+ * The underlying {@code DirectoryStream} instance.
+ */
+ protected final DirectoryStream<T> delegate;
+
+ /**
+ * Construct a {@code FilterDirectoryStream} based on
+ * the specified base stream.
+ * <p>
+ * Note that base stream is closed if this stream is closed.
+ * @param delegate specified base stream.
+ */
+ public FilterDirectoryStream(DirectoryStream<T> delegate) {
+ this.delegate = Objects.requireNonNull(delegate);
+ }
+
+ @Override
+ public void close() throws IOException {
+ delegate.close();
+ }
+
+ @Override
+ public Iterator<T> iterator() {
+ return delegate.iterator();
+ }
+}
Added: lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/mockfile/FilterFileChannel.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/mockfile/FilterFileChannel.java?rev=1641632&view=auto
==============================================================================
--- lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/mockfile/FilterFileChannel.java (added)
+++ lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/mockfile/FilterFileChannel.java Tue Nov 25 15:21:18 2014
@@ -0,0 +1,157 @@
+package org.apache.lucene.mockfile;
+
+/*
+ * 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.
+ */
+
+import java.io.IOError;
+import java.io.IOException;
+import java.lang.reflect.Method;
+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;
+import java.util.Objects;
+
+/**
+ * A {@code FilterFileChannel} contains another
+ * {@code FileChannel}, which it uses as its basic
+ * source of data, possibly transforming the data along the
+ * way or providing additional functionality.
+ */
+public class FilterFileChannel extends FileChannel {
+
+ /**
+ * The underlying {@code FileChannel} instance.
+ */
+ protected final FileChannel delegate;
+
+ /**
+ * Construct a {@code FilterFileChannel} based on
+ * the specified base channel.
+ * <p>
+ * Note that base channel is closed if this channel is closed.
+ * @param delegate specified base channel.
+ */
+ public FilterFileChannel(FileChannel delegate) {
+ this.delegate = Objects.requireNonNull(delegate);
+ }
+
+ @Override
+ public int read(ByteBuffer dst) throws IOException {
+ return delegate.read(dst);
+ }
+
+ @Override
+ public long read(ByteBuffer[] dsts, int offset, int length) throws IOException {
+ return delegate.read(dsts, offset, length);
+ }
+
+ @Override
+ public int write(ByteBuffer src) throws IOException {
+ return delegate.write(src);
+ }
+
+ @Override
+ public long write(ByteBuffer[] srcs, int offset, int length) throws IOException {
+ return delegate.write(srcs, offset, length);
+ }
+
+ @Override
+ public long position() throws IOException {
+ return delegate.position();
+ }
+
+ @Override
+ public FileChannel position(long newPosition) throws IOException {
+ delegate.position(newPosition);
+ return this;
+ }
+
+ @Override
+ public long size() throws IOException {
+ return delegate.size();
+ }
+
+ @Override
+ public FileChannel truncate(long size) throws IOException {
+ delegate.truncate(size);
+ return this;
+ }
+
+ @Override
+ public void force(boolean metaData) throws IOException {
+ delegate.force(metaData);
+ }
+
+ @Override
+ public long transferTo(long position, long count, WritableByteChannel target) throws IOException {
+ return delegate.transferTo(position, count, target);
+ }
+
+ @Override
+ public long transferFrom(ReadableByteChannel src, long position, long count) throws IOException {
+ return delegate.transferFrom(src, position, count);
+ }
+
+ @Override
+ public int read(ByteBuffer dst, long position) throws IOException {
+ return delegate.read(dst, position);
+ }
+
+ @Override
+ public int write(ByteBuffer src, long position) throws IOException {
+ return delegate.write(src, position);
+ }
+
+ @Override
+ public MappedByteBuffer map(MapMode mode, long position, long size) throws IOException {
+ return delegate.map(mode, position, size);
+ }
+
+ @Override
+ public FileLock lock(long position, long size, boolean shared) throws IOException {
+ return delegate.lock(position, size, shared);
+ }
+
+ @Override
+ public FileLock tryLock(long position, long size, boolean shared) throws IOException {
+ return delegate.tryLock(position, size, shared);
+ }
+
+ @Override
+ protected void implCloseChannel() throws IOException {
+ // our only way to call delegate.implCloseChannel()
+ for (Class<?> clazz = delegate.getClass(); clazz != null; clazz = clazz.getSuperclass()) {
+ final Method method;
+ try {
+ method = clazz.getDeclaredMethod("implCloseChannel");
+ } catch (NoSuchMethodException e) {
+ continue;
+ }
+ try {
+ method.setAccessible(true);
+ method.invoke(delegate);
+ return;
+ } catch (ReflectiveOperationException e) {
+ throw new IOError(e);
+ }
+ }
+ throw new AssertionError();
+ }
+}
Added: lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/mockfile/FilterFileStore.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/mockfile/FilterFileStore.java?rev=1641632&view=auto
==============================================================================
--- lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/mockfile/FilterFileStore.java (added)
+++ lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/mockfile/FilterFileStore.java Tue Nov 25 15:21:18 2014
@@ -0,0 +1,109 @@
+package org.apache.lucene.mockfile;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.nio.file.FileStore;
+import java.nio.file.attribute.FileAttributeView;
+import java.nio.file.attribute.FileStoreAttributeView;
+import java.util.Objects;
+
+/**
+ * A {@code FilterFileStore} contains another
+ * {@code FileStore}, which it uses as its basic
+ * source of data, possibly transforming the data along the
+ * way or providing additional functionality.
+ */
+public class FilterFileStore extends FileStore {
+
+ /**
+ * The underlying {@code FileStore} instance.
+ */
+ protected final FileStore delegate;
+
+ /**
+ * URI scheme used for this instance.
+ */
+ protected final String scheme;
+
+ /**
+ * Construct a {@code FilterFileStore} based on
+ * the specified base store.
+ * @param delegate specified base store.
+ * @param scheme URI scheme identifying this instance.
+ */
+ public FilterFileStore(FileStore delegate, String scheme) {
+ this.delegate = Objects.requireNonNull(delegate);
+ this.scheme = Objects.requireNonNull(scheme);
+ }
+
+ @Override
+ public String name() {
+ return delegate.name();
+ }
+
+ @Override
+ public String type() {
+ return scheme + "(" + delegate.type() + ")";
+ }
+
+ @Override
+ public String toString() {
+ return scheme + "(" + delegate.toString() + ")";
+ }
+
+ @Override
+ public boolean isReadOnly() {
+ return delegate.isReadOnly();
+ }
+
+ @Override
+ public long getTotalSpace() throws IOException {
+ return delegate.getTotalSpace();
+ }
+
+ @Override
+ public long getUsableSpace() throws IOException {
+ return delegate.getUsableSpace();
+ }
+
+ @Override
+ public long getUnallocatedSpace() throws IOException {
+ return delegate.getUnallocatedSpace();
+ }
+
+ @Override
+ public boolean supportsFileAttributeView(Class<? extends FileAttributeView> type) {
+ return delegate.supportsFileAttributeView(type);
+ }
+
+ @Override
+ public boolean supportsFileAttributeView(String name) {
+ return delegate.supportsFileAttributeView(name);
+ }
+
+ @Override
+ public <V extends FileStoreAttributeView> V getFileStoreAttributeView(Class<V> type) {
+ return delegate.getFileStoreAttributeView(type);
+ }
+
+ @Override
+ public Object getAttribute(String attribute) throws IOException {
+ return delegate.getAttribute(attribute);
+ }
+}
Added: lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/mockfile/FilterFileSystem.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/mockfile/FilterFileSystem.java?rev=1641632&view=auto
==============================================================================
--- lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/mockfile/FilterFileSystem.java (added)
+++ lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/mockfile/FilterFileSystem.java Tue Nov 25 15:21:18 2014
@@ -0,0 +1,165 @@
+package org.apache.lucene.mockfile;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.nio.file.FileStore;
+import java.nio.file.FileSystem;
+import java.nio.file.FileSystems;
+import java.nio.file.Path;
+import java.nio.file.PathMatcher;
+import java.nio.file.WatchService;
+import java.nio.file.attribute.UserPrincipalLookupService;
+import java.nio.file.spi.FileSystemProvider;
+import java.util.Iterator;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * A {@code FilterFileSystem} contains another
+ * {@code FileSystem}, which it uses as its basic
+ * source of data, possibly transforming the data along the
+ * way or providing additional functionality.
+ */
+public class FilterFileSystem extends FileSystem {
+
+ /**
+ * FileSystemProvider that created this FilterFileSystem
+ */
+ protected final FilterFileSystemProvider parent;
+
+ /**
+ * The underlying {@code FileSystem} instance.
+ */
+ protected final FileSystem delegate;
+
+ /**
+ * Construct a {@code FilterFileSystem} based on
+ * the specified base filesystem.
+ * <p>
+ * Note that base filesystem is closed if this filesystem is closed,
+ * however the default filesystem provider will never be closed, it doesn't
+ * support that.
+ * @param delegate specified base channel.
+ */
+ public FilterFileSystem(FilterFileSystemProvider parent, FileSystem delegate) {
+ this.parent = Objects.requireNonNull(parent);
+ this.delegate = Objects.requireNonNull(delegate);
+ }
+
+ @Override
+ public FileSystemProvider provider() {
+ return parent;
+ }
+
+ @Override
+ public void close() throws IOException {
+ if (delegate == FileSystems.getDefault()) {
+ // you can't close the default provider!
+ parent.onClose();
+ } else {
+ try (FileSystem d = delegate) {
+ parent.onClose();
+ }
+ }
+ }
+
+ @Override
+ public boolean isOpen() {
+ return delegate.isOpen();
+ }
+
+ @Override
+ public boolean isReadOnly() {
+ return delegate.isReadOnly();
+ }
+
+ @Override
+ public String getSeparator() {
+ return delegate.getSeparator();
+ }
+
+ @Override
+ public Iterable<Path> getRootDirectories() {
+ final Iterable<Path> roots = delegate.getRootDirectories();
+ return () -> {
+ final Iterator<Path> iterator = roots.iterator();
+ return new Iterator<Path>() {
+ @Override
+ public boolean hasNext() {
+ return iterator.hasNext();
+ }
+
+ @Override
+ public Path next() {
+ return new FilterPath(iterator.next(), FilterFileSystem.this);
+ }
+ };
+ };
+ }
+
+ @Override
+ public Iterable<FileStore> getFileStores() {
+ final Iterable<FileStore> fileStores = delegate.getFileStores();
+ return () -> {
+ final Iterator<FileStore> iterator = fileStores.iterator();
+ return new Iterator<FileStore>() {
+ @Override
+ public boolean hasNext() {
+ return iterator.hasNext();
+ }
+
+ @Override
+ public FileStore next() {
+ return new FilterFileStore(iterator.next(), parent.getScheme());
+ }
+ };
+ };
+ }
+
+ @Override
+ public Set<String> supportedFileAttributeViews() {
+ return delegate.supportedFileAttributeViews();
+ }
+
+ @Override
+ public Path getPath(String first, String... more) {
+ return new FilterPath(delegate.getPath(first, more), this);
+ }
+
+ @Override
+ public PathMatcher getPathMatcher(String syntaxAndPattern) {
+ final PathMatcher matcher = delegate.getPathMatcher(syntaxAndPattern);
+ return path -> {
+ if (path instanceof FilterPath) {
+ return matcher.matches(((FilterPath)path).delegate);
+ }
+ return false;
+ };
+ }
+
+ @Override
+ public UserPrincipalLookupService getUserPrincipalLookupService() {
+ return delegate.getUserPrincipalLookupService();
+ }
+
+ @Override
+ public WatchService newWatchService() throws IOException {
+ return delegate.newWatchService();
+ }
+}
Added: lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/mockfile/FilterFileSystemProvider.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/mockfile/FilterFileSystemProvider.java?rev=1641632&view=auto
==============================================================================
--- lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/mockfile/FilterFileSystemProvider.java (added)
+++ lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/mockfile/FilterFileSystemProvider.java Tue Nov 25 15:21:18 2014
@@ -0,0 +1,245 @@
+package org.apache.lucene.mockfile;
+
+/*
+ * 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.
+ */
+
+import java.io.IOError;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.nio.channels.AsynchronousFileChannel;
+import java.nio.channels.FileChannel;
+import java.nio.channels.SeekableByteChannel;
+import java.nio.file.AccessMode;
+import java.nio.file.CopyOption;
+import java.nio.file.DirectoryStream;
+import java.nio.file.DirectoryStream.Filter;
+import java.nio.file.FileStore;
+import java.nio.file.FileSystem;
+import java.nio.file.LinkOption;
+import java.nio.file.OpenOption;
+import java.nio.file.Path;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.nio.file.attribute.FileAttribute;
+import java.nio.file.attribute.FileAttributeView;
+import java.nio.file.spi.FileSystemProvider;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.concurrent.ExecutorService;
+
+/**
+ * A {@code FilterFileSystemProvider} contains another
+ * {@code FileSystemProvider}, which it uses as its basic
+ * source of data, possibly transforming the data along the
+ * way or providing additional functionality.
+ */
+public class FilterFileSystemProvider extends FileSystemProvider {
+
+ /**
+ * The underlying {@code FileSystemProvider}.
+ */
+ protected final FileSystemProvider delegate;
+ /**
+ * The underlying {@code FileSystem} instance.
+ */
+ protected final FileSystem fileSystem;
+ /**
+ * The URI scheme for this provider.
+ */
+ protected final String scheme;
+
+ /**
+ * Construct a {@code FilterFileSystemProvider} indicated by
+ * the specified {@code scheme} and wrapping functionality of the
+ * provider of the specified base filesystem.
+ * @param scheme URI scheme
+ * @param delegateInstance specified base filesystem.
+ */
+ public FilterFileSystemProvider(String scheme, FileSystem delegateInstance) {
+ this.scheme = Objects.requireNonNull(scheme);
+ Objects.requireNonNull(delegateInstance);
+ this.delegate = delegateInstance.provider();
+ this.fileSystem = new FilterFileSystem(this, delegateInstance);
+ }
+
+ @Override
+ public String getScheme() {
+ return scheme;
+ }
+
+ @Override
+ public FileSystem newFileSystem(URI uri, Map<String,?> env) throws IOException {
+ return fileSystem;
+ }
+
+ @Override
+ public FileSystem newFileSystem(Path path, Map<String,?> env) throws IOException {
+ return fileSystem;
+ }
+
+ @Override
+ public FileSystem getFileSystem(URI uri) {
+ return fileSystem;
+ }
+
+ @Override
+ public Path getPath(URI uri) {
+ Path path = delegate.getPath(toDelegate(uri));
+ return new FilterPath(path, fileSystem);
+ }
+
+ @Override
+ public void createDirectory(Path dir, FileAttribute<?>... attrs) throws IOException {
+ delegate.createDirectory(toDelegate(dir), attrs);
+ }
+
+ @Override
+ public void delete(Path path) throws IOException {
+ delegate.delete(toDelegate(path));
+ }
+
+ @Override
+ public void copy(Path source, Path target, CopyOption... options) throws IOException {
+ delegate.copy(toDelegate(source), toDelegate(target), options);
+ }
+
+ @Override
+ public void move(Path source, Path target, CopyOption... options) throws IOException {
+ delegate.move(toDelegate(source), toDelegate(target), options);
+ }
+
+ @Override
+ public boolean isSameFile(Path path, Path path2) throws IOException {
+ return delegate.isSameFile(toDelegate(path), toDelegate(path2));
+ }
+
+ @Override
+ public boolean isHidden(Path path) throws IOException {
+ return delegate.isHidden(toDelegate(path));
+ }
+
+ @Override
+ public FileStore getFileStore(Path path) throws IOException {
+ return delegate.getFileStore(toDelegate(path));
+ }
+
+ @Override
+ public void checkAccess(Path path, AccessMode... modes) throws IOException {
+ delegate.checkAccess(toDelegate(path), modes);
+ }
+
+ @Override
+ public <V extends FileAttributeView> V getFileAttributeView(Path path, Class<V> type, LinkOption... options) {
+ return delegate.getFileAttributeView(toDelegate(path), type, options);
+ }
+
+ @Override
+ public <A extends BasicFileAttributes> A readAttributes(Path path, Class<A> type, LinkOption... options) throws IOException {
+ return delegate.readAttributes(toDelegate(path), type, options);
+ }
+
+ @Override
+ public Map<String,Object> readAttributes(Path path, String attributes, LinkOption... options) throws IOException {
+ return delegate.readAttributes(toDelegate(path), attributes, options);
+ }
+
+ @Override
+ public void setAttribute(Path path, String attribute, Object value, LinkOption... options) throws IOException {
+ delegate.setAttribute(toDelegate(path), attribute, value, options);
+ }
+
+ @Override
+ public InputStream newInputStream(Path path, OpenOption... options) throws IOException {
+ return delegate.newInputStream(toDelegate(path), options);
+ }
+
+ @Override
+ public OutputStream newOutputStream(Path path, OpenOption... options) throws IOException {
+ return delegate.newOutputStream(toDelegate(path), options);
+ }
+
+ @Override
+ public FileChannel newFileChannel(Path path, Set<? extends OpenOption> options, FileAttribute<?>... attrs) throws IOException {
+ return delegate.newFileChannel(toDelegate(path), options, attrs);
+ }
+
+ @Override
+ public AsynchronousFileChannel newAsynchronousFileChannel(Path path, Set<? extends OpenOption> options, ExecutorService executor, FileAttribute<?>... attrs) throws IOException {
+ return delegate.newAsynchronousFileChannel(toDelegate(path), options, executor, attrs);
+ }
+
+ @Override
+ public SeekableByteChannel newByteChannel(Path path, Set<? extends OpenOption> options, FileAttribute<?>... attrs) throws IOException {
+ return delegate.newByteChannel(toDelegate(path), options, attrs);
+ }
+
+ @Override
+ public DirectoryStream<Path> newDirectoryStream(Path dir, Filter<? super Path> filter) throws IOException {
+ return delegate.newDirectoryStream(toDelegate(dir), filter);
+ }
+
+ @Override
+ public void createSymbolicLink(Path link, Path target, FileAttribute<?>... attrs) throws IOException {
+ delegate.createSymbolicLink(toDelegate(link), toDelegate(target), attrs);
+ }
+
+ @Override
+ public void createLink(Path link, Path existing) throws IOException {
+ delegate.createLink(toDelegate(link), toDelegate(existing));
+ }
+
+ @Override
+ public boolean deleteIfExists(Path path) throws IOException {
+ return delegate.deleteIfExists(toDelegate(path));
+ }
+
+ @Override
+ public Path readSymbolicLink(Path link) throws IOException {
+ return delegate.readSymbolicLink(toDelegate(link));
+ }
+
+ private Path toDelegate(Path path) {
+ if (path instanceof FilterPath) {
+ return ((FilterPath) path).delegate;
+ }
+ return path;
+ }
+
+ private URI toDelegate(URI uri) {
+ try {
+ return new URI(delegate.getScheme(), uri.getSchemeSpecificPart(), uri.getFragment());
+ } catch (URISyntaxException e) {
+ throw new IOError(e);
+ }
+ }
+
+ /**
+ * Override to trigger some behavior when the filesystem is closed.
+ * <p>
+ * This is always called for each FilterFileSystemProvider in the chain.
+ */
+ protected void onClose() {
+ }
+
+ @Override
+ public String toString() {
+ return getClass().getSimpleName() + "(" + delegate + ")";
+ }
+}
Added: lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/mockfile/FilterInputStream2.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/mockfile/FilterInputStream2.java?rev=1641632&view=auto
==============================================================================
--- lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/mockfile/FilterInputStream2.java (added)
+++ lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/mockfile/FilterInputStream2.java Tue Nov 25 15:21:18 2014
@@ -0,0 +1,100 @@
+package org.apache.lucene.mockfile;
+
+/*
+ * 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.
+ */
+
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Objects;
+
+/**
+ * A {@code FilterInputStream2} contains another
+ * {@code InputStream}, which it uses as its basic
+ * source of data, possibly transforming the data along the
+ * way or providing additional functionality.
+ * <p>
+ * Note: unlike {@link FilterInputStream} this class
+ * delegates every method by default. This means to transform
+ * {@code read} calls, you need to override multiple methods.
+ * On the other hand, it is less trappy: a simple implementation
+ * that just overrides {@code close} will not force bytes to be
+ * read one-at-a-time.
+ */
+public class FilterInputStream2 extends InputStream {
+
+ /**
+ * The underlying {@code InputStream} instance.
+ */
+ protected final InputStream delegate;
+
+ /**
+ * Construct a {@code FilterInputStream2} based on
+ * the specified base stream.
+ * <p>
+ * Note that base stream is closed if this stream is closed.
+ * @param delegate specified base stream.
+ */
+ public FilterInputStream2(InputStream delegate) {
+ this.delegate = Objects.requireNonNull(delegate);
+ }
+
+ @Override
+ public int read() throws IOException {
+ return delegate.read();
+ }
+
+ @Override
+ public int read(byte[] b) throws IOException {
+ return delegate.read(b);
+ }
+
+ @Override
+ public int read(byte[] b, int off, int len) throws IOException {
+ return delegate.read(b, off, len);
+ }
+
+ @Override
+ public long skip(long n) throws IOException {
+ return delegate.skip(n);
+ }
+
+ @Override
+ public int available() throws IOException {
+ return delegate.available();
+ }
+
+ @Override
+ public void close() throws IOException {
+ delegate.close();
+ }
+
+ @Override
+ public synchronized void mark(int readlimit) {
+ delegate.mark(readlimit);
+ }
+
+ @Override
+ public synchronized void reset() throws IOException {
+ delegate.reset();
+ }
+
+ @Override
+ public boolean markSupported() {
+ return delegate.markSupported();
+ }
+}
Added: lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/mockfile/FilterOutputStream2.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/mockfile/FilterOutputStream2.java?rev=1641632&view=auto
==============================================================================
--- lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/mockfile/FilterOutputStream2.java (added)
+++ lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/mockfile/FilterOutputStream2.java Tue Nov 25 15:21:18 2014
@@ -0,0 +1,80 @@
+package org.apache.lucene.mockfile;
+
+/*
+ * 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.
+ */
+
+import java.io.FilterOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Objects;
+
+/**
+ * A {@code FilterOutputStream2} contains another
+ * {@code OutputStream}, which it uses as its basic
+ * source of data, possibly transforming the data along the
+ * way or providing additional functionality.
+ * <p>
+ * Note: unlike {@link FilterOutputStream} this class
+ * delegates every method by default. This means to transform
+ * {@code write} calls, you need to override multiple methods.
+ * On the other hand, it is less trappy: a simple implementation
+ * that just overrides {@code close} will not force bytes to be
+ * written one-at-a-time.
+ */
+public class FilterOutputStream2 extends OutputStream {
+
+ /**
+ * The underlying {@code OutputStream} instance.
+ */
+ protected final OutputStream delegate;
+
+ /**
+ * Construct a {@code FilterOutputStream2} based on
+ * the specified base stream.
+ * <p>
+ * Note that base stream is closed if this stream is closed.
+ * @param delegate specified base stream.
+ */
+ public FilterOutputStream2(OutputStream delegate) {
+ this.delegate = Objects.requireNonNull(delegate);
+ }
+
+ @Override
+ public void write(byte[] b) throws IOException {
+ delegate.write(b);
+ }
+
+ @Override
+ public void write(byte[] b, int off, int len) throws IOException {
+ delegate.write(b, off, len);
+ }
+
+ @Override
+ public void flush() throws IOException {
+ delegate.flush();
+ }
+
+ @Override
+ public void close() throws IOException {
+ delegate.close();
+ }
+
+ @Override
+ public void write(int b) throws IOException {
+ delegate.write(b);
+ }
+}
Added: lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/mockfile/FilterPath.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/mockfile/FilterPath.java?rev=1641632&view=auto
==============================================================================
--- lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/mockfile/FilterPath.java (added)
+++ lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/mockfile/FilterPath.java Tue Nov 25 15:21:18 2014
@@ -0,0 +1,265 @@
+package org.apache.lucene.mockfile;
+
+/*
+ * 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.
+ */
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URI;
+import java.nio.file.FileSystem;
+import java.nio.file.LinkOption;
+import java.nio.file.Path;
+import java.nio.file.WatchEvent.Kind;
+import java.nio.file.WatchEvent.Modifier;
+import java.nio.file.WatchKey;
+import java.nio.file.WatchService;
+import java.util.Iterator;
+
+/**
+ * A {@code FilterPath} contains another
+ * {@code Path}, which it uses as its basic
+ * source of data, possibly transforming the data along the
+ * way or providing additional functionality.
+ */
+public class FilterPath implements Path {
+
+ /**
+ * The underlying {@code Path} instance.
+ */
+ protected final Path delegate;
+
+ /**
+ * The parent {@code FileSystem} for this path.
+ */
+ protected final FileSystem fileSystem;
+
+ /**
+ * Construct a {@code FilterPath} with parent
+ * {@code fileSystem}, based on the specified base path.
+ * @param delegate specified base path.
+ * @param fileSystem parent fileSystem.
+ */
+ public FilterPath(Path delegate, FileSystem fileSystem) {
+ this.delegate = delegate;
+ this.fileSystem = fileSystem;
+ }
+
+ /**
+ * Get the underlying wrapped path.
+ * @return wrapped path.
+ */
+ public Path getDelegate() {
+ return delegate;
+ }
+
+ @Override
+ public FileSystem getFileSystem() {
+ return fileSystem;
+ }
+
+ @Override
+ public boolean isAbsolute() {
+ return delegate.isAbsolute();
+ }
+
+ @Override
+ public Path getRoot() {
+ Path root = delegate.getRoot();
+ if (root == null) {
+ return null;
+ }
+ return new FilterPath(root, fileSystem);
+ }
+
+ @Override
+ public Path getFileName() {
+ Path fileName = delegate.getFileName();
+ if (fileName == null) {
+ return null;
+ }
+ return new FilterPath(fileName, fileSystem);
+ }
+
+ @Override
+ public Path getParent() {
+ Path parent = delegate.getParent();
+ if (parent == null) {
+ return null;
+ }
+ return new FilterPath(parent, fileSystem);
+ }
+
+ @Override
+ public int getNameCount() {
+ return delegate.getNameCount();
+ }
+
+ @Override
+ public Path getName(int index) {
+ return new FilterPath(delegate.getName(index), fileSystem);
+ }
+
+ @Override
+ public Path subpath(int beginIndex, int endIndex) {
+ return new FilterPath(delegate.subpath(beginIndex, endIndex), fileSystem);
+ }
+
+ @Override
+ public boolean startsWith(Path other) {
+ if (other instanceof FilterPath) {
+ FilterPath f = (FilterPath) other;
+ return fileSystem == f.fileSystem && delegate.startsWith(f.delegate);
+ }
+ return false;
+ }
+
+ @Override
+ public boolean startsWith(String other) {
+ return delegate.startsWith(other);
+ }
+
+ @Override
+ public boolean endsWith(Path other) {
+ if (other instanceof FilterPath) {
+ FilterPath f = (FilterPath) other;
+ return fileSystem == f.fileSystem && delegate.endsWith(f.delegate);
+ }
+ return false;
+ }
+
+ @Override
+ public boolean endsWith(String other) {
+ return delegate.startsWith(other);
+ }
+
+ @Override
+ public Path normalize() {
+ return new FilterPath(delegate.normalize(), fileSystem);
+ }
+
+ @Override
+ public Path resolve(Path other) {
+ if (other instanceof FilterPath) {
+ other = ((FilterPath)other).delegate;
+ }
+ return new FilterPath(delegate.resolve(other), fileSystem);
+ }
+
+ @Override
+ public Path resolve(String other) {
+ return new FilterPath(delegate.resolve(other), fileSystem);
+ }
+
+ @Override
+ public Path resolveSibling(Path other) {
+ if (other instanceof FilterPath) {
+ other = ((FilterPath)other).delegate;
+ }
+ return new FilterPath(delegate.resolveSibling(other), fileSystem);
+ }
+
+ @Override
+ public Path resolveSibling(String other) {
+ return new FilterPath(delegate.resolveSibling(other), fileSystem);
+ }
+
+ @Override
+ public Path relativize(Path other) {
+ if (other instanceof FilterPath) {
+ other = ((FilterPath)other).delegate;
+ }
+ return new FilterPath(delegate.relativize(other), fileSystem);
+ }
+
+ // TODO: should these methods not expose delegate result directly?
+ // it could allow code to "escape" the sandbox...
+
+ @Override
+ public URI toUri() {
+ return delegate.toUri();
+ }
+
+ @Override
+ public String toString() {
+ return delegate.toString();
+ }
+
+ @Override
+ public Path toAbsolutePath() {
+ return new FilterPath(delegate.toAbsolutePath(), fileSystem);
+ }
+
+ @Override
+ public Path toRealPath(LinkOption... options) throws IOException {
+ return new FilterPath(delegate.toRealPath(options), fileSystem);
+ }
+
+ @Override
+ public File toFile() {
+ // TODO: should we throw exception here?
+ return delegate.toFile();
+ }
+
+ @Override
+ public WatchKey register(WatchService watcher, Kind<?>[] events, Modifier... modifiers) throws IOException {
+ return delegate.register(watcher, events, modifiers);
+ }
+
+ @Override
+ public WatchKey register(WatchService watcher, Kind<?>... events) throws IOException {
+ return delegate.register(watcher, events);
+ }
+
+ @Override
+ public Iterator<Path> iterator() {
+ final Iterator<Path> iterator = delegate.iterator();
+ return new Iterator<Path>() {
+ @Override
+ public boolean hasNext() {
+ return iterator.hasNext();
+ }
+
+ @Override
+ public Path next() {
+ return new FilterPath(iterator.next(), fileSystem);
+ }
+ };
+ }
+
+ @Override
+ public int compareTo(Path other) {
+ if (other instanceof FilterPath) {
+ other = ((FilterPath)other).delegate;
+ }
+ return delegate.compareTo(other);
+ }
+
+ /**
+ * Unwraps all {@code FilterPath}s, returning
+ * the innermost {@code Path}.
+ * <p>
+ * WARNING: this is exposed for testing only!
+ * @param path specified path.
+ * @return innermost Path instance
+ */
+ public static Path unwrap(Path path) {
+ while (path instanceof FilterPath) {
+ path = ((FilterPath)path).delegate;
+ }
+ return path;
+ }
+}
Added: lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/mockfile/FilterSecureDirectoryStream.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/mockfile/FilterSecureDirectoryStream.java?rev=1641632&view=auto
==============================================================================
--- lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/mockfile/FilterSecureDirectoryStream.java (added)
+++ lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/mockfile/FilterSecureDirectoryStream.java Tue Nov 25 15:21:18 2014
@@ -0,0 +1,98 @@
+package org.apache.lucene.mockfile;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.nio.channels.SeekableByteChannel;
+import java.nio.file.LinkOption;
+import java.nio.file.OpenOption;
+import java.nio.file.SecureDirectoryStream;
+import java.nio.file.attribute.FileAttribute;
+import java.nio.file.attribute.FileAttributeView;
+import java.util.Iterator;
+import java.util.Set;
+
+/**
+ * A {@code FilterSecureDirectoryStream} contains another
+ * {@code SecureDirectoryStream}, which it uses as its basic
+ * source of data, possibly transforming the data along the
+ * way or providing additional functionality.
+ */
+public class FilterSecureDirectoryStream<T> implements SecureDirectoryStream<T> {
+
+ /**
+ * The underlying {@code SecureDirectoryStream} instance.
+ */
+ protected final SecureDirectoryStream<T> delegate;
+
+ /**
+ * Construct a {@code FilterSecureDirectoryStream} based on
+ * the specified base stream.
+ * <p>
+ * Note that base stream is closed if this stream is closed.
+ * @param delegate specified base stream.
+ */
+ public FilterSecureDirectoryStream(SecureDirectoryStream<T> delegate) {
+ this.delegate = delegate;
+ }
+
+ @Override
+ public Iterator<T> iterator() {
+ return delegate.iterator();
+ }
+
+ @Override
+ public void close() throws IOException {
+ delegate.close();
+ }
+
+ @Override
+ public SecureDirectoryStream<T> newDirectoryStream(T path, LinkOption... options) throws IOException {
+ return delegate.newDirectoryStream(path, options);
+ }
+
+ @Override
+ public SeekableByteChannel newByteChannel(T path, Set<? extends OpenOption> options, FileAttribute<?>... attrs) throws IOException {
+ return delegate.newByteChannel(path, options, attrs);
+ }
+
+ @Override
+ public void deleteFile(T path) throws IOException {
+ delegate.deleteFile(path);
+ }
+
+ @Override
+ public void deleteDirectory(T path) throws IOException {
+ delegate.deleteDirectory(path);
+ }
+
+ @Override
+ public void move(T srcpath, SecureDirectoryStream<T> targetdir, T targetpath) throws IOException {
+ delegate.move(srcpath, targetdir, targetpath);
+ }
+
+ @Override
+ public <V extends FileAttributeView> V getFileAttributeView(Class<V> type) {
+ return delegate.getFileAttributeView(type);
+ }
+
+ @Override
+ public <V extends FileAttributeView> V getFileAttributeView(T path, Class<V> type, LinkOption... options) {
+ return delegate.getFileAttributeView(path, type, options);
+ }
+}
Added: lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/mockfile/FilterSeekableByteChannel.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/mockfile/FilterSeekableByteChannel.java?rev=1641632&view=auto
==============================================================================
--- lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/mockfile/FilterSeekableByteChannel.java (added)
+++ lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/mockfile/FilterSeekableByteChannel.java Tue Nov 25 15:21:18 2014
@@ -0,0 +1,89 @@
+package org.apache.lucene.mockfile;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.SeekableByteChannel;
+
+/**
+ * A {@code FilterSeekableByteChannel} contains another
+ * {@code SeekableByteChannel}, which it uses as its basic
+ * source of data, possibly transforming the data along the
+ * way or providing additional functionality.
+ */
+public class FilterSeekableByteChannel implements SeekableByteChannel {
+
+ /**
+ * The underlying {@code SeekableByteChannel} instance.
+ */
+ protected final SeekableByteChannel delegate;
+
+ /**
+ * Construct a {@code FilterSeekableByteChannel} based on
+ * the specified base channel.
+ * <p>
+ * Note that base channel is closed if this channel is closed.
+ * @param delegate specified base channel.
+ */
+ public FilterSeekableByteChannel(SeekableByteChannel delegate) {
+ this.delegate = delegate;
+ }
+
+ @Override
+ public boolean isOpen() {
+ return delegate.isOpen();
+ }
+
+ @Override
+ public void close() throws IOException {
+ delegate.close();
+ }
+
+ @Override
+ public int read(ByteBuffer dst) throws IOException {
+ return delegate.read(dst);
+ }
+
+ @Override
+ public int write(ByteBuffer src) throws IOException {
+ return delegate.write(src);
+ }
+
+ @Override
+ public long position() throws IOException {
+ return delegate.position();
+ }
+
+ @Override
+ public SeekableByteChannel position(long newPosition) throws IOException {
+ delegate.position(newPosition);
+ return this;
+ }
+
+ @Override
+ public long size() throws IOException {
+ return delegate.size();
+ }
+
+ @Override
+ public SeekableByteChannel truncate(long size) throws IOException {
+ delegate.truncate(size);
+ return this;
+ }
+}
Added: lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/mockfile/HandleTrackingFS.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/mockfile/HandleTrackingFS.java?rev=1641632&view=auto
==============================================================================
--- lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/mockfile/HandleTrackingFS.java (added)
+++ lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/mockfile/HandleTrackingFS.java Tue Nov 25 15:21:18 2014
@@ -0,0 +1,314 @@
+package org.apache.lucene.mockfile;
+
+/*
+ * 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.
+ */
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.channels.AsynchronousFileChannel;
+import java.nio.channels.FileChannel;
+import java.nio.channels.SeekableByteChannel;
+import java.nio.file.DirectoryStream;
+import java.nio.file.FileSystem;
+import java.nio.file.LinkOption;
+import java.nio.file.OpenOption;
+import java.nio.file.Path;
+import java.nio.file.SecureDirectoryStream;
+import java.nio.file.DirectoryStream.Filter;
+import java.nio.file.attribute.FileAttribute;
+import java.util.Set;
+import java.util.concurrent.ExecutorService;
+
+/**
+ * Base class for tracking file handles.
+ * <p>
+ * This class adds tracking to all streams/channels and
+ * provides two hooks to handle file management:
+ * <ul>
+ * <li>{@link #onOpen(Path, Object)}
+ * <li>{@link #onClose(Path, Object)}
+ * </ul>
+ */
+public abstract class HandleTrackingFS extends FilterFileSystemProvider {
+
+ /**
+ * Create a new instance, identified by {@code scheme} and passing
+ * through operations to {@code delegate}.
+ * @param scheme URI scheme for this provider
+ * @param delegate delegate filesystem to wrap.
+ */
+ public HandleTrackingFS(String scheme, FileSystem delegate) {
+ super(scheme, delegate);
+ }
+
+ /**
+ * Called when {@code path} is opened via {@code stream}.
+ * @param path Path that was opened
+ * @param stream Stream or Channel opened against the path.
+ * @throws IOException if an I/O error occurs.
+ */
+ protected abstract void onOpen(Path path, Object stream) throws IOException;
+
+
+ /**
+ * Called when {@code path} is closed via {@code stream}.
+ * @param path Path that was closed
+ * @param stream Stream or Channel closed against the path.
+ * @throws IOException if an I/O error occurs.
+ */
+ protected abstract void onClose(Path path, Object stream) throws IOException;
+
+ @Override
+ public InputStream newInputStream(Path path, OpenOption... options) throws IOException {
+ InputStream stream = new FilterInputStream2(super.newInputStream(path, options)) {
+ @Override
+ public void close() throws IOException {
+ onClose(path, this);
+ super.close();
+ }
+
+ @Override
+ public String toString() {
+ return "InputStream(" + path.toString() + ")";
+ }
+
+ @Override
+ public int hashCode() {
+ return System.identityHashCode(this);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return this == obj;
+ }
+ };
+ onOpen(path, stream);
+ return stream;
+ }
+
+ @Override
+ public OutputStream newOutputStream(final Path path, OpenOption... options) throws IOException {
+ OutputStream stream = new FilterOutputStream2(super.newOutputStream(path, options)) {
+ @Override
+ public void close() throws IOException {
+ onClose(path, this);
+ super.close();
+ }
+
+ @Override
+ public String toString() {
+ return "OutputStream(" + path.toString() + ")";
+ }
+
+ @Override
+ public int hashCode() {
+ return System.identityHashCode(this);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return this == obj;
+ }
+ };
+ onOpen(path, stream);
+ return stream;
+ }
+
+ @Override
+ public FileChannel newFileChannel(Path path, Set<? extends OpenOption> options, FileAttribute<?>... attrs) throws IOException {
+ FileChannel channel = new FilterFileChannel(super.newFileChannel(path, options, attrs)) {
+ @Override
+ protected void implCloseChannel() throws IOException {
+ onClose(path, this);
+ super.implCloseChannel();
+ }
+
+ @Override
+ public String toString() {
+ return "FileChannel(" + path.toString() + ")";
+ }
+
+ @Override
+ public int hashCode() {
+ return System.identityHashCode(this);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return this == obj;
+ }
+ };
+ onOpen(path, channel);
+ return channel;
+ }
+
+ @Override
+ public AsynchronousFileChannel newAsynchronousFileChannel(Path path, Set<? extends OpenOption> options, ExecutorService executor, FileAttribute<?>... attrs) throws IOException {
+ AsynchronousFileChannel channel = new FilterAsynchronousFileChannel(super.newAsynchronousFileChannel(path, options, executor, attrs)) {
+ @Override
+ public void close() throws IOException {
+ onClose(path, this);
+ super.close();
+ }
+
+ @Override
+ public String toString() {
+ return "AsynchronousFileChannel(" + path.toString() + ")";
+ }
+
+ @Override
+ public int hashCode() {
+ return System.identityHashCode(this);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return this == obj;
+ }
+ };
+ onOpen(path, channel);
+ return channel;
+ }
+
+ @Override
+ public SeekableByteChannel newByteChannel(Path path, Set<? extends OpenOption> options, FileAttribute<?>... attrs) throws IOException {
+ SeekableByteChannel channel = new FilterSeekableByteChannel(super.newByteChannel(path, options, attrs)) {
+ @Override
+ public void close() throws IOException {
+ onClose(path, this);
+ super.close();
+ }
+
+ @Override
+ public String toString() {
+ return "SeekableByteChannel(" + path.toString() + ")";
+ }
+
+ @Override
+ public int hashCode() {
+ return System.identityHashCode(this);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return this == obj;
+ }
+ };
+ onOpen(path, channel);
+ return channel;
+ }
+
+ @Override
+ public DirectoryStream<Path> newDirectoryStream(Path dir, Filter<? super Path> filter) throws IOException {
+ DirectoryStream<Path> stream = super.newDirectoryStream(dir, filter);
+ if (stream instanceof SecureDirectoryStream) {
+ stream = new TrackingSecureDirectoryStream((SecureDirectoryStream<Path>)stream, dir);
+ } else {
+ stream = new FilterDirectoryStream<Path>(stream) {
+ @Override
+ public void close() throws IOException {
+ onClose(dir, this);
+ super.close();
+ }
+
+ @Override
+ public String toString() {
+ return "DirectoryStream(" + dir + ")";
+ }
+
+ @Override
+ public int hashCode() {
+ return System.identityHashCode(this);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return this == obj;
+ }
+ };
+ }
+ onOpen(dir, stream);
+ return stream;
+ }
+
+ /** You can also open various things from SecureDirectoryStream, so we ensure we track those */
+ class TrackingSecureDirectoryStream extends FilterSecureDirectoryStream<Path> {
+ final Path dir;
+
+ TrackingSecureDirectoryStream(SecureDirectoryStream<Path> delegate, Path dir) {
+ super(delegate);
+ this.dir = dir;
+ }
+
+ @Override
+ public void close() throws IOException {
+ onClose(dir, this);
+ super.close();
+ }
+
+ @Override
+ public String toString() {
+ return "SecureDirectoryStream(" + dir + ")";
+ }
+
+ @Override
+ public int hashCode() {
+ return System.identityHashCode(this);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return this == obj;
+ }
+
+ @Override
+ public SecureDirectoryStream<Path> newDirectoryStream(Path path, LinkOption... options) throws IOException {
+ SecureDirectoryStream<Path> stream = new TrackingSecureDirectoryStream(super.newDirectoryStream(path, options), path);
+ onOpen(path, stream);
+ return stream;
+ }
+
+ @Override
+ public SeekableByteChannel newByteChannel(Path path, Set<? extends OpenOption> options, FileAttribute<?>... attrs) throws IOException {
+ SeekableByteChannel channel = new FilterSeekableByteChannel(super.newByteChannel(path, options, attrs)) {
+ @Override
+ public void close() throws IOException {
+ onClose(path, this);
+ super.close();
+ }
+
+ @Override
+ public String toString() {
+ return "SeekableByteChannel(" + path.toString() + ")";
+ }
+
+ @Override
+ public int hashCode() {
+ return System.identityHashCode(this);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return this == obj;
+ }
+ };
+ onOpen(path, channel);
+ return channel;
+ }
+ }
+}
Added: lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/mockfile/LeakFS.java
URL: http://svn.apache.org/viewvc/lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/mockfile/LeakFS.java?rev=1641632&view=auto
==============================================================================
--- lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/mockfile/LeakFS.java (added)
+++ lucene/dev/trunk/lucene/test-framework/src/java/org/apache/lucene/mockfile/LeakFS.java Tue Nov 25 15:21:18 2014
@@ -0,0 +1,67 @@
+package org.apache.lucene.mockfile;
+
+/*
+ * 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.
+ */
+
+import java.nio.file.FileSystem;
+import java.nio.file.Path;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * FileSystem that tracks open handles.
+ * <p>
+ * When {@link FileSystem#close()} is called, this class will throw
+ * an exception if any file handles are still open.
+ */
+public class LeakFS extends HandleTrackingFS {
+ // we explicitly use reference hashcode/equality in our keys
+ private final Map<Object,Exception> openHandles = new ConcurrentHashMap<>();
+
+ /**
+ * Create a new instance, tracking file handle leaks for the
+ * specified delegate filesystem.
+ * @param delegate delegate filesystem to wrap.
+ */
+ public LeakFS(FileSystem delegate) {
+ super("leakfs://", delegate);
+ }
+
+ @Override
+ protected void onOpen(Path path, Object stream) {
+ openHandles.put(stream, new Exception());
+ }
+
+ @Override
+ protected void onClose(Path path, Object stream) {
+ openHandles.remove(stream);
+ }
+
+ @Override
+ public synchronized void onClose() {
+ if (!openHandles.isEmpty()) {
+ // print the first one as its very verbose otherwise
+ Exception cause = null;
+ Iterator<Exception> stacktraces = openHandles.values().iterator();
+ if (stacktraces.hasNext()) {
+ cause = stacktraces.next();
+ }
+ throw new RuntimeException("file handle leaks: " + openHandles.keySet(), cause);
+ }
+ }
+}