I am having a problem that i hope people can help me with a workaround. The
options not available to me are patching Camel code, using pre-released
versions or beta versions. I have to work around the problem with the
existing camel software. The problem is fairly simple but takes a bit to
explain.

I run camel as a web app in a WAR on JBoss EAP 6.2 (the commercial version
of JBossAS). We use the JNDI Registry in order to store items and also
access EJBs deployed in the system. Our Camel Infrastructure uses ActiveMQ
as a message broker and JTA transaction manager to manage composite JDBC -
JMS Transactions. I would like to create route tests that will test these
transacted routes. To that end I have created an embedded ActiveMQ broker
which works fabulously and now I would like to get the transacted routes be
able to be route tested. So I integrated Atomikos JTA transaction manager.
The problem is now the transaction manager is not being found in the JNDI
registry by the activemq component in test. It works fine in container. I
can't spawn a container because there are too many tests and having to
bring up Arquillian or something would mean the tests would take forever.
The reason the TxMgr is not being found in the test case is because of bugs
in camel's JNDI implementation; specifically "lookupByType()" doesn't work
properly. Here is the atomikes config:

  public AtomikosJTATxnMgrSupport(final String txnManagerServiceName) {
    final Properties txnSvcProps = new Properties();
    txnSvcProps.setProperty("com.atomikos.icatch.service",
"com.atomikos.icatch.standalone.UserTransactionServiceFactory");
    txnSvcProps.setProperty("com.atomikos.icatch.output_dir",
"./target/atomikos/");
    txnSvcProps.setProperty("com.atomikos.icatch.log_base_dir",
"./target/atomikos/");
    txnSvcProps.setProperty("com.atomikos.icatch.console_log_level",
"DEBUG");
    txnSvcProps.setProperty("com.atomikos.icatch.tm_unique_name",
txnManagerServiceName);
    this.atomikosUserTxnService = new
UserTransactionServiceImp(txnSvcProps);
    atomikosUserTxnService.init();
    this.atomikosTxMgr = new UserTransactionManager();
    this.atomikosTxMgr.setStartupTransactionService(false); // already
started above.
    try {
      this.atomikosTxMgr.init();
    } catch (final SystemException ex) {
      throw new AssertionError("Error initializing JTA transaction
manager", ex);
    }
    this.userTxn = new UserTransactionImp();
  }

  public JtaTransactionManager fetchJTATxnMgr() {
    if (null == this.jtaTxnMgr) {
      this.jtaTxnMgr = new JtaTransactionManager();
      this.jtaTxnMgr.setTransactionManager(this.atomikosTxMgr);
      this.jtaTxnMgr.setUserTransaction(this.userTxn);
    }
    return this.jtaTxnMgr;
  }

And this is used in my TransactedRouteTestSupport like so.

 /** Transaction manager for JTA transactions in the broker. */
  protected final static AtomikosJTATxnMgrSupport txnMgrSupport;

  static {
    try {
      txnMgrSupport = new AtomikosJTATxnMgrSupport("TestAtomikosTxnMgr-" +
RouteTestSupport.NOW);
    } catch (final Exception ex) { // unrecoverable!
      throw new AssertionError("Failed to start embedded Atomikos JTA
Transaction manager; cannot proceed with tests.", ex);
    }
  }

  @SuppressWarnings("javadoc")
  @AfterSuite
  public static void afterSuite() throws Exception {
    // Make sure we shut down all the support service when tests are all
done.
    txnMgrSupport.close();
  }

  @Override
  protected JndiRegistry createRegistry() throws Exception {
    // Subclasses should always call this method if they put items in the
registry as well.
    final JndiRegistry registry = super.createRegistry();
    if (log.isDebugEnabled()) log.debug("Registering transaction manager in
camel Context using key: " + KEY_JTA_TXN_MANAGER);
    registry.bind(KEY_JTA_TXN_MANAGER, txnMgrSupport.fetchJTATxnMgr());
    assertNotNull(registry.lookupByType(PlatformTransactionManager.class));
// <<<<<===== Fails
    return registry;
  }

and finally the route under test:

  protected void configureBasicRoute() {
    from(String.format("activemq:queue:%s?concurrentConsumers=%d",
config.basicRouteInboxQueue(), config.concurrentConsumers()))
      .routeId(ROUTE_ID_BASIC_ROUTE)
      .transacted() // Make this route transacted
      .setHeader(HDR_REQUESTOR, constant(getContext().getName()))
      .to(String.format("activemq:queue:%s",
config.basicRouteOutboxQueue()));
  }

I would love to figure out a simple way to work around this and would be
grateful for any suggestions. I tried, in vain, to look up another JNDI
implementation to use that would be local only. All of the JNDI
implementations I found required connections to application servers,
activemq or so on. It seems if there is a local-only JNDI implementation
somewhere it is hidden. The only thing I found that was close was a VERY
old post relating to JBoss AS 5.0 which is definitely not possible to use.

Thanks in advance

*Robert Simmons Jr. MSc. - Lead Java Architect @ EA*
*Author of: Hardcore Java (2003) and Maintainable Java (2012)*
*LinkedIn: **http://www.linkedin.com/pub/robert-simmons/40/852/a39
<http://www.linkedin.com/pub/robert-simmons/40/852/a39>*

Reply via email to