001: /*
002: * JBoss, Home of Professional Open Source.
003: * Copyright 2006, Red Hat Middleware LLC, and individual contributors
004: * as indicated by the @author tags. See the copyright.txt file in the
005: * distribution for a full listing of individual contributors.
006: *
007: * This is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU Lesser General Public License as
009: * published by the Free Software Foundation; either version 2.1 of
010: * the License, or (at your option) any later version.
011: *
012: * This software is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this software; if not, write to the Free
019: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021: */
022: package org.jboss.ejb.plugins.cmp.jdbc;
023:
024: import java.io.ByteArrayInputStream;
025: import java.io.InputStream;
026: import java.io.OutputStream;
027: import java.sql.Blob;
028: import java.sql.SQLException;
029:
030: /**
031: * The representation (mapping) in the Java<sup><font size=-2>TM</font></sup>
032: * programming language of an SQL <code>BLOB</code> value to an array of bytes.
033: * A ByteArrayBlob contains an internal buffer that contains bytes that may be
034: * read from the stream. The <code>Blob</code> interface provides methods for
035: * getting the length of an SQL <code>BLOB</code> (Binary Large Object) value,
036: * for materializing a <code>BLOB</code> value on the client, and for
037: * determining the position of a pattern of bytes within a <code>BLOB</code>
038: * value. The ByteArrayBlob has static factory methods for construting an
039: * <code>BLOB</code> using either an existing serializable object, or an array
040: * of bytes. This is a nice way to store serialized objects in a relational
041: * field of type SQL <code>BLOB</code>.
042: *
043: * @author <a href="mailto:amccullo@sourceforge.new">Andrew McCulloch</a>
044: * @version $Revision: 63479 $
045: */
046: public final class ByteArrayBlob implements Blob {
047: /**
048: * The internal buffer for the bytes of the Blob.
049: */
050: private byte[] mBytes;
051:
052: public ByteArrayBlob(byte[] bytes) {
053: if (bytes == null) {
054: bytes = new byte[0];
055: }
056:
057: mBytes = bytes;
058: }
059:
060: public InputStream getBinaryStream() throws SQLException {
061: return new ByteArrayInputStream(mBytes);
062: }
063:
064: public byte[] getBytes(long pos, int length) throws SQLException {
065: // Defensive code, parameter checks.
066: if (length < 0 || length > mBytes.length || pos > mBytes.length) {
067: return new byte[0];
068: }
069:
070: if (pos <= 0) {
071: pos = 1; // One since the copy starts at pos.
072: }
073:
074: byte[] buffer = new byte[length];
075:
076: System.arraycopy(mBytes, (int) pos - 1, buffer, 0, length);
077: return buffer;
078: }
079:
080: public long length() throws SQLException {
081: return mBytes.length;
082: }
083:
084: public long position(Blob pattern, long start) throws SQLException {
085: return position(pattern.getBytes(0, (int) pattern.length()),
086: start);
087: }
088:
089: public long position(byte pattern[], long start)
090: throws SQLException {
091: // Small optimization, no need to look beyond this.
092: int max = mBytes.length - pattern.length;
093:
094: if (start < 0) {
095: start = 0; // Cannot start negative, so put it at the beginning.
096: } else if (start >= mBytes.length) {
097: return -1; // Out of bounds, start was past the end of the buffer.
098: }
099:
100: if (pattern.length == 0) {
101: return -1; // Indicate that the pattern was not found.
102: }
103:
104: byte first = pattern[0];
105: int i = (int) start;
106:
107: while (true) {
108: // Look for the first character.
109: while (i <= max && mBytes[i] != first) {
110: i++;
111: }
112:
113: if (i > max) {
114: return -1; // Went to far, reject the pattern.
115: }
116:
117: // Found the first character, now look for remainder of v2.
118: int j = i + 1;
119: int end = j + pattern.length - 1;
120: int k = 1;
121: boolean cont = true;
122:
123: // While the bytes remain equal and the end of v1 is not reached
124: // continue the either rejecting this match, or accepting it.
125: while (cont && j < end) {
126: if (mBytes[j++] != pattern[k++]) {
127: i++;
128: cont = false;
129: }
130: } // If cont == false then the pattern was found.
131:
132: if (cont) {
133: return i;
134: }
135: }
136: }
137:
138: public OutputStream setBinaryStream(long pos) throws SQLException {
139: throw new UnsupportedOperationException(
140: "ByteArrayBlob is immutable");
141: }
142:
143: public int setBytes(long pos, byte[] bytes) throws SQLException {
144: throw new UnsupportedOperationException(
145: "ByteArrayBlob is immutable");
146: }
147:
148: public int setBytes(long pos, byte[] bytes, int offset, int length)
149: throws SQLException {
150: throw new UnsupportedOperationException(
151: "ByteArrayBlob is immutable");
152: }
153:
154: public void truncate(long length) throws SQLException {
155: throw new UnsupportedOperationException(
156: "ByteArrayBlob is immutable");
157: }
158:
159: public void free() throws SQLException {
160: mBytes = null;
161: }
162:
163: public InputStream getBinaryStream(long pos, long length)
164: throws SQLException {
165: return new ByteArrayInputStream(mBytes, (int) pos, (int) length);
166: }
167: }
|