001: /*
002: * Copyright 2004 (C) TJDO.
003: * All rights reserved.
004: *
005: * This software is distributed under the terms of the TJDO License version 1.0.
006: * See the terms of the TJDO License in the documentation provided with this software.
007: *
008: * $Id: OracleBlobMapping.java,v 1.3 2004/03/30 06:15:56 jackknifebarber Exp $
009: */
010: package com.triactive.jdo.store;
011:
012: import com.triactive.jdo.PersistenceManager;
013: import com.triactive.jdo.StateManager;
014: import java.io.InputStream;
015: import java.io.OutputStream;
016: import java.io.IOException;
017: import java.sql.Connection;
018: import java.sql.PreparedStatement;
019: import java.sql.ResultSet;
020: import java.sql.SQLException;
021: import java.sql.Types;
022: import javax.jdo.JDODataStoreException;
023: import javax.jdo.JDOFatalInternalException;
024: import oracle.sql.BLOB;
025: import org.apache.log4j.Category;
026:
027: public class OracleBlobMapping extends ByteArrayMapping implements
028: PostInsertProcessing, PostUpdateProcessing {
029: private static final Category LOG = Category
030: .getInstance(OracleBlobMapping.class);
031:
032: private final ClassBaseTable table;
033: private ColumnMapping idMapping = null;
034: private String fetchStmt = null;
035: private String updateStmt = null;
036:
037: public OracleBlobMapping(DatabaseAdapter dba, Class type) {
038: super (dba, type);
039:
040: this .table = null;
041: }
042:
043: public OracleBlobMapping(Column col) {
044: super (col);
045:
046: this .table = null;
047: }
048:
049: public OracleBlobMapping(ClassBaseTable table,
050: int relativeFieldNumber) {
051: super (table.newColumn(relativeFieldNumber));
052:
053: col.setUnlimitedLength();
054:
055: this .table = table;
056: }
057:
058: private synchronized void initialize() {
059: if (idMapping == null) {
060: if (table == null)
061: throw new JDOFatalInternalException(
062: "Not mapped to class base table: " + this );
063:
064: idMapping = table.getIDMapping();
065:
066: FetchStatement stmt = new FetchStatement(table);
067: stmt.select(getColumn());
068: stmt.andCondition(stmt.referenceColumn(idMapping
069: .getColumn())
070: + " = ?");
071:
072: fetchStmt = stmt.toString() + " FOR UPDATE";
073:
074: updateStmt = "UPDATE " + table.getName() + " SET "
075: + col.getName() + " = NULL WHERE "
076: + idMapping.getColumn().getName() + " = ?";
077:
078: }
079: }
080:
081: protected TypeInfo getTypeInfo() {
082: return dba.getTypeInfo(Types.BLOB);
083: }
084:
085: public String getSQLInsertionValue() {
086: return "EMPTY_BLOB()";
087: }
088:
089: public String getSQLUpdateValue() {
090: return "EMPTY_BLOB()";
091: }
092:
093: public void setObject(PersistenceManager pm, PreparedStatement ps,
094: int param, Object value) {
095: // No-op. Statement text includes "EMPTY_BLOB()" instead of "?"
096: }
097:
098: public Object getObject(PersistenceManager pm, ResultSet rs,
099: int param) {
100: byte[] value = null;
101:
102: try {
103: BLOB blob = (BLOB) rs.getBlob(param);
104:
105: if (!rs.wasNull() && blob != null) {
106: int len = (int) Math.min(blob.length(),
107: Integer.MAX_VALUE);
108: value = new byte[len];
109:
110: try {
111: InputStream in = blob.getBinaryStream();
112:
113: try {
114: int off = 0;
115:
116: while (off < len) {
117: int n = in.read(value, off, len - off);
118:
119: if (n < 0)
120: throw new SQLException(
121: "Premature end-of-BLOB, expected "
122: + len + ", got " + off);
123:
124: off += n;
125: }
126: } finally {
127: in.close();
128: }
129: } catch (IOException e) {
130: throw new JDODataStoreException(
131: "Error reading Oracle BLOB object: param = "
132: + param, e);
133: }
134: }
135: } catch (SQLException e) {
136: throw dba.newDataStoreException(
137: "Can't get byte[] result: param = " + param, e);
138: }
139:
140: return value;
141: }
142:
143: public void postInsert(StateManager sm, Connection conn,
144: Object value) {
145: postUpdate(sm, conn, value);
146: }
147:
148: /**
149: * Retrieve the empty BLOB locator created by the insert statement
150: * and write out the current BLOB field value to the Oracle BLOB object
151: */
152: public void postUpdate(StateManager sm, Connection conn,
153: Object value) {
154: initialize();
155:
156: byte[] ba = (byte[]) value;
157:
158: /*
159: * Need to do this more efficiently, but it's going to take a refactor
160: * of the way the whole getSQLInsertionValue()/getSQLUpdateValue()
161: * stuff works.
162: */
163: if (ba == null)
164: updateAsNull(sm, conn);
165: else
166: updateWithValue(sm, conn, ba);
167: }
168:
169: private void updateAsNull(StateManager sm, Connection conn) {
170: PersistenceManager pm = sm.getPersistenceManager();
171:
172: try {
173: PreparedStatement ps = conn.prepareStatement(updateStmt);
174:
175: try {
176: Object id = sm.getObjectId();
177: idMapping.setObject(pm, ps, 1, id);
178:
179: long startTime = System.currentTimeMillis();
180:
181: ps.executeUpdate();
182:
183: if (LOG.isDebugEnabled())
184: LOG.debug("Time = "
185: + (System.currentTimeMillis() - startTime)
186: + " ms: " + updateStmt);
187: } finally {
188: ps.close();
189: }
190: } catch (SQLException e) {
191: throw dba.newDataStoreException("BLOB update failed: "
192: + updateStmt, e);
193: }
194: }
195:
196: private void updateWithValue(StateManager sm, Connection conn,
197: byte[] value) {
198: PersistenceManager pm = sm.getPersistenceManager();
199:
200: try {
201: PreparedStatement ps = conn.prepareStatement(fetchStmt);
202:
203: try {
204: Object id = sm.getObjectId();
205: idMapping.setObject(pm, ps, 1, id);
206:
207: long startTime = System.currentTimeMillis();
208:
209: ResultSet rs = ps.executeQuery();
210:
211: try {
212: if (LOG.isDebugEnabled())
213: LOG
214: .debug("Time = "
215: + (System.currentTimeMillis() - startTime)
216: + " ms: " + fetchStmt);
217:
218: if (!rs.next())
219: throw new ObjectNotFoundException(
220: "No such database row", sm.getObject());
221:
222: BLOB blob = (BLOB) rs.getBlob(1);
223:
224: try {
225: OutputStream out = blob.getBinaryOutputStream();
226:
227: try {
228: out.write(value);
229: } finally {
230: out.close();
231: }
232: } catch (IOException e) {
233: throw new JDODataStoreException(
234: "Error writing Oracle BLOB object", e);
235: }
236: } finally {
237: rs.close();
238: }
239: } finally {
240: ps.close();
241: }
242: } catch (SQLException e) {
243: throw dba.newDataStoreException("BLOB update failed: "
244: + fetchStmt, e);
245: }
246: }
247: }
|