1 19 20 package org.apache.cayenne.access.types; 21 22 import java.io.BufferedInputStream ; 23 import java.io.ByteArrayOutputStream ; 24 import java.io.IOException ; 25 import java.io.InputStream ; 26 import java.sql.Blob ; 27 import java.sql.CallableStatement ; 28 import java.sql.PreparedStatement ; 29 import java.sql.ResultSet ; 30 import java.sql.SQLException ; 31 import java.sql.Types ; 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 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 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 getClassName() { 80 return "byte[]"; 81 } 82 83 89 public boolean validateProperty( 90 Object source, 91 String property, 92 Object 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 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 materializeObject(ResultSet rs, int index, int type) throws Exception { 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 if (bytes != null && type == Types.BINARY && isTrimmingBytes()) { 136 bytes = trimBytes(bytes); 137 } 138 } 139 140 return bytes; 141 } 142 143 public Object materializeObject(CallableStatement cs, int index, int type) 144 throws Exception { 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 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 st, 170 Object val, 171 int pos, 172 int type, 173 int precision) throws Exception { 174 175 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 writeBlob(byte[] bytes) { 191 return bytes != null ? new MemoryBlob(bytes) : null; 192 } 193 194 protected byte[] readBlob(Blob blob) throws IOException , SQLException { 195 if (blob == null) { 196 return null; 197 } 198 199 if (blob.length() > Integer.MAX_VALUE) { 201 throw new IllegalArgumentException ( 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 in = blob.getBinaryStream(); 212 return (in != null) ? readValueStream( 213 new BufferedInputStream (in, bufSize), 214 size, 215 bufSize) : null; 216 } 217 218 protected byte[] readBinaryStream(ResultSet rs, int index) throws IOException , 219 SQLException { 220 InputStream in = rs.getBinaryStream(index); 221 return (in != null) ? readValueStream(in, -1, BUF_SIZE) : null; 222 } 223 224 protected byte[] readValueStream(InputStream in, int streamSize, int bufSize) 225 throws IOException { 226 227 byte[] buf = new byte[bufSize]; 228 int read; 229 ByteArrayOutputStream out = (streamSize > 0) ? new ByteArrayOutputStream ( 230 streamSize) : new ByteArrayOutputStream (); 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 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 |