public int prepare(Xid xid) throws XAException
   {
      if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled()) SibTr.entry(this, tc, "prepare", xid);

      if (TraceComponent.isAnyTracingEnabled()) {
        CommsLightTrace.traceTransaction(tc, "PrepareTxnTrace", xid, getTransactionId(), -1);
      }

      final int result;

      // Find the XAResource implementation that was used to start this
      // transaction.
      boolean performingRecovery = false;
      boolean thisResourceStartedUnitOfWork = false;
      boolean serverTransactionWasCreated = true;
      OptimizedSIXAResourceProxy delegateResource = null;

      ResourceInfo info = null; // PK61176
      synchronized(xidToResourceInfoMap)
      {
         info = xidToResourceInfoMap.get(xid);
         if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) SibTr.debug(this, tc, "Resource Info: ", info);

         // If there is no resource in the map, then start() was never invoked
         // for this XID.  We must be performing recovery.
         if (info == null)
         {
            performingRecovery = true;
         }
         else
         {
            // This XID was started by a resource in this JVM - but was it
            // this resource?
            if (info.resource == this)
            {
               // If the resource has not been ended - then the XID is
               // invalid as an argument to this method.
               if (!info.resourceEnded)
               {
                  final XAException exception = new XAException(XAException.XAER_INVAL);
                  if (TraceComponent.isAnyTracingEnabled() && tc.isEventEnabled()) SibTr.exception(this, tc, exception);
                  throw exception;
               }

               thisResourceStartedUnitOfWork = true;
               serverTransactionWasCreated = info.serverTransactionCreated;

               // Mark the resource as prepared
               info.resourcePrepared = true;
            }
            else
            {
               delegateResource = info.resource;
            }
         }
      }

      if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled())
      {
         String debugText =
            "thisResourceStartedUnitOfWork="+thisResourceStartedUnitOfWork+
            "\nperformingRecovery="+performingRecovery+
            "\nserverTransactionWasCreated="+serverTransactionWasCreated;
         SibTr.debug(this, tc, debugText);
      }

      // If this resource started the transaction (or we are performing
      // recovery) then attempt to resolve the unit of work.
      if (thisResourceStartedUnitOfWork || performingRecovery)
      {
         // Only attempt to contact the server if the transaction was
         // actually created.  If no work was done inside the scope
         // of the transaction - this is a no-op.
         if (serverTransactionWasCreated)
         {
            // Take a "reader" lock on the connections reader/writer
            // lock.  This will prevent the connection that "owns" this
            // resource from closing whilst the unit of work is resolved.
            takeCloseLock();
            try
            {
               // If the connection that "owns" this resource is closed
               // then we can assume that the unit of work must have been
               // resolved (rolled back) by the server-side code as part
               // of it's clean-up
               if (isClosed())
               {
                  final XAException exception = new XAException(XAException.XA_RBROLLBACK);
                  if (TraceComponent.isAnyTracingEnabled() && tc.isEventEnabled()) SibTr.exception(this, tc, exception);
                  throw exception;
               }

               CommsByteBuffer request = getCommsByteBuffer();
               request.putInt(getTransactionId());
               request.putXid(xid);

               if (isEndRequired())
               {
                  request.put((byte)0x01);
                  request.putInt(getEndFlags());
                  setEndNotRequired();
               }
               else
               {
                  request.put((byte)0x00);
                  request.putInt(0);
               }
               if (fapLevel >= JFapChannelConstants.FAP_VERSION_5)
               {
                  request.put((byte)(isMSResource ? 0x01 : 0x00));
               }

               final CommsByteBuffer reply = jfapExchange(request,
                                                          JFapChannelConstants.SEG_XAPREPARE,
                                                          JFapChannelConstants.PRIORITY_LOWEST,
                                                          true);
               try
               {
                  reply.checkXACommandCompletionStatus(JFapChannelConstants.SEG_XAPREPARE_R, getConversation());

                  // Get the return code and return that
                  result = reply.getInt();
               }
               finally
               {
                  if (reply != null) reply.release();
               }
            }
            catch (XAException xa)
            {
               // No FFDC Code needed

               // PK61176 If the XAException is a XA_RBXXXX then this will be the last time we will get called.
               if (xa.errorCode >= XAException.XA_RBBASE && xa.errorCode <= XAException.XA_RBEND)
               {
                 // Remove the failed xid (which will have been rolled back by the messaging engine) from xidToResourceInfoMap
                 // PK61176 - XA spec says this is correct for any return code (XA_RB or XA_RMERR).
                 synchronized(xidToResourceInfoMap) {
                   if (xidToResourceInfoMap.containsKey(xid)) {
                     xidToResourceInfoMap.remove(xid);
                   }
                 }
               }

               if (TraceComponent.isAnyTracingEnabled() && tc.isEventEnabled()) SibTr.exception(this, tc, xa);
               throw xa;
            }
            catch (Exception e)
            {
               FFDCFilter.processException(e, CLASS_NAME + ".prepare",
                                           CommsConstants.SIXARESOURCEPROXY_COMMIT_01, this);

               // Any non-XA exception is mapped to an XA RM error.
               if (TraceComponent.isAnyTracingEnabled() && tc.isDebugEnabled()) SibTr.debug(this, tc, "Non-XA exception caught: "+e);
               if (TraceComponent.isAnyTracingEnabled() && tc.isEventEnabled()) SibTr.exception(this, tc, e);
               final XAException xaException = new XAException(XAException.XAER_RMFAIL);
               xaException.initCause(e);
               
               /** PM11871 - we need to tear down the Connection to ensure the ME cleans up the tran
                *  if it is still associated (ie not ended).  This should also cause the Listener
                *  to restart and so recreate the SIXAResourceProxy; thus we don't have to fake the
                *  state transition to UNENLISTED to avoid problems when it is reused. 
                */
               
               invalidateConnection(true, e, "Exception in SIXAResourceProxy.end");
               
               if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled()) SibTr.exit(this, tc, "prepare");
               throw xaException;
            }
            finally
            {
               // Stop "reading" the owning connection's read/writer close
               // lock.  This allows the connection to be closed.
               releaseCloseLock();
            }
         }
         else
         {
            // The transaction was never created on the server.  The caller must
            // not have carried out any work for this resource inside the scope
            // of the unit of work.  Decide how to vote based on the flags used
            // to end the unit of work.
            if ((endFlags & TMFAIL) == TMFAIL)
            {
               final XAException exception = new XAException(XAException.XA_RBROLLBACK);
               if (TraceComponent.isAnyTracingEnabled() && tc.isEventEnabled()) SibTr.exception(this, tc, exception);
               throw exception;
            }

            result = XA_OK;
         }
      }
      else
      {
         // The unit of work was started by another XA resource.
         // Delegate the resolution of the unit of work to the resource
         // that started it.
         result = delegateResource.prepare(xid);
      }
      
      /* PM40261 - Start */
      // In case of a Readonly  is the result of prepare the transaction manager would drop the branch 
      // of the transaction as commit wouldn't make any sense for that particular branch. So we should
      // remove the XID of the transaction from the map else we would simply accumulate in map and never 
      // remove from it as this transaction would never get into commit or rollback.
      if (XA_RDONLY == result) {
    	  synchronized (xidToResourceInfoMap) {
    		  if (xidToResourceInfoMap.containsKey(xid)) {
    			  xidToResourceInfoMap.remove(xid);
    		  }
    	  }
      }    	  	
      /* PM40261 - End */
      	 
      if (TraceComponent.isAnyTracingEnabled() && tc.isEntryEnabled()) SibTr.exit(this, tc, "prepare", ""+result);
      return result;
   }
public int prepare ( Xid xid ) throws XAException { if ( TraceComponent . isAnyTracingEnabled ( ) && tc . isEntryEnabled ( ) ) SibTr . entry ( this , tc , "prepare" , xid ) ; if ( TraceComponent . isAnyTracingEnabled ( ) ) { CommsLightTrace . traceTransaction ( tc , "PrepareTxnTrace" , xid , getTransactionId ( ) , - 1 ) ; } final int result ; boolean performingRecovery = false ; boolean thisResourceStartedUnitOfWork = false ; boolean serverTransactionWasCreated = true ; OptimizedSIXAResourceProxy delegateResource = null ; ResourceInfo info = null ; synchronized ( xidToResourceInfoMap ) { info = xidToResourceInfoMap . get ( xid ) ; if ( TraceComponent . isAnyTracingEnabled ( ) && tc . isDebugEnabled ( ) ) SibTr . debug ( this , tc , "Resource Info: " , info ) ; if ( info == null ) { performingRecovery = true ; } else { if ( info . resource == this ) { if ( ! info . resourceEnded ) { final XAException exception = new XAException ( XAException . XAER_INVAL ) ; if ( TraceComponent . isAnyTracingEnabled ( ) && tc . isEventEnabled ( ) ) SibTr . exception ( this , tc , exception ) ; throw exception ; } thisResourceStartedUnitOfWork = true ; serverTransactionWasCreated = info . serverTransactionCreated ; info . resourcePrepared = true ; } else { delegateResource = info . resource ; } } } if ( TraceComponent . isAnyTracingEnabled ( ) && tc . isDebugEnabled ( ) ) { String debugText = "thisResourceStartedUnitOfWork=" + thisResourceStartedUnitOfWork + "\nperformingRecovery=" + performingRecovery + "\nserverTransactionWasCreated=" + serverTransactionWasCreated ; SibTr . debug ( this , tc , debugText ) ; } if ( thisResourceStartedUnitOfWork || performingRecovery ) { if ( serverTransactionWasCreated ) { takeCloseLock ( ) ; try { if ( isClosed ( ) ) { final XAException exception = new XAException ( XAException . XA_RBROLLBACK ) ; if ( TraceComponent . isAnyTracingEnabled ( ) && tc . isEventEnabled ( ) ) SibTr . exception ( this , tc , exception ) ; throw exception ; } CommsByteBuffer request = getCommsByteBuffer ( ) ; request . putInt ( getTransactionId ( ) ) ; request . putXid ( xid ) ; if ( isEndRequired ( ) ) { request . put ( ( byte ) 0x01 ) ; request . putInt ( getEndFlags ( ) ) ; setEndNotRequired ( ) ; } else { request . put ( ( byte ) 0x00 ) ; request . putInt ( 0 ) ; } if ( fapLevel >= JFapChannelConstants . FAP_VERSION_5 ) { request . put ( ( byte ) ( isMSResource ? 0x01 : 0x00 ) ) ; } final CommsByteBuffer reply = jfapExchange ( request , JFapChannelConstants . SEG_XAPREPARE , JFapChannelConstants . PRIORITY_LOWEST , true ) ; try { reply . checkXACommandCompletionStatus ( JFapChannelConstants . SEG_XAPREPARE_R , getConversation ( ) ) ; result = reply . getInt ( ) ; } finally { if ( reply != null ) reply . release ( ) ; } } catch ( XAException xa ) { if ( xa . errorCode >= XAException . XA_RBBASE && xa . errorCode <= XAException . XA_RBEND ) { synchronized ( xidToResourceInfoMap ) { if ( xidToResourceInfoMap . containsKey ( xid ) ) { xidToResourceInfoMap . remove ( xid ) ; } } } if ( TraceComponent . isAnyTracingEnabled ( ) && tc . isEventEnabled ( ) ) SibTr . exception ( this , tc , xa ) ; throw xa ; } catch ( Exception e ) { FFDCFilter . processException ( e , CLASS_NAME + ".prepare" , CommsConstants . SIXARESOURCEPROXY_COMMIT_01 , this ) ; if ( TraceComponent . isAnyTracingEnabled ( ) && tc . isDebugEnabled ( ) ) SibTr . debug ( this , tc , "Non-XA exception caught: " + e ) ; if ( TraceComponent . isAnyTracingEnabled ( ) && tc . isEventEnabled ( ) ) SibTr . exception ( this , tc , e ) ; final XAException xaException = new XAException ( XAException . XAER_RMFAIL ) ; xaException . initCause ( e ) ; invalidateConnection ( true , e , "Exception in SIXAResourceProxy.end" ) ; if ( TraceComponent . isAnyTracingEnabled ( ) && tc . isEntryEnabled ( ) ) SibTr . exit ( this , tc , "prepare" ) ; throw xaException ; } finally { releaseCloseLock ( ) ; } } else { if ( ( endFlags & TMFAIL ) == TMFAIL ) { final XAException exception = new XAException ( XAException . XA_RBROLLBACK ) ; if ( TraceComponent . isAnyTracingEnabled ( ) && tc . isEventEnabled ( ) ) SibTr . exception ( this , tc , exception ) ; throw exception ; } result = XA_OK ; } } else { result = delegateResource . prepare ( xid ) ; } if ( XA_RDONLY == result ) { synchronized ( xidToResourceInfoMap ) { if ( xidToResourceInfoMap . containsKey ( xid ) ) { xidToResourceInfoMap . remove ( xid ) ; } } } if ( TraceComponent . isAnyTracingEnabled ( ) && tc . isEntryEnabled ( ) ) SibTr . exit ( this , tc , "prepare" , "" + result ) ; return result ; }
@see javax.transaction.xa.XAResource#prepare(javax.transaction.xa.Xid)