Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright (c) 1998, 2024 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2024 IBM Corporation and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0,
* or the Eclipse Distribution License v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
// Contributors:
// Oracle - initial API and implementation from Oracle TopLink
//
// 05/28/2008-1.0M8 Andrei Ilitchev
// - 224964: Provide support for Proxy Authentication through JPA.
// Added setProperties method to be used in case properties couldn't be passed to createEM method.
// The properties now set to the uow's parent - not to the uow itself.
// In case there's no active transaction, close method now releases uow.
// UowImpl was amended to allow value holders instantiation even after it has been released,
// the parent ClientSession is released, too.
// 03/19/2009-2.0 Michael O'Brien
// - 266912: JPA 2.0 Metamodel API (part of the JSR-317 EJB 3.1 Criteria API)
// 07/13/2009-2.0 Guy Pelletier
// - 277039: JPA 2.0 Cache Usage Settings
// 02/08/2012-2.4 Guy Pelletier
// - 350487: JPA 2.1 Specification defined support for Stored Procedure Calls
// 14/05/2012-2.4 Guy Pelletier
// - 376603: Provide for table per tenant support for multitenant applications
// 06/20/2012-2.5 Guy Pelletier
// - 350487: JPA 2.1 Specification defined support for Stored Procedure Calls
// 08/24/2012-2.5 Guy Pelletier
// - 350487: JPA 2.1 Specification defined support for Stored Procedure Calls
// 09/13/2012-2.5 Guy Pelletier
// - 350487: JPA 2.1 Specification defined support for Stored Procedure Calls
// 08/11/2012-2.5 Guy Pelletier
// - 393867: Named queries do not work when using EM level Table Per Tenant Multitenancy.
// 02/16/2017-2.6 Jody Grassel
// - 512255: Eclipselink JPA/Auditing capablity in EE Environment fails with JNDI name parameter type
// 07/16/2019-2.7 Jody Grassel
// - 547173: EntityManager.unwrap(Connection.class) returns null
// 09/02/2019-2.7 Alexandre Jacob
// - 527415: Fix code when locale is tr, az or lt
// 08/23/2023: Tomas Kraus
// - New Jakarta Persistence 3.2 Features
package org.eclipse.persistence.internal.jpa;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.WeakHashMap;
import javax.sql.DataSource;
import jakarta.persistence.CacheRetrieveMode;
import jakarta.persistence.CacheStoreMode;
import jakarta.persistence.ConnectionConsumer;
import jakarta.persistence.ConnectionFunction;
import jakarta.persistence.EntityExistsException;
import jakarta.persistence.EntityGraph;
import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory;
import jakarta.persistence.EntityNotFoundException;
import jakarta.persistence.FindOption;
import jakarta.persistence.FlushModeType;
import jakarta.persistence.LockModeType;
import jakarta.persistence.LockOption;
import jakarta.persistence.LockTimeoutException;
import jakarta.persistence.OptimisticLockException;
import jakarta.persistence.PersistenceException;
import jakarta.persistence.PessimisticLockException;
import jakarta.persistence.Query;
import jakarta.persistence.RefreshOption;
import jakarta.persistence.StoredProcedureQuery;
import jakarta.persistence.SynchronizationType;
import jakarta.persistence.TransactionRequiredException;
import jakarta.persistence.TypedQuery;
import jakarta.persistence.TypedQueryReference;
import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaDelete;
import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.CriteriaSelect;
import jakarta.persistence.criteria.CriteriaUpdate;
import jakarta.persistence.metamodel.Metamodel;
import org.eclipse.persistence.annotations.CacheKeyType;
import org.eclipse.persistence.config.EntityManagerProperties;
import org.eclipse.persistence.config.QueryHints;
import org.eclipse.persistence.config.ReferenceMode;
import org.eclipse.persistence.descriptors.CMPPolicy;
import org.eclipse.persistence.descriptors.ClassDescriptor;
import org.eclipse.persistence.descriptors.VersionLockingPolicy;
import org.eclipse.persistence.exceptions.DatabaseException;
import org.eclipse.persistence.exceptions.EclipseLinkException;
import org.eclipse.persistence.exceptions.JPQLException;
import org.eclipse.persistence.exceptions.ValidationException;
import org.eclipse.persistence.expressions.Expression;
import org.eclipse.persistence.internal.databaseaccess.Accessor;
import org.eclipse.persistence.internal.descriptors.OptimisticLockingPolicy;
import org.eclipse.persistence.internal.helper.BasicTypeHelperImpl;
import org.eclipse.persistence.internal.identitymaps.CacheId;
import org.eclipse.persistence.internal.jpa.querydef.CriteriaDeleteImpl;
import org.eclipse.persistence.internal.jpa.querydef.CriteriaQueryImpl;
import org.eclipse.persistence.internal.jpa.querydef.CriteriaSelectInternal;
import org.eclipse.persistence.internal.jpa.querydef.CriteriaUpdateImpl;
import org.eclipse.persistence.internal.jpa.transaction.EntityTransactionImpl;
import org.eclipse.persistence.internal.jpa.transaction.EntityTransactionWrapper;
import org.eclipse.persistence.internal.jpa.transaction.JTATransactionWrapper;
import org.eclipse.persistence.internal.jpa.transaction.TransactionWrapper;
import org.eclipse.persistence.internal.jpa.transaction.TransactionWrapperImpl;
import org.eclipse.persistence.internal.localization.ExceptionLocalization;
import org.eclipse.persistence.internal.sessions.AbstractSession;
import org.eclipse.persistence.internal.sessions.DatabaseSessionImpl;
import org.eclipse.persistence.internal.sessions.MergeManager;
import org.eclipse.persistence.internal.sessions.PropertiesHandler;
import org.eclipse.persistence.internal.sessions.RepeatableWriteUnitOfWork;
import org.eclipse.persistence.internal.sessions.UnitOfWorkImpl;
import org.eclipse.persistence.jpa.JpaEntityManager;
import org.eclipse.persistence.logging.SessionLog;
import org.eclipse.persistence.queries.AttributeGroup;
import org.eclipse.persistence.queries.Call;
import org.eclipse.persistence.queries.DataReadQuery;
import org.eclipse.persistence.queries.DatabaseQuery;
import org.eclipse.persistence.queries.FetchGroupTracker;
import org.eclipse.persistence.queries.ObjectLevelReadQuery;
import org.eclipse.persistence.queries.ReadAllQuery;
import org.eclipse.persistence.queries.ReadObjectQuery;
import org.eclipse.persistence.queries.ResultSetMappingQuery;
import org.eclipse.persistence.queries.SQLResultSetMapping;
import org.eclipse.persistence.queries.StoredProcedureCall;
import org.eclipse.persistence.sessions.DatabaseSession;
import org.eclipse.persistence.sessions.DatasourceLogin;
import org.eclipse.persistence.sessions.DefaultConnector;
import org.eclipse.persistence.sessions.JNDIConnector;
import org.eclipse.persistence.sessions.Session;
import org.eclipse.persistence.sessions.UnitOfWork;
import org.eclipse.persistence.sessions.UnitOfWork.CommitOrderType;
import org.eclipse.persistence.sessions.broker.SessionBroker;
import org.eclipse.persistence.sessions.factories.SessionManager;
import org.eclipse.persistence.sessions.server.ConnectionPolicy;
import org.eclipse.persistence.sessions.server.Server;
import org.eclipse.persistence.sessions.server.ServerSession;
/**
*
* Purpose: Contains the implementation of the EntityManager.
*
* Description: This class provides the implementation for the combined
* EclipseLink and JPA EntityManager class.
*
* Responsibilities: It is responsible for tracking transaction state and
* the objects within that transaction.
*
* @see jakarta.persistence.EntityManager
* @see org.eclipse.persistence.jpa.JpaEntityManager
*
* @author gyorke
* @since TopLink Essentials - JPA 1.0
*/
public class EntityManagerImpl implements org.eclipse.persistence.jpa.JpaEntityManager {
protected enum OperationType {FIND, REFRESH, LOCK}
/** Allows transparent transactions across JTA and local transactions. */
private TransactionWrapperImpl transaction;
/** Store if this entity manager has been closed. */
protected boolean isOpen;
/** Stores the UnitOfWork representing the persistence context. */
protected RepeatableWriteUnitOfWork extendedPersistenceContext;
/** Stores a session used for read-only queries. */
protected AbstractSession readOnlySession;
/**
* References the DatabaseSession that this deployment is using.
*/
protected AbstractSession databaseSession;
/**
* References to the parent factory that has created this entity manager.
* Ensures that the factory is not garbage collected.
*/
protected EntityManagerFactoryDelegate factory;
/**
* Join existing transaction property, allows reading through write
* connection.
*/
protected boolean beginEarlyTransaction;
/** Local properties passed from createEntityManager. */
protected Map properties;
/** Flush mode property, allows flush before query to be avoided. */
protected FlushModeType flushMode;
/**
* Reference mode property, allows weak unit of work references to allow
* garbage collection during a transaction.
*/
protected ReferenceMode referenceMode;
/**
* Connection policy used to create ClientSession, allows using a different
* pool/connection/exclusive connections.
* Not used in SessionBroker case (composite persistence unit case).
*/
protected ConnectionPolicy connectionPolicy;
/**
* In case of composite persistence unit this map is used instead of connectionPolicy attribute.
* Member sessions' ConnectionPolicies keyed by sessions' names (composite members' persistence unit names).
* Used only in SessionBroker case (composite persistence unit case): in that case guaranteed to be always non null.
*/
protected Map connectionPolicies;
/**
* Keep a list of openQueries that are executed in this entity manager.
*/
protected WeakHashMap openQueriesMap;
/**
* Property to avoid resuming unit of work if going to be closed on commit
* anyway.
*/
protected boolean closeOnCommit;
/**
* Property to avoid discover new objects in unit of work if application
* always uses persist.
*/
protected boolean persistOnCommit;
/**
* Property to avoid writing to the cache on commit (merge)
*/
protected boolean cacheStoreBypass;
/**
* The FlashClearCache mode to be used. Relevant only in case call to flush
* method followed by call to clear method.
*
* @see org.eclipse.persistence.config.FlushClearCache
*/
protected String flushClearCache;
/** Determine if does-exist should be performed on persist. */
protected boolean shouldValidateExistence;
/** Allow updates to be ordered by id to avoid possible deadlocks. */
protected org.eclipse.persistence.sessions.UnitOfWork.CommitOrderType commitOrder;
protected boolean commitWithoutPersistRules;
/** Tracks if this EntityManager should automatically associate with the transaction or not*/
protected SynchronizationType syncType;
abstract static class PropertyProcessor {
abstract void process(String name, Object value, EntityManagerImpl em);
}
static Map processors = new HashMap<>() {
{
put(EntityManagerProperties.JOIN_EXISTING_TRANSACTION, new PropertyProcessor() {
@Override
void process(String name, Object value, EntityManagerImpl em) {
em.beginEarlyTransaction = "true".equalsIgnoreCase(getPropertiesHandlerProperty(name, (String)value));
}});
put(EntityManagerProperties.PERSISTENCE_CONTEXT_REFERENCE_MODE, new PropertyProcessor() {
@Override
void process(String name, Object value, EntityManagerImpl em) {
em.referenceMode = ReferenceMode.valueOf(getPropertiesHandlerProperty(name, (String)value));
if (em.hasActivePersistenceContext()) {
em.extendedPersistenceContext.log(SessionLog.WARNING, SessionLog.PROPERTIES, "entity_manager_sets_property_while_context_is_active", new Object[]{name});
}
}});
put(EntityManagerProperties.PERSISTENCE_CONTEXT_FLUSH_MODE, new PropertyProcessor() {
@Override
void process(String name, Object value, EntityManagerImpl em) {
em.flushMode = FlushModeType.valueOf(getPropertiesHandlerProperty(name, (String)value));
}});
put(EntityManagerProperties.PERSISTENCE_CONTEXT_CLOSE_ON_COMMIT, new PropertyProcessor() {
@Override
void process(String name, Object value, EntityManagerImpl em) {
em.closeOnCommit = "true".equalsIgnoreCase(getPropertiesHandlerProperty(name, (String)value));
if(em.hasActivePersistenceContext()) {
em.extendedPersistenceContext.setResumeUnitOfWorkOnTransactionCompletion(!em.closeOnCommit);
}
}});
put(EntityManagerProperties.PERSISTENCE_CONTEXT_PERSIST_ON_COMMIT, new PropertyProcessor() {
@Override
void process(String name, Object value, EntityManagerImpl em) {
em.persistOnCommit = "true".equalsIgnoreCase(getPropertiesHandlerProperty(name, (String)value));
if(em.hasActivePersistenceContext()) {
em.extendedPersistenceContext.setShouldDiscoverNewObjects(em.persistOnCommit);
}
}});
put(EntityManagerProperties.PERSISTENCE_CONTEXT_COMMIT_WITHOUT_PERSIST_RULES, new PropertyProcessor() {
@Override
void process(String name, Object value, EntityManagerImpl em) {
em.commitWithoutPersistRules = "true".equalsIgnoreCase(getPropertiesHandlerProperty(name, (String)value));
if (em.hasActivePersistenceContext()) {
em.extendedPersistenceContext.setDiscoverUnregisteredNewObjectsWithoutPersist(em.commitWithoutPersistRules);
}
}});
put(EntityManagerProperties.VALIDATE_EXISTENCE, new PropertyProcessor() {
@Override
void process(String name, Object value, EntityManagerImpl em) {
em.shouldValidateExistence = "true".equalsIgnoreCase(getPropertiesHandlerProperty(name, (String)value));
if (em.hasActivePersistenceContext()) {
em.extendedPersistenceContext.setShouldValidateExistence(em.shouldValidateExistence);
}
}});
put(EntityManagerProperties.ORDER_UPDATES, new PropertyProcessor() {
@Override
void process(String name, Object value, EntityManagerImpl em) {
if ("true".equalsIgnoreCase(getPropertiesHandlerProperty(name, (String)value))) {
em.commitOrder = CommitOrderType.ID;
} else {
em.commitOrder = CommitOrderType.NONE;
}
if (em.hasActivePersistenceContext()) {
em.extendedPersistenceContext.setCommitOrder(em.commitOrder);
}
}});
put(EntityManagerProperties.PERSISTENCE_CONTEXT_COMMIT_ORDER, new PropertyProcessor() {
@Override
void process(String name, Object value, EntityManagerImpl em) {
em.commitOrder = CommitOrderType.valueOf(getPropertiesHandlerProperty(name, (String)value).toUpperCase(Locale.ROOT));
if (em.hasActivePersistenceContext()) {
em.extendedPersistenceContext.setCommitOrder(em.commitOrder);
}
}});
put(EntityManagerProperties.FLUSH_CLEAR_CACHE, new PropertyProcessor() {
@Override
void process(String name, Object value, EntityManagerImpl em) {
em.flushClearCache = getPropertiesHandlerProperty(name, (String)value);
if( em.hasActivePersistenceContext()) {
em.extendedPersistenceContext.setFlushClearCache(em.flushClearCache);
}
}});
put(QueryHints.CACHE_STORE_MODE, new PropertyProcessor() {
@Override
void process(String name, Object value, EntityManagerImpl em) {
// This property could be a string or an enum.
em.cacheStoreBypass = value.equals(CacheStoreMode.BYPASS) || value.equals(CacheStoreMode.BYPASS.name());
if(em.hasActivePersistenceContext()) {
em.extendedPersistenceContext.setShouldStoreByPassCache(em.cacheStoreBypass);
}
}});
PropertyProcessor connectionPolicyPropertyProcessor = new PropertyProcessor() {
@Override
void process(String name, Object value, EntityManagerImpl em) {
// Property used to create ConnectionPolicy has changed - already existing ConnectionPolicy should be removed.
// A new one will be created when the new active persistence context is created.
em.connectionPolicy = null;
if (em.hasActivePersistenceContext()) {
em.extendedPersistenceContext.log(SessionLog.WARNING, SessionLog.PROPERTIES, "entity_manager_sets_property_while_context_is_active", new Object[]{name});
}
}};
put(EntityManagerProperties.EXCLUSIVE_CONNECTION_MODE, connectionPolicyPropertyProcessor);
put(EntityManagerProperties.EXCLUSIVE_CONNECTION_IS_LAZY, connectionPolicyPropertyProcessor);
put(EntityManagerProperties.JTA_DATASOURCE, connectionPolicyPropertyProcessor);
put(EntityManagerProperties.NON_JTA_DATASOURCE, connectionPolicyPropertyProcessor);
put(EntityManagerProperties.JDBC_DRIVER, connectionPolicyPropertyProcessor);
put(EntityManagerProperties.JDBC_URL, connectionPolicyPropertyProcessor);
put(EntityManagerProperties.JDBC_USER, connectionPolicyPropertyProcessor);
put(EntityManagerProperties.JDBC_PASSWORD, connectionPolicyPropertyProcessor);
put(EntityManagerProperties.CONNECTION_POLICY, connectionPolicyPropertyProcessor);
put(EntityManagerProperties.ORACLE_PROXY_TYPE, new PropertyProcessor() {
@Override
void process(String name, Object value, EntityManagerImpl em) {
if (em.hasActivePersistenceContext()) {
em.extendedPersistenceContext.log(SessionLog.WARNING, SessionLog.PROPERTIES, "entity_manager_sets_property_while_context_is_active", new Object[]{name});
}
}});
put(EntityManagerProperties.COMPOSITE_UNIT_PROPERTIES, new PropertyProcessor() {
@Override
void process(String name, Object value, EntityManagerImpl em) {
if( em.connectionPolicies != null) {
Map mapOfProperties = (Map) value;
Iterator it = mapOfProperties.keySet().iterator();
while (it.hasNext()) {
String sessionName = it.next();
if (em.connectionPolicies.containsKey(sessionName)) {
// Property used to create ConnectionPolicy has changed - already existing ConnectionPolicy should be removed.
// A new one will be created when the new active persistence context is created.
em.connectionPolicies.put(sessionName, null);
}
}
if (em.hasActivePersistenceContext()) {
em.extendedPersistenceContext.log(SessionLog.WARNING, SessionLog.PROPERTIES, "entity_manager_sets_property_while_context_is_active", new Object[]{name});
}
}
}});
}
};
/**
* Constructor returns an EntityManager assigned to the a particular
* DatabaseSession.
*
* @param sessionName
* the DatabaseSession name that should be used. This constructor
* can potentially throw EclipseLink exceptions regarding the
* existence, or errors with the specified session.
*/
public EntityManagerImpl(String sessionName) {
this(SessionManager.getManager().getSession(sessionName), null, SynchronizationType.SYNCHRONIZED);
}
/**
* Return the weak reference to the open queries.
*/
protected Map getOpenQueriesMap() {
if (openQueriesMap == null) {
openQueriesMap = new WeakHashMap<>();
}
return openQueriesMap;
}
/**
* Return the weak reference to the open queries.
*/
protected Set getOpenQueriesSet() {
return getOpenQueriesMap().keySet();
}
/**
* Queries that leave the connection and are executed against this entity
* manager will be added here. On rollback or commit any left over open
* queries should be closed.
*
*/
public void addOpenQuery(QueryImpl query) {
getOpenQueriesMap().put(query, query);
// If there is an open entity transaction, tag the query to it to be closed
// on commit or rollback.
Object transaction = checkForTransaction(false);
if (transaction != null && transaction instanceof EntityTransactionImpl) {
((EntityTransactionImpl) transaction).addOpenQuery(query);
}
}
/**
* Constructor called from the EntityManagerFactory to create an
* EntityManager
*
* @param databaseSession
* the databaseSession assigned to this deployment.
*/
public EntityManagerImpl(AbstractSession databaseSession, SynchronizationType syncType) {
this(databaseSession, null, syncType);
}
/**
* Constructor called from the EntityManagerFactory to create an
* EntityManager
*
* @param databaseSession
* the databaseSession assigned to this deployment. Note: The
* properties argument is provided to allow properties to be
* passed into this EntityManager, but there are currently no
* such properties implemented
*/
public EntityManagerImpl(AbstractSession databaseSession, Map properties, SynchronizationType syncType) {
this(new EntityManagerFactoryImpl(databaseSession).unwrap(), properties, syncType);
}
/**
* Constructor called from the EntityManagerFactory to create an
* EntityManager
*
* @param factory
* the EntityMangerFactoryImpl that created this entity manager.
* Note: The properties argument is provided to allow properties
* to be passed into this EntityManager, but there are currently
* no such properties implemented
*/
public EntityManagerImpl(EntityManagerFactoryDelegate factory, Map properties, SynchronizationType syncType) {
this.factory = factory;
this.databaseSession = factory.getAbstractSession();
this.beginEarlyTransaction = factory.getBeginEarlyTransaction();
this.closeOnCommit = factory.getCloseOnCommit();
this.flushMode = factory.getFlushMode();
this.persistOnCommit = factory.getPersistOnCommit();
this.commitWithoutPersistRules = factory.getCommitWithoutPersistRules();
this.referenceMode = factory.getReferenceMode();
this.flushClearCache = factory.getFlushClearCache();
this.shouldValidateExistence = factory.shouldValidateExistence();
this.commitOrder = factory.getCommitOrder();
this.isOpen = true;
this.cacheStoreBypass = false;
this.syncType = syncType;
initialize(properties);
}
/**
* Initialize the state after construction.
*/
protected void initialize(Map properties) {
detectTransactionWrapper();
// Cache default ConnectionPolicy. If ConnectionPolicy property(ies) specified
// then connectionPolicy will be set to null and re-created when when active persistence context is created.
if(this.databaseSession.isServerSession()) {
this.connectionPolicy = ((ServerSession)this.databaseSession).getDefaultConnectionPolicy();
} else if (this.databaseSession.isBroker()) {
SessionBroker broker = (SessionBroker)this.databaseSession;
this.connectionPolicies = new HashMap<>(broker.getSessionsByName().size());
Iterator> it = broker.getSessionsByName().entrySet().iterator();
while (it.hasNext()) {
Map.Entry entry = it.next();
this.connectionPolicies.put(entry.getKey(), ((ServerSession)entry.getValue()).getDefaultConnectionPolicy());
}
}
// bug 236249: In JPA session.setProperty() throws
// UnsupportedOperationException.
if (properties != null) {
this.properties = new HashMap<>(properties);
if(!properties.isEmpty()) {
processProperties();
}
}
}
/**
* Clear the persistence context, causing all managed entities to become
* detached. Changes made to entities that have not been flushed to the
* database will not be persisted.
*/
@Override
public void clear() {
try {
verifyOpen();
if (this.extendedPersistenceContext != null) {
if (checkForTransaction(false) == null) {
// 259993: WebSphere 7.0 during a JPAEMPool.putEntityManager() afterCompletion callback
// may attempt to clear an entityManager in lifecyle/state 4 with a transaction commit active
// that is in the middle of a commit for an insert or update by calling em.clear(true).
// We only clear the entityManager if we are in the states
// (Birth == 0, WriteChangesFailed==3, Death==5 or AfterExternalTransactionRolledBack==6).
// If we are in one of the following *Pending states (1,2 and 4) we defer the clear() to the release() call later.
// Note: the single state CommitTransactionPending==2 may never happen as a result of an em.clear
if(this.extendedPersistenceContext.isSynchronized() &&
( this.extendedPersistenceContext.isCommitPending()
|| this.extendedPersistenceContext.isAfterWriteChangesButBeforeCommit()
|| this.extendedPersistenceContext.isMergePending())) {
// when jta transaction afterCompleteion callback will have completed merge,
// the uow will be released.
// Change sets will be cleared, but the cache will be kept.
// uow still could be used for instantiating of ValueHolders
// after it's released.
extendedPersistenceContext.setResumeUnitOfWorkOnTransactionCompletion(false);
} else {
// clear all change sets and cache
this.extendedPersistenceContext.clearForClose(true);
this.extendedPersistenceContext.release();
this.extendedPersistenceContext.getParent().release();
}
this.extendedPersistenceContext = null;
} else {
// clear all change sets created after the last flush and
// cache
this.extendedPersistenceContext.clear(true);
}
}
} catch (RuntimeException exception) {
setRollbackOnly();
throw exception;
}
}
/**
* Internal method called by EntityTransactionImpl class in case of
* transaction rollback. The caller is responsible for releasing
* extendedPersistenceContext and it's parent.
*/
public void removeExtendedPersistenceContext() {
this.extendedPersistenceContext = null;
}
/**
* If in a transaction this method will check for existence and register the
* object if it is new. The instance of the entity provided will become
* managed.
*
* @throws IllegalArgumentException
* if the given Object is not an entity.
*/
@Override
public void persist(Object entity) {
try {
verifyOpen();
if (entity == null) {
throw new IllegalArgumentException(ExceptionLocalization.buildMessage("not_an_entity", new Object[] { null }));
}
try {
getActivePersistenceContext(checkForTransaction(false)).registerNewObjectForPersist(entity, new IdentityHashMap());
} catch (RuntimeException exception) {
if (exception instanceof ValidationException) {
throw new EntityExistsException(exception.getLocalizedMessage(), exception);
}
throw exception;
}
} catch (RuntimeException exception) {
setRollbackOnly();
throw exception;
}
}
/**
* Merge the state of the given entity into the current persistence context,
* using the unqualified class name as the entity name.
*
* @return the instance that the state was merged to
*/
@Override
public T merge(T entity) {
try {
verifyOpen();
return (T) mergeInternal(entity);
} catch (RuntimeException e) {
setRollbackOnly();
throw e;
}
}
/**
* Merge the state of the given entity into the current persistence context,
* using the unqualified class name as the entity name.
*
* @return the instance that the state was merged to
* @throws IllegalArgumentException
* if given Object is not an entity or is a removed entity
*/
protected Object mergeInternal(Object entity) {
if (entity == null) {
throw new IllegalArgumentException(ExceptionLocalization.buildMessage("not_an_entity", new Object[] { null }));
}
Object merged = null;
UnitOfWorkImpl context = getActivePersistenceContext(checkForTransaction(false));
try {
merged = context.mergeCloneWithReferences(entity, MergeManager.CASCADE_BY_MAPPING, true);
} catch (org.eclipse.persistence.exceptions.OptimisticLockException ole) {
throw new jakarta.persistence.OptimisticLockException(ole);
}
return merged;
}
/**
* Remove the instance.
*
* @throws IllegalArgumentException
* if Object passed in is not an entity
*/
@Override
public void remove(Object entity) {
try {
verifyOpen();
if (entity == null) { // gf732 - check for null
throw new IllegalArgumentException(ExceptionLocalization.buildMessage("not_an_entity", new Object[] { null }));
}
try {
getActivePersistenceContext(checkForTransaction(false)).performRemove(entity, new IdentityHashMap());
} catch (RuntimeException e) {
throw e;
}
} catch (RuntimeException e) {
setRollbackOnly();
throw e;
}
}
/**
* Find by primary key.
*
* @param entityClass
* - the entity class to find.
* @param primaryKey
* - the entity primary key value, or primary key class, or a
* List of primary key values.
* @return the found entity instance or null if the entity does not exist
* @throws IllegalArgumentException
* if the first argument does not denote an entity type or the
* second argument is not a valid type for that entity's primary
* key.
*/
@Override
public T find(Class entityClass, Object primaryKey) {
return find(entityClass, primaryKey, null, getQueryHints(entityClass, OperationType.FIND));
}
/**
* Find by primary key, using the specified properties. Search for an entity
* of the specified class and primary key. If the entity instance is
* contained in the persistence context it is returned from there. If a
* vendor-specific property or hint is not recognized, it is silently
* ignored.
*
* @param properties
* standard and vendor-specific properties
* @return the found entity instance or null if the entity does not exist
* @throws IllegalArgumentException
* if the first argument does not denote an entity type or the
* second argument is is not a valid type for that entity's
* primary key or is null
*
* @since Java Persistence API 2.0
*/
@Override
public T find(Class entityClass, Object primaryKey, Map properties) {
return find(entityClass, primaryKey, null, properties);
}
/**
* Find by primary key and lock. Search for an entity of the specified class
* and primary key and lock it with respect to the specified lock type. If
* the entity instance is contained in the persistence context it is
* returned from there. If the entity is found within the persistence
* context and the lock mode type is pessimistic and the entity has a
* version attribute, the persistence provider must perform optimistic
* version checks when obtaining the database lock. If these checks fail,
* the OptimisticLockException will be thrown. If the lock mode type is
* pessimistic and the entity instance is found but cannot be locked: - the
* PessimisticLockException will be thrown if the database locking failure
* causes transaction-level rollback. - the LockTimeoutException will be
* thrown if the database locking failure causes only statement-level
* rollback
*
* @return the found entity instance or null if the entity does not exist
* @throws IllegalArgumentException
* if the first argument does not denote an entity type or the
* second argument is not a valid type for that entity's primary
* key or is null
* @throws TransactionRequiredException
* if there is no transaction and a lock mode other than NONE is
* set
* @throws OptimisticLockException
* if the optimistic version check fails
* @throws PessimisticLockException
* if pessimistic locking fails and the transaction is rolled
* back
* @throws LockTimeoutException
* if pessimistic locking fails and only the statement is rolled
* back
* @throws PersistenceException
* if an unsupported lock call is made
*/
@Override
public T find(Class entityClass, Object primaryKey, LockModeType lockMode) {
return find(entityClass, primaryKey, lockMode, getQueryHints(entityClass, OperationType.FIND));
}
/**
* Find by primary key and lock. Search for an entity of the specified class
* and primary key and lock it with respect to the specified lock type. If
* the entity instance is contained in the persistence context it is
* returned from there. If the entity is found within the persistence
* context and the lock mode type is pessimistic and the entity has a
* version attribute, the persistence provider must perform optimistic
* version checks when obtaining the database lock. If these checks fail,
* the OptimisticLockException will be thrown. If the lock mode type is
* pessimistic and the entity instance is found but cannot be locked: - the
* PessimisticLockException will be thrown if the database locking failure
* causes transaction-level rollback. - the LockTimeoutException will be
* thrown if the database locking failure causes only statement-level
* rollback If a vendor-specific property or hint is not recognized, it is
* silently ignored. Portable applications should not rely on the standard
* timeout hint. Depending on the database in use and the locking mechanisms
* used by the provider, the hint may or may not be observed.
*
* @param properties
* standard and vendor-specific properties and hints
* @return the found entity instance or null if the entity does not exist
* @throws IllegalArgumentException
* if the first argument does not denote an entity type or the
* second argument is not a valid type for that entity's primary
* key or is null
* @throws TransactionRequiredException
* if there is no transaction and a lock mode other than NONE is
* set
* @throws OptimisticLockException
* if the optimistic version check fails
* @throws PessimisticLockException
* if pessimistic locking fails and the transaction is rolled
* back
* @throws LockTimeoutException
* if pessimistic locking fails and only the statement is rolled
* back
* @throws PersistenceException
* if an unsupported lock call is made
*/
@Override
public T find(Class entityClass, Object primaryKey, LockModeType lockMode, Map properties) {
try {
verifyOpen();
if (lockMode != null && !lockMode.equals(LockModeType.NONE)){
checkForTransaction(true);
}
AbstractSession session = this.databaseSession;
ClassDescriptor descriptor = session.getDescriptor(entityClass);
// PERF: Avoid uow creation for read-only.
if (descriptor == null || descriptor.isDescriptorTypeAggregate()) {
throw new IllegalArgumentException(ExceptionLocalization.buildMessage("unknown_bean_class", new Object[] { entityClass }));
}
if (!descriptor.shouldBeReadOnly() || !descriptor.isSharedIsolation()) {
session = (AbstractSession) getActiveSession();
} else {
session = (AbstractSession) getReadOnlySession();
}
// Be sure to use the descriptor from the active session.
if (descriptor.hasTablePerMultitenantPolicy()) {
descriptor = session.getDescriptor(entityClass);
}
return (T) findInternal(descriptor, session, primaryKey, lockMode, properties);
} catch (LockTimeoutException e) {
throw e;
} catch (RuntimeException e) {
setRollbackOnly();
throw e;
}
}
// TODO-API-3.2 - Missing tests
@Override
public T find(Class entityClass, Object primaryKey, FindOption... options) {
// Passing default find query hints, may be overwritten by options
FindOptionUtils.Options parsedOptions = FindOptionUtils.parse(getQueryHints(entityClass, OperationType.FIND), options);
return find(entityClass, primaryKey, parsedOptions.lockModeType(), parsedOptions.properties());
}
// TODO-API-3.2 - Missing tests
@Override
public T find(EntityGraph entityGraph, Object primaryKey, FindOption... options) {
Class entityClass = ((EntityGraphImpl)entityGraph).getClassType();
Map properties = getQueryHints(entityClass, OperationType.FIND);
properties.put(QueryHints.JPA_FETCH_GRAPH, entityGraph);
FindOptionUtils.Options parsedOptions = FindOptionUtils.parse(getQueryHints(entityClass, OperationType.FIND), options);
return find(entityClass, primaryKey, parsedOptions.lockModeType(), parsedOptions.properties());
}
/**
* Find by primary key.
*
* @param entityName
* - the entity class to find.
* @param primaryKey
* - the entity primary key value, or primary key class, or a
* List of primary key values.
* @return the found entity instance or null, if the entity does not exist.
* @throws IllegalArgumentException
* if the first argument does not indicate an entity or if the
* second argument is not a valid type for that entity's
* primaryKey.
*/
public Object find(String entityName, Object primaryKey) {
try {
verifyOpen();
AbstractSession session = (AbstractSession) getActiveSession();
ClassDescriptor descriptor = session.getDescriptorForAlias(entityName);
if (descriptor == null || descriptor.isDescriptorTypeAggregate()) {
throw new IllegalArgumentException(ExceptionLocalization.buildMessage("unknown_entitybean_name", new Object[] { entityName }));
}
return findInternal(descriptor, session, primaryKey, null, null);
} catch (LockTimeoutException e) {
throw e;
} catch (RuntimeException e) {
setRollbackOnly();
throw e;
}
}
/**
* Find by primary key.
*
* @param descriptor
* - the entity class to find.
* @param id
* - the entity primary key value, or primary key class, or a
* List of primary key values.
* @return the found entity instance or null, if the entity does not exist.
* @throws IllegalArgumentException
* if the first argument does not denote an entity type or the
* second argument is not a valid type for that entity's primary
* key.
*/
protected Object findInternal(ClassDescriptor descriptor, AbstractSession session, Object id, LockModeType lockMode, Map properties) {
if (id == null) { // gf721 - check for null PK
throw new IllegalArgumentException(ExceptionLocalization.buildMessage("null_pk"));
}
Object primaryKey;
if (id instanceof List) {
if (descriptor.getCacheKeyType() == CacheKeyType.ID_VALUE) {
if (((List)id).isEmpty()) {
primaryKey = null;
} else {
primaryKey = ((List)id).get(0);
}
} else {
primaryKey = new CacheId(((List)id).toArray());
}
} else if (id instanceof CacheId) {
primaryKey = id;
} else {
CMPPolicy policy = descriptor.getCMPPolicy();
Class