package betsy.bpel.ws; import java.util.concurrent.atomic.AtomicInteger; import betsy.common.tasks.WaitTasks; import org.apache.log4j.Logger; /** * Detects concurrency from the perspective of the partner service. * <p> * This is done by checking whether the partner service can detect multiple parallel pending requests. * A pending request has already sent its request to the partner service, but the caller is still waiting for the reply to arrive. * During this time, another request may enter the partner service. * If this is the case, we can be sure that the calls were done in parallel, as the caller has to wait for the response normally. */ public class ConcurrencyDetector { private static final Logger log = Logger.getLogger(ConcurrencyDetector.class); // value in ms public static final int CONCURRENCY_TIMEOUT = 1000; // only for internal use private final AtomicInteger concurrentAccesses = new AtomicInteger(0); // these two are observable from the outside private final AtomicInteger totalConcurrentAccesses = new AtomicInteger(0); private final AtomicInteger totalAccesses = new AtomicInteger(0); /** * resets all counters, as if the instance would have been created anew */ public int reset() { concurrentAccesses.set(0); totalConcurrentAccesses.set(0); totalAccesses.set(0); return 0; } public int access() { log.info("call to detect concurrency"); // access detected totalAccesses.incrementAndGet(); //magic number for tracking concurrent accesses concurrentAccesses.incrementAndGet(); int result = -1; try { WaitTasks.sleep(CONCURRENCY_TIMEOUT); if (isAccessedConcurrently()) { log.info("no concurrency detected"); result = 0; } else { log.info("concurrency detected"); result = 100; totalConcurrentAccesses.incrementAndGet(); } } finally { concurrentAccesses.decrementAndGet(); } return result; } public boolean isAccessedConcurrently() { return concurrentAccesses.get() == 1; } public int getNumberOfCalls() { return totalAccesses.get(); } public int getNumberOfConcurrentCalls() { return totalConcurrentAccesses.get(); } }