All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.atomikos.remoting.CheckedExportingTransactionManager Maven / Gradle / Ivy

There is a newer version: 6.0.0
Show newest version
/**
 * Copyright (C) 2000-2020 Atomikos 
 *
 * LICENSE CONDITIONS
 *
 * See http://www.atomikos.com/Main/WhichLicenseApplies for details.
 */

package com.atomikos.remoting;

import java.util.HashMap;
import java.util.Map;

import com.atomikos.icatch.CompositeTransaction;
import com.atomikos.icatch.CompositeTransactionManager;
import com.atomikos.icatch.ExportingTransactionManager;
import com.atomikos.icatch.Extent;
import com.atomikos.icatch.Propagation;
import com.atomikos.icatch.RollbackException;
import com.atomikos.icatch.Synchronization;
import com.atomikos.icatch.SysException;
import com.atomikos.icatch.config.Configuration;
import com.atomikos.logging.Logger;
import com.atomikos.logging.LoggerFactory;
import com.atomikos.recovery.TxState;

 /**
  * Wrapper implementation that decorates another implementation with checking:
  * at commit time, this instance makes sure that there are no outstanding calls.
  * 
  * The original motivation for adding this functionality was due to HTTP 202 
  * response codes: in such cases, our response filters are not invoked at all
  * and the transaction will commit without extent for the remote work - 
  * which in turn means an unclear commit scope (since what your application commits
  * is not what it may think it commits: the pending work of the remote 202 response is not part of the commit).
  *
  */
public class CheckedExportingTransactionManager implements ExportingTransactionManager {
    
    private static final Logger LOGGER = LoggerFactory.createLogger(CheckedExportingTransactionManager.class);
    
    private static Map pendingRequestSynchronisation = new HashMap();

    private ExportingTransactionManager delegate;
    
    public CheckedExportingTransactionManager(ExportingTransactionManager delegate) {
        this.delegate = delegate;
    }
    
    @Override
    public Propagation getPropagation() throws SysException, IllegalStateException {
        CompositeTransactionManager ctm = Configuration.getCompositeTransactionManager();
        CompositeTransaction ct = ctm.getCompositeTransaction();
        if (ct == null) {
            throw new IllegalStateException("This method requires a transaction but none was found");
        }
        registerPendingRequestSynchronisation(ct);
        return delegate.getPropagation();
    }

    @Override
    public void addExtent(Extent extent) throws SysException, IllegalArgumentException, RollbackException {
        delegate.addExtent(extent);
        markRequestAsCompleted(extent.getParentTransactionId());
    }
    
    private void registerPendingRequestSynchronisation(CompositeTransaction ct) {
        PendingRequestSynchronisation s = new PendingRequestSynchronisation(ct);
        pendingRequestSynchronisation.put(ct.getTid(), s);
        ct.registerSynchronization(s);
    }
    

    private static void markRequestAsCompleted(String tid) {
        PendingRequestSynchronisation s = pendingRequestSynchronisation.get(tid);
        if (s != null) {
            s.markAsDone();
            pendingRequestSynchronisation.remove(tid);
        }
    }
    
    private static class PendingRequestSynchronisation implements Synchronization {

        private boolean done;
        private CompositeTransaction ct;

        PendingRequestSynchronisation(CompositeTransaction ct) {
            this.ct = ct;
        }

        private void markAsDone() {
            done = true;
        }

        @Override
        public void beforeCompletion() {
            if (!done) {
                LOGGER.logWarning(
                        "Pending outgoing remote request detected at transaction commit - forcing rollback since commit scope will not be as expected!\n"
                                + "Possible causes: attempting to commit a transaction with timed out remote calls, calling a remote service that returns HTTP 202 Accepted or an invalid extent in the return...");
                ct.setRollbackOnly();
            }
        }

        @Override
        public void afterCompletion(TxState txstate) {
            markRequestAsCompleted(ct.getTid());
        }

    }



}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy