public Object execute()

in jee-modules/jpa-module/impl/src/main/java/org/apache/myfaces/extensions/cdi/jpa/impl/transaction/TransactionalInterceptorStrategy.java [80:262]


    public Object execute(InvocationContext invocationContext) throws Exception
    {
        Transactional transactionalAnnotation = extractTransactionalAnnotation(invocationContext);

        Class<? extends Annotation> qualifierClass = getTransactionQualifier(transactionalAnnotation);
        String qualifierKey = qualifierClass.getName();

        // the 'layer' of the transactional invocation, aka the refCounter for the current qualifier
        int transactionLayer = incrementRefCounter(qualifierKey);

        if (transactionLayer == 0)
        {
            if (TransactionBeanStorage.getStorage() == null)
            {
                TransactionBeanStorage.activateNewStorage();
            }

            // 0 indicates that a new Context needs to get started
            TransactionBeanStorage.getStorage().startTransactionScope(qualifierKey);
        }

        String previousTransactionKey = TransactionBeanStorage.getStorage().activateTransactionScope(qualifierKey);

        EntityManager entityManager = resolveEntityManagerForQualifier(qualifierClass);

        if(entityManager == null)
        {
            //fallback to support direct injection via @PersistenceContext
            entityManager = PersistenceHelper.tryToFindEntityManagerReference(invocationContext.getTarget());
        }

        storeEntityManagerForQualifier(qualifierKey, entityManager);

        EntityTransaction transaction = entityManager.getTransaction();

        // used to store any exception we get from the services
        Exception firstException = null;

        try
        {
            if(!transaction.isActive())
            {
                transaction.begin();
            }

            return invocationContext.proceed();
        }
        catch(Exception e)
        {
            firstException = e;

            // we only cleanup and rollback all open transactions in the outermost interceptor!
            // this way, we allow inner functions to catch and handle exceptions properly.
            if (isOutermostInterceptor())
            {
                HashMap<String, EntityManager> emsEntries = ems.get();
                for (Map.Entry<String, EntityManager> emsEntry: emsEntries.entrySet())
                {
                    EntityManager em = emsEntry.getValue();
                    transaction = em.getTransaction();
                    if (transaction != null && transaction.isActive())
                    {
                        try
                        {
                            transaction.rollback();
                        }
                        catch (Exception eRollback)
                        {
                            if(LOGGER.isLoggable(Level.SEVERE))
                            {
                                LOGGER.log(Level.SEVERE,
                                        "Got additional Exception while subsequently " +
                                                "rolling back other SQL transactions", eRollback);
                            }
                        }
                    }
                }

                // drop all EntityManagers from the ThreadLocal
                ems.remove();
            }

            // give any extensions a chance to supply a better error message
            e = prepareException(e);

            // rethrow the exception
            throw e;

        }
        finally
        {
            // will get set if we got an Exception while committing
            // in this case, we rollback all later transactions too.
            boolean commitFailed = false;

            // commit all open transactions in the outermost interceptor!
            // this is a 'JTA for poor men' only, and will not guaranty
            // commit stability over various databases!
            if (isOutermostInterceptor())
            {

                // only commit all transactions if we didn't rollback
                // them already
                if (firstException == null)
                {
                    // but first try to flush all the transactions and write the updates to the database
                    for (EntityManager em: ems.get().values())
                    {
                        transaction = em.getTransaction();
                        if(transaction != null && transaction.isActive())
                        {
                            try
                            {
                                if (!commitFailed)
                                {
                                    em.flush();
                                }
                            }
                            catch (Exception e)
                            {
                                firstException = e;
                                commitFailed = true;
                                break;
                            }
                        }
                    }

                    // and now either commit or rollback all transactions
                    for (Map.Entry<String, EntityManager> emEntry: ems.get().entrySet())
                    {
                        EntityManager em = emEntry.getValue();
                        transaction = em.getTransaction();
                        if(transaction != null && transaction.isActive())
                        {
                            try
                            {
                                if (!commitFailed)
                                {
                                    transaction.commit();
                                }
                                else
                                {
                                    transaction.rollback();
                                }
                            }
                            catch (Exception e)
                            {
                                firstException = e;
                                commitFailed = true;
                            }
                        }
                    }

                    ems.remove();
                    ems.set(null);

                    refCounterMaps.set(null);
                    refCounterMaps.remove();

                    // and now we close all open transactionscopes and reset the storage
                    TransactionBeanStorage oldStorage = TransactionBeanStorage.getStorage();
                    TransactionBeanStorage.resetStorage();

                    // we do this delayed to allow new transactions in a PreDestroy method
                    oldStorage.endAllTransactionScopes();
                }
            }
            else
            {
                // we are NOT the outermost TransactionInterceptor
                // so we have to re-activate the previous transaction
                TransactionBeanStorage.getStorage().activateTransactionScope(previousTransactionKey);
            }

            decrementRefCounter(qualifierKey);

            if (commitFailed)
            {
                //noinspection ThrowFromFinallyBlock
                throw firstException;
            }
        }
    }