Atomikos Forum

Problems enlisting a custom XAResource to a transaction

Hi all,

In my current project I'm trying to enlist a custom XA resource into my transaction so that I can perform certain functionality only after a transaction has successfully been committed.

The main driver for this is to process all of our LDAP updates only if the SQL database changes are all good.

The code I'm working with can be viewed at:

For the most part this all seems to work fine, but having never done anything at the XAResource layer before ( and with Google not really helping out much ) I'm not entirely sure what I'm doing wrong.

I seem to get the following error coming out of Atomikos regularly at the same few spots in my code:

04.05.2010 13:56:48.829 *WARN* [66156411@qtp-46719652-4] atomikos The given XAResource instance is being enlisted a second time without delist in between?

    at com.atomikos.icatch.jta.TransactionImp.enlistResource(
    at smx3.agreement.resources.LdapGuard.performAfterCommit(
    at smx3.agreement.policyset.ldap.PolicySetDomainAdvice.trigger(
    at sun.reflect.GeneratedMethodAccessor474.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(

I believe I've traced this backwards to XAResourceKey#equals calling the XAResource#isSameRM method in my resource, and somehow getting confused about duplicates.

I've tried variations of #isSameRM just chaining directly to its own #equals method to what's currently mentioned in the gist.  Either way, both check that the ID variable is the same.  From my logs I see that no duplicate IDs are generated.

Whilst I see the log from Atomikos says reports the duplicate as a WARNING, I also see that the resource's #commit doesn't always run.

Am I missing something stupid here?  Does anyone have any examples of what/how I should actually be writing a custom resource?

Mark Derricutt Send private email
Wednesday, May 05, 2010
Tracing into this further I see that Atomikos is wrapping my resource in a TemporaryXATransactionalResource instance which gives me giant WTF's.

When a call to Configuration#addResource is performed, a call to #purgeResources is made which iterates over resources calling res.isClosed.

com.atomikos.datasource.xa.TemporaryXATransactionalResource#isClosed calls needsRefresh() which is implemented as:

    protected boolean needsRefresh ()
        boolean ret = true;

        // check if connection has not timed out
        try {
            // we should be the same as ourselves!
            // NOTE: xares_ is null if no connection could be gotten
            // in that case we just return true
            // otherwise, test the xaresource liveness
            if ( xares_ != null ) {
                xares_.isSameRM ( xares_ );
                ret = false;
        } catch ( XAException xa ) {
            // timed out?
            Configuration.logDebug ( servername_
                    + ": XAResource needs refresh?", xa );

        return ret;

What strikes me as odd here is that in the if() in the middle, the response of xares_.isSameRM() is ignored and the method will ALWAYS return false when xares_ is not null, unless an XAException is called.

My guess is that the code -should- look like something like:

            if ( xares_ != null && xares_.isSameRM ( xares_ ) ) {
                ret = false;

and actually take into account the response.

Am I correct here or am I running around in circles looking at misleading trails?
Mark Derricutt Send private email
Wednesday, May 05, 2010

I don't see the problem with needsRefresh: if an xaResource is the same as itself (no errors due to connectivity problems etc) then we do NOT need refresh so we return false?

For your other problem: did you consider getting developer access (support)?

Guy Pardon Send private email
Wednesday, May 05, 2010
I guess I'm having a misunderstanding of the lifecycle of an XAResource then.

What I'm doing is creating an instance of my own XAResource for every custom operation I want to happen after a successful commit.  Each instance has its own unique UUID internally, which it's isSameRM() method checks for equality/sameness.

In the needsRefresh() method it seems you're ignoring the response of isSameRM() and relying on the fact that no exceptions were thrown.

Throwing an exception from isSameRM() seems wrong for something that is by contract a boolean expression that doesn't imply connectivity checks.

I'm just trying to figure out why Atomikos keeps telling me it has duplicate resources when I see my code only enlisting fresh instances with unique ids.

Maybe there's a better way to do what I want rather than going to the level of a custom XAResource?
Mark Derricutt Send private email
Wednesday, May 05, 2010
After reading some other docs on XAResources I'll rewrite my code to track each of my work units in a single instance keyed on the Xid  ( which sounds a more correct way of doing things ).

I'll report back in the morning as to whether that solves my issues.
Mark Derricutt Send private email
Wednesday, May 05, 2010
A Synchronization (rather than XAResource) might be another option for you - depending on what you need to do.

Guy Pardon Send private email
Friday, May 07, 2010

This topic is archived. No further replies will be accepted.

Other recent topics Other recent topics