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: AbstractSetStore.java,v 1.9 2004/01/18 03:01:06 jackknifebarber Exp $
009: */
010:
011: package com.triactive.jdo.store;
012:
013: import com.triactive.jdo.PersistenceManager;
014: import com.triactive.jdo.StateManager;
015: import java.sql.Connection;
016: import java.sql.PreparedStatement;
017: import java.sql.ResultSet;
018: import java.sql.SQLException;
019: import java.util.ArrayList;
020: import java.util.Collection;
021: import java.util.Iterator;
022: import java.util.Set;
023: import javax.jdo.JDODataStoreException;
024: import javax.jdo.JDOHelper;
025: import javax.jdo.JDOUserException;
026: import org.apache.log4j.Category;
027:
028: abstract class AbstractSetStore implements SetStore {
029: private static final Category LOG = Category
030: .getInstance(AbstractSetStore.class);
031:
032: protected Table setTable;
033: protected String setName;
034: protected StoreManager storeMgr;
035: protected DatabaseAdapter dba;
036: protected ColumnMapping ownerMapping;
037: protected ColumnMapping elementMapping;
038: protected Column ownerColumn;
039: protected Column elementColumn;
040: protected Class elementType;
041: protected boolean elementsAreEmbedded;
042: protected String loadStmt;
043: protected String sizeStmt;
044: protected String containsStmt;
045: protected String addStmt;
046: protected String removeStmt;
047: protected String clearStmt;
048: protected int[] prefetchFieldNumbers;
049: protected ColumnMapping[] prefetchFieldMappings;
050:
051: protected AbstractSetStore() {
052: }
053:
054: public StoreManager getStoreManager() {
055: return storeMgr;
056: }
057:
058: public Class getElementType() {
059: return elementType;
060: }
061:
062: public boolean allowsNulls() {
063: return elementColumn.isNullable();
064: }
065:
066: public Query.ResultObjectFactory newResultObjectFactory(
067: StateManager sm, QueryStatement stmt) {
068: PersistenceManager pm = sm.getPersistenceManager();
069:
070: if (stmt.getDistinctResults() || prefetchFieldMappings == null)
071: return new PersistentIDROF(pm, elementType);
072: else {
073: int[] columnNumbersByField = new int[prefetchFieldMappings.length];
074:
075: for (int i = 0; i < prefetchFieldMappings.length; ++i) {
076: ColumnMapping m = prefetchFieldMappings[i];
077:
078: if (m != null)
079: columnNumbersByField[i] = stmt
080: .select(m.getColumn());
081: }
082:
083: return new PersistentIDROF(pm, elementType,
084: prefetchFieldNumbers, prefetchFieldMappings,
085: columnNumbersByField);
086: }
087: }
088:
089: public QueryStatement getExistsSubquery(
090: QueryStatement.QueryColumn ownerIDColumn,
091: SQLIdentifier setRangeVar) {
092: QueryStatement stmt = dba.newQueryStatement(setTable,
093: setRangeVar);
094:
095: SQLExpression ownerExpr = new ObjectExpression(stmt,
096: ownerIDColumn);
097: SQLExpression ownerInSetExpr = new ObjectExpression(stmt, stmt
098: .getColumn(setRangeVar, ownerColumn));
099:
100: stmt.andCondition(ownerExpr.eq(ownerInSetExpr));
101:
102: stmt.select(setRangeVar, elementColumn);
103:
104: return stmt;
105: }
106:
107: protected boolean validateElementForReading(StateManager sm,
108: Object element) {
109: if (!elementsAreEmbedded) {
110: PersistenceManager pm = sm.getPersistenceManager();
111:
112: if (!JDOHelper.isPersistent(element)
113: || pm != JDOHelper.getPersistenceManager(element))
114: return false;
115: }
116:
117: return true;
118: }
119:
120: protected void validateElementForWriting(StateManager sm,
121: Object element) {
122: if (!elementsAreEmbedded) {
123: PersistenceManager pm = sm.getPersistenceManager();
124:
125: if (!JDOHelper.isPersistent(element))
126: pm.makePersistent(element);
127: else if (pm != JDOHelper.getPersistenceManager(element))
128: throw new JDOUserException(
129: "Can't write element from a different persistence manager",
130: JDOHelper.getObjectId(element));
131: }
132: }
133:
134: public Collection load(StateManager sm) {
135: ArrayList contents = new ArrayList();
136: PersistenceManager pm = sm.getPersistenceManager();
137:
138: try {
139: Connection conn = pm.getConnection(false);
140:
141: try {
142: PreparedStatement ps = conn.prepareStatement(loadStmt);
143:
144: try {
145: ownerMapping.setObject(pm, ps, 1, sm.getObject());
146:
147: long startTime = System.currentTimeMillis();
148:
149: ResultSet rs = ps.executeQuery();
150:
151: try {
152: if (LOG.isDebugEnabled())
153: LOG
154: .debug("Time = "
155: + (System
156: .currentTimeMillis() - startTime)
157: + " ms: " + loadStmt);
158:
159: while (rs.next())
160: contents.add(elementMapping.getObject(pm,
161: rs, 1));
162: } finally {
163: rs.close();
164: }
165: } finally {
166: ps.close();
167: }
168: } finally {
169: pm.releaseConnection(conn);
170: }
171: } catch (SQLException e) {
172: throw dba.newDataStoreException("Load request failed: "
173: + loadStmt, e);
174: }
175:
176: return contents;
177: }
178:
179: public int size(StateManager sm) {
180: int numRows;
181: PersistenceManager pm = sm.getPersistenceManager();
182:
183: try {
184: Connection conn = pm.getConnection(false);
185:
186: try {
187: PreparedStatement ps = conn.prepareStatement(sizeStmt);
188:
189: try {
190: ownerMapping.setObject(pm, ps, 1, sm.getObject());
191:
192: long startTime = System.currentTimeMillis();
193:
194: ResultSet rs = ps.executeQuery();
195:
196: try {
197: if (LOG.isDebugEnabled())
198: LOG
199: .debug("Time = "
200: + (System
201: .currentTimeMillis() - startTime)
202: + " ms: " + sizeStmt);
203:
204: if (!rs.next())
205: throw new JDODataStoreException(
206: "Size request returned no result row: "
207: + sizeStmt);
208:
209: numRows = rs.getInt(1);
210:
211: storeMgr.logSQLWarnings(rs);
212: } finally {
213: rs.close();
214: }
215: } finally {
216: ps.close();
217: }
218: } finally {
219: pm.releaseConnection(conn);
220: }
221: } catch (SQLException e) {
222: throw dba.newDataStoreException("Size request failed: "
223: + sizeStmt, e);
224: }
225:
226: return numRows;
227: }
228:
229: public boolean isEmpty(StateManager sm) {
230: /* There are probably more efficient ways of doing this in SQL. */
231: return size(sm) == 0;
232: }
233:
234: public boolean contains(StateManager sm, Object element) {
235: if (!validateElementForReading(sm, element))
236: return false;
237:
238: boolean retval;
239: PersistenceManager pm = sm.getPersistenceManager();
240:
241: try {
242: Connection conn = pm.getConnection(false);
243:
244: try {
245: PreparedStatement ps = conn
246: .prepareStatement(containsStmt);
247:
248: try {
249: ownerMapping.setObject(pm, ps, 1, sm.getObject());
250: elementMapping.setObject(pm, ps, 2, element);
251:
252: long startTime = System.currentTimeMillis();
253:
254: ResultSet rs = ps.executeQuery();
255:
256: try {
257: if (LOG.isDebugEnabled())
258: LOG
259: .debug("Time = "
260: + (System
261: .currentTimeMillis() - startTime)
262: + " ms: " + containsStmt);
263:
264: retval = rs.next();
265:
266: storeMgr.logSQLWarnings(rs);
267: } finally {
268: rs.close();
269: }
270: } finally {
271: ps.close();
272: }
273: } finally {
274: pm.releaseConnection(conn);
275: }
276: } catch (SQLException e) {
277: throw dba.newDataStoreException(
278: "Request failed to check if set contains an element: "
279: + containsStmt, e);
280: }
281:
282: return retval;
283: }
284:
285: public boolean add(StateManager sm, Object element) {
286: validateElementForWriting(sm, element);
287:
288: boolean modified = false;
289: PersistenceManager pm = sm.getPersistenceManager();
290:
291: try {
292: Connection conn = pm.getConnection(true);
293:
294: try {
295: PreparedStatement ps = conn.prepareStatement(addStmt);
296:
297: try {
298: ownerMapping.setObject(pm, ps, 1, sm.getObject());
299: elementMapping.setObject(pm, ps, 2, element);
300:
301: long startTime = System.currentTimeMillis();
302:
303: ps.executeUpdate();
304:
305: if (LOG.isDebugEnabled())
306: LOG
307: .debug("Time = "
308: + (System.currentTimeMillis() - startTime)
309: + " ms: " + addStmt);
310:
311: modified = true;
312: } finally {
313: ps.close();
314: }
315: } finally {
316: pm.releaseConnection(conn);
317: }
318: } catch (SQLException e) {
319: if (!contains(sm, element))
320: throw dba.newDataStoreException("Add request failed: "
321: + addStmt, e);
322: }
323:
324: return modified;
325: }
326:
327: public boolean addAll(StateManager sm, Collection elements) {
328: boolean modified = false;
329: Iterator i = elements.iterator();
330:
331: while (i.hasNext()) {
332: if (add(sm, i.next()))
333: modified = true;
334: }
335:
336: return modified;
337: }
338:
339: public boolean remove(StateManager sm, Object element) {
340: if (!validateElementForReading(sm, element))
341: return false;
342:
343: boolean modified = false;
344: PersistenceManager pm = sm.getPersistenceManager();
345:
346: try {
347: Connection conn = pm.getConnection(true);
348:
349: try {
350: PreparedStatement ps = conn
351: .prepareStatement(removeStmt);
352:
353: try {
354: ownerMapping.setObject(pm, ps, 1, sm.getObject());
355: elementMapping.setObject(pm, ps, 2, element);
356:
357: long startTime = System.currentTimeMillis();
358:
359: int rowsDeleted = ps.executeUpdate();
360:
361: if (LOG.isDebugEnabled())
362: LOG
363: .debug("Time = "
364: + (System.currentTimeMillis() - startTime)
365: + " ms: " + removeStmt);
366:
367: modified = rowsDeleted == 1;
368: } finally {
369: ps.close();
370: }
371: } finally {
372: pm.releaseConnection(conn);
373: }
374: } catch (SQLException e) {
375: if (contains(sm, element))
376: throw dba.newDataStoreException(
377: "Remove request failed: " + removeStmt, e);
378: }
379:
380: return modified;
381: }
382:
383: public void clear(StateManager sm) {
384: PersistenceManager pm = sm.getPersistenceManager();
385:
386: try {
387: Connection conn = pm.getConnection(true);
388:
389: try {
390: PreparedStatement ps = conn.prepareStatement(clearStmt);
391:
392: try {
393: ownerMapping.setObject(pm, ps, 1, sm.getObject());
394:
395: long startTime = System.currentTimeMillis();
396:
397: ps.executeUpdate();
398:
399: if (LOG.isDebugEnabled())
400: LOG
401: .debug("Time = "
402: + (System.currentTimeMillis() - startTime)
403: + " ms: " + clearStmt);
404: } finally {
405: ps.close();
406: }
407: } finally {
408: pm.releaseConnection(conn);
409: }
410: } catch (SQLException e) {
411: throw dba.newDataStoreException("Clear request failed: "
412: + clearStmt, e);
413: }
414: }
415: }
|