KickJava   Java API By Example, From Geeks To Geeks.

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


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.ByteArrayInputStream JavaDoc;
23 import java.io.InputStream JavaDoc;
24 import java.io.OutputStream JavaDoc;
25 import java.sql.Blob JavaDoc;
26 import java.sql.SQLException JavaDoc;
27
28 import org.apache.cayenne.CayenneRuntimeException;
29
30 /**
31  * A Blob implementation that stores content in memory.
32  * <p>
33  * <i>This implementation is based on jdbcBlob from HSQLDB (copyright HSQL Development
34  * Group).</i>
35  * </p>
36  *
37  * @since 1.2
38  * @author Andrus Adamchik, based on HSQLDB jdbcBlob.
39  */

40 public class MemoryBlob implements Blob JavaDoc {
41
42     volatile byte[] data;
43
44     public MemoryBlob() {
45         this(new byte[0]);
46     }
47
48     /**
49      * Constructs a new MemoryBlob instance wrapping the given octet sequence.
50      *
51      * @param data the octet sequence representing the Blob value
52      * @throws CayenneRuntimeException if the argument is null
53      */

54     public MemoryBlob(byte[] data) {
55
56         if (data == null) {
57             throw new CayenneRuntimeException("Null data");
58         }
59
60         this.data = data;
61     }
62
63     /**
64      * Returns the number of bytes in the <code>BLOB</code> value designated by this
65      * <code>Blob</code> object.
66      *
67      * @return length of the <code>BLOB</code> in bytes
68      * @exception SQLException if there is an error accessing the length of the
69      * <code>BLOB</code>
70      */

71     public long length() throws SQLException JavaDoc {
72         return data.length;
73     }
74
75     /**
76      * Retrieves all or part of the <code>BLOB</code> value that this <code>Blob</code>
77      * object represents, as an array of bytes. This <code>byte</code> array contains up
78      * to <code>length</code> consecutive bytes starting at position <code>pos</code>.
79      * <p>
80      * The official specification is ambiguous in that it does not precisely indicate the
81      * policy to be observed when pos > this.length() - length. One policy would be to
82      * retrieve the octets from pos to this.length(). Another would be to throw an
83      * exception. This implementation observes the later policy.
84      *
85      * @param pos the ordinal position of the first byte in the <code>BLOB</code> value
86      * to be extracted; the first byte is at position 1
87      * @param length the number of consecutive bytes to be copied
88      * @return a byte array containing up to <code>length</code> consecutive bytes from
89      * the <code>BLOB</code> value designated by this <code>Blob</code>
90      * object, starting with the byte at position <code>pos</code>
91      * @exception SQLException if there is an error accessing the <code>BLOB</code>
92      * value
93      */

94     public byte[] getBytes(long pos, final int length) throws SQLException JavaDoc {
95
96         final byte[] ldata = data;
97         final int dlen = ldata.length;
98
99         pos--;
100
101         if (pos < 0 || pos > dlen) {
102             throw new SQLException JavaDoc("Invalid pos: " + (pos + 1));
103         }
104
105         if (length < 0 || length > dlen - pos) {
106             throw new SQLException JavaDoc("length: " + length);
107         }
108
109         final byte[] out = new byte[length];
110         System.arraycopy(ldata, (int) pos, out, 0, length);
111         return out;
112     }
113
114     /**
115      * Retrieves the <code>BLOB</code> value designated by this <code>Blob</code>
116      * instance as a stream.
117      *
118      * @return a stream containing the <code>BLOB</code> data
119      * @exception SQLException if there is an error accessing the <code>BLOB</code>
120      * value
121      */

122     public InputStream JavaDoc getBinaryStream() throws SQLException JavaDoc {
123         return new ByteArrayInputStream JavaDoc(data);
124     }
125
126     /**
127      * Retrieves the byte position at which the specified byte array <code>pattern</code>
128      * begins within the <code>BLOB</code> value that this <code>Blob</code> object
129      * represents. The search for <code>pattern</code> begins at position
130      * <code>start</code>.
131      * <p>
132      *
133      * @param pattern the byte array for which to search
134      * @param start the position at which to begin searching; the first position is 1
135      * @return the position at which the pattern appears, else -1
136      * @exception SQLException if there is an error accessing the <code>BLOB</code>
137      */

138     public long position(final byte[] pattern, long start) throws SQLException JavaDoc {
139
140         final byte[] ldata = data;
141         final int dlen = ldata.length;
142
143         if (start > dlen || pattern == null) {
144             return -1;
145         }
146         else if (start < 1) {
147             start = 0;
148         }
149         else {
150             start--;
151         }
152
153         final int plen = pattern.length;
154
155         if (plen == 0 || start > dlen - plen) {
156             return -1;
157         }
158
159         final int stop = dlen - plen;
160         final byte b0 = pattern[0];
161
162         outer_loop: for (int i = (int) start; i <= stop; i++) {
163             if (ldata[i] != b0) {
164                 continue;
165             }
166
167             int len = plen;
168             int doffset = i;
169             int poffset = 0;
170
171             while (len-- > 0) {
172                 if (ldata[doffset++] != pattern[poffset++]) {
173                     continue outer_loop;
174                 }
175             }
176
177             return i + 1;
178         }
179
180         return -1;
181     }
182
183     /**
184      * Retrieves the byte position in the <code>BLOB</code> value designated by this
185      * <code>Blob</code> object at which <code>pattern</code> begins. The search
186      * begins at position <code>start</code>.
187      *
188      * @param pattern the <code>Blob</code> object designating the <code>BLOB</code>
189      * value for which to search
190      * @param start the position in the <code>BLOB</code> value at which to begin
191      * searching; the first position is 1
192      * @return the position at which the pattern begins, else -1
193      * @exception SQLException if there is an error accessing the <code>BLOB</code>
194      * value
195      */

196     public long position(final Blob JavaDoc pattern, long start) throws SQLException JavaDoc {
197
198         final byte[] ldata = data;
199         final int dlen = ldata.length;
200
201         if (start > dlen || pattern == null) {
202             return -1;
203         }
204         else if (start < 1) {
205             start = 0;
206         }
207         else {
208             start--;
209         }
210
211         final long plen = pattern.length();
212
213         if (plen == 0 || start > dlen - plen) {
214             return -1;
215         }
216
217         // by now, we know plen <= Integer.MAX_VALUE
218
final int iplen = (int) plen;
219         byte[] bap;
220
221         if (pattern instanceof MemoryBlob) {
222             bap = ((MemoryBlob) pattern).data;
223         }
224         else {
225             bap = pattern.getBytes(1, iplen);
226         }
227
228         final int stop = dlen - iplen;
229         final byte b0 = bap[0];
230
231         outer_loop: for (int i = (int) start; i <= stop; i++) {
232             if (ldata[i] != b0) {
233                 continue;
234             }
235
236             int len = iplen;
237             int doffset = i;
238             int poffset = 0;
239
240             while (len-- > 0) {
241                 if (ldata[doffset++] != bap[poffset++]) {
242                     continue outer_loop;
243                 }
244             }
245
246             return i + 1;
247         }
248
249         return -1;
250     }
251
252     /**
253      * Always throws an exception.
254      */

255     public int setBytes(long pos, byte[] bytes) throws SQLException JavaDoc {
256         throw new SQLException JavaDoc("Not supported");
257     }
258
259     /**
260      * Always throws an exception.
261      */

262     public int setBytes(long pos, byte[] bytes, int offset, int len) throws SQLException JavaDoc {
263         throw new SQLException JavaDoc("Not supported");
264     }
265
266     /**
267      * Always throws an exception.
268      */

269     public OutputStream JavaDoc setBinaryStream(long pos) throws SQLException JavaDoc {
270         throw new SQLException JavaDoc("Not supported");
271     }
272
273     /**
274      * Truncates the <code>BLOB</code> value that this <code>Blob</code> object
275      * represents to be <code>len</code> bytes in length.
276      *
277      * @param len the length, in bytes, to which the <code>BLOB</code> value that this
278      * <code>Blob</code> object represents should be truncated
279      * @exception SQLException if there is an error accessing the <code>BLOB</code>
280      * value
281      */

282     public void truncate(final long len) throws SQLException JavaDoc {
283
284         final byte[] ldata = data;
285
286         if (len < 0 || len > ldata.length) {
287             throw new SQLException JavaDoc("Invalid length: " + Long.toString(len));
288         }
289
290         if (len == ldata.length) {
291             return;
292         }
293
294         byte[] newData = new byte[(int) len];
295         System.arraycopy(ldata, 0, newData, 0, (int) len);
296         data = newData;
297     }
298 }
299
Popular Tags