KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > cayenne > util > MemoryClob


1 /*****************************************************************
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements. See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership. The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License. You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15  * KIND, either express or implied. See the License for the
16  * specific language governing permissions and limitations
17  * under the License.
18  ****************************************************************/

19
20 package org.apache.cayenne.util;
21
22 import java.io.IOException JavaDoc;
23 import java.io.InputStream JavaDoc;
24 import java.io.StringReader JavaDoc;
25 import java.sql.Clob JavaDoc;
26 import java.sql.SQLException JavaDoc;
27
28 import org.apache.cayenne.CayenneRuntimeException;
29
30 /**
31  * A Clob implementation that stores contents in memory.
32  * <p>
33  * <i>This implementation is based on jdbcClob from HSQLDB (copyright HSQL Development
34  * Group).</i>
35  * </p>
36  *
37  * @since 1.2
38  * @author Andrus Adamchik
39  */

40 public class MemoryClob implements Clob JavaDoc {
41
42     volatile String JavaDoc data;
43
44     /**
45      * Constructs a new jdbcClob object wrapping the given character sequence.
46      * <p>
47      * This constructor is used internally to retrieve result set values as Clob objects,
48      * yet it must be public to allow access from other packages. As such (in the interest
49      * of efficiency) this object maintains a reference to the given String object rather
50      * than making a copy and so it is gently suggested (in the interest of effective
51      * memory management) that extenal clients using this constructor either take pause to
52      * consider the implications or at least take care to provide a String object whose
53      * internal character buffer is not much larger than required to represent the value.
54      *
55      * @param data the character sequence representing the Clob value
56      * @throws SQLException if the argument is null
57      */

58     public MemoryClob(String JavaDoc data) {
59
60         if (data == null) {
61             throw new CayenneRuntimeException("Null data");
62         }
63
64         this.data = data;
65     }
66
67     /**
68      * Retrieves the number of characters in the <code>CLOB</code> value designated by
69      * this <code>Clob</code> object.
70      *
71      * @return length of the <code>CLOB</code> in characters
72      * @exception SQLException if there is an error accessing the length of the
73      * <code>CLOB</code> value
74      */

75     public long length() throws SQLException JavaDoc {
76
77         final String JavaDoc ldata = data;
78
79         return ldata.length();
80     }
81
82     /**
83      * Retrieves a copy of the specified substring in the <code>CLOB</code> value
84      * designated by this <code>Clob</code> object. The substring begins at position
85      * <code>pos</code> and has up to <code>length</code> consecutive characters.
86      */

87     public String JavaDoc getSubString(long pos, final int length) throws SQLException JavaDoc {
88
89         final String JavaDoc ldata = data;
90         final int dlen = ldata.length();
91
92         pos--;
93
94         if (pos < 0 || pos > dlen) {
95             new CayenneRuntimeException("Invalid position: " + (pos + 1L));
96         }
97
98         if (length < 0 || length > dlen - pos) {
99             throw new CayenneRuntimeException("Invalid length: " + length);
100         }
101
102         if (pos == 0 && length == dlen) {
103             return ldata;
104         }
105
106         return ldata.substring((int) pos, (int) pos + length);
107     }
108
109     /**
110      * Retrieves the <code>CLOB</code> value designated by this <code>Clob</code>
111      * object as a <code>java.io.Reader</code> object (or as a stream of characters).
112      *
113      * @return a <code>java.io.Reader</code> object containing the <code>CLOB</code>
114      * data
115      * @exception SQLException if there is an error accessing the <code>CLOB</code>
116      * value
117      */

118     public java.io.Reader JavaDoc getCharacterStream() throws SQLException JavaDoc {
119
120         final String JavaDoc ldata = data;
121
122         return new StringReader JavaDoc(ldata);
123     }
124
125     /**
126      * Retrieves the <code>CLOB</code> value designated by this <code>Clob</code>
127      * object as an ascii stream.
128      *
129      * @return a <code>java.io.InputStream</code> object containing the
130      * <code>CLOB</code> data
131      * @exception SQLException if there is an error accessing the <code>CLOB</code>
132      * value
133      */

134     public java.io.InputStream JavaDoc getAsciiStream() throws SQLException JavaDoc {
135
136         final String JavaDoc ldata = data;
137
138         return new AsciiStringInputStream(ldata);
139     }
140
141     /**
142      * Retrieves the character position at which the specified substring
143      * <code>searchstr</code> appears in the SQL <code>CLOB</code> value represented
144      * by this <code>Clob</code> object. The search begins at position
145      * <code>start</code>.
146      *
147      * @param searchstr the substring for which to search
148      * @param start the position at which to begin searching; the first position is 1
149      * @return the position at which the substring appears or -1 if it is not present; the
150      * first position is 1
151      * @exception SQLException if there is an error accessing the <code>CLOB</code>
152      * value
153      */

154     public long position(final String JavaDoc searchstr, long start) throws SQLException JavaDoc {
155
156         if (searchstr == null || start > Integer.MAX_VALUE) {
157             return -1;
158         }
159
160         final String JavaDoc ldata = data;
161         final int pos = ldata.indexOf(searchstr, (int) --start);
162
163         return (pos < 0) ? -1 : pos + 1;
164     }
165
166     /**
167      * Retrieves the character position at which the specified <code>Clob</code> object
168      * <code>searchstr</code> appears in this <code>Clob</code> object. The search
169      * begins at position <code>start</code>.
170      *
171      * @param searchstr the <code>Clob</code> object for which to search
172      * @param start the position at which to begin searching; the first position is 1
173      * @return the position at which the <code>Clob</code> object appears or -1 if it is
174      * not present; the first position is 1
175      * @exception SQLException if there is an error accessing the <code>CLOB</code>
176      * value
177      */

178     public long position(final Clob JavaDoc searchstr, long start) throws SQLException JavaDoc {
179
180         if (searchstr == null) {
181             return -1;
182         }
183
184         final String JavaDoc ldata = data;
185         final long dlen = ldata.length();
186         final long sslen = searchstr.length();
187
188         // This is potentially much less expensive than materializing a large
189
// substring from some other vendor's CLOB. Indeed, we should probably
190
// do the comparison piecewise, using an in-memory buffer (or temp-files
191
// when available), if it is detected that the input CLOB is very long.
192
if (start > dlen - sslen) {
193             return -1;
194         }
195
196         // by now, we know sslen and start are both < Integer.MAX_VALUE
197
String JavaDoc s;
198
199         if (searchstr instanceof MemoryClob) {
200             s = ((MemoryClob) searchstr).data;
201         }
202         else {
203             s = searchstr.getSubString(1L, (int) sslen);
204         }
205
206         final int pos = ldata.indexOf(s, (int) start);
207
208         return (pos < 0) ? -1 : pos + 1;
209     }
210
211     /**
212      * Writes the given Java <code>String</code> to the <code>CLOB</code> value that
213      * this <code>Clob</code> object designates at the position <code>pos</code>.
214      * Calling this method always throws an <code>SQLException</code>.
215      */

216     public int setString(long pos, String JavaDoc str) throws SQLException JavaDoc {
217         throw new CayenneRuntimeException("Not supported");
218     }
219
220     /**
221      * Writes <code>len</code> characters of <code>str</code>, starting at character
222      * <code>offset</code>, to the <code>CLOB</code> value that this
223      * <code>Clob</code> represents. Calling this method always throws an
224      * <code>SQLException</code>.
225      */

226     public int setString(long pos, String JavaDoc str, int offset, int len) throws SQLException JavaDoc {
227         throw new CayenneRuntimeException("Not supported");
228     }
229
230     /**
231      * Retrieves a stream to be used to write Ascii characters to the <code>CLOB</code>
232      * value that this <code>Clob</code> object represents, starting at position
233      * <code>pos</code>.
234      * <p>
235      * Calling this method always throws an <code>SQLException</code>.
236      */

237     public java.io.OutputStream JavaDoc setAsciiStream(long pos) throws SQLException JavaDoc {
238         throw new CayenneRuntimeException("Not supported");
239     }
240
241     /**
242      * Retrieves a stream to be used to write a stream of Unicode characters to the
243      * <code>CLOB</code> value that this <code>Clob</code> object represents, at
244      * position <code>pos</code>.
245      * <p>
246      * Calling this method always throws an <code>SQLException</code>.
247      */

248     public java.io.Writer JavaDoc setCharacterStream(long pos) throws SQLException JavaDoc {
249         throw new CayenneRuntimeException("Not supported");
250     }
251
252     /**
253      * Truncates the <code>CLOB</code> value that this <code>Clob</code> designates to
254      * have a length of <code>len</code> characters.
255      * <p>
256      */

257     public void truncate(final long len) throws SQLException JavaDoc {
258
259         final String JavaDoc ldata = data;
260         final long dlen = ldata.length();
261         final long chars = len >> 1;
262
263         if (chars == dlen) {
264
265             // nothing has changed, so there's nothing to be done
266
}
267         else if (len < 0 || chars > dlen) {
268             throw new CayenneRuntimeException("Invalid length: " + len);
269         }
270         else {
271
272             // use new String() to ensure we get rid of slack
273
data = new String JavaDoc(ldata.substring(0, (int) chars));
274         }
275     }
276
277     class AsciiStringInputStream extends InputStream JavaDoc {
278
279         protected int strOffset = 0;
280         protected int charOffset = 0;
281         protected int available;
282         protected String JavaDoc str;
283
284         public AsciiStringInputStream(String JavaDoc s) {
285             str = s;
286             available = s.length() * 2;
287         }
288
289         public int doRead() throws IOException JavaDoc {
290
291             if (available == 0) {
292                 return -1;
293             }
294
295             available--;
296
297             char c = str.charAt(strOffset);
298
299             if (charOffset == 0) {
300                 charOffset = 1;
301
302                 return (c & 0x0000ff00) >> 8;
303             }
304             else {
305                 charOffset = 0;
306                 strOffset++;
307                 return c & 0x000000ff;
308             }
309         }
310
311         public int read() throws IOException JavaDoc {
312             doRead();
313             return doRead();
314         }
315
316         public int available() throws IOException JavaDoc {
317             return available / 2;
318         }
319     }
320 }
321
Popular Tags