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: import javax.jdo.PersistenceManagerFactory;
022:
023: import org.apache.commons.logging.Log;
024: import org.apache.commons.logging.LogFactory;
025:
026: import org.springframework.beans.factory.InitializingBean;
027: import org.springframework.dao.DataAccessException;
028:
029: /**
030: * Base class for JdoTemplate and JdoInterceptor, defining common
031: * properties such as PersistenceManagerFactory and flushing behavior.
032: *
033: * <p>Note: With JDO, modifications to persistent objects are just possible
034: * within a transaction (in contrast to Hibernate). Therefore, eager flushing
035: * will just get applied when in a transaction. Furthermore, there is no
036: * explicit notion of flushing never, as this would not imply a performance
037: * gain due to JDO's field interception mechanism (which doesn't involve
038: * the overhead of snapshot comparisons).
039: *
040: * <p>Eager flushing is just available for specific JDO providers.
041: * You need to a corresponding JdoDialect to make eager flushing work.
042: *
043: * <p>Not intended to be used directly. See JdoTemplate and JdoInterceptor.
044: *
045: * @author Juergen Hoeller
046: * @since 02.11.2003
047: * @see JdoTemplate
048: * @see JdoInterceptor
049: * @see #setFlushEager
050: */
051: public abstract class JdoAccessor implements InitializingBean {
052:
053: /** Logger available to subclasses */
054: protected final Log logger = LogFactory.getLog(getClass());
055:
056: private PersistenceManagerFactory persistenceManagerFactory;
057:
058: private JdoDialect jdoDialect;
059:
060: private boolean flushEager = false;
061:
062: /**
063: * Set the JDO PersistenceManagerFactory that should be used to create
064: * PersistenceManagers.
065: */
066: public void setPersistenceManagerFactory(
067: PersistenceManagerFactory pmf) {
068: this .persistenceManagerFactory = pmf;
069: }
070:
071: /**
072: * Return the JDO PersistenceManagerFactory that should be used to create
073: * PersistenceManagers.
074: */
075: public PersistenceManagerFactory getPersistenceManagerFactory() {
076: return persistenceManagerFactory;
077: }
078:
079: /**
080: * Set the JDO dialect to use for this accessor.
081: * <p>The dialect object can be used to retrieve the underlying JDBC
082: * connection and to eagerly flush changes to the database.
083: * <p>Default is a DefaultJdoDialect based on the PersistenceManagerFactory's
084: * underlying DataSource, if any.
085: */
086: public void setJdoDialect(JdoDialect jdoDialect) {
087: this .jdoDialect = jdoDialect;
088: }
089:
090: /**
091: * Return the JDO dialect to use for this accessor.
092: * <p>Creates a default one for the specified PersistenceManagerFactory if none set.
093: */
094: public JdoDialect getJdoDialect() {
095: if (this .jdoDialect == null) {
096: this .jdoDialect = new DefaultJdoDialect();
097: }
098: return this .jdoDialect;
099: }
100:
101: /**
102: * Set if this accessor should flush changes to the database eagerly.
103: * <p>Eager flushing leads to immediate synchronization with the database,
104: * even if in a transaction. This causes inconsistencies to show up and throw
105: * a respective exception immediately, and JDBC access code that participates
106: * in the same transaction will see the changes as the database is already
107: * aware of them then. But the drawbacks are:
108: * <ul>
109: * <li>additional communication roundtrips with the database, instead of a
110: * single batch at transaction commit;
111: * <li>the fact that an actual database rollback is needed if the JDO
112: * transaction rolls back (due to already submitted SQL statements).
113: * </ul>
114: */
115: public void setFlushEager(boolean flushEager) {
116: this .flushEager = flushEager;
117: }
118:
119: /**
120: * Return if this accessor should flush changes to the database eagerly.
121: */
122: public boolean isFlushEager() {
123: return flushEager;
124: }
125:
126: /**
127: * Eagerly initialize the JDO dialect, creating a default one
128: * for the specified PersistenceManagerFactory if none set.
129: */
130: public void afterPropertiesSet() {
131: if (getPersistenceManagerFactory() == null) {
132: throw new IllegalArgumentException(
133: "persistenceManagerFactory is required");
134: }
135: // Build default JdoDialect if none explicitly specified.
136: if (this .jdoDialect == null) {
137: this .jdoDialect = new DefaultJdoDialect(
138: getPersistenceManagerFactory()
139: .getConnectionFactory());
140: }
141: }
142:
143: /**
144: * Flush the given JDO persistence manager if necessary.
145: * @param pm the current JDO PersistenceManager
146: * @param existingTransaction if executing within an existing transaction
147: * (within an existing JDO PersistenceManager that won't be closed immediately)
148: * @throws JDOException in case of JDO flushing errors
149: */
150: protected void flushIfNecessary(PersistenceManager pm,
151: boolean existingTransaction) throws JDOException {
152: if (isFlushEager()) {
153: logger.debug("Eagerly flushing JDO persistence manager");
154: getJdoDialect().flush(pm);
155: }
156: }
157:
158: /**
159: * Convert the given JDOException to an appropriate exception from the
160: * <code>org.springframework.dao</code> hierarchy.
161: * <p>Default implementation delegates to the JdoDialect.
162: * May be overridden in subclasses.
163: * @param ex JDOException that occured
164: * @return the corresponding DataAccessException instance
165: * @see JdoDialect#translateException
166: */
167: public DataAccessException convertJdoAccessException(JDOException ex) {
168: return getJdoDialect().translateException(ex);
169: }
170:
171: }
|