001: /*
002: * Copyright 2002-2007 the original author or authors.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.springframework.orm.jdo;
018:
019: import java.sql.SQLException;
020: import java.util.Collection;
021:
022: import javax.jdo.JDOException;
023: import javax.jdo.PersistenceManager;
024: import javax.jdo.Query;
025: import javax.jdo.Transaction;
026:
027: import org.springframework.dao.DataAccessException;
028: import org.springframework.jdbc.datasource.ConnectionHandle;
029: import org.springframework.transaction.TransactionDefinition;
030: import org.springframework.transaction.TransactionException;
031:
032: /**
033: * SPI strategy that encapsulates certain functionality that standard JDO 1.0 does
034: * not offer despite being relevant in the context of O/R mapping, such as access to
035: * the underlying JDBC Connection and explicit flushing of changes to the database.
036: * Also defines various further hooks that even go beyond standard JDO 2.0.
037: *
038: * <p>To be implemented for specific JDO providers such as JPOX, Kodo, Lido,
039: * Versant Open Access. Almost every O/R-based JDO provider offers proprietary
040: * means to access the underlying JDBC Connection and to explicitly flush changes;
041: * hence, this would be the minimum functionality level that should be supported.
042: *
043: * <p>JDO 2.0 defines standard ways for most of the functionality covered here.
044: * Hence, Spring's DefaultJdoDialect uses the corresponding JDO 2.0 methods
045: * by default, to be overridden in a vendor-specific fashion if necessary.
046: * Vendor-specific subclasses of DefaultJdoDialect are still required for special
047: * transaction semantics and more sophisticated exception translation (if needed).
048: *
049: * <p>In general, it is recommended to derive from DefaultJdoDialect instead of
050: * implementing this interface directly. This allows for inheriting common
051: * behavior (present and future) from DefaultJdoDialect, only overriding
052: * specific hooks to plug in concrete vendor-specific behavior.
053: *
054: * @author Juergen Hoeller
055: * @since 02.11.2003
056: * @see JdoTransactionManager#setJdoDialect
057: * @see JdoAccessor#setJdoDialect
058: * @see DefaultJdoDialect
059: */
060: public interface JdoDialect {
061:
062: //-------------------------------------------------------------------------
063: // Hooks for transaction management (used by JdoTransactionManager)
064: //-------------------------------------------------------------------------
065:
066: /**
067: * Begin the given JDO transaction, applying the semantics specified by the
068: * given Spring transaction definition (in particular, an isolation level
069: * and a timeout). Invoked by JdoTransactionManager on transaction begin.
070: * <p>An implementation can configure the JDO Transaction object and then
071: * invoke <code>begin</code>, or invoke a special begin method that takes,
072: * for example, an isolation level.
073: * <p>An implementation can also apply read-only flag and isolation level to the
074: * underlying JDBC Connection before beginning the transaction. In that case,
075: * a transaction data object can be returned that holds the previous isolation
076: * level (and possibly other data), to be reset in <code>cleanupTransaction</code>.
077: * <p>Implementations can also use the Spring transaction name, as exposed by the
078: * passed-in TransactionDefinition, to optimize for specific data access use cases
079: * (effectively using the current transaction name as use case identifier).
080: * @param transaction the JDO transaction to begin
081: * @param definition the Spring transaction definition that defines semantics
082: * @return an arbitrary object that holds transaction data, if any
083: * (to be passed into cleanupTransaction)
084: * @throws JDOException if thrown by JDO methods
085: * @throws SQLException if thrown by JDBC methods
086: * @throws TransactionException in case of invalid arguments
087: * @see #cleanupTransaction
088: * @see javax.jdo.Transaction#begin
089: * @see org.springframework.jdbc.datasource.DataSourceUtils#prepareConnectionForTransaction
090: */
091: Object beginTransaction(Transaction transaction,
092: TransactionDefinition definition) throws JDOException,
093: SQLException, TransactionException;
094:
095: /**
096: * Clean up the transaction via the given transaction data.
097: * Invoked by JdoTransactionManager on transaction cleanup.
098: * <p>An implementation can, for example, reset read-only flag and
099: * isolation level of the underlying JDBC Connection. Furthermore,
100: * an exposed data access use case can be reset here.
101: * @param transactionData arbitrary object that holds transaction data, if any
102: * (as returned by beginTransaction)
103: * @see #beginTransaction
104: * @see org.springframework.jdbc.datasource.DataSourceUtils#resetConnectionAfterTransaction
105: */
106: void cleanupTransaction(Object transactionData);
107:
108: /**
109: * Retrieve the JDBC Connection that the given JDO PersistenceManager uses underneath,
110: * if accessing a relational database. This method will just get invoked if actually
111: * needing access to the underlying JDBC Connection, usually within an active JDO
112: * transaction (for example, by JdoTransactionManager). The returned handle will
113: * be passed into the <code>releaseJdbcConnection</code> method when not needed anymore.
114: * <p>This strategy is necessary as JDO 1.0 does not provide a standard way to retrieve
115: * the underlying JDBC Connection (due to the fact that a JDO provider might not work
116: * with a relational database at all).
117: * <p>Implementations are encouraged to return an unwrapped Connection object, i.e.
118: * the Connection as they got it from the connection pool. This makes it easier for
119: * application code to get at the underlying native JDBC Connection, like an
120: * OracleConnection, which is sometimes necessary for LOB handling etc. We assume
121: * that calling code knows how to properly handle the returned Connection object.
122: * <p>In a simple case where the returned Connection will be auto-closed with the
123: * PersistenceManager or can be released via the Connection object itself, an
124: * implementation can return a SimpleConnectionHandle that just contains the
125: * Connection. If some other object is needed in <code>releaseJdbcConnection</code>,
126: * an implementation should use a special handle that references that other object.
127: * @param pm the current JDO PersistenceManager
128: * @param readOnly whether the Connection is only needed for read-only purposes
129: * @return a handle for the JDBC Connection, to be passed into
130: * <code>releaseJdbcConnection</code>, or <code>null</code>
131: * if no JDBC Connection can be retrieved
132: * @throws JDOException if thrown by JDO methods
133: * @throws SQLException if thrown by JDBC methods
134: * @see #releaseJdbcConnection
135: * @see org.springframework.jdbc.datasource.ConnectionHandle#getConnection
136: * @see org.springframework.jdbc.datasource.SimpleConnectionHandle
137: * @see JdoTransactionManager#setDataSource
138: * @see org.springframework.jdbc.support.nativejdbc.NativeJdbcExtractor
139: */
140: ConnectionHandle getJdbcConnection(PersistenceManager pm,
141: boolean readOnly) throws JDOException, SQLException;
142:
143: /**
144: * Release the given JDBC Connection, which has originally been retrieved
145: * via <code>getJdbcConnection</code>. This should be invoked in any case,
146: * to allow for proper release of the retrieved Connection handle.
147: * <p>An implementation might simply do nothing, if the Connection returned
148: * by <code>getJdbcConnection</code> will be implicitly closed when the JDO
149: * transaction completes or when the PersistenceManager is closed.
150: * @param conHandle the JDBC Connection handle to release
151: * @param pm the current JDO PersistenceManager
152: * @throws JDOException if thrown by JDO methods
153: * @throws SQLException if thrown by JDBC methods
154: * @see #getJdbcConnection
155: */
156: void releaseJdbcConnection(ConnectionHandle conHandle,
157: PersistenceManager pm) throws JDOException, SQLException;
158:
159: //-------------------------------------------------------------------------
160: // Hooks for special data access operations (used by JdoTemplate)
161: //-------------------------------------------------------------------------
162:
163: /**
164: * Detach a copy of the given persistent instance from the current JDO transaction,
165: * for use outside a JDO transaction (for example, as web form object).
166: * @param pm the current JDO PersistenceManager
167: * @param entity the persistent instance to detach
168: * @throws JDOException in case of errors
169: * @see javax.jdo.PersistenceManager#detachCopy(Object)
170: */
171: Object detachCopy(PersistenceManager pm, Object entity)
172: throws JDOException;
173:
174: /**
175: * Detach copies of the given persistent instances from the current JDO transaction,
176: * for use outside a JDO transaction (for example, as web form objects).
177: * @param pm the current JDO PersistenceManager
178: * @param entities the persistent instances to detach
179: * @throws JDOException in case of errors
180: * @see javax.jdo.PersistenceManager#detachCopyAll(java.util.Collection)
181: */
182: Collection detachCopyAll(PersistenceManager pm, Collection entities)
183: throws JDOException;
184:
185: /**
186: * Reattach the given detached instance (for example, a web form object) with
187: * the current JDO transaction, merging its changes into the current persistence
188: * instance that represents the corresponding entity.
189: * @param pm the current JDO PersistenceManager
190: * @param detachedEntity the detached instance to attach
191: * @return the corresponding persistent instance
192: * @throws JDOException in case of errors
193: * @see javax.jdo.PersistenceManager#makePersistent(Object)
194: */
195: Object attachCopy(PersistenceManager pm, Object detachedEntity)
196: throws JDOException;
197:
198: /**
199: * Reattach the given detached instances (for example, web form objects) with
200: * the current JDO transaction, merging their changes into the current persistence
201: * instances that represent the corresponding entities.
202: * @param pm the current JDO PersistenceManager
203: * @param detachedEntities the detached instances to reattach
204: * @return the corresponding persistent instances
205: * @throws JDOException in case of errors
206: * @see javax.jdo.PersistenceManager#makePersistentAll(java.util.Collection)
207: */
208: Collection attachCopyAll(PersistenceManager pm,
209: Collection detachedEntities) throws JDOException;
210:
211: /**
212: * Flush the given PersistenceManager, i.e. flush all changes (that have been
213: * applied to persistent objects) to the underlying database. This method will
214: * just get invoked when eager flushing is actually necessary, for example when
215: * JDBC access code needs to see changes within the same transaction.
216: * @param pm the current JDO PersistenceManager
217: * @throws JDOException in case of errors
218: * @see JdoAccessor#setFlushEager
219: */
220: void flush(PersistenceManager pm) throws JDOException;
221:
222: /**
223: * Create a new Query object for the given named query.
224: * @param pm the current JDO PersistenceManager
225: * @param entityClass a persistent class
226: * @param queryName the name of the query
227: * @return the Query object
228: * @throws JDOException in case of errors
229: * @see javax.jdo.PersistenceManager#newNamedQuery(Class, String)
230: */
231: Query newNamedQuery(PersistenceManager pm, Class entityClass,
232: String queryName) throws JDOException;
233:
234: /**
235: * Apply the given timeout to the given JDO query object.
236: * <p>Invoked by JdoTemplate with the remaining time of a specified
237: * transaction timeout, if any.
238: * @param query the JDO query object to apply the timeout to
239: * @param timeout the timeout value to apply
240: * @throws JDOException if thrown by JDO methods
241: * @see JdoTemplate#prepareQuery
242: */
243: void applyQueryTimeout(Query query, int timeout)
244: throws JDOException;
245:
246: //-----------------------------------------------------------------------------------
247: // Hook for exception translation (used by JdoTransactionManager and JdoTemplate)
248: //-----------------------------------------------------------------------------------
249:
250: /**
251: * Translate the given JDOException to a corresponding exception from Spring's
252: * generic DataAccessException hierarchy. An implementation should apply
253: * PersistenceManagerFactoryUtils' standard exception translation if can't do
254: * anything more specific.
255: * <p>Of particular importance is the correct translation to
256: * DataIntegrityViolationException, for example on constraint violation.
257: * Unfortunately, standard JDO does not allow for portable detection of this.
258: * <p>Can use a SQLExceptionTranslator for translating underlying SQLExceptions
259: * in a database-specific fashion.
260: * @param ex the JDOException thrown
261: * @return the corresponding DataAccessException (must not be <code>null</code>)
262: * @see JdoAccessor#convertJdoAccessException
263: * @see JdoTransactionManager#convertJdoAccessException
264: * @see PersistenceManagerFactoryUtils#convertJdoAccessException
265: * @see org.springframework.dao.DataIntegrityViolationException
266: * @see org.springframework.jdbc.support.SQLExceptionTranslator
267: */
268: DataAccessException translateException(JDOException ex);
269:
270: }
|