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.toplink;
018:
019: import java.sql.SQLException;
020:
021: import oracle.toplink.exceptions.DatabaseException;
022: import oracle.toplink.exceptions.TopLinkException;
023:
024: import org.springframework.beans.factory.BeanClassLoaderAware;
025: import org.springframework.beans.factory.DisposableBean;
026: import org.springframework.beans.factory.FactoryBean;
027: import org.springframework.beans.factory.InitializingBean;
028: import org.springframework.dao.DataAccessException;
029: import org.springframework.dao.support.PersistenceExceptionTranslator;
030: import org.springframework.jdbc.support.SQLExceptionTranslator;
031:
032: /**
033: * {@link org.springframework.beans.factory.FactoryBean} that creates a
034: * TopLink {@link SessionFactory}. This is the usual way to set up a shared
035: * TopLink SessionFactory in a Spring application context; the SessionFactory
036: * can then be passed to TopLink-based DAOs via dependency injection.
037: *
038: * <p>See the base class {@link LocalSessionFactory} for configuration details.
039: *
040: * <p>This class also implements the
041: * {@link org.springframework.dao.support.PersistenceExceptionTranslator}
042: * interface, as autodetected by Spring's
043: * {@link org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor},
044: * for AOP-based translation of native exceptions to Spring DataAccessExceptions.
045: * Hence, the presence of a LocalSessionFactoryBean automatically enables a
046: * PersistenceExceptionTranslationPostProcessor to translate TopLink exceptions.
047: *
048: * <p>If your DAOs expect to receive a raw TopLink Session, consider defining a
049: * {@link org.springframework.orm.toplink.support.TransactionAwareSessionAdapter}
050: * in front of this bean. This adapter will provide a TopLink Session rather
051: * than a SessionFactory as bean reference. Your DAOs can then, for example,
052: * access the currently active Session and UnitOfWork via
053: * <code>Session.getActiveSession()</code> and <code>Session.getActiveUnitOfWork()</code>,
054: * respectively. Note that you can still access the SessionFactory as well, by
055: * defining a bean reference that points directly at the LocalSessionFactoryBean.
056: *
057: * @author Juergen Hoeller
058: * @since 1.2
059: * @see LocalSessionFactory
060: * @see org.springframework.orm.toplink.support.TransactionAwareSessionAdapter
061: * @see org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor
062: */
063: public class LocalSessionFactoryBean extends LocalSessionFactory
064: implements FactoryBean, BeanClassLoaderAware, InitializingBean,
065: DisposableBean, PersistenceExceptionTranslator {
066:
067: private SessionFactory sessionFactory;
068:
069: private SQLExceptionTranslator jdbcExceptionTranslator;
070:
071: /**
072: * Set the JDBC exception translator for this SessionFactory.
073: * <p>Applied to any SQLException root cause of a TopLink DatabaseException,
074: * within Spring's PersistenceExceptionTranslator mechanism.
075: * The default is to rely on TopLink's native exception translation.
076: * @see oracle.toplink.exceptions.DatabaseException
077: * @see org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator
078: * @see org.springframework.jdbc.support.SQLStateSQLExceptionTranslator
079: */
080: public void setJdbcExceptionTranslator(
081: SQLExceptionTranslator jdbcExceptionTranslator) {
082: this .jdbcExceptionTranslator = jdbcExceptionTranslator;
083: }
084:
085: /**
086: * Return the JDBC exception translator for this instance, if any.
087: */
088: public SQLExceptionTranslator getJdbcExceptionTranslator() {
089: return this .jdbcExceptionTranslator;
090: }
091:
092: /**
093: * Sets the given bean ClassLoader as TopLink Session ClassLoader.
094: * @see #setSessionClassLoader
095: */
096: public void setBeanClassLoader(ClassLoader classLoader) {
097: setSessionClassLoader(classLoader);
098: }
099:
100: public void afterPropertiesSet() throws TopLinkException {
101: this .sessionFactory = createSessionFactory();
102: }
103:
104: public Object getObject() {
105: return this .sessionFactory;
106: }
107:
108: public Class getObjectType() {
109: return (this .sessionFactory != null ? this .sessionFactory
110: .getClass() : SessionFactory.class);
111: }
112:
113: public boolean isSingleton() {
114: return true;
115: }
116:
117: /**
118: * Implementation of the PersistenceExceptionTranslator interface,
119: * as autodetected by Spring's PersistenceExceptionTranslationPostProcessor.
120: * <p>Converts the exception if it is a TopLinkException;
121: * else returns <code>null</code> to indicate an unknown exception.
122: * @see org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor
123: * @see #convertTopLinkAccessException
124: */
125: public DataAccessException translateExceptionIfPossible(
126: RuntimeException ex) {
127: if (ex instanceof TopLinkException) {
128: return convertTopLinkAccessException((TopLinkException) ex);
129: }
130: return null;
131: }
132:
133: /**
134: * Convert the given TopLinkException to an appropriate exception from the
135: * <code>org.springframework.dao</code> hierarchy.
136: * <p>Will automatically apply a specified SQLExceptionTranslator to a
137: * TopLink DatabaseException, else rely on TopLink's default translation.
138: * @param ex TopLinkException that occured
139: * @return a corresponding DataAccessException
140: * @see SessionFactoryUtils#convertTopLinkAccessException
141: * @see #setJdbcExceptionTranslator
142: */
143: public DataAccessException convertTopLinkAccessException(
144: TopLinkException ex) {
145: if (getJdbcExceptionTranslator() != null
146: && ex instanceof DatabaseException) {
147: Throwable internalEx = ex.getInternalException();
148: // Should always be a SQLException inside a DatabaseException.
149: if (internalEx instanceof SQLException) {
150: return getJdbcExceptionTranslator().translate(
151: "TopLink operation: " + ex.getMessage(), null,
152: (SQLException) internalEx);
153: }
154: }
155: return SessionFactoryUtils.convertTopLinkAccessException(ex);
156: }
157:
158: public void destroy() {
159: logger.info("Closing TopLink SessionFactory");
160: this.sessionFactory.close();
161: }
162:
163: }
|