Search in sources :

Example 1 with OwnableReentrantLock

use of org.jboss.as.ejb3.tx.OwnableReentrantLock in project wildfly by wildfly.

the class StatefulSessionSynchronizationInterceptor method processInvocation.

@Override
public Object processInvocation(final InterceptorContext context) throws Exception {
    final StatefulSessionComponent component = getComponent(context, StatefulSessionComponent.class);
    final StatefulSessionComponentInstance instance = getComponentInstance(context);
    final OwnableReentrantLock lock = instance.getLock();
    final Object threadLock = instance.getThreadLock();
    final AtomicInteger invocationSyncState = instance.getInvocationSynchState();
    final TransactionSynchronizationRegistry transactionSynchronizationRegistry = component.getTransactionSynchronizationRegistry();
    final Object lockOwner = getLockOwner(transactionSynchronizationRegistry);
    final AccessTimeoutDetails timeout = component.getAccessTimeout(context.getMethod());
    boolean toDiscard = false;
    if (ROOT_LOGGER.isTraceEnabled()) {
        ROOT_LOGGER.trace("Trying to acquire lock: " + lock + " for stateful component instance: " + instance + " during invocation: " + context);
    }
    // we obtain a lock in this synchronization interceptor because the lock needs to be tied to the synchronization
    // so that it can released on the tx synchronization callbacks
    boolean acquired = lock.tryLock(timeout.getValue(), timeout.getTimeUnit(), lockOwner);
    if (!acquired) {
        throw EjbLogger.ROOT_LOGGER.failToObtainLock(component.getComponentName(), timeout.getValue(), timeout.getTimeUnit());
    }
    synchronized (threadLock) {
        //invocation in progress
        invocationSyncState.set(SYNC_STATE_INVOCATION_IN_PROGRESS);
        if (ROOT_LOGGER.isTraceEnabled()) {
            ROOT_LOGGER.trace("Acquired lock: " + lock + " for stateful component instance: " + instance + " during invocation: " + context);
        }
        Object currentTransactionKey = null;
        boolean wasTxSyncRegistered = false;
        try {
            //so enrolling in an existing transaction is not correct
            if (containerManagedTransactions) {
                if (!instance.isSynchronizationRegistered()) {
                    // get the key to current transaction associated with this thread
                    currentTransactionKey = transactionSynchronizationRegistry.getTransactionKey();
                    final int status = transactionSynchronizationRegistry.getTransactionStatus();
                    // if the thread is currently associated with a tx, then register a tx synchronization
                    if (currentTransactionKey != null && status != Status.STATUS_COMMITTED && status != Status.STATUS_ROLLEDBACK) {
                        // register a tx synchronization for this SFSB instance
                        final Synchronization statefulSessionSync = new StatefulSessionSynchronization(instance);
                        transactionSynchronizationRegistry.registerInterposedSynchronization(statefulSessionSync);
                        wasTxSyncRegistered = true;
                        if (ROOT_LOGGER.isTraceEnabled()) {
                            ROOT_LOGGER.trace("Registered tx synchronization: " + statefulSessionSync + " for tx: " + currentTransactionKey + " associated with stateful component instance: " + instance);
                        }
                        // invoke the afterBegin callback on the SFSB
                        instance.afterBegin();
                        instance.setSynchronizationRegistered(true);
                        context.putPrivateData(StatefulTransactionMarker.class, StatefulTransactionMarker.of(true));
                    }
                } else {
                    context.putPrivateData(StatefulTransactionMarker.class, StatefulTransactionMarker.of(false));
                }
            }
            // proceed with the invocation
            try {
                return context.proceed();
            } catch (Exception e) {
                if (component.shouldDiscard(e, context.getMethod())) {
                    toDiscard = true;
                }
                throw e;
            }
        } finally {
            // taken care off by a tx synchronization callbacks.
            if (!wasTxSyncRegistered && !instance.isSynchronizationRegistered()) {
                releaseInstance(instance);
            } else if (!wasTxSyncRegistered) {
                //if we don't release the lock here then it will be acquired multiple times
                //and only released once
                releaseLock(instance);
                //we also call the cache release to decrease the usage count
                if (!instance.isDiscarded()) {
                    instance.getComponent().getCache().release(instance);
                }
            }
            for (; ; ) {
                int state = invocationSyncState.get();
                if (state == SYNC_STATE_INVOCATION_IN_PROGRESS && invocationSyncState.compareAndSet(SYNC_STATE_INVOCATION_IN_PROGRESS, SYNC_STATE_NO_INVOCATION)) {
                    break;
                } else if (state == SYNC_STATE_AFTER_COMPLETE_DELAYED_COMMITTED || state == SYNC_STATE_AFTER_COMPLETE_DELAYED_NO_COMMIT) {
                    try {
                        //invoke the after completion method, other after completion syncs may have already run
                        handleAfterCompletion(state == SYNC_STATE_AFTER_COMPLETE_DELAYED_COMMITTED, instance, toDiscard);
                    } finally {
                        invocationSyncState.set(SYNC_STATE_NO_INVOCATION);
                    }
                } else {
                    EjbLogger.ROOT_LOGGER.unexpectedInvocationState(state);
                    break;
                }
            }
        }
    }
}
Also used : AtomicInteger(java.util.concurrent.atomic.AtomicInteger) TransactionSynchronizationRegistry(javax.transaction.TransactionSynchronizationRegistry) OwnableReentrantLock(org.jboss.as.ejb3.tx.OwnableReentrantLock) AccessTimeoutDetails(org.jboss.as.ejb3.concurrency.AccessTimeoutDetails) Synchronization(javax.transaction.Synchronization) EJBException(javax.ejb.EJBException)

Aggregations

AtomicInteger (java.util.concurrent.atomic.AtomicInteger)1 EJBException (javax.ejb.EJBException)1 Synchronization (javax.transaction.Synchronization)1 TransactionSynchronizationRegistry (javax.transaction.TransactionSynchronizationRegistry)1 AccessTimeoutDetails (org.jboss.as.ejb3.concurrency.AccessTimeoutDetails)1 OwnableReentrantLock (org.jboss.as.ejb3.tx.OwnableReentrantLock)1