KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > cayenne > access > types > ByteArrayType


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.access.types;
21
22 import java.io.BufferedInputStream JavaDoc;
23 import java.io.ByteArrayOutputStream JavaDoc;
24 import java.io.IOException JavaDoc;
25 import java.io.InputStream JavaDoc;
26 import java.sql.Blob JavaDoc;
27 import java.sql.CallableStatement JavaDoc;
28 import java.sql.PreparedStatement JavaDoc;
29 import java.sql.ResultSet JavaDoc;
30 import java.sql.SQLException JavaDoc;
31 import java.sql.Types JavaDoc;
32
33 import org.apache.cayenne.CayenneException;
34 import org.apache.cayenne.map.DbAttribute;
35 import org.apache.cayenne.util.MemoryBlob;
36 import org.apache.cayenne.validation.BeanValidationFailure;
37 import org.apache.cayenne.validation.ValidationResult;
38
39 /**
40  * Handles <code>byte[]</code>, mapping it as either of JDBC types - BLOB or
41  * (VAR)BINARY. Can be configured to trim trailing zero bytes.
42  *
43  * @author Andrus Adamchik
44  */

45 public class ByteArrayType extends AbstractType {
46
47     private static final int BUF_SIZE = 8 * 1024;
48
49     protected boolean trimmingBytes;
50     protected boolean usingBlobs;
51
52     /**
53      * Strips null bytes from the byte array, returning a potentially smaller array that
54      * contains no trailing zero bytes.
55      */

56     public static byte[] trimBytes(byte[] bytes) {
57         int bytesToTrim = 0;
58         for (int i = bytes.length - 1; i >= 0; i--) {
59             if (bytes[i] != 0) {
60                 bytesToTrim = bytes.length - 1 - i;
61                 break;
62             }
63         }
64
65         if (bytesToTrim == 0) {
66             return bytes;
67         }
68
69         byte[] dest = new byte[bytes.length - bytesToTrim];
70         System.arraycopy(bytes, 0, dest, 0, dest.length);
71         return dest;
72     }
73
74     public ByteArrayType(boolean trimmingBytes, boolean usingBlobs) {
75         this.usingBlobs = usingBlobs;
76         this.trimmingBytes = trimmingBytes;
77     }
78
79     public String JavaDoc getClassName() {
80         return "byte[]";
81     }
82
83     /**
84      * Validates byte[] property.
85      *
86      * @since 1.1
87      * @deprecated since 3.0 as validation should not be done at the DataNode level.
88      */

89     public boolean validateProperty(
90             Object JavaDoc source,
91             String JavaDoc property,
92             Object JavaDoc value,
93             DbAttribute dbAttribute,
94             ValidationResult validationResult) {
95
96         if (!(value instanceof byte[])) {
97             return true;
98         }
99
100         if (dbAttribute.getMaxLength() <= 0) {
101             return true;
102         }
103
104         byte[] bytes = (byte[]) value;
105         if (bytes.length > dbAttribute.getMaxLength()) {
106             String JavaDoc message = "\""
107                     + property
108                     + "\" exceeds maximum allowed length ("
109                     + dbAttribute.getMaxLength()
110                     + " bytes): "
111                     + bytes.length;
112             validationResult.addFailure(new BeanValidationFailure(
113                     source,
114                     property,
115                     message));
116             return false;
117         }
118
119         return true;
120     }
121
122     public Object JavaDoc materializeObject(ResultSet JavaDoc rs, int index, int type) throws Exception JavaDoc {
123
124         byte[] bytes = null;
125
126         if (type == Types.BLOB) {
127             bytes = (isUsingBlobs()) ? readBlob(rs.getBlob(index)) : readBinaryStream(
128                     rs,
129                     index);
130         }
131         else {
132             bytes = rs.getBytes(index);
133
134             // trim BINARY type
135
if (bytes != null && type == Types.BINARY && isTrimmingBytes()) {
136                 bytes = trimBytes(bytes);
137             }
138         }
139
140         return bytes;
141     }
142
143     public Object JavaDoc materializeObject(CallableStatement JavaDoc cs, int index, int type)
144             throws Exception JavaDoc {
145
146         byte[] bytes = null;
147
148         if (type == Types.BLOB) {
149             if (!isUsingBlobs()) {
150                 throw new CayenneException(
151                         "Binary streams are not supported in stored procedure parameters.");
152             }
153             bytes = readBlob(cs.getBlob(index));
154         }
155         else {
156
157             bytes = cs.getBytes(index);
158
159             // trim BINARY type
160
if (bytes != null && type == Types.BINARY && isTrimmingBytes()) {
161                 bytes = trimBytes(bytes);
162             }
163         }
164
165         return bytes;
166     }
167
168     public void setJdbcObject(
169             PreparedStatement JavaDoc st,
170             Object JavaDoc val,
171             int pos,
172             int type,
173             int precision) throws Exception JavaDoc {
174
175         // if this is a BLOB column, set the value as "bytes"
176
// instead. This should work with most drivers
177
if (type == Types.BLOB) {
178             if (isUsingBlobs()) {
179                 st.setBlob(pos, writeBlob((byte[]) val));
180             }
181             else {
182                 st.setBytes(pos, (byte[]) val);
183             }
184         }
185         else {
186             super.setJdbcObject(st, val, pos, type, precision);
187         }
188     }
189
190     protected Blob JavaDoc writeBlob(byte[] bytes) {
191         return bytes != null ? new MemoryBlob(bytes) : null;
192     }
193
194     protected byte[] readBlob(Blob JavaDoc blob) throws IOException JavaDoc, SQLException JavaDoc {
195         if (blob == null) {
196             return null;
197         }
198
199         // sanity check on size
200
if (blob.length() > Integer.MAX_VALUE) {
201             throw new IllegalArgumentException JavaDoc(
202                     "BLOB is too big to be read as byte[] in memory: " + blob.length());
203         }
204
205         int size = (int) blob.length();
206         if (size == 0) {
207             return new byte[0];
208         }
209
210         int bufSize = (size < BUF_SIZE) ? size : BUF_SIZE;
211         InputStream JavaDoc in = blob.getBinaryStream();
212         return (in != null) ? readValueStream(
213                 new BufferedInputStream JavaDoc(in, bufSize),
214                 size,
215                 bufSize) : null;
216     }
217
218     protected byte[] readBinaryStream(ResultSet JavaDoc rs, int index) throws IOException JavaDoc,
219             SQLException JavaDoc {
220         InputStream JavaDoc in = rs.getBinaryStream(index);
221         return (in != null) ? readValueStream(in, -1, BUF_SIZE) : null;
222     }
223
224     protected byte[] readValueStream(InputStream JavaDoc in, int streamSize, int bufSize)
225             throws IOException JavaDoc {
226
227         byte[] buf = new byte[bufSize];
228         int read;
229         ByteArrayOutputStream JavaDoc out = (streamSize > 0) ? new ByteArrayOutputStream JavaDoc(
230                 streamSize) : new ByteArrayOutputStream JavaDoc();
231
232         try {
233             while ((read = in.read(buf, 0, bufSize)) >= 0) {
234                 out.write(buf, 0, read);
235             }
236             return out.toByteArray();
237         }
238         finally {
239             in.close();
240         }
241     }
242
243     /**
244      * Returns <code>true</code> if byte columns are handled as BLOBs internally.
245      */

246     public boolean isUsingBlobs() {
247         return usingBlobs;
248     }
249
250     public void setUsingBlobs(boolean usingBlobs) {
251         this.usingBlobs = usingBlobs;
252     }
253
254     public boolean isTrimmingBytes() {
255         return trimmingBytes;
256     }
257
258     public void setTrimmingBytes(boolean trimingBytes) {
259         this.trimmingBytes = trimingBytes;
260     }
261 }
262
Popular Tags