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 2009/05/27 12:18:13 UTC

svn commit: r779081 - in /jackrabbit/trunk/jackrabbit-core/src: main/java/org/apache/jackrabbit/core/data/ test/java/org/apache/jackrabbit/core/data/

Author: thomasm
Date: Wed May 27 10:18:12 2009
New Revision: 779081

URL: http://svn.apache.org/viewvc?rev=779081&view=rev
Log:
JCR-2067 FileDataStore: only open a stream when really necessary - close() can throw a NullPointerException

Added:
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/data/LazyFileInputStreamTest.java
Modified:
    jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/LazyFileInputStream.java
    jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/data/TestAll.java

Modified: jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/LazyFileInputStream.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/LazyFileInputStream.java?rev=779081&r1=779080&r2=779081&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/LazyFileInputStream.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/main/java/org/apache/jackrabbit/core/data/LazyFileInputStream.java Wed May 27 10:18:12 2009
@@ -17,13 +17,12 @@
 package org.apache.jackrabbit.core.data;
 
 import java.io.File;
+import java.io.FileDescriptor;
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.IOException;
 
 import org.apache.commons.io.input.AutoCloseInputStream;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 /**
  * This input stream delays opening the file until the first byte is read, and
@@ -32,7 +31,10 @@
  */
 public class LazyFileInputStream extends AutoCloseInputStream {
 
-    private static Logger log = LoggerFactory.getLogger(LazyFileInputStream.class);
+    /**
+     * The file descriptor to use.
+     */
+    protected final FileDescriptor fd;
 
     /**
      * The file to read from.
@@ -47,83 +49,119 @@
     protected boolean opened;
 
     /**
-     * Create a lazy input stream for the given file.
+     * Creates a new <code>LazyFileInputStream</code> for the given file. If the
+     * file is unreadable, a FileNotFoundException is thrown.
      * The file is not opened until the first byte is read from the stream.
-     * 
+     *
      * @param file the file
+     * @throws java.io.FileNotFoundException
      */
-    public LazyFileInputStream(File file) throws FileNotFoundException {
+    public LazyFileInputStream(File file)
+            throws FileNotFoundException {
         super(null);
         if (!file.canRead()) {
             throw new FileNotFoundException(file.getPath());
-        }        
+        }
         this.file = file;
+        this.fd = null;
+    }
+
+    /**
+     * Creates a new <code>LazyFileInputStream</code> for the given file
+     * descriptor.
+     * The file is not opened until the first byte is read from the stream.
+     *
+     * @param fdObj
+     */
+    public LazyFileInputStream(FileDescriptor fd) {
+        super(null);
+        this.file = null;
+        this.fd = fd;
+    }
+
+    /**
+     * Creates a new <code>LazyFileInputStream</code> for the given file. If the
+     * file is unreadable, a FileNotFoundException is thrown.
+     *
+     * @param name
+     * @throws java.io.FileNotFoundException
+     */
+    public LazyFileInputStream(String name) throws FileNotFoundException {
+        this(new File(name));
     }
 
     /**
      * Open the stream if required.
-     * 
-     * @throws IOException
+     *
+     * @throws java.io.IOException
      */
-    protected void openStream() throws IOException {
+    protected void open() throws IOException {
         if (!opened) {
             opened = true;
-            in = new FileInputStream(file);
+            if (fd != null) {
+                in = new FileInputStream(fd);
+            } else {
+                in = new FileInputStream(file);
+            }
         }
     }
-    
+
     public int read() throws IOException {
-        openStream();
+        open();
         return super.read();
     }
 
-    public int read(byte[] b) throws IOException {
-        return read(b, 0, b.length);
-    }
-
-    public int read(byte[] b, int off, int len) throws IOException {
-        openStream();
-        return super.read(b, off, len);
+    public int available() throws IOException {
+        open();
+        return super.available();
     }
 
     public void close() throws IOException {
         // make sure the file is not opened afterwards
         opened = true;
-        super.close();
+        
+        // only close the file if it was in fact opened
+        if (in != null) {
+            super.close();
+        }
     }
 
-    public long skip(long n) throws IOException {
-        openStream();
-        return super.skip(n);
+    public synchronized void reset() throws IOException {
+        open();
+        super.reset();
     }
 
-    public int available() throws IOException {
-        openStream();
-        return super.available();
+    public boolean markSupported() {
+        try {
+            open();
+        } catch (IOException e) {
+            throw new IllegalStateException(e.toString());
+        }
+        return super.markSupported();
     }
 
-    public void mark(int readlimit) {
+    public synchronized void mark(int readlimit) {
         try {
-            openStream();
+            open();
         } catch (IOException e) {
-            log.info("Error getting underlying stream: ", e);
+            throw new IllegalStateException(e.toString());
         }
         super.mark(readlimit);
     }
 
-    public void reset() throws IOException {
-        openStream();
-        super.reset();
+    public long skip(long n) throws IOException {
+        open();
+        return super.skip(n);
     }
 
-    public boolean markSupported() {
-        try {
-            openStream();
-        } catch (IOException e) {
-            log.info("Error getting underlying stream: ", e);
-            return false;
-        }
-        return super.markSupported();
+    public int read(byte[] b) throws IOException {
+        open();
+        return super.read(b, 0, b.length);
+    }
+
+    public int read(byte[] b, int off, int len) throws IOException {
+        open();
+        return super.read(b, off, len);
     }
 
 }

Added: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/data/LazyFileInputStreamTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/data/LazyFileInputStreamTest.java?rev=779081&view=auto
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/data/LazyFileInputStreamTest.java (added)
+++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/data/LazyFileInputStreamTest.java Wed May 27 10:18:12 2009
@@ -0,0 +1,143 @@
+/*
+ * 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.core.data;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+
+import org.apache.jackrabbit.test.JUnitTest;
+
+/**
+ * Tests the LazyFileInputStream class.
+ */
+public class LazyFileInputStreamTest extends JUnitTest {
+    
+    private static final String TEST_FILE = "target/test.txt";
+    
+    private File file = new File(TEST_FILE);
+
+    public void setUp() {
+        // Create the test directory
+        new File(TEST_FILE).getParentFile().mkdirs();
+    }
+    
+    public void tearDown() {
+        new File(TEST_FILE).delete();
+    }
+    
+    private void createFile() throws IOException {
+        FileOutputStream out = new FileOutputStream(file);
+        out.write(new byte[1]);
+        out.close();
+    }    
+    
+    public void test() throws IOException {
+        
+        createFile();
+        
+        // test exception if file doesn't exist
+        try {
+            LazyFileInputStream in = new LazyFileInputStream(file.getAbsolutePath() + "XX");
+            in.close();
+            fail();
+        } catch (IOException e) {
+            // expected
+        }
+        
+        // test open / close (without reading)
+        LazyFileInputStream in = new LazyFileInputStream(file);
+        in.close();
+        
+        // test reading too much and closing too much
+        in = new LazyFileInputStream(file);
+        assertEquals(0, in.read());
+        assertEquals(-1, in.read());
+        assertEquals(-1, in.read());
+        assertEquals(-1, in.read());
+        in.close();
+        in.close();
+        in.close();
+        assertEquals(-1, in.read());
+        
+        // test with file name
+        in = new LazyFileInputStream(file.getAbsolutePath());
+        assertEquals(1, in.available());
+        assertEquals(0, in.read());
+        assertEquals(0, in.available());
+        assertEquals(-1, in.read());
+        assertEquals(0, in.available());
+        in.close();
+        
+        // test markSupported, mark, and reset
+        in = new LazyFileInputStream(file);
+        assertFalse(in.markSupported());
+        in.mark(1);
+        assertEquals(0, in.read());
+        try {
+            in.reset();
+            fail();
+        } catch (IOException e) {
+            // expected
+        }
+        assertEquals(-1, in.read());
+        in.close();
+        
+        // test read(byte[])
+        in = new LazyFileInputStream(file);
+        byte[] test = new byte[2];
+        assertEquals(1, in.read(test));
+        in.close();        
+        
+        // test read(byte[],int,int)
+        in = new LazyFileInputStream(file);
+        assertEquals(1, in.read(test, 0, 2));
+        in.close();        
+
+        // test skip
+        in = new LazyFileInputStream(file);
+        assertEquals(2, in.skip(2));
+        assertEquals(-1, in.read(test));
+        assertEquals(0, in.skip(2));
+        in.close();        
+
+        // test with the file descriptor
+        RandomAccessFile ra = new RandomAccessFile(file, "r");
+        in = new LazyFileInputStream(ra.getFD());
+        assertEquals(0, in.read());
+        assertEquals(-1, in.read());
+        in.close();
+        ra.close();
+        
+        // test that the file is not opened before reading
+        in = new LazyFileInputStream(file);
+        // this should fail in Windows if the file was opened
+        file.delete();
+        
+        createFile();
+        
+        // test that the file is closed after reading the last byte
+        in = new LazyFileInputStream(file);
+        assertEquals(0, in.read());
+        assertEquals(-1, in.read());
+        // this should fail in Windows if the file was opened
+        file.delete();
+        
+    }
+
+}

Modified: jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/data/TestAll.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/data/TestAll.java?rev=779081&r1=779080&r2=779081&view=diff
==============================================================================
--- jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/data/TestAll.java (original)
+++ jackrabbit/trunk/jackrabbit-core/src/test/java/org/apache/jackrabbit/core/data/TestAll.java Wed May 27 10:18:12 2009
@@ -32,6 +32,7 @@
      */
     public static Test suite() {
         TestSuite suite = new TestSuite("Data tests");
+        suite.addTestSuite(LazyFileInputStreamTest.class);
         suite.addTestSuite(OpenFilesTest.class);
         suite.addTestSuite(DataStoreTest.class);
         suite.addTestSuite(NodeTypeTest.class);