/** * Obtain a RabbitMQ Channel that is synchronized with the current transaction, if any. * @param connectionFactory the ConnectionFactory to obtain a Channel for * @param synchedLocalTransactionAllowed whether to allow for a local RabbitMQ transaction that is synchronized with * a Spring-managed transaction (where the main transaction might be a JDBC-based one for a specific DataSource, for * example), with the RabbitMQ transaction committing right after the main transaction. If not allowed, the given * ConnectionFactory needs to handle transaction enlistment underneath the covers. * @return the transactional Channel, or <code>null</code> if none found */ public static RabbitResourceHolder getTransactionalResourceHolder(final ConnectionFactory connectionFactory, final boolean synchedLocalTransactionAllowed) { return getTransactionalResourceHolder(connectionFactory, synchedLocalTransactionAllowed, false); }
@Override public Connection createConnection() throws IOException { return ConnectionFactoryUtils.createConnection(this.connectionFactory, this.publisherConnectionIfPossible); }
/** * Obtain a RabbitMQ Channel that is synchronized with the current transaction, if any. * @param connectionFactory the ConnectionFactory to obtain a Channel for * @param synchedLocalTransactionAllowed whether to allow for a local RabbitMQ transaction that is synchronized with * a Spring-managed transaction (where the main transaction might be a JDBC-based one for a specific DataSource, for * example), with the RabbitMQ transaction committing right after the main transaction. If not allowed, the given * ConnectionFactory needs to handle transaction enlistment underneath the covers. * @param publisherConnectionIfPossible obtain a connection from a separate publisher connection * if possible. * @return the transactional Channel, or <code>null</code> if none found */ public static RabbitResourceHolder getTransactionalResourceHolder(final ConnectionFactory connectionFactory, final boolean synchedLocalTransactionAllowed, final boolean publisherConnectionIfPossible) { return doGetTransactionalResourceHolder(connectionFactory, new RabbitResourceFactory(connectionFactory, synchedLocalTransactionAllowed, publisherConnectionIfPossible)); }
resourceHolder = ConnectionFactoryUtils.getTransactionalResourceHolder(getConnectionFactory(), true); channel = resourceHolder.getChannel(); if (channel == null) { ConnectionFactoryUtils.releaseResources(resourceHolder); throw new IllegalStateException("Resource holder returned a null channel");
if (isChannelTransacted()) { resourceHolder = ConnectionFactoryUtils. getTransactionalResourceHolder(connectionFactory, true, this.usePublisherConnection); channel = resourceHolder.getChannel(); if (channel == null) { ConnectionFactoryUtils.releaseResources(resourceHolder); throw new IllegalStateException("Resource holder returned a null channel"); connection = ConnectionFactoryUtils.createConnection(connectionFactory, this.usePublisherConnection); // NOSONAR - RabbitUtils closes if (connection == null) {
@Test public void testReceiveBlockingGlobalTx() throws Exception { template.convertAndSend(ROUTE, "blockGTXNoTO"); RabbitResourceHolder resourceHolder = ConnectionFactoryUtils .getTransactionalResourceHolder(this.template.getConnectionFactory(), true); TransactionSynchronizationManager.setActualTransactionActive(true); ConnectionFactoryUtils.bindResourceToTransaction(resourceHolder, this.template.getConnectionFactory(), true); template.setReceiveTimeout(-1); template.setChannelTransacted(true); String out = (String) template.receiveAndConvert(ROUTE); resourceHolder.commitAll(); resourceHolder.closeAll(); assertSame(resourceHolder, TransactionSynchronizationManager.unbindResource(template.getConnectionFactory())); assertNotNull(out); assertEquals("blockGTXNoTO", out); this.template.setReceiveTimeout(0); assertNull(this.template.receive(ROUTE)); }
@Test public void testResourceHolder() { RabbitResourceHolder h1 = new RabbitResourceHolder(); RabbitResourceHolder h2 = new RabbitResourceHolder(); ConnectionFactory connectionFactory = mock(ConnectionFactory.class); TransactionSynchronizationManager.setActualTransactionActive(true); ConnectionFactoryUtils.bindResourceToTransaction(h1, connectionFactory, true); assertSame(h1, ConnectionFactoryUtils.bindResourceToTransaction(h2, connectionFactory, true)); TransactionSynchronizationManager.clear(); }
@Override protected void releaseResource(RabbitResourceHolder resourceHolder, Object resourceKey) { ConnectionFactoryUtils.releaseResources(resourceHolder); }
ConnectionFactoryUtils.registerDeliveryTag(this.connectionFactory, this.channel, delivery.getEnvelope().getDeliveryTag());
/** * Check whether the given Channel is locally transacted, that is, whether its transaction is managed by this * template's Channel handling and not by an external transaction coordinator. * @param channel the Channel to check * @return whether the given Channel is locally transacted * @see ConnectionFactoryUtils#isChannelTransactional * @see #isChannelTransacted */ protected boolean isChannelLocallyTransacted(Channel channel) { return isChannelTransacted() && !ConnectionFactoryUtils.isChannelTransactional(channel, getConnectionFactory()); }
resourceHolder = ConnectionFactoryUtils.getTransactionalResourceHolder(getConnectionFactory(), true); channel = resourceHolder.getChannel(); if (channel == null) { ConnectionFactoryUtils.releaseResources(resourceHolder); throw new IllegalStateException("Resource holder returned a null channel");
if (isChannelTransacted()) { resourceHolder = ConnectionFactoryUtils. getTransactionalResourceHolder(connectionFactory, true, this.usePublisherConnection); channel = resourceHolder.getChannel(); if (channel == null) { ConnectionFactoryUtils.releaseResources(resourceHolder); throw new IllegalStateException("Resource holder returned a null channel"); connection = ConnectionFactoryUtils.createConnection(connectionFactory, this.usePublisherConnection); // NOSONAR - RabbitUtils closes if (connection == null) {
private void executeListenerInTransaction(Message message, long deliveryTag) { if (this.isRabbitTxManager) { ConsumerChannelRegistry.registerConsumerChannel(getChannel(), this.connectionFactory); } if (this.transactionTemplate == null) { this.transactionTemplate = new TransactionTemplate(this.transactionManager, this.transactionAttribute); } this.transactionTemplate.execute(s -> { RabbitResourceHolder resourceHolder = ConnectionFactoryUtils.bindResourceToTransaction( new RabbitResourceHolder(getChannel(), false), this.connectionFactory, true); if (resourceHolder != null) { resourceHolder.addDeliveryTag(getChannel(), deliveryTag); } // unbound in ResourceHolderSynchronization.beforeCompletion() try { callExecuteListener(message, deliveryTag); } catch (RuntimeException e1) { prepareHolderForRollback(resourceHolder, e1); throw e1; } catch (Throwable e2) { //NOSONAR ok to catch Throwable here because we re-throw it below throw new WrappedTransactionException(e2); } return null; }); }
@Override protected void releaseResource(RabbitResourceHolder resourceHolder, Object resourceKey) { ConnectionFactoryUtils.releaseResources(resourceHolder); }
ConnectionFactoryUtils.registerDeliveryTag(this.connectionFactory, this.channel, delivery.getEnvelope().getDeliveryTag());
/** * Check whether the given Channel is locally transacted, that is, whether its transaction is managed by this * template's Channel handling and not by an external transaction coordinator. * @param channel the Channel to check * @return whether the given Channel is locally transacted * @see ConnectionFactoryUtils#isChannelTransactional * @see #isChannelTransacted */ protected boolean isChannelLocallyTransacted(Channel channel) { return isChannelTransacted() && !ConnectionFactoryUtils.isChannelTransactional(channel, getConnectionFactory()); }
@Override protected void doBegin(Object transaction, TransactionDefinition definition) { if (definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT) { throw new InvalidIsolationLevelException("AMQP does not support an isolation level concept"); } RabbitTransactionObject txObject = (RabbitTransactionObject) transaction; RabbitResourceHolder resourceHolder = null; try { resourceHolder = ConnectionFactoryUtils.getTransactionalResourceHolder(getConnectionFactory(), true); if (logger.isDebugEnabled()) { logger.debug("Created AMQP transaction on channel [" + resourceHolder.getChannel() + "]"); } // resourceHolder.declareTransactional(); txObject.setResourceHolder(resourceHolder); txObject.getResourceHolder().setSynchronizedWithTransaction(true); int timeout = determineTimeout(definition); if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) { txObject.getResourceHolder().setTimeoutInSeconds(timeout); } TransactionSynchronizationManager.bindResource(getConnectionFactory(), txObject.getResourceHolder()); } catch (AmqpException ex) { if (resourceHolder != null) { ConnectionFactoryUtils.releaseResources(resourceHolder); } throw new CannotCreateTransactionException("Could not create AMQP transaction", ex); } }
private void executeListenerInTransaction(Message message, long deliveryTag) { if (this.isRabbitTxManager) { ConsumerChannelRegistry.registerConsumerChannel(getChannel(), this.connectionFactory); } if (this.transactionTemplate == null) { this.transactionTemplate = new TransactionTemplate(this.transactionManager, this.transactionAttribute); } this.transactionTemplate.execute(s -> { RabbitResourceHolder resourceHolder = ConnectionFactoryUtils.bindResourceToTransaction( new RabbitResourceHolder(getChannel(), false), this.connectionFactory, true); if (resourceHolder != null) { resourceHolder.addDeliveryTag(getChannel(), deliveryTag); } // unbound in ResourceHolderSynchronization.beforeCompletion() try { callExecuteListener(message, deliveryTag); } catch (RuntimeException e1) { prepareHolderForRollback(resourceHolder, e1); throw e1; } catch (Throwable e2) { //NOSONAR ok to catch Throwable here because we re-throw it below throw new WrappedTransactionException(e2); } return null; }); }
/** * Obtain a RabbitMQ Channel that is synchronized with the current transaction, if any. * @param connectionFactory the ConnectionFactory to obtain a Channel for * @param synchedLocalTransactionAllowed whether to allow for a local RabbitMQ transaction that is synchronized with * a Spring-managed transaction (where the main transaction might be a JDBC-based one for a specific DataSource, for * example), with the RabbitMQ transaction committing right after the main transaction. If not allowed, the given * ConnectionFactory needs to handle transaction enlistment underneath the covers. * @return the transactional Channel, or <code>null</code> if none found */ public static RabbitResourceHolder getTransactionalResourceHolder(final ConnectionFactory connectionFactory, final boolean synchedLocalTransactionAllowed) { return getTransactionalResourceHolder(connectionFactory, synchedLocalTransactionAllowed, false); }
private void cleanUpAfterAction(Channel channel, boolean invokeScope, RabbitResourceHolder resourceHolder, Connection connection) { if (!invokeScope) { if (resourceHolder != null) { ConnectionFactoryUtils.releaseResources(resourceHolder); } else { RabbitUtils.closeChannel(channel); RabbitUtils.closeConnection(connection); } } }