All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.springframework.orm.toplink.TopLinkTemplate Maven / Gradle / Ivy

There is a newer version: 5.3.34
Show newest version
/*
 * 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.toplink;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;

import oracle.toplink.exceptions.TopLinkException;
import oracle.toplink.expressions.Expression;
import oracle.toplink.queryframework.Call;
import oracle.toplink.queryframework.DatabaseQuery;
import oracle.toplink.queryframework.ReadObjectQuery;
import oracle.toplink.sessions.ObjectCopyingPolicy;
import oracle.toplink.sessions.Session;
import oracle.toplink.sessions.UnitOfWork;

import org.springframework.dao.DataAccessException;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.orm.ObjectRetrievalFailureException;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

/**
 * Helper class that simplifies TopLink data access code, and converts
 * TopLinkExceptions into unchecked DataAccessExceptions, following the
 * org.springframework.dao exception hierarchy.
 * Uses the same SQLExceptionTranslator mechanism as JdbcTemplate.
 *
 * 

Typically used to implement data access or business logic services that use * TopLink within their implementation but are TopLink-agnostic in their interface. * The latter or code calling the latter only have to deal with business * objects, query objects, and org.springframework.dao exceptions. * *

The central method is execute, supporting TopLink access code * implementing the {@link TopLinkCallback} interface. It provides TopLink Session * handling such that neither the TopLinkCallback implementation nor the calling * code needs to explicitly care about retrieving/closing TopLink Sessions, * or handling Session lifecycle exceptions. For typical single step actions, * there are various convenience methods (read, readAll, merge, delete, etc). * *

Can be used within a service implementation via direct instantiation * with a SessionFactory reference, or get prepared in an application context * and given to services as bean reference. Note: The SessionFactory should * always be configured as bean in the application context, in the first case * given to the service directly, in the second case to the prepared template. * *

This class can be considered as direct alternative to working with the raw * TopLink Session API (through SessionFactoryUtils.getSession()). * The major advantage is its automatic conversion to DataAccessExceptions, the * major disadvantage that no checked application exceptions can get thrown from * within data access code. Corresponding checks and the actual throwing of such * exceptions can often be deferred to after callback execution, though. * *

Note that even if {@link TopLinkTransactionManager} is used for transaction * demarcation in higher-level services, all those services above the data * access layer don't need to be TopLink-aware. Setting such a special * PlatformTransactionManager is a configuration issue, without introducing * code dependencies. For example, switching to JTA is just a matter of Spring * configuration (use JtaTransactionManager instead) and TopLink session * configuration, neither affecting application code. * *

{@link LocalSessionFactoryBean} is the preferred way of obtaining a reference * to a specific TopLink SessionFactory. It will usually be configured to * create ClientSessions for a ServerSession held by it, allowing for seamless * multi-threaded execution. The Spring application context will manage its lifecycle, * initializing and shutting down the factory as part of the application. * *

Thanks to Slavik Markovich for implementing the initial TopLink support prototype! * * @author Juergen Hoeller * @author James Clark * @since 1.2 * @see #setSessionFactory * @see TopLinkCallback * @see oracle.toplink.sessions.Session * @see TopLinkInterceptor * @see LocalSessionFactoryBean * @see TopLinkTransactionManager * @see org.springframework.transaction.jta.JtaTransactionManager */ public class TopLinkTemplate extends TopLinkAccessor implements TopLinkOperations { private boolean allowCreate = true; /** * Create a new TopLinkTemplate instance. */ public TopLinkTemplate() { } /** * Create a new TopLinkTemplate instance. */ public TopLinkTemplate(SessionFactory sessionFactory) { setSessionFactory(sessionFactory); afterPropertiesSet(); } /** * Create a new TopLinkTemplate instance. * @param allowCreate if a new Session should be created if no thread-bound found */ public TopLinkTemplate(SessionFactory sessionFactory, boolean allowCreate) { setSessionFactory(sessionFactory); setAllowCreate(allowCreate); afterPropertiesSet(); } /** * Set if a new Session should be created when no transactional Session * can be found for the current thread. *

TopLinkTemplate is aware of a corresponding Session bound to the * current thread, for example when using TopLinkTransactionManager. * If allowCreate is true, a new non-transactional Session will be created * if none found, which needs to be closed at the end of the operation. * If false, an IllegalStateException will get thrown in this case. * @see SessionFactoryUtils#getSession(SessionFactory, boolean) */ public void setAllowCreate(boolean allowCreate) { this.allowCreate = allowCreate; } /** * Return if a new Session should be created if no thread-bound found. */ public boolean isAllowCreate() { return allowCreate; } public Object execute(TopLinkCallback action) throws DataAccessException { Assert.notNull(action, "Callback object must not be null"); Session session = SessionFactoryUtils.getSession(getSessionFactory(), this.allowCreate); try { return action.doInTopLink(session); } catch (TopLinkException ex) { throw convertTopLinkAccessException(ex); } catch (RuntimeException ex) { // callback code threw application exception throw ex; } finally { SessionFactoryUtils.releaseSession(session, getSessionFactory()); } } public List executeFind(TopLinkCallback action) throws DataAccessException { Object result = execute(action); if (result != null && !(result instanceof List)) { throw new InvalidDataAccessApiUsageException( "Result object returned from TopLinkCallback isn't a List: [" + result + "]"); } return (List) result; } //------------------------------------------------------------------------- // Convenience methods for executing generic queries //------------------------------------------------------------------------- public Object executeNamedQuery(Class entityClass, String queryName) throws DataAccessException { return executeNamedQuery(entityClass, queryName, null, false); } public Object executeNamedQuery(Class entityClass, String queryName, boolean enforceReadOnly) throws DataAccessException { return executeNamedQuery(entityClass, queryName, null, enforceReadOnly); } public Object executeNamedQuery(Class entityClass, String queryName, Object[] args) throws DataAccessException { return executeNamedQuery(entityClass, queryName, args, false); } public Object executeNamedQuery( final Class entityClass, final String queryName, final Object[] args, final boolean enforceReadOnly) throws DataAccessException { return execute(new SessionReadCallback(enforceReadOnly) { protected Object readFromSession(Session session) throws TopLinkException { if (args != null) { return session.executeQuery(queryName, entityClass, new Vector(Arrays.asList(args))); } else { return session.executeQuery(queryName, entityClass, new Vector()); } } }); } public Object executeQuery(DatabaseQuery query) throws DataAccessException { return executeQuery(query, null, false); } public Object executeQuery(DatabaseQuery query, boolean enforceReadOnly) throws DataAccessException { return executeQuery(query, null, enforceReadOnly); } public Object executeQuery(DatabaseQuery query, Object[] args) throws DataAccessException { return executeQuery(query, args, false); } public Object executeQuery(final DatabaseQuery query, final Object[] args, final boolean enforceReadOnly) throws DataAccessException { return execute(new SessionReadCallback(enforceReadOnly) { protected Object readFromSession(Session session) throws TopLinkException { if (args != null) { return session.executeQuery(query, new Vector(Arrays.asList(args))); } else { return session.executeQuery(query); } } }); } //------------------------------------------------------------------------- // Convenience methods for reading a specific set of objects //------------------------------------------------------------------------- public List readAll(Class entityClass) throws DataAccessException { return readAll(entityClass, false); } public List readAll(final Class entityClass, final boolean enforceReadOnly) throws DataAccessException { return executeFind(new SessionReadCallback(enforceReadOnly) { protected Object readFromSession(Session session) throws TopLinkException { return session.readAllObjects(entityClass); } }); } public List readAll(Class entityClass, Expression expression) throws DataAccessException { return readAll(entityClass, expression, false); } public List readAll(final Class entityClass, final Expression expression, final boolean enforceReadOnly) throws DataAccessException { return executeFind(new SessionReadCallback(enforceReadOnly) { protected Object readFromSession(Session session) throws TopLinkException { return session.readAllObjects(entityClass, expression); } }); } public List readAll(Class entityClass, Call call) throws DataAccessException { return readAll(entityClass, call, false); } public List readAll(final Class entityClass, final Call call, final boolean enforceReadOnly) throws DataAccessException { return executeFind(new SessionReadCallback(enforceReadOnly) { protected Object readFromSession(Session session) throws TopLinkException { return session.readAllObjects(entityClass, call); } }); } public Object read(Class entityClass, Expression expression) throws DataAccessException { return read(entityClass, expression, false); } public Object read(final Class entityClass, final Expression expression, final boolean enforceReadOnly) throws DataAccessException { return execute(new SessionReadCallback(enforceReadOnly) { protected Object readFromSession(Session session) throws TopLinkException { return session.readObject(entityClass, expression); } }); } public Object read(Class entityClass, Call call) throws DataAccessException { return read(entityClass, call, false); } public Object read(final Class entityClass, final Call call, final boolean enforceReadOnly) throws DataAccessException { return execute(new SessionReadCallback(enforceReadOnly) { protected Object readFromSession(Session session) throws TopLinkException { return session.readObject(entityClass, call); } }); } //------------------------------------------------------------------------- // Convenience methods for reading an individual object by id //------------------------------------------------------------------------- public Object readById(Class entityClass, Object id) throws DataAccessException { return readById(entityClass, id, false); } public Object readById(Class entityClass, Object id, boolean enforceReadOnly) throws DataAccessException { return readById(entityClass, new Object[] {id}, enforceReadOnly); } public Object readById(Class entityClass, Object[] keys) throws DataAccessException { return readById(entityClass, keys, false); } public Object readById(final Class entityClass, final Object[] keys, final boolean enforceReadOnly) throws DataAccessException { Assert.isTrue(keys != null && keys.length > 0, "Non-empty keys or id is required"); ReadObjectQuery query = new ReadObjectQuery(entityClass); query.setSelectionKey(new Vector(Arrays.asList(keys))); Object result = executeQuery(query, enforceReadOnly); if (result == null) { Object identifier = (keys.length == 1 ? keys[0] : StringUtils.arrayToCommaDelimitedString(keys)); throw new ObjectRetrievalFailureException(entityClass, identifier); } return result; } public Object readAndCopy(Class entityClass, Object id) throws DataAccessException { return readAndCopy(entityClass, id, false); } public Object readAndCopy(Class entityClass, Object id, boolean enforceReadOnly) throws DataAccessException { Object entity = readById(entityClass, id, enforceReadOnly); return copy(entity); } public Object readAndCopy(Class entityClass, Object[] keys) throws DataAccessException { return readAndCopy(entityClass, keys, false); } public Object readAndCopy(Class entityClass, Object[] keys, boolean enforceReadOnly) throws DataAccessException { Object entity = readById(entityClass, keys, enforceReadOnly); return copy(entity); } //------------------------------------------------------------------------- // Convenience methods for copying and refreshing objects //------------------------------------------------------------------------- public Object copy(Object entity) throws DataAccessException { ObjectCopyingPolicy copyingPolicy = new ObjectCopyingPolicy(); copyingPolicy.cascadeAllParts(); copyingPolicy.setShouldResetPrimaryKey(false); return copy(entity, copyingPolicy); } public Object copy(final Object entity, final ObjectCopyingPolicy copyingPolicy) throws DataAccessException { return execute(new TopLinkCallback() { public Object doInTopLink(Session session) throws TopLinkException { return session.copyObject(entity, copyingPolicy); } }); } public List copyAll(Collection entities) throws DataAccessException { ObjectCopyingPolicy copyingPolicy = new ObjectCopyingPolicy(); copyingPolicy.cascadeAllParts(); copyingPolicy.setShouldResetPrimaryKey(false); return copyAll(entities, copyingPolicy); } public List copyAll(final Collection entities, final ObjectCopyingPolicy copyingPolicy) throws DataAccessException { return (List) execute(new TopLinkCallback() { public Object doInTopLink(Session session) throws TopLinkException { List result = new ArrayList(entities.size()); for (Iterator it = entities.iterator(); it.hasNext();) { Object entity = it.next(); result.add(session.copyObject(entity, copyingPolicy)); } return result; } }); } public Object refresh(Object entity) throws DataAccessException { return refresh(entity, false); } public Object refresh(final Object entity, final boolean enforceReadOnly) throws DataAccessException { return execute(new SessionReadCallback(enforceReadOnly) { protected Object readFromSession(Session session) throws TopLinkException { return session.refreshObject(entity); } }); } public List refreshAll(Collection entities) throws DataAccessException { return refreshAll(entities, false); } public List refreshAll(final Collection entities, final boolean enforceReadOnly) throws DataAccessException { return (List) execute(new SessionReadCallback(enforceReadOnly) { protected Object readFromSession(Session session) throws TopLinkException { List result = new ArrayList(entities.size()); for (Iterator it = entities.iterator(); it.hasNext();) { Object entity = it.next(); result.add(session.refreshObject(entity)); } return result; } }); } //------------------------------------------------------------------------- // Convenience methods for persisting and deleting objects //------------------------------------------------------------------------- public Object register(final Object entity) { return execute(new UnitOfWorkCallback() { protected Object doInUnitOfWork(UnitOfWork unitOfWork) throws TopLinkException { return unitOfWork.registerObject(entity); } }); } public List registerAll(final Collection entities) { return (List) execute(new UnitOfWorkCallback() { protected Object doInUnitOfWork(UnitOfWork unitOfWork) throws TopLinkException { return unitOfWork.registerAllObjects(entities); } }); } public void registerNew(final Object entity) { execute(new UnitOfWorkCallback() { protected Object doInUnitOfWork(UnitOfWork unitOfWork) throws TopLinkException { return unitOfWork.registerNewObject(entity); } }); } public Object registerExisting(final Object entity) { return execute(new UnitOfWorkCallback() { protected Object doInUnitOfWork(UnitOfWork unitOfWork) throws TopLinkException { return unitOfWork.registerExistingObject(entity); } }); } public Object merge(final Object entity) throws DataAccessException { return execute(new UnitOfWorkCallback() { protected Object doInUnitOfWork(UnitOfWork unitOfWork) throws TopLinkException { return unitOfWork.mergeClone(entity); } }); } public Object deepMerge(final Object entity) throws DataAccessException { return execute(new UnitOfWorkCallback() { protected Object doInUnitOfWork(UnitOfWork unitOfWork) throws TopLinkException { return unitOfWork.deepMergeClone(entity); } }); } public Object shallowMerge(final Object entity) throws DataAccessException { return execute(new UnitOfWorkCallback() { protected Object doInUnitOfWork(UnitOfWork unitOfWork) throws TopLinkException { return unitOfWork.shallowMergeClone(entity); } }); } public Object mergeWithReferences(final Object entity) throws DataAccessException { return execute(new UnitOfWorkCallback() { protected Object doInUnitOfWork(UnitOfWork unitOfWork) throws TopLinkException { return unitOfWork.mergeCloneWithReferences(entity); } }); } public void delete(final Object entity) throws DataAccessException { execute(new UnitOfWorkCallback() { protected Object doInUnitOfWork(UnitOfWork unitOfWork) throws TopLinkException { return unitOfWork.deleteObject(entity); } }); } public void deleteAll(final Collection entities) throws DataAccessException { execute(new UnitOfWorkCallback() { protected Object doInUnitOfWork(UnitOfWork unitOfWork) throws TopLinkException { unitOfWork.deleteAllObjects(entities); return null; } }); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy