001: /*
002: * Copyright 2002-2006 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 javax.jdo.JDOException;
020: import javax.jdo.PersistenceManager;
021:
022: import org.aopalliance.intercept.MethodInterceptor;
023: import org.aopalliance.intercept.MethodInvocation;
024:
025: import org.springframework.transaction.support.TransactionSynchronizationManager;
026:
027: /**
028: * This interceptor binds a new JDO PersistenceManager to the thread before a method
029: * call, closing and removing it afterwards in case of any method outcome.
030: * If there already is a pre-bound PersistenceManager (e.g. from JdoTransactionManager,
031: * or from a surrounding JDO-intercepted method), the interceptor simply participates in it.
032: *
033: * <p>Application code must retrieve a JDO PersistenceManager via the
034: * <code>PersistenceManagerFactoryUtils.getPersistenceManager</code> method,
035: * to be able to detect a thread-bound PersistenceManager. It is preferable to use
036: * <code>getPersistenceManager</code> with allowCreate=false, if the code relies on
037: * the interceptor to provide proper PersistenceManager handling. Typically, the code
038: * will look like as follows:
039: *
040: * <pre>
041: * public void doSomeDataAccessAction() {
042: * PersistenceManager pm = PersistenceManagerFactoryUtils.getPersistenceManager(this.pmf, false);
043: * ...
044: * }</pre>
045: *
046: * <p>Note that this interceptor automatically translates JDOExceptions, via
047: * delegating to the <code>PersistenceManagerFactoryUtils.convertJdoAccessException</code>
048: * method that converts them to exceptions that are compatible with the
049: * <code>org.springframework.dao</code> exception hierarchy (like JdoTemplate does).
050: * This can be turned off if the raw exceptions are preferred.
051: *
052: * <p>This class can be considered a declarative alternative to JdoTemplate's
053: * callback approach. The advantages are:
054: * <ul>
055: * <li>no anonymous classes necessary for callback implementations;
056: * <li>the possibility to throw any application exceptions from within data access code.
057: * </ul>
058: *
059: * <p>The drawback is the dependency on interceptor configuration. However, note
060: * that this interceptor is usually <i>not</i> necessary in scenarios where the
061: * data access code always executes within transactions. A transaction will always
062: * have a thread-bound PersistenceManager in the first place, so adding this interceptor
063: * to the configuration just adds value when fine-tuning PersistenceManager settings
064: * like the flush mode - or when relying on exception translation.
065: *
066: * @author Juergen Hoeller
067: * @since 13.06.2003
068: * @see PersistenceManagerFactoryUtils#getPersistenceManager
069: * @see JdoTransactionManager
070: * @see JdoTemplate
071: */
072: public class JdoInterceptor extends JdoAccessor implements
073: MethodInterceptor {
074:
075: private boolean exceptionConversionEnabled = true;
076:
077: /**
078: * Set whether to convert any JDOException raised to a Spring DataAccessException,
079: * compatible with the <code>org.springframework.dao</code> exception hierarchy.
080: * <p>Default is "true". Turn this flag off to let the caller receive raw exceptions
081: * as-is, without any wrapping.
082: * @see org.springframework.dao.DataAccessException
083: */
084: public void setExceptionConversionEnabled(
085: boolean exceptionConversionEnabled) {
086: this .exceptionConversionEnabled = exceptionConversionEnabled;
087: }
088:
089: public Object invoke(MethodInvocation methodInvocation)
090: throws Throwable {
091: boolean existingTransaction = false;
092: PersistenceManager pm = PersistenceManagerFactoryUtils
093: .getPersistenceManager(getPersistenceManagerFactory(),
094: true);
095: if (TransactionSynchronizationManager
096: .hasResource(getPersistenceManagerFactory())) {
097: logger
098: .debug("Found thread-bound PersistenceManager for JDO interceptor");
099: existingTransaction = true;
100: } else {
101: logger
102: .debug("Using new PersistenceManager for JDO interceptor");
103: TransactionSynchronizationManager.bindResource(
104: getPersistenceManagerFactory(),
105: new PersistenceManagerHolder(pm));
106: }
107: try {
108: Object retVal = methodInvocation.proceed();
109: flushIfNecessary(pm, existingTransaction);
110: return retVal;
111: } catch (JDOException ex) {
112: if (this .exceptionConversionEnabled) {
113: throw convertJdoAccessException(ex);
114: } else {
115: throw ex;
116: }
117: } finally {
118: if (existingTransaction) {
119: logger
120: .debug("Not closing pre-bound JDO PersistenceManager after interceptor");
121: } else {
122: TransactionSynchronizationManager
123: .unbindResource(getPersistenceManagerFactory());
124: PersistenceManagerFactoryUtils
125: .releasePersistenceManager(pm,
126: getPersistenceManagerFactory());
127: }
128: }
129: }
130:
131: }
|