alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Spring Framework example source code file (HibernateAccessor.java)

This example Spring Framework source code file (HibernateAccessor.java) is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Java - Spring Framework tags/keywords

dataaccessexception, flush_always, flush_eager, flush_eager, flush_never, flushmode, flushmode, hibernate, interceptor, jdbc, sessionfactory, sql, sqlexceptiontranslator, sqlexceptiontranslator, string, string

The Spring Framework HibernateAccessor.java source code

/*
 * Copyright 2002-2007 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.orm.hibernate3;

import java.sql.SQLException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.FlushMode;
import org.hibernate.HibernateException;
import org.hibernate.Interceptor;
import org.hibernate.JDBCException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.exception.GenericJDBCException;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.Constants;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.support.SQLExceptionTranslator;

/**
 * Base class for {@link HibernateTemplate} and {@link HibernateInterceptor},
 * defining common properties such as SessionFactory and flushing behavior.
 *
 * <p>Not intended to be used directly.
 * See {@link HibernateTemplate} and {@link HibernateInterceptor}.
 *
 * @author Juergen Hoeller
 * @since 1.2
 * @see HibernateTemplate
 * @see HibernateInterceptor
 * @see #setFlushMode
 */
public abstract class HibernateAccessor implements InitializingBean, BeanFactoryAware {

	/**
	 * Never flush is a good strategy for read-only units of work.
	 * Hibernate will not track and look for changes in this case,
	 * avoiding any overhead of modification detection.
	 * <p>In case of an existing Session, FLUSH_NEVER will turn the flush mode
	 * to NEVER for the scope of the current operation, resetting the previous
	 * flush mode afterwards.
	 * @see #setFlushMode
	 */
	public static final int FLUSH_NEVER = 0;

	/**
	 * Automatic flushing is the default mode for a Hibernate Session.
	 * A session will get flushed on transaction commit, and on certain find
	 * operations that might involve already modified instances, but not
	 * after each unit of work like with eager flushing.
	 * <p>In case of an existing Session, FLUSH_AUTO will participate in the
	 * existing flush mode, not modifying it for the current operation.
	 * This in particular means that this setting will not modify an existing
	 * flush mode NEVER, in contrast to FLUSH_EAGER.
	 * @see #setFlushMode
	 */
	public static final int FLUSH_AUTO = 1;

	/**
	 * Eager flushing leads to immediate synchronization with the database,
	 * even if in a transaction. This causes inconsistencies to show up and throw
	 * a respective exception immediately, and JDBC access code that participates
	 * in the same transaction will see the changes as the database is already
	 * aware of them then. But the drawbacks are:
	 * <ul>
	 * <li>additional communication roundtrips with the database, instead of a
	 * single batch at transaction commit;
	 * <li>the fact that an actual database rollback is needed if the Hibernate
	 * transaction rolls back (due to already submitted SQL statements).
	 * </ul>
	 * <p>In case of an existing Session, FLUSH_EAGER will turn the flush mode
	 * to AUTO for the scope of the current operation and issue a flush at the
	 * end, resetting the previous flush mode afterwards.
	 * @see #setFlushMode
	 */
	public static final int FLUSH_EAGER = 2;

	/**
	 * Flushing at commit only is intended for units of work where no
	 * intermediate flushing is desired, not even for find operations
	 * that might involve already modified instances.
	 * <p>In case of an existing Session, FLUSH_COMMIT will turn the flush mode
	 * to COMMIT for the scope of the current operation, resetting the previous
	 * flush mode afterwards. The only exception is an existing flush mode
	 * NEVER, which will not be modified through this setting.
	 * @see #setFlushMode
	 */
	public static final int FLUSH_COMMIT = 3;

	/**
	 * Flushing before every query statement is rarely necessary.
	 * It is only available for special needs.
	 * <p>In case of an existing Session, FLUSH_ALWAYS will turn the flush mode
	 * to ALWAYS for the scope of the current operation, resetting the previous
	 * flush mode afterwards.
	 * @see #setFlushMode
	 */
	public static final int FLUSH_ALWAYS = 4;


	/** Constants instance for HibernateAccessor */
	private static final Constants constants = new Constants(HibernateAccessor.class);

	/** Logger available to subclasses */
	protected final Log logger = LogFactory.getLog(getClass());

	private SessionFactory sessionFactory;

	private Object entityInterceptor;

	private SQLExceptionTranslator jdbcExceptionTranslator;

	private SQLExceptionTranslator defaultJdbcExceptionTranslator;

	private int flushMode = FLUSH_AUTO;

	private String[] filterNames;

	/**
	 * Just needed for entityInterceptorBeanName.
	 * @see #setEntityInterceptorBeanName
	 */
	private BeanFactory beanFactory;


	/**
	 * Set the Hibernate SessionFactory that should be used to create
	 * Hibernate Sessions.
	 */
	public void setSessionFactory(SessionFactory sessionFactory) {
		this.sessionFactory = sessionFactory;
	}

	/**
	 * Return the Hibernate SessionFactory that should be used to create
	 * Hibernate Sessions.
	 */
	public SessionFactory getSessionFactory() {
		return this.sessionFactory;
	}

	/**
	 * Set the bean name of a Hibernate entity interceptor that allows to inspect
	 * and change property values before writing to and reading from the database.
	 * Will get applied to any new Session created by this transaction manager.
	 * <p>Requires the bean factory to be known, to be able to resolve the bean
	 * name to an interceptor instance on session creation. Typically used for
	 * prototype interceptors, i.e. a new interceptor instance per session.
	 * <p>Can also be used for shared interceptor instances, but it is recommended
	 * to set the interceptor reference directly in such a scenario.
	 * @param entityInterceptorBeanName the name of the entity interceptor in
	 * the bean factory
	 * @see #setBeanFactory
	 * @see #setEntityInterceptor
	 */
	public void setEntityInterceptorBeanName(String entityInterceptorBeanName) {
		this.entityInterceptor = entityInterceptorBeanName;
	}

	/**
	 * Set a Hibernate entity interceptor that allows to inspect and change
	 * property values before writing to and reading from the database.
	 * Will get applied to any <b>new Session created by this object.
	 * <p>Such an interceptor can either be set at the SessionFactory level,
	 * i.e. on LocalSessionFactoryBean, or at the Session level, i.e. on
	 * HibernateTemplate, HibernateInterceptor, and HibernateTransactionManager.
	 * It's preferable to set it on LocalSessionFactoryBean or HibernateTransactionManager
	 * to avoid repeated configuration and guarantee consistent behavior in transactions.
	 * @see #setEntityInterceptorBeanName
	 * @see LocalSessionFactoryBean#setEntityInterceptor
	 * @see HibernateTransactionManager#setEntityInterceptor
	 */
	public void setEntityInterceptor(Interceptor entityInterceptor) {
		this.entityInterceptor = entityInterceptor;
	}

	/**
	 * Return the current Hibernate entity interceptor, or <code>null if none.
	 * Resolves an entity interceptor bean name via the bean factory,
	 * if necessary.
	 * @throws IllegalStateException if bean name specified but no bean factory set
	 * @throws org.springframework.beans.BeansException if bean name resolution via the bean factory failed
	 * @see #setEntityInterceptor
	 * @see #setEntityInterceptorBeanName
	 * @see #setBeanFactory
	 */
	public Interceptor getEntityInterceptor() throws IllegalStateException, BeansException {
		if (this.entityInterceptor instanceof String) {
			if (this.beanFactory == null) {
				throw new IllegalStateException("Cannot get entity interceptor via bean name if no bean factory set");
			}
			return (Interceptor) this.beanFactory.getBean((String) this.entityInterceptor, Interceptor.class);
		}
		return (Interceptor) this.entityInterceptor;
	}

	/**
	 * Set the JDBC exception translator for this instance.
	 * <p>Applied to any SQLException root cause of a Hibernate JDBCException,
	 * overriding Hibernate's default SQLException translation (which is
	 * based on Hibernate's Dialect for a specific target database).
	 * @param jdbcExceptionTranslator the exception translator
	 * @see java.sql.SQLException
	 * @see org.hibernate.JDBCException
	 * @see org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator
	 * @see org.springframework.jdbc.support.SQLStateSQLExceptionTranslator
	 */
	public void setJdbcExceptionTranslator(SQLExceptionTranslator jdbcExceptionTranslator) {
		this.jdbcExceptionTranslator = jdbcExceptionTranslator;
	}

	/**
	 * Return the JDBC exception translator for this instance, if any.
	 */
	public SQLExceptionTranslator getJdbcExceptionTranslator() {
		return this.jdbcExceptionTranslator;
	}

	/**
	 * Set the flush behavior by the name of the respective constant
	 * in this class, e.g. "FLUSH_AUTO". Default is "FLUSH_AUTO".
	 * @param constantName name of the constant
	 * @see #setFlushMode
	 * @see #FLUSH_AUTO
	 */
	public void setFlushModeName(String constantName) {
		setFlushMode(constants.asNumber(constantName).intValue());
	}

	/**
	 * Set the flush behavior to one of the constants in this class.
	 * Default is FLUSH_AUTO.
	 * @see #setFlushModeName
	 * @see #FLUSH_AUTO
	 */
	public void setFlushMode(int flushMode) {
		this.flushMode = flushMode;
	}

	/**
	 * Return if a flush should be forced after executing the callback code.
	 */
	public int getFlushMode() {
		return this.flushMode;
	}

	/**
	 * Set the name of a Hibernate filter to be activated for all
	 * Sessions that this accessor works with.
	 * <p>This filter will be enabled at the beginning of each operation
	 * and correspondingly disabled at the end of the operation.
	 * This will work for newly opened Sessions as well as for existing
	 * Sessions (for example, within a transaction).
	 * @see #enableFilters(org.hibernate.Session)
	 * @see org.hibernate.Session#enableFilter(String)
	 * @see LocalSessionFactoryBean#setFilterDefinitions
	 */
	public void setFilterName(String filter) {
		this.filterNames = new String[] {filter};
	}

	/**
	 * Set one or more names of Hibernate filters to be activated for all
	 * Sessions that this accessor works with.
	 * <p>Each of those filters will be enabled at the beginning of each
	 * operation and correspondingly disabled at the end of the operation.
	 * This will work for newly opened Sessions as well as for existing
	 * Sessions (for example, within a transaction).
	 * @see #enableFilters(org.hibernate.Session)
	 * @see org.hibernate.Session#enableFilter(String)
	 * @see LocalSessionFactoryBean#setFilterDefinitions
	 */
	public void setFilterNames(String[] filterNames) {
		this.filterNames = filterNames;
	}

	/**
	 * Return the names of Hibernate filters to be activated, if any.
	 */
	public String[] getFilterNames() {
		return this.filterNames;
	}

	/**
	 * The bean factory just needs to be known for resolving entity interceptor
	 * bean names. It does not need to be set for any other mode of operation.
	 * @see #setEntityInterceptorBeanName
	 */
	public void setBeanFactory(BeanFactory beanFactory) {
		this.beanFactory = beanFactory;
	}

	public void afterPropertiesSet() {
		if (getSessionFactory() == null) {
			throw new IllegalArgumentException("Property 'sessionFactory' is required");
		}
	}


	/**
	 * Apply the flush mode that's been specified for this accessor
	 * to the given Session.
	 * @param session the current Hibernate Session
	 * @param existingTransaction if executing within an existing transaction
	 * @return the previous flush mode to restore after the operation,
	 * or <code>null if none
	 * @see #setFlushMode
	 * @see org.hibernate.Session#setFlushMode
	 */
	protected FlushMode applyFlushMode(Session session, boolean existingTransaction) {
		if (getFlushMode() == FLUSH_NEVER) {
			if (existingTransaction) {
				FlushMode previousFlushMode = session.getFlushMode();
				if (!previousFlushMode.lessThan(FlushMode.COMMIT)) {
					session.setFlushMode(FlushMode.NEVER);
					return previousFlushMode;
				}
			}
			else {
				session.setFlushMode(FlushMode.NEVER);
			}
		}
		else if (getFlushMode() == FLUSH_EAGER) {
			if (existingTransaction) {
				FlushMode previousFlushMode = session.getFlushMode();
				if (!previousFlushMode.equals(FlushMode.AUTO)) {
					session.setFlushMode(FlushMode.AUTO);
					return previousFlushMode;
				}
			}
			else {
				// rely on default FlushMode.AUTO
			}
		}
		else if (getFlushMode() == FLUSH_COMMIT) {
			if (existingTransaction) {
				FlushMode previousFlushMode = session.getFlushMode();
				if (previousFlushMode.equals(FlushMode.AUTO) || previousFlushMode.equals(FlushMode.ALWAYS)) {
					session.setFlushMode(FlushMode.COMMIT);
					return previousFlushMode;
				}
			}
			else {
				session.setFlushMode(FlushMode.COMMIT);
			}
		}
		else if (getFlushMode() == FLUSH_ALWAYS) {
			if (existingTransaction) {
				FlushMode previousFlushMode = session.getFlushMode();
				if (!previousFlushMode.equals(FlushMode.ALWAYS)) {
					session.setFlushMode(FlushMode.ALWAYS);
					return previousFlushMode;
				}
			}
			else {
				session.setFlushMode(FlushMode.ALWAYS);
			}
		}
		return null;
	}

	/**
	 * Flush the given Hibernate Session if necessary.
	 * @param session the current Hibernate Session
	 * @param existingTransaction if executing within an existing transaction
	 * @throws HibernateException in case of Hibernate flushing errors
	 */
	protected void flushIfNecessary(Session session, boolean existingTransaction) throws HibernateException {
		if (getFlushMode() == FLUSH_EAGER || (!existingTransaction && getFlushMode() != FLUSH_NEVER)) {
			logger.debug("Eagerly flushing Hibernate session");
			session.flush();
		}
	}


	/**
	 * Convert the given HibernateException to an appropriate exception
	 * from the <code>org.springframework.dao hierarchy.
	 * <p>Will automatically apply a specified SQLExceptionTranslator to a
	 * Hibernate JDBCException, else rely on Hibernate's default translation.
	 * @param ex HibernateException that occured
	 * @return a corresponding DataAccessException
	 * @see SessionFactoryUtils#convertHibernateAccessException
	 * @see #setJdbcExceptionTranslator
	 */
	public DataAccessException convertHibernateAccessException(HibernateException ex) {
		if (getJdbcExceptionTranslator() != null && ex instanceof JDBCException) {
			return convertJdbcAccessException((JDBCException) ex, getJdbcExceptionTranslator());
		}
		else if (GenericJDBCException.class.equals(ex.getClass())) {
			return convertJdbcAccessException((GenericJDBCException) ex, getDefaultJdbcExceptionTranslator());
		}
		return SessionFactoryUtils.convertHibernateAccessException(ex);
	}

	/**
	 * Convert the given Hibernate JDBCException to an appropriate exception
	 * from the <code>org.springframework.dao hierarchy, using the
	 * given SQLExceptionTranslator.
	 * @param ex Hibernate JDBCException that occured
	 * @param translator the SQLExceptionTranslator to use
	 * @return a corresponding DataAccessException
	 */
	protected DataAccessException convertJdbcAccessException(JDBCException ex, SQLExceptionTranslator translator) {
		return translator.translate("Hibernate operation: " + ex.getMessage(), ex.getSQL(), ex.getSQLException());
	}

	/**
	 * Convert the given SQLException to an appropriate exception from the
	 * <code>org.springframework.dao hierarchy. Can be overridden in subclasses.
	 * <p>Note that a direct SQLException can just occur when callback code
	 * performs direct JDBC access via <code>Session.connection().
	 * @param ex the SQLException
	 * @return the corresponding DataAccessException instance
	 * @see #setJdbcExceptionTranslator
	 * @see org.hibernate.Session#connection()
	 */
	protected DataAccessException convertJdbcAccessException(SQLException ex) {
		SQLExceptionTranslator translator = getJdbcExceptionTranslator();
		if (translator == null) {
			translator = getDefaultJdbcExceptionTranslator();
		}
		return translator.translate("Hibernate-related JDBC operation", null, ex);
	}

	/**
	 * Obtain a default SQLExceptionTranslator, lazily creating it if necessary.
	 * <p>Creates a default
	 * {@link org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator}
	 * for the SessionFactory's underlying DataSource.
	 */
	protected synchronized SQLExceptionTranslator getDefaultJdbcExceptionTranslator() {
		if (this.defaultJdbcExceptionTranslator == null) {
			this.defaultJdbcExceptionTranslator = SessionFactoryUtils.newJdbcExceptionTranslator(getSessionFactory());
		}
		return this.defaultJdbcExceptionTranslator;
	}


	/**
	 * Enable the specified filters on the given Session.
	 * @param session the current Hibernate Session
	 * @see #setFilterNames
	 * @see org.hibernate.Session#enableFilter(String)
	 */
	protected void enableFilters(Session session) {
		String[] filterNames = getFilterNames();
		if (filterNames != null) {
			for (int i = 0; i < filterNames.length; i++) {
				session.enableFilter(filterNames[i]);
			}
		}
	}

	/**
	 * Disable the specified filters on the given Session.
	 * @param session the current Hibernate Session
	 * @see #setFilterNames
	 * @see org.hibernate.Session#disableFilter(String)
	 */
	protected void disableFilters(Session session) {
		String[] filterNames = getFilterNames();
		if (filterNames != null) {
			for (int i = 0; i < filterNames.length; i++) {
				session.disableFilter(filterNames[i]);
			}
		}
	}

}

Other Spring Framework examples (source code examples)

Here is a short list of links related to this Spring Framework HibernateAccessor.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2024 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.