title: Spring @Transactional JPA within a JMSConsumer Camel processor
body: <p>I'am in the process of updating an existing Java SE Camel Application to make use of Spring JPA managed EntityManger using @PersitentContext injection. Currently  it is instanciated in our code using  Persistence.createEntityManagerFactory and it works well. But we'd like to have more flexible and testable application by using injection of this entityManager, use the powerful @Transactional aop capacities and also to switch between local and global XA transactions just by using different @Configuration @Profiles.</p>
  
  <p>My first test was to test xa transactions involving JMS and JPA resources with an Atomikos TransactionManager and it worked.</p>
  
  <p>Now in this application I want to test local transactions using OpenJPA, Camel and JpaTransactionManager i.e without involving XA transaction.</p>
  
  <p>I have unit tests that works pretty well without Camel, the @Transactional weaving does the work of starting transactions with the jpaTransactionManager and everything is fine.</p>
  
  <p>Now when I try to integrate my configuration beans into the camel applications things are not going well.</p>
  
  <p>I have a JMS consumer that triggers a camel processor where the process method is annotated with @Transactional. </p>
  
  <p>I think I have misconfigured something because the JMSConsumer start a transaction even tough I did not set up the JMS component explicitly for being transactional (no transacted() in the route, not transaction manager set to the JMSConfiguration)</p>
  
  <p>Here is a breakpoint showing the JmsConsumer trying registering to the transaction synchronisation stuff:</p>
  
  <pre><code>Daemon Thread [Camel (worker) thread #1 - JmsConsumer[&lt;consumerName&gt;]] (Suspended (breakpoint at line 175 in TransactionSynchronizationManager))
      TransactionSynchronizationManager.bindResource(Object, Object) line: 175
      DefaultJmsMessageListenerContainer(AbstractPollingMessageListenerContainer).doReceiveAndExecute(Object, Session, MessageConsumer, TransactionStatus) line: 313
      DefaultJmsMessageListenerContainer(AbstractPollingMessageListenerContainer).receiveAndExecute(Object, Session, MessageConsumer) line: 255
      DefaultMessageListenerContainer$AsyncMessageListenerInvoker.invokeListener() line: 1168
      DefaultMessageListenerContainer$AsyncMessageListenerInvoker.executeOngoingLoop() line: 1160
      DefaultMessageListenerContainer$AsyncMessageListenerInvoker.run() line: 1057
      ThreadPoolExecutor.runWorker(ThreadPoolExecutor$Worker) line: 1142
      ThreadPoolExecutor$Worker.run() line: 617   
      Thread.run() line: 745 [local variables unavailable]
  </code></pre>
  
  <p>I don't see any other resource being bound to the TransactionSynchronisationManager.</p>
  
  <p>On the contrary in my unit tests seems are going well and we see in the stack trace the @Transactional playing its role as expected:</p>
  
  <pre><code>Thread [main] (Suspended (breakpoint at line 175 in TransactionSynchronizationManager))
      TransactionSynchronizationManager.bindResource(Object, Object) line: 175
      JpaTransactionManager.doBegin(Object, TransactionDefinition) line: 406
      JpaTransactionManager(AbstractPlatformTransactionManager).getTransaction(TransactionDefinition) line: 377
      TransactionInterceptor(TransactionAspectSupport).createTransactionIfNecessary(PlatformTransactionManager, TransactionAttribute, String) line: 461
      TransactionInterceptor(TransactionAspectSupport).invokeWithinTransaction(Method, Class&lt;?&gt;, InvocationCallback) line: 277
      TransactionInterceptor.invoke(MethodInvocation) line: 96    
      CglibAopProxy$CglibMethodInvocation(ReflectiveMethodInvocation).proceed() line: 179
      CglibAopProxy$DynamicAdvisedInterceptor.intercept(Object, Method, Object[], MethodProxy) line: 671
      MyRepo$$EnhancerBySpringCGLIB$$5edadd7f.createRun(String) line: not available
      DataSourceConfigTest.testIt2() line: 38 
      ...
  </code></pre>
  
  <p>So clearly something is misconfigured here it seems @Transactional is totally ignored or overridden by some magic auto-configuration of SpringBoot. Does anyone has any hint ?</p>
  
  <p>Here is my CamelConfiguration and My Data/JPA configuration</p>
  
  <p>Camel Config</p>
  
  <pre><code>@Configuration
  public class CamelConfiguration {
      protected static Logger LOGGER = LoggerFactory.getLogger(CamelConfiguration.class);
  
  
      @Value("${broker.mqURL}")
      String mqURL;
  
      /**
       * The runId is injected from command Line arguments
       */
      @Value("${runId}")
      long runId;
  
  
      @Bean
      CamelContextConfiguration contextConfiguration() {
          return new CamelContextConfiguration() {
              @Override
              public void beforeApplicationStart(CamelContext context) {
  
                  ((SpringCamelContext)context).setName("worker");
  
                  DefaultShutdownStrategy shutdownStrategy = new DefaultShutdownStrategy();
                  shutdownStrategy.setTimeUnit(TimeUnit.SECONDS);
                  shutdownStrategy.setTimeout(5);
                  context.setShutdownStrategy(shutdownStrategy);
              }
  
              @Override
              public void afterApplicationStart(CamelContext camelContext) {
                  try {
                      LOGGER.info("Starting route dataspecProcessing." + runId);
                      camelContext.startAllRoutes();
                  } catch (Exception e) {
                      LOGGER.error("Error during Camel post start",e);
                  }
              }
          };
      }
  
      @Bean
      @Scope(value = ConfigurableBeanFactory.SCOPE_SINGLETON)
      public ActiveMQConnectionFactory jmsConnectionFactory() {
          ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory();
          connectionFactory.setBrokerURL(mqURL);
          connectionFactory.setTrustAllPackages(true);
          return connectionFactory;
      }
  
      @Bean
      @Scope(value = ConfigurableBeanFactory.SCOPE_SINGLETON)
      public JmsConfiguration myJmsConfiguration(ActiveMQConnectionFactory jmsConnectionFactory,JpaTransactionManager jpaTransactionManager) {
          JmsConfiguration jmsConfiguration = new JmsConfiguration();
  //      jmsConfiguration.setTransacted(true);
  //      jmsConfiguration.setLazyCreateTransactionManager(false);
  //      jmsConfiguration.setTransactionManager(jpaTransactionManager);
          jmsConfiguration.setConnectionFactory(jmsConnectionFactory);
          jmsConfiguration.setCacheLevelName("CACHE_CONSUMER");
          return jmsConfiguration;
      }
  </code></pre>
  
  <p>Jpa Config</p>
  
  <pre><code>@Configuration
  @EnableTransactionManagement(mode=AdviceMode.ASPECTJ)
  @EnableAspectJAutoProxy(proxyTargetClass = true)
  public class DataSourceConfig {
  
      @Bean
      public JpaTransactionManager jpaTransactionManager() {
          JpaTransactionManager transactionManager = new JpaTransactionManager();
          transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
          transactionManager.setDataSource(dataSource());
          transactionManager.setJpaDialect(new OpenJpaDialect());
          return transactionManager;
      }
  
      @Bean
      public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
          LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
          em.setPersistenceXmlLocation("META-INF/persistence.xml");
          em.setJpaProperties(additionalProperties());
          em.setDataSource(dataSource());
          em.setValidationMode(ValidationMode.NONE);
          JpaVendorAdapter vendorAdapter = new OpenJpaVendorAdapter();
          em.setJpaVendorAdapter(vendorAdapter);
          em.setJpaProperties(additionalProperties());
  
          return em;
      }
  
      @Bean
      public DataSource dataSource() {
          PGSimpleDataSource pgDataSource = new PGSimpleDataSource();
          pgDataSource.setUrl(...);
          pgDataSource.setUser(...);
          pgDataSource.setPassword(...);
          return pgDataSource;
      }
  </code></pre>
  
  <p>And the code that should be transactional</p>
  
  <pre><code>@Component
  @EnableTransactionManagement(mode=AdviceMode.ASPECTJ)
  @EnableAspectJAutoProxy(proxyTargetClass = true)
  public class MyCamelProcessor implements Processor {
  ...
  @Transactional(propagation=Propagation.REQUIRES_NEW,transactionManager="jpaTransactionManager")
      public void process(Exchange exchange) throws Exception {
          ... calls to entitymanager here ...
  </code></pre>
  
  <p>The route calling the processor</p>
  
  <pre><code>@Component
  public class DataSpecProcessingRoute extends SpringRouteBuilder {
  ....
  public void configure() throws Exception {
  ...
  from("jms:queue:thequeue"?concurrentConsumers=" + numConsumerThreads)
              .autoStartup(false)
          .shutdownRunningTask(ShutdownRunningTask.CompleteCurrentTaskOnly)
                  .routeId("dataspecProcessing." + runId)
                  .process(initialisationProcessor)
                  .process(processorWithTransactionnalNeeded)
  .to("jms:queue:anotherqueue") ;
  </code></pre>
  
  <p><strong>EDIT</strong></p>
  
  <p>It works with programmatic transactions, not with @Transactional annotation.</p>