1 56 package org.objectstyle.cayenne.access.types; 57 58 import java.io.BufferedInputStream ; 59 import java.io.ByteArrayOutputStream ; 60 import java.io.IOException ; 61 import java.io.InputStream ; 62 import java.sql.Blob ; 63 import java.sql.CallableStatement ; 64 import java.sql.PreparedStatement ; 65 import java.sql.ResultSet ; 66 import java.sql.SQLException ; 67 import java.sql.Types ; 68 69 import org.apache.log4j.Logger; 70 import org.objectstyle.cayenne.CayenneException; 71 import org.objectstyle.cayenne.dba.TypesMapping; 72 import org.objectstyle.cayenne.map.DbAttribute; 73 import org.objectstyle.cayenne.validation.BeanValidationFailure; 74 import org.objectstyle.cayenne.validation.ValidationResult; 75 76 79 public class ByteArrayType extends AbstractType { 80 private static Logger logObj = Logger.getLogger(ByteArrayType.class); 81 82 private static final int BUF_SIZE = 8 * 1024; 83 private static final byte[] EMPTY_BYTES = new byte[0]; 84 85 protected boolean trimmingBytes; 86 protected boolean usingBlobs; 87 88 92 public static byte[] trimBytes(byte[] bytes) { 93 int bytesToTrim = 0; 94 for (int i = bytes.length - 1; i >= 0; i--) { 95 if (bytes[i] != 0) { 96 bytesToTrim = bytes.length - 1 - i; 97 break; 98 } 99 } 100 101 if (bytesToTrim == 0) { 102 return bytes; 103 } 104 105 byte[] dest = new byte[bytes.length - bytesToTrim]; 106 System.arraycopy(bytes, 0, dest, 0, dest.length); 107 return dest; 108 } 109 110 public ByteArrayType(boolean trimmingBytes, boolean usingBlobs) { 111 this.usingBlobs = usingBlobs; 112 this.trimmingBytes = trimmingBytes; 113 } 114 115 public String getClassName() { 116 return "byte[]"; 117 } 118 119 124 public boolean validateProperty( 125 Object source, 126 String property, 127 Object value, 128 DbAttribute dbAttribute, 129 ValidationResult validationResult) { 130 131 if (!(value instanceof byte[])) { 132 return true; 133 } 134 135 if (dbAttribute.getMaxLength() <= 0) { 136 return true; 137 } 138 139 byte[] bytes = (byte[]) value; 140 if (bytes.length > dbAttribute.getMaxLength()) { 141 String message = 142 "\"" 143 + property 144 + "\" exceeds maximum allowed length (" 145 + dbAttribute.getMaxLength() 146 + " bytes): " 147 + bytes.length; 148 validationResult.addFailure( 149 new BeanValidationFailure(source, property, message)); 150 return false; 151 } 152 153 return true; 154 } 155 156 public Object materializeObject(ResultSet rs, int index, int type) 157 throws Exception { 158 159 byte[] bytes = null; 160 161 if (type == Types.BLOB) { 162 bytes = 163 (isUsingBlobs()) 164 ? readBlob(rs.getBlob(index)) 165 : readBinaryStream(rs, index); 166 } else { 167 bytes = rs.getBytes(index); 168 169 if (bytes != null && type == Types.BINARY && isTrimmingBytes()) { 171 bytes = trimBytes(bytes); 172 } 173 } 174 175 return bytes; 176 } 177 178 public Object materializeObject(CallableStatement cs, int index, int type) 179 throws Exception { 180 181 byte[] bytes = null; 182 183 if (type == Types.BLOB) { 184 if (!isUsingBlobs()) { 185 throw new CayenneException("Binary streams are not supported in stored procedure parameters."); 186 } 187 bytes = readBlob(cs.getBlob(index)); 188 } else { 189 190 bytes = cs.getBytes(index); 191 192 if (bytes != null && type == Types.BINARY && isTrimmingBytes()) { 194 bytes = trimBytes(bytes); 195 } 196 } 197 198 return bytes; 199 } 200 201 public void setJdbcObject( 202 PreparedStatement st, 203 Object val, 204 int pos, 205 int type, 206 int precision) 207 throws Exception { 208 209 if (type == Types.BLOB) { 212 st.setBytes(pos, (byte[]) val); 213 } else { 214 try { 215 super.setJdbcObject(st, val, pos, type, precision); 216 } 217 catch(Exception ex) { 218 logObj.warn("bad type: " + TypesMapping.getSqlNameByType(type), ex); 219 throw ex; 220 } 221 } 222 } 223 224 protected byte[] readBlob(Blob blob) throws IOException , SQLException { 225 if (blob == null) { 226 return null; 227 } 228 229 if (blob.length() > Integer.MAX_VALUE) { 231 throw new IllegalArgumentException ( 232 "BLOB is too big to be read as byte[] in memory: " 233 + blob.length()); 234 } 235 236 int size = (int) blob.length(); 237 if(size == 0) { 238 return EMPTY_BYTES; 239 } 240 241 int bufSize = (size < BUF_SIZE) ? size : BUF_SIZE; 242 InputStream in = blob.getBinaryStream(); 243 return (in != null) 244 ? readValueStream( 245 new BufferedInputStream (in, bufSize), 246 size, 247 bufSize) 248 : null; 249 } 250 251 protected byte[] readBinaryStream(ResultSet rs, int index) 252 throws IOException , SQLException { 253 InputStream in = rs.getBinaryStream(index); 254 return (in != null) ? readValueStream(in, -1, BUF_SIZE) : null; 255 } 256 257 protected byte[] readValueStream( 258 InputStream in, 259 int streamSize, 260 int bufSize) 261 throws IOException { 262 263 byte[] buf = new byte[bufSize]; 264 int read; 265 ByteArrayOutputStream out = 266 (streamSize > 0) 267 ? new ByteArrayOutputStream (streamSize) 268 : new ByteArrayOutputStream (); 269 270 try { 271 while ((read = in.read(buf, 0, bufSize)) >= 0) { 272 out.write(buf, 0, read); 273 } 274 return out.toByteArray(); 275 } finally { 276 in.close(); 277 } 278 } 279 280 284 public boolean isUsingBlobs() { 285 return usingBlobs; 286 } 287 288 public void setUsingBlobs(boolean usingBlobs) { 289 this.usingBlobs = usingBlobs; 290 } 291 292 public boolean isTrimmingBytes() { 293 return trimmingBytes; 294 } 295 296 public void setTrimmingBytes(boolean trimingBytes) { 297 this.trimmingBytes = trimingBytes; 298 } 299 } 300 | Popular Tags |