Adding JMCR-Stable version
[Benchmarks_CSolver.git] / JMCR-Stable / real-world application / derby-10.3.2.1 / java / engine / org / apache / derby / impl / jdbc / ClobUpdatableReader.java
diff --git a/JMCR-Stable/real-world application/derby-10.3.2.1/java/engine/org/apache/derby/impl/jdbc/ClobUpdatableReader.java b/JMCR-Stable/real-world application/derby-10.3.2.1/java/engine/org/apache/derby/impl/jdbc/ClobUpdatableReader.java
new file mode 100644 (file)
index 0000000..5162e21
--- /dev/null
@@ -0,0 +1,234 @@
+/*\r
+\r
+   Derby - Class org.apache.derby.impl.jdbc.ClobUpdatableReader\r
+\r
+   Licensed to the Apache Software Foundation (ASF) under one\r
+   or more contributor license agreements.  See the NOTICE file\r
+   distributed with this work for additional information\r
+   regarding copyright ownership.  The ASF licenses this file\r
+   to you under the Apache License, Version 2.0 (the\r
+   "License"); you may not use this file except in compliance\r
+   with the License.  You may obtain a copy of the License at\r
+\r
+     http://www.apache.org/licenses/LICENSE-2.0\r
+\r
+   Unless required by applicable law or agreed to in writing,\r
+   software distributed under the License is distributed on an\r
+   "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\r
+   KIND, either express or implied.  See the License for the\r
+   specific language governing permissions and limitations\r
+   under the License.\r
+\r
+ */\r
+package org.apache.derby.impl.jdbc;\r
+\r
+import java.io.EOFException;\r
+import java.io.IOException;\r
+import java.io.InputStream;\r
+import java.io.Reader;\r
+import java.sql.SQLException;\r
+import org.apache.derby.iapi.reference.SQLState;\r
+import org.apache.derby.iapi.services.i18n.MessageService;\r
+import org.apache.derby.iapi.services.sanity.SanityManager;\r
+\r
+/**\r
+ * <code>ClobUpdatableReader</code> is used to create a <code>Reader</code>\r
+ * over a <code>LOBInputStream</code>.\r
+ * <p>\r
+ * This class is aware that the underlying stream can be modified and\r
+ * reinitializes itself if it detects any change in the stream. This\r
+ * invalidates the cache so the changes are reflected immediately.\r
+ * \r
+ * @see LOBInputStream\r
+ */\r
+final class ClobUpdatableReader extends Reader {\r
+    \r
+    /** Reader accessing the Clob data and doing the work. */\r
+    private Reader streamReader;\r
+    /** Character position of this reader. */\r
+    private long pos;\r
+    /** Underlying stream of byte data. */\r
+    private InputStream stream = null;\r
+    /** Connection object used to obtain synchronization-object. */\r
+    private ConnectionChild conChild;\r
+    /** flag to indicate if its associated with materialized clob */\r
+    private boolean materialized;\r
+    /** clob object this object is associated */\r
+    private final EmbedClob clob;\r
+    /**\r
+     * Position in Clob where to stop reading unless EOF is reached first.\r
+     */\r
+    private final long maxPos;\r
+    \r
+    \r
+    /**\r
+     * Constructs a <code>Reader</code> over a <code>LOBInputStream</code>.\r
+     * @param stream underlying stream of byte data\r
+     * @param conChild a connection object used to obtain synchronization-object\r
+     * @throws IOException\r
+     */\r
+    ClobUpdatableReader (LOBInputStream stream, ConnectionChild conChild)\r
+                                                        throws IOException {\r
+        clob = null;\r
+        materialized = true;\r
+        this.conChild = conChild;\r
+        this.stream = stream;\r
+        //The subset of the Clob has not been requested. \r
+        //Hence set maxPos to infinity (or as close as we get).\r
+        this.maxPos = Long.MAX_VALUE;\r
+\r
+        init (stream, 0);\r
+    }\r
+\r
+    /**\r
+     * Constructs a <code>Reader</code> over a <code>LOBInputStream</code>.\r
+     * @param clob EmbedClob this Reader is associated to.\r
+     * @throws IOException\r
+     * @throws SQLException\r
+     */\r
+    ClobUpdatableReader (EmbedClob clob) throws IOException, SQLException {\r
+        // A subset of the Clob has not been requested.\r
+        // Hence set length to infinity (or as close as we get).\r
+        this(clob, 0L, Long.MAX_VALUE);\r
+    }\r
+    \r
+    /**\r
+     * Construct an <code>ClobUpdatableReader<code> using the \r
+     * <code>EmbedClob</code> received as parameter. The initial\r
+     * position in the stream is set to <code>pos</code> and the\r
+     * stream is restricted to a length of <code>len</code>.\r
+     * \r
+     * @param clob EmbedClob this stream is associated with.\r
+     * @param pos initial position. The position starts from 0.\r
+     * @param len The length to which the underlying <code>InputStream</code>\r
+     *            has to be restricted.\r
+     * @throws IOException\r
+     * @throws SQLException\r
+     */\r
+    ClobUpdatableReader (EmbedClob clob, long pos, long len) \r
+    throws IOException, SQLException {\r
+        this.clob = clob;\r
+        this.conChild = clob;\r
+        this.maxPos = pos + len;\r
+\r
+        InternalClob internalClob = clob.getInternalClob();\r
+        materialized = internalClob.isWritable();        \r
+        if (materialized) {\r
+            long byteLength = internalClob.getByteLength();\r
+            this.stream = internalClob.getRawByteStream();\r
+            // Position the stream on pos using the init method.\r
+            init ((LOBInputStream)stream, pos);\r
+        } else {\r
+            if (SanityManager.DEBUG) {\r
+                SanityManager.ASSERT(internalClob instanceof StoreStreamClob,\r
+                        "Wrong type of internal clob representation: " +\r
+                        internalClob.toString());\r
+            }\r
+            // Since this representation is read-only, the stream never has to\r
+            // update itself, until the Clob representation itself has been\r
+            // changed. That even will be detected by {@link #updateIfRequired}.\r
+            this.streamReader = internalClob.getReader(pos + 1);\r
+            this.pos = pos;\r
+        }\r
+    }\r
+        \r
+    /**\r
+     * Reads chars into the cbuf char array. Changes made in uderlying storage \r
+     * will be reflected immidiatly from the corrent position.\r
+     * @param cbuf buffer to read into\r
+     * @param off offet of the cbuf array to start writing read chars\r
+     * @param len number of chars to be read\r
+     * @return number of bytes read\r
+     * @throws IOException\r
+     */\r
+    public int read(char[] cbuf, int off, int len) throws IOException {        \r
+        updateIfRequired();\r
+        \r
+        //If the stream has exceeded maxPos the read should return -1\r
+        //signifying end of stream.\r
+        if (pos >= maxPos) {\r
+            return -1;\r
+        }\r
+\r
+        int actualLength = (int) Math.min(len, maxPos - pos);\r
+        int ret = streamReader.read (cbuf, off, actualLength);\r
+        if (ret >= 0) {\r
+            pos += ret;\r
+        }\r
+        return ret;\r
+    }\r
+\r
+    /**\r
+     * Closes the reader.\r
+     * @throws IOException\r
+     */\r
+    public void close() throws IOException {\r
+        streamReader.close();\r
+    }\r
+    \r
+    /**\r
+     * Initializes the streamReader and skips to the given position.\r
+     * @param skip number of characters to skip to reach initial position\r
+     * @throws IOException if a streaming error occurs\r
+     */\r
+    private void init(LOBInputStream stream, long skip) \r
+                                                    throws IOException {\r
+        streamReader = new UTF8Reader (stream, 0, stream.length (), \r
+                                        conChild, \r
+                                conChild.getConnectionSynchronization());\r
+        long remainToSkip = skip;\r
+        while (remainToSkip > 0) {\r
+            long skipBy = streamReader.skip(remainToSkip);\r
+            if (skipBy == 0) {\r
+                if (streamReader.read() == -1) {\r
+                    throw new EOFException (\r
+                                 MessageService.getCompleteMessage (\r
+                                 SQLState.STREAM_EOF, new Object [0]));\r
+                }\r
+                skipBy = 1;\r
+            }\r
+            remainToSkip -= skipBy;\r
+        }\r
+        pos = skip;\r
+    }    \r
+\r
+    /**\r
+     * Updates the stream if underlying clob is modified since\r
+     * this reader was created. \r
+     * If the stream is associated with a materialized clob, it \r
+     * checks if the underlying clob is updated since last read and \r
+     * updates itself if it is. If the stream is associated with \r
+     * non materialized clob and clob is materialized since last read it \r
+     * fetches the stream again and sets the position to current position.\r
+     * @throws IOException\r
+     */\r
+    private void updateIfRequired () throws IOException {\r
+        if (materialized) {\r
+            LOBInputStream lobStream = (LOBInputStream) stream;\r
+            if (lobStream.isObsolete()) {\r
+                lobStream.reInitialize();\r
+                init (lobStream, pos);\r
+            }\r
+        }\r
+        else {\r
+            //clob won't be null if the stream wasn't materialized\r
+            //but still try to be safe\r
+            if (SanityManager.DEBUG) {\r
+                SanityManager.ASSERT (!(clob == null), \r
+                        "Internal error while updating stream");\r
+            }\r
+            if (clob.getInternalClob().isWritable()) {\r
+                try {\r
+                    stream = clob.getInternalClob().getRawByteStream();\r
+                }\r
+                catch (SQLException e) {\r
+                    IOException ioe = new IOException (e.getMessage());\r
+                    ioe.initCause (e);\r
+                    throw ioe;\r
+                }\r
+                init ((LOBInputStream) stream, pos);\r
+                materialized = true;\r
+            }\r
+        }\r
+    }\r
+}\r