/** {@inheritDoc} */ public ConnectionListener getConnection( Transaction trackByTransaction, Subject subject, ConnectionRequestInfo cri) throws ResourceException { ConnectionListener cl = null; boolean separateNoTx = false; if (noTxSeparatePools) { separateNoTx = clf.isTransactional(); } // Get specific managed connection pool key Object key = getKey(subject, cri, separateNoTx); // Get managed connection pool ManagedConnectionPool mcp = getManagedConnectionPool(key, subject, cri); // Are we doing track by transaction ? TransactionSynchronizationRegistry tsr = getTransactionSynchronizationRegistry(); Object transactionKey = tsr != null ? tsr.getTransactionKey() : null; if (trackByTransaction == null || transactionKey == null) { return getSimpleConnection(subject, cri, mcp); } // Transaction old connections cl = getTransactionOldConnection(trackByTransaction, mcp); // Creates a new connection with given transaction if (cl == null) { cl = getTransactionNewConnection(trackByTransaction, mcp, subject, cri); } return cl; }
/** * Gets connection listener instance associated with transaction. This method is package protected * beacause it is intended only for test case use. Please don't use it in your production code. * * @param trackByTransaction transaction instance * @param mcp the managed connection pool associated with the desired connection listener * @return connection listener instance * @throws ResourceException Thrown if an error occurs */ ConnectionListener getTransactionOldConnection( Transaction trackByTransaction, ManagedConnectionPool mcp) throws ResourceException { TransactionSynchronizationRegistry tsr = getTransactionSynchronizationRegistry(); Lock lock = getLock(); try { lock.lockInterruptibly(); } catch (InterruptedException ie) { Thread.interrupted(); throw new ResourceException(bundle.unableObtainLock(), ie); } try { // Already got one ConnectionListener cl = (ConnectionListener) tsr.getResource(mcp); if (cl != null) { if (trace) log.tracef("Previous connection tracked by transaction=%s tx=%s", cl, trackByTransaction); return cl; } return null; } finally { lock.unlock(); } }
private void addWaitingOnTxCompletionTimer(final TimerImpl timer) { Map<String, TimerImpl> timers = (Map<String, TimerImpl>) tsr.getResource(waitingOnTxCompletionKey); if (timers == null) { tsr.putResource(waitingOnTxCompletionKey, timers = new HashMap<String, TimerImpl>()); } timers.put(timer.getId(), timer); }
@TransactionAttribute(TransactionAttributeType.MANDATORY) public void sameTransaction(boolean first) throws RemoteException { if (first) { transactionKey = transactionSynchronizationRegistry.getTransactionKey(); } else { if (!transactionKey.equals(transactionSynchronizationRegistry.getTransactionKey())) { throw new RemoteException("Transaction on second call was not the same as on first call"); } } }
/** * Gets new connection listener if necessary instance with transaction. This method is package * protected beacause it is intended only for test case use. Please don't use it in your * production code. * * @param trackByTransaction transaction instance * @param mcp pool instance * @param subject subject instance * @param cri connection request info * @return connection listener instance * @throws ResourceException ResourceException */ ConnectionListener getTransactionNewConnection( Transaction trackByTransaction, ManagedConnectionPool mcp, Subject subject, ConnectionRequestInfo cri) throws ResourceException { // Need a new one for this transaction // This must be done outside the tx local lock, otherwise // the tx timeout won't work and get connection can do a lot of other work // with many opportunities for deadlocks. // Instead we do a double check after we got the transaction to see // whether another thread beat us to the punch. ConnectionListener cl = mcp.getConnection(subject, cri); if (trace) log.tracef( "Got connection from pool tracked by transaction=%s tx=%s", cl, trackByTransaction); TransactionSynchronizationRegistry tsr = getTransactionSynchronizationRegistry(); Lock lock = getLock(); try { lock.lockInterruptibly(); } catch (InterruptedException ie) { Thread.interrupted(); throw new ResourceException(bundle.unableObtainLock(), ie); } try { // Check we weren't racing with another transaction ConnectionListener other = (ConnectionListener) tsr.getResource(mcp); if (other != null) { mcp.returnConnection(cl, false); if (trace) log.tracef( "Another thread already got a connection tracked by transaction=%s tx=%s", other, trackByTransaction); cl = other; } // This is the connection for this transaction cl.setTrackByTx(true); tsr.putResource(mcp, cl); if (trace) log.tracef( "Using connection from pool tracked by transaction=%s tx=%s", cl, trackByTransaction); return cl; } finally { lock.unlock(); } }
/** * Get lock * * @return The lock */ private Lock getLock() { Lock result = null; TransactionSynchronizationRegistry tsr = getTransactionSynchronizationRegistry(); if (tsr != null && tsr.getTransactionKey() != null) { result = (Lock) tsr.getResource(LockKey.INSTANCE); if (result == null) { result = initLock(); } } return result; }
/** * Init lock * * @return The lock */ private synchronized Lock initLock() { TransactionSynchronizationRegistry tsr = getTransactionSynchronizationRegistry(); if (tsr != null && tsr.getTransactionKey() != null) { if (tsr.getResource(LockKey.INSTANCE) == null) { Lock lock = new ReentrantLock(true); tsr.putResource(LockKey.INSTANCE, lock); return lock; } else { return (Lock) tsr.getResource(LockKey.INSTANCE); } } return null; }
private void ejbLoad(final EntityBean entityBean) { if (entityBean == null) { throw new NullPointerException("entityBean is null"); } final ThreadContext callContext = createThreadContext(entityBean); callContext.setCurrentOperation(Operation.LOAD); final ThreadContext oldCallContext = ThreadContext.enter(callContext); try { entityBean.ejbLoad(); } catch (final RemoteException e) { throw new EJBException(e); } finally { ThreadContext.exit(oldCallContext); } // if we call load we must call store try { //noinspection unchecked Set<EntityBean> registeredEntities = (LinkedHashSet<EntityBean>) synchronizationRegistry.getResource(ENTITIES_TO_STORE); if (registeredEntities == null) { registeredEntities = new LinkedHashSet<EntityBean>(); synchronizationRegistry.putResource(ENTITIES_TO_STORE, registeredEntities); synchronizationRegistry.registerInterposedSynchronization( new Synchronization() { @Override public void beforeCompletion() { //noinspection unchecked final Set<EntityBean> registeredEntities = (LinkedHashSet<EntityBean>) synchronizationRegistry.getResource(ENTITIES_TO_STORE); if (registeredEntities == null) { return; } for (final EntityBean entityBean : registeredEntities) { ejbStore(entityBean); } } @Override public void afterCompletion(final int i) {} }); } registeredEntities.add(entityBean); } catch (final Exception e) { // no-op } }
public void enlist(Transaction transaction, LocalTransaction localTransaction) { if (!localTransaction.isEnlisted()) { SynchronizationAdapter sync = new SynchronizationAdapter( localTransaction, txCoordinator, commandsFactory, rpcManager, this, clusteringLogic, configuration); if (transactionSynchronizationRegistry != null) { try { transactionSynchronizationRegistry.registerInterposedSynchronization(sync); } catch (Exception e) { log.failedSynchronizationRegistration(e); throw new CacheException(e); } } else { try { transaction.registerSynchronization(sync); } catch (Exception e) { log.failedSynchronizationRegistration(e); throw new CacheException(e); } } ((SyncLocalTransaction) localTransaction).setEnlisted(true); } }
/** * Returns an unmodifiable view of timers in the current transaction that are waiting for the * transaction to finish */ private Map<String, TimerImpl> getWaitingOnTxCompletionTimers() { Map<String, TimerImpl> timers = null; if (getTransaction() != null) { timers = (Map<String, TimerImpl>) tsr.getResource(waitingOnTxCompletionKey); } return timers == null ? Collections.<String, TimerImpl>emptyMap() : timers; }
@Override @Asynchronous @AccessTimeout(value = 60000) @TransactionAttribute(REQUIRED) public void booksUnavailable(BooksUnavailableMessage booksUnavailableMessage) { String correlationId = getCorrelationId(booksUnavailableMessage); log.info("#### [seller]: BooksUnavailable response received: " + correlationId); SellerContext sellerContext = getContext(correlationId); try { sellerContext.validate(booksUnavailableMessage); sellerContext.fire_BooksUnavailable_response_received(); if (sellerContext.isGlobalTransactionActive()) enrollTransaction("bookReservation", sellerContext); sellerProcess.handle_BooksUnavailable_response(booksUnavailableMessage); } catch (Throwable e) { log.error("Error", e); e = ExceptionUtil.getRootCause(e); transactionSynchronizationRegistry.setRollbackOnly(); sellerContext.fire_BooksUnavailable_incoming_response_aborted(e); } }
@PreDestroy public void destroy() { System.out.println("In SingletonBean::destroy()"); try { javax.transaction.TransactionSynchronizationRegistry r = (javax.transaction.TransactionSynchronizationRegistry) new InitialContext().lookup("java:comp/TransactionSynchronizationRegistry"); if (r.getTransactionStatus() != javax.transaction.Status.STATUS_ACTIVE) { throw new IllegalStateException( "Transaction status is not STATUS_ACTIVE: " + r.getTransactionStatus()); } FooEntity fe = new FooEntity("FOO"); em.persist(fe); } catch (Exception e) { throw new EJBException(e); } }
/** * Looks for a current Spring managed transaction and wraps/returns that as a Ebean transaction. * * <p>Returns null if there is no current spring transaction (lazy loading outside a spring txn * etc). */ public Object getCurrentTransaction() { TransactionSynchronizationRegistry syncRegistry = getSyncRegistry(); SpiTransaction t = (SpiTransaction) syncRegistry.getResource(EBEAN_TXN_RESOURCE); if (t != null) { // we have already seen this transaction return t; } // check current Ebean transaction SpiTransaction currentEbeanTransaction = DefaultTransactionThreadLocal.get(serverName); if (currentEbeanTransaction != null) { // NOT expecting this so log WARNING String msg = "JTA Transaction - no current txn BUT using current Ebean one " + currentEbeanTransaction.getId(); logger.warn(msg); return currentEbeanTransaction; } UserTransaction ut = getUserTransaction(); if (ut == null) { // no current JTA transaction if (logger.isDebugEnabled()) { logger.debug("JTA Transaction - no current txn"); } return null; } // This is a transaction that Ebean has not seen before. // "wrap" it in a Ebean specific JtaTransaction String txnId = String.valueOf(System.currentTimeMillis()); JtaTransaction newTrans = new JtaTransaction(txnId, true, ut, dataSource, transactionManager); // create and register transaction listener JtaTxnListener txnListener = createJtaTxnListener(newTrans); syncRegistry.putResource(EBEAN_TXN_RESOURCE, newTrans); syncRegistry.registerInterposedSynchronization(txnListener); // also put in Ebean ThreadLocal DefaultTransactionThreadLocal.set(serverName, newTrans); return newTrans; }
private Map<Contextual<?>, BeanInstanceBag<?>> findMap() { final Object resource; try { // we can't call registry.getResource(KEY) in afterCompletion resource = context.geronimoTxMgr ? TransactionImpl.class .cast(context.transactionManager.getTransaction()) .getResource(KEY) : registry.getResource(KEY); } catch (final SystemException e) { throw new IllegalStateException(e); } if (resource == null) { final Map<Contextual<?>, BeanInstanceBag<?>> map = new HashMap<>(); registry.putResource(KEY, map); registry.registerInterposedSynchronization(context); return map; } return Map.class.cast(resource); }