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

com.sun.enterprise.container.common.impl.EntityManagerWrapper Maven / Gradle / Ivy

There is a newer version: 7.2024.1.Alpha1
Show newest version
/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 1997-2014 Oracle and/or its affiliates. All rights reserved.
 *
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License.  You can
 * obtain a copy of the License at
 * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
 * or packager/legal/LICENSE.txt.  See the License for the specific
 * language governing permissions and limitations under the License.
 *
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at packager/legal/LICENSE.txt.
 *
 * GPL Classpath Exception:
 * Oracle designates this particular file as subject to the "Classpath"
 * exception as provided by Oracle in the GPL Version 2 section of the License
 * file that accompanied this code.
 *
 * Modifications:
 * If applicable, add the following below the License Header, with the fields
 * enclosed by brackets [] replaced by your own identifying information:
 * "Portions Copyright [year] [name of copyright owner]"
 *
 * Contributor(s):
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don't indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 */
// Portions Copyright [2016-2021] [Payara Foundation]

package com.sun.enterprise.container.common.impl;

import com.sun.enterprise.container.common.spi.JavaEEContainer;
import com.sun.enterprise.container.common.spi.util.CallFlowAgent;
import com.sun.enterprise.container.common.spi.util.ComponentEnvManager;
import com.sun.enterprise.container.common.spi.util.EntityManagerMethod;
import com.sun.enterprise.transaction.api.JavaEETransaction;
import com.sun.logging.LogDomains;
import org.glassfish.api.invocation.ComponentInvocation;
import org.glassfish.api.invocation.ComponentInvocationHandler;
import org.glassfish.api.invocation.InvocationException;
import org.glassfish.api.invocation.InvocationManager;
import org.glassfish.hk2.api.ServiceLocator;
import org.glassfish.internal.api.Globals;
import org.jvnet.hk2.annotations.Service;

import static jakarta.persistence.SynchronizationType.SYNCHRONIZED;
import static jakarta.persistence.SynchronizationType.UNSYNCHRONIZED;
import jakarta.persistence.criteria.*;
import jakarta.persistence.*;
import jakarta.persistence.metamodel.Metamodel;
import jakarta.transaction.TransactionManager;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Implementation of a container-managed entity manager.
 * A new instance of this class will be created for each injected
 * EntityManager reference or each lookup of an EntityManager
 * reference within the component jndi environment.
 * The underlying EntityManager object does not support concurrent access.
 * Likewise, this wrapper does not support concurrent access.
 *
 * @author Kenneth Saks
 */
public class EntityManagerWrapper implements EntityManager, Serializable {

    static Logger _logger=LogDomains.getLogger(EntityManagerWrapper.class, LogDomains.UTIL_LOGGER, false);

    // Serializable state

    private String unitName;
    private PersistenceContextType contextType;
    private Map emProperties;
    private SynchronizationType synchronizationType;

    // transient state

    transient private EntityManagerFactory entityManagerFactory;

    transient private TransactionManager txManager;

    transient private InvocationManager invMgr;

    // Only used to cache entity manager with EXTENDED persistence context
    transient private EntityManager extendedEntityManager;

    transient private ComponentEnvManager compEnvMgr;

    transient private CallFlowAgent callFlowAgent;

    public EntityManagerWrapper(TransactionManager txManager, InvocationManager invMgr,
                                ComponentEnvManager compEnvMgr, CallFlowAgent callFlowAgent) {
        this.txManager = txManager;
        this.invMgr = invMgr;
        this.compEnvMgr = compEnvMgr;
        this.callFlowAgent = callFlowAgent;
    }

    public void initializeEMWrapper(String unitName,
        PersistenceContextType contextType, SynchronizationType synchronizationType, Map emProperties) {
        this.unitName = unitName;
        this.contextType = contextType;
        this.synchronizationType = synchronizationType;
        this.emProperties = emProperties;
        if(contextType == PersistenceContextType.EXTENDED) {
            // We are initializing an extended EM. The physical em is already created and stored in SessionContext to
            // enable persistence context propagation.
            // Initialize the delegate eagerly to support use cases like issue 11805
            _getDelegate();
        }
    }

    private void init() {

        entityManagerFactory = EntityManagerFactoryWrapper.
            lookupEntityManagerFactory(invMgr, compEnvMgr, unitName);

        if( entityManagerFactory == null ) {
            throw new IllegalStateException
                ("Unable to retrieve EntityManagerFactory for unitName "
                 + unitName);
        }

    }

    private void doTransactionScopedTxCheck() {

        if( contextType != PersistenceContextType.TRANSACTION) {
            return;
        }

        doTxRequiredCheck();

    }

    private void doTxRequiredCheck() {

        if( entityManagerFactory == null ) {
            init();
        }
        if( getCurrentTransaction() == null ) {
            throw new TransactionRequiredException();
        }

    }
    private EntityManager _getDelegate() {

        // Populate any transient objects the first time
        // this method is called.

        if( entityManagerFactory == null ) {
            init();
        }

        EntityManager delegate;

        if( contextType == PersistenceContextType.TRANSACTION ) {

            JavaEETransaction tx = getCurrentTransaction();

            if( tx != null ) {

                // If there is an active extended persistence context
                // for the same entity manager factory and the same tx,
                // it takes precedence.
                PhysicalEntityManagerWrapper propagatedPersistenceContext = getExtendedEntityManager(tx, entityManagerFactory);
                if(propagatedPersistenceContext == null) {

                    propagatedPersistenceContext = getTxEntityManager(tx, entityManagerFactory);


                    if( propagatedPersistenceContext == null ) {

                        // If there is a transaction and this is the first
                        // access of the wrapped entity manager, create an
                        // actual entity manager and associate it with the
                        // entity manager factory.
                        EntityManager em = entityManagerFactory.createEntityManager(synchronizationType, emProperties);
                        propagatedPersistenceContext = new PhysicalEntityManagerWrapper(em, synchronizationType);
                        tx.addTxEntityManagerMapping(entityManagerFactory, propagatedPersistenceContext);
                    } else {

                        //Check if sync type of current persistence context is compatible with persistence context being propagated
                        if(synchronizationType == SYNCHRONIZED && propagatedPersistenceContext.getSynchronizationType() == UNSYNCHRONIZED) {
                            throw new IllegalStateException("Detected an UNSYNCHRONIZED  persistence context being propagated to SYNCHRONIZED persistence context.");
                        }

                    }
                }
                delegate = propagatedPersistenceContext.getEM();

            } else {
                //Get non transactional entity manager corresponding to this wrapper from current invocation
                delegate  = getNonTxEMFromCurrentInvocation();
            }

        } else {

            // EXTENDED Persitence Context

            if( extendedEntityManager == null ) {
                ComponentInvocation ci = invMgr.getCurrentInvocation();
                if (ci != null) {
                    Object cc = ci.getContainer();
                    if (cc instanceof JavaEEContainer) {
                        extendedEntityManager = ((JavaEEContainer) cc).lookupExtendedEntityManager(
                                entityManagerFactory);
                    }
                }
            }
            if (extendedEntityManager == null) {
                throw new IllegalStateException("No EntityManager available in current extended persistence context.");
            }
            delegate = extendedEntityManager;

        }

        if( _logger.isLoggable(Level.FINE) ) {
            _logger.fine("In EntityManagerWrapper::_getDelegate(). " +
                         "Logical entity manager  = " + this);
            _logger.fine("Physical entity manager = " + delegate);
        }

        return delegate;

    }

    private JavaEETransaction getCurrentTransaction() {
        try {
            return (JavaEETransaction) txManager.getTransaction();
        } catch(Exception e) {
            throw new IllegalStateException("exception retrieving tx", e);
        }
    }

    private static final Class INVOCATION_PAYLOAD_KEY = EntityManagerWrapper.class; //Key used to look up payload from current invocation

    private EntityManager getNonTxEMFromCurrentInvocation() {
        // We store nonTxEM as a payload in a map from EMF to EM inside current invocation.
        // It will be closed during  NonTxEntityManagerCleaner.beforePostInvoke() below

        ComponentInvocation currentInvocation = invMgr.getCurrentInvocation();
        Map nonTxEMs = getNonTxEMsFromCurrentInvocation(currentInvocation);
        if(nonTxEMs == null) {
            nonTxEMs = new HashMap<>();
            currentInvocation.setRegistryFor(INVOCATION_PAYLOAD_KEY, nonTxEMs);
        }
        EntityManager nonTxEM = nonTxEMs.get(entityManagerFactory);
        if(nonTxEM == null) {
            // Could not find one, create new one and store it within current invocation for cleanup
            nonTxEM = entityManagerFactory.createEntityManager(synchronizationType, emProperties);
            nonTxEMs.put(entityManagerFactory, nonTxEM);
        }
        return nonTxEM;
    }

    @SuppressWarnings("unchecked")
    private static Map getNonTxEMsFromCurrentInvocation(ComponentInvocation currentInvocation) {
        return (Map)currentInvocation.getRegistryFor(INVOCATION_PAYLOAD_KEY);
    }

    @Override
    public void persist(Object entity) {
        doTransactionScopedTxCheck();

        try {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodStart(EntityManagerMethod.PERSIST);
            }
            _getDelegate().persist(entity);
        } finally {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodEnd();
            }
        }

        // tx is required so there's no need to do any non-tx cleanup
    }

    @Override
    public  T merge(T entity) {
        doTransactionScopedTxCheck();

        try {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodStart(EntityManagerMethod.MERGE);
            }
            return _getDelegate().merge(entity);
        } finally {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodEnd();
            }
        }

        // tx is required so there's no need to do any non-tx cleanup
    }

    @Override
    public void remove(Object entity) {
        doTransactionScopedTxCheck();

        try {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodStart(EntityManagerMethod.REMOVE);
            }
            _getDelegate().remove(entity);
        } finally {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodEnd();
            }
        }

        // tx is required so there's no need to do any non-tx cleanup
    }

    @Override
    public  T find(Class entityClass, Object primaryKey) {
        T returnValue = null;

        try {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodStart(EntityManagerMethod.FIND);
            }
            EntityManager delegate = _getDelegate();
            returnValue = delegate.find(entityClass, primaryKey);
            clearDetachedPersistenceContext (delegate);
        } finally {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodEnd();
            }
        }
        return returnValue;
    }

    @Override
    public  T find(Class entityClass, Object primaryKey, Map properties) {
        T returnValue = null;

        try {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodStart(EntityManagerMethod.FIND);
            }
            EntityManager delegate = _getDelegate();
            returnValue = _getDelegate().find(entityClass, primaryKey, properties);
            clearDetachedPersistenceContext (delegate);
        } finally {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodEnd();
            }
        }
        return returnValue;
    }


    @Override
    public  T find(Class entityClass, Object primaryKey, LockModeType lockMode) {
        T returnValue = null;

        try {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodStart(EntityManagerMethod.FIND_CLASS_OBJECT_LOCKMODETYPE);
            }
            EntityManager delegate = _getDelegate();
            returnValue = _getDelegate().find(entityClass, primaryKey, lockMode);
            clearDetachedPersistenceContext (delegate);
        } finally {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodEnd();
            }
        }
        return returnValue;
    }

    @Override
    public  T find(Class entityClass, Object primaryKey, LockModeType lockMode, Map properties) {
        T returnValue = null;

        try {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodStart(EntityManagerMethod.FIND_CLASS_OBJECT_LOCKMODETYPE_PROPERTIES);
            }
            EntityManager delegate = _getDelegate();
            returnValue = _getDelegate().find(entityClass, primaryKey, lockMode, properties);
            clearDetachedPersistenceContext (delegate);
        } finally {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodEnd();
            }
        }
        return returnValue;
    }

    @Override
    public  T getReference(Class entityClass, Object primaryKey) {
        T returnValue = null;

        try {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodStart(EntityManagerMethod.GET_REFERENCE);
            }
            returnValue = _getDelegate().getReference(entityClass, primaryKey);
        } finally {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodEnd();
            }
        }
        return returnValue;
    }

    @Override
    public void flush() {
        // tx is ALWAYS required, regardless of persistence context type.
        doTxRequiredCheck();


        try {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodStart(EntityManagerMethod.FLUSH);
            }
            _getDelegate().flush();
        } finally {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodEnd();
            }
        }

        // tx is required so there's no need to do any non-tx cleanup
    }

    @Override
    public Query createQuery(String ejbqlString) {
        Query returnValue = null;

        try {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodStart(EntityManagerMethod.CREATE_QUERY);
            }
            EntityManager delegate = _getDelegate();
            returnValue = delegate.createQuery(ejbqlString);

            returnValue = wrapDetachedQuery(returnValue, delegate);
        } finally {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodEnd();
            }
        }
        return returnValue;
    }

    @Override
    public  TypedQuery createQuery(String ejbqlString, Class resultClass) {
        TypedQuery returnValue = null;

        try {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodStart(EntityManagerMethod.CREATE_QUERY_STRING_CLASS);
            }
            EntityManager delegate = _getDelegate();
            returnValue = delegate.createQuery(ejbqlString, resultClass);

            returnValue = wrapDetachedQuery(returnValue, delegate);
        } finally {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodEnd();
            }
        }
        return returnValue;
    }

    @Override
    public  TypedQuery createQuery(CriteriaQuery criteriaQuery) {
        TypedQuery returnValue = null;

        try {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodStart(EntityManagerMethod.CREATE_QUERY_CRITERIA_QUERY);
            }
            EntityManager delegate = _getDelegate();
            returnValue = delegate.createQuery(criteriaQuery);

            returnValue = wrapDetachedQuery(returnValue, delegate);
        }finally {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodEnd();
            }
        }
        return returnValue;
    }

    @Override
    public Query createNamedQuery(String name) {
        Query returnValue = null;

        try {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodStart(EntityManagerMethod.CREATE_NAMED_QUERY);
            }
            EntityManager delegate = _getDelegate();
            returnValue = delegate.createNamedQuery(name);

            returnValue = wrapDetachedQuery(returnValue, delegate);
        }finally {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodEnd();
            }
        }

        return returnValue;
    }

    @Override
    public  TypedQuery createNamedQuery(String name, Class resultClass) {
        TypedQuery returnValue = null;

        try {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodStart(EntityManagerMethod.CREATE_NAMED_QUERY);
            }
            EntityManager delegate = _getDelegate();
            returnValue = delegate.createNamedQuery(name, resultClass);

            returnValue = wrapDetachedQuery(returnValue, delegate);
        }finally {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodEnd();
            }
        }

        return returnValue;
    }

    @Override
    public Query createNativeQuery(String sqlString) {
        Query returnValue = null;

        try {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodStart(EntityManagerMethod.CREATE_NATIVE_QUERY_STRING);
            }
            EntityManager delegate = _getDelegate();
            returnValue = delegate.createNativeQuery(sqlString);

            returnValue = wrapDetachedQuery(returnValue, delegate);
        }finally {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodEnd();
            }
        }
        return returnValue;
    }

    @Override
    public Query createNativeQuery(String sqlString, Class resultClass) {
        Query returnValue = null;

        try {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodStart(EntityManagerMethod.CREATE_NATIVE_QUERY_STRING_CLASS);
            }
            EntityManager delegate = _getDelegate();
            returnValue = delegate.createNativeQuery(sqlString, resultClass);

            returnValue = wrapDetachedQuery(returnValue, delegate);
        }finally {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodEnd();
            }
        }
        return returnValue;
    }

    @Override
    public Query createNativeQuery(String sqlString, String resultSetMapping) {
        Query returnValue = null;

        try {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodStart(EntityManagerMethod.CREATE_NATIVE_QUERY_STRING_STRING);
            }
            EntityManager delegate = _getDelegate();
            returnValue = delegate.createNativeQuery
                (sqlString, resultSetMapping);

            returnValue = wrapDetachedQuery(returnValue, delegate);
        }finally {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodEnd();
            }
        }
        return returnValue;
    }
    
    private StoredProcedureQuery wrapDetachedQuery(StoredProcedureQuery returnValue, EntityManager delegate) {
        if( operatesDetached() ) {
            returnValue = StoreProcedureQueryWrapper.createQueryWrapper(returnValue, delegate);
        }
        return returnValue;
    }
    
    private  TypedQuery wrapDetachedQuery(TypedQuery returnValue, EntityManager delegate) {
        if( operatesDetached() ) {
            returnValue = TypedQueryWrapper.createQueryWrapper(returnValue, delegate);
        }
        return returnValue;
    }
    
    private Query wrapDetachedQuery(Query returnValue, EntityManager delegate) {
        if( operatesDetached()) {
            returnValue = QueryWrapper.createQueryWrapper(returnValue, delegate);
        }
        return returnValue;
    }
    
    private boolean operatesDetached() {
        return getCurrentTransaction() == null && contextType != PersistenceContextType.EXTENDED;
    }

    @Override
    public void refresh(Object entity) {
        doTransactionScopedTxCheck();


        try {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodStart(EntityManagerMethod.REFRESH);
            }
            _getDelegate().refresh(entity);
        } finally {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodEnd();
            }
        }

        // tx is required so there's no need to do any non-tx cleanup
    }

    @Override
    public void refresh(Object entity, Map properties) {
        doTransactionScopedTxCheck();


        try {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodStart(EntityManagerMethod.REFRESH_OBJECT_PROPERTIES);
            }
            _getDelegate().refresh(entity, properties);
        } finally {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodEnd();
            }
        }

        // tx is required so there's no need to do any non-tx cleanup
    }

    @Override
    public void refresh(Object entity, LockModeType lockMode) {
        doTransactionScopedTxCheck();

        try {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodStart(EntityManagerMethod.REFRESH_OBJECT_LOCKMODETYPE);
            }
            _getDelegate().refresh(entity, lockMode);
        } finally {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodEnd();
            }
        }

        // tx is required so there's no need to do any non-tx cleanup
    }

    @Override
    public void refresh(Object entity, LockModeType lockMode, Map properties) {
        doTransactionScopedTxCheck();

        try {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodStart(EntityManagerMethod.REFRESH_OBJECT_LOCKMODETYPE_MAP);
            }
            _getDelegate().refresh(entity, lockMode, properties);
        } finally {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodEnd();
            }
        }

        // tx is required so there's no need to do any non-tx cleanup
    }

    @Override
    public boolean contains(Object entity) {

        try {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodStart(EntityManagerMethod.CONTAINS);
            }
            EntityManager delegate = _getDelegate();
            return delegate.contains(entity);
        } finally {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodEnd();
            }
        }
    }

    @Override
    public LockModeType getLockMode(Object o) {

        doTxRequiredCheck();

        try {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodStart(EntityManagerMethod.GET_LOCK_MODE);
            }
            return _getDelegate().getLockMode(o);
        } finally {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodEnd();
            }
        }

        // tx is required so there's no need to do any non-tx cleanup
    }

    @Override
    public void setProperty(String propertyName, Object value) {

        try {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodStart(EntityManagerMethod.SET_PROPERTY);
            }
            _getDelegate().setProperty(propertyName, value);
        } finally {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodEnd();
            }
        }

        // tx is required so there's no need to do any non-tx cleanup
    }


    @Override
    public Map getProperties() {

        try {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodStart(EntityManagerMethod.GET_PROPERTIES);
            }
            return _getDelegate().getProperties();
        } finally {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodEnd();
            }
        }
    }

    @Override
    public void close() {

        if(callFlowAgent.isEnabled()) {
            callFlowAgent.entityManagerMethodStart(EntityManagerMethod.CLOSE);
            callFlowAgent.entityManagerMethodEnd();
        }
        // close() not allowed on container-managed EMs.
        throw new IllegalStateException();
    }

    @Override
    public boolean isOpen() {

        if(callFlowAgent.isEnabled()) {
            callFlowAgent.entityManagerMethodStart(EntityManagerMethod.IS_OPEN);
            callFlowAgent.entityManagerMethodEnd();
        }
        // Not relevant for container-managed EMs.  Just return true.
        return true;
    }

    @Override
    public EntityTransaction getTransaction() {

        try {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodStart(EntityManagerMethod.GET_TRANSACTION);
            }
            return _getDelegate().getTransaction();
        } finally {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodEnd();
            }
        }
    }

    @Override
    public EntityManagerFactory getEntityManagerFactory() {

        try {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodStart(EntityManagerMethod.GET_ENTITY_MANAGER_FACTORY);
            }
            if( entityManagerFactory == null ) {
                init();
            }

            // Spec requires to throw IllegalStateException if this em has been closed.
            // No need to perform the check here as this can not happen for managed em.
            // No need to go to delegate for this.
            return entityManagerFactory;
        } finally {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodEnd();
            }
        }
    }

    @Override
    public CriteriaBuilder getCriteriaBuilder() {

        try {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodStart(EntityManagerMethod.GET_CRITERIA_BUILDER);
            }
            return _getDelegate().getCriteriaBuilder();
        } finally {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodEnd();
            }
        }

    }

    @Override
    public Metamodel getMetamodel() {

        try {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodStart(EntityManagerMethod.GET_METAMODEL);
            }
            return _getDelegate().getMetamodel();
        } finally {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodEnd();
            }
        }

    }

    @Override
    public void lock(Object entity, LockModeType lockMode) {

        try {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodStart(EntityManagerMethod.LOCK);
            }
            _getDelegate().lock(entity, lockMode);
        } finally {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodEnd();
            }
        }
    }

    @Override
    public void lock(Object entity, LockModeType lockMode, Map properties) {

        try {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodStart(EntityManagerMethod.LOCK_LOCKMODETYPE_MAP);
            }
            _getDelegate().lock(entity, lockMode, properties);
        } finally {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodEnd();
            }
        }
    }

    @Override
    public void clear() {

        try {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodStart(EntityManagerMethod.CLEAR);
            }
            _getDelegate().clear();
        } finally {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodEnd();
            }
        }
    }

    @Override
    public void detach(Object o) {

        //TODO revisit this check once Linda confirms whether it is required or not.
        doTransactionScopedTxCheck();

        try {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodStart(EntityManagerMethod.DETATCH);
            }
            _getDelegate().detach(o);
        } finally {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodEnd();
            }
        }

        // tx is required so there's no need to do any non-tx cleanup
    }

    @Override
    public Object getDelegate() {

        try {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodStart(EntityManagerMethod.GET_DELEGATE);
            }
            return _getDelegate();
        } finally {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodEnd();
            }
        }

    }

    @Override
    public FlushModeType getFlushMode() {

        try {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodStart(EntityManagerMethod.GET_FLUSH_MODE);
            }
            return _getDelegate().getFlushMode();
        } finally {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodEnd();
            }
        }
    }

    @Override
    public void setFlushMode(FlushModeType flushMode) {

        try {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodStart(EntityManagerMethod.SET_FLUSH_MODE);
            }
            _getDelegate().setFlushMode(flushMode);
        } finally {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodEnd();
            }
        }
    }

    @Override
    public void joinTransaction() {
        // Doesn't apply to the container-managed case, but all the
        // spec says is that an exception should be thrown if called
        // without a tx.
        doTxRequiredCheck();

        try {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodStart(EntityManagerMethod.JOIN_TRANSACTION);
            }
            _getDelegate().joinTransaction();
        } finally {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodEnd();
            }
        }

    }

    @Override
    public  T unwrap(Class tClass) {

        try {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodStart(EntityManagerMethod.UNWRAP);
            }
            return _getDelegate().unwrap(tClass);
        } finally {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodEnd();
            }
        }
    }

    @Override
    public StoredProcedureQuery createNamedStoredProcedureQuery(String name)  {
        StoredProcedureQuery returnValue = null;

        try {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodStart(EntityManagerMethod.CREATE_NAMED_STORED_PROCEDURE_QUERY);
            }
            EntityManager delegate = _getDelegate();
            returnValue = delegate.createNamedStoredProcedureQuery(name);

            returnValue = wrapDetachedQuery(returnValue, delegate);
        } finally {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodEnd();
            }
        }
        return returnValue;
    }

    @Override
    public StoredProcedureQuery createStoredProcedureQuery(String procedureName) {
        StoredProcedureQuery returnValue = null;

        try {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodStart(EntityManagerMethod.CREATE_STORED_PROCEDURE_QUERY);
            }
            EntityManager delegate = _getDelegate();
            returnValue = delegate.createStoredProcedureQuery(procedureName);

            returnValue = wrapDetachedQuery(returnValue, delegate);
        } finally {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodEnd();
            }
        }
        return returnValue;
    }

    @Override
    public StoredProcedureQuery createStoredProcedureQuery(String procedureName, Class... resultClasses) {
        StoredProcedureQuery returnValue = null;

        try {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodStart(EntityManagerMethod.CREATE_STORED_PROCEDURE_QUERY_STRING_CLASS);
            }
            EntityManager delegate = _getDelegate();
            returnValue = delegate.createStoredProcedureQuery(procedureName, resultClasses);

            returnValue = wrapDetachedQuery(returnValue, delegate);
        } finally {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodEnd();
            }
        }
        return returnValue;
    }

    @Override
    public StoredProcedureQuery createStoredProcedureQuery(String procedureName, String... resultSetMappings) {
        StoredProcedureQuery returnValue = null;

        try {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodStart(EntityManagerMethod.CREATE_STORED_PROCEDURE_QUERY_STRING_STRING);
            }
            EntityManager delegate = _getDelegate();
            returnValue = delegate.createStoredProcedureQuery(procedureName, resultSetMappings);

            returnValue = wrapDetachedQuery(returnValue, delegate);
        } finally {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodEnd();
            }
        }
        return returnValue;
    }

    public Query createQuery(CriteriaUpdate updateQuery) {
        // Unlike other create*Query() methods, there is not need to create a QueryWrapper for non trnsactional case here.
        // QueryWrappers are created to ensure that entities returned by query are detatched. This is an update query and thus will not return any entities.
        try {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodStart(EntityManagerMethod.CREATE_QUERY_CRITERIA_UPDATE);
            }
            return _getDelegate().createQuery(updateQuery);
        } finally {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodEnd();
            }
        }
    }

    @Override
    public Query createQuery(CriteriaDelete deleteQuery) {
        // Please refer to comments in method createQuery(CriteriaUpdate) for the reason we do not create a QueryWrapper here.
        try {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodStart(EntityManagerMethod.CREATE_QUERY_CRITERIA_DELETE);
            }
            return _getDelegate().createQuery(deleteQuery);
        } finally {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodEnd();
            }
        }
    }

    @Override
    public boolean isJoinedToTransaction() {
        try {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodStart(EntityManagerMethod.IS_JOINED_TO_TRANSACTION);
            }
            return _getDelegate().isJoinedToTransaction();
        } finally {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodEnd();
            }
        }
    }

    @Override
    public  EntityGraph createEntityGraph(Class rootType) {
        try {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodStart(EntityManagerMethod.CREATE_ENTITY_GRAPH_CLASS);
            }
            return _getDelegate().createEntityGraph(rootType);
        } finally {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodEnd();
            }
        }
    }

    @Override
    public EntityGraph createEntityGraph(String graphName) {
        try {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodStart(EntityManagerMethod.CREATE_ENTITY_GRAPH_STRING);
            }
            return _getDelegate().createEntityGraph(graphName);
        } finally {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodEnd();
            }
        }
    }

    @Override
    public EntityGraph getEntityGraph(String graphName) {
        try {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodStart(EntityManagerMethod.GET_ENTITY_GRAPH);
            }
            return _getDelegate().getEntityGraph(graphName);
        } finally {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodEnd();
            }
        }
    }

    @Override
    public  List> getEntityGraphs(Class entityClass) {
        try {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodStart(EntityManagerMethod.GET_ENTITY_GRAPHS);
            }
            return _getDelegate().getEntityGraphs(entityClass);
        } finally {
            if(callFlowAgent.isEnabled()) {
                callFlowAgent.entityManagerMethodEnd();
            }
        }
     }

    private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
        stream.defaultReadObject();

        //Initialize the transients that were passed at ctor.
        ServiceLocator defaultServiceLocator = Globals.getDefaultHabitat();
        txManager     = defaultServiceLocator.getService(TransactionManager.class);
        invMgr        = defaultServiceLocator.getService(InvocationManager.class);
        compEnvMgr    = defaultServiceLocator.getService(ComponentEnvManager.class);
        callFlowAgent = defaultServiceLocator.getService(CallFlowAgent.class);
    }

    private void clearDetachedPersistenceContext(EntityManager em) {
        if(operatesDetached()) {
            em.clear();
        }
    }

    public static PhysicalEntityManagerWrapper getExtendedEntityManager(JavaEETransaction transaction, EntityManagerFactory factory) {
        return (PhysicalEntityManagerWrapper)transaction.getExtendedEntityManagerResource(factory);
    }

    public static PhysicalEntityManagerWrapper  getTxEntityManager(JavaEETransaction transaction, EntityManagerFactory factory) {
        return (PhysicalEntityManagerWrapper) transaction.getTxEntityManagerResource(factory);

    }

    @Service
    /**
     * NonTxEMs are saved as payload in current invocation. Clean them up at end of any component invocation
     */
    public static class NonTxEMCleaner implements ComponentInvocationHandler {

        @Override
        public void beforePreInvoke(ComponentInvocation.ComponentInvocationType invType, ComponentInvocation prevInv, ComponentInvocation newInv) throws InvocationException { }

        @Override
        public void afterPreInvoke(ComponentInvocation.ComponentInvocationType invType, ComponentInvocation prevInv, ComponentInvocation curInv) throws InvocationException { }

        @Override
        public void beforePostInvoke(ComponentInvocation.ComponentInvocationType invType, ComponentInvocation prevInv, ComponentInvocation curInv) throws InvocationException {
            // Close all the NonTxEMs for current invocation
            Map nonTxEMs = getNonTxEMsFromCurrentInvocation(curInv);

            if(nonTxEMs != null) {
                for (EntityManager nonTxEM : nonTxEMs.values()) {
                    nonTxEM.close();
                }
            }
        }

        @Override
        public void afterPostInvoke(ComponentInvocation.ComponentInvocationType invType, ComponentInvocation prevInv, ComponentInvocation curInv) throws InvocationException { }
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy