View Javadoc

1   package com.atlassian.vcache.internal.core;
2   
3   import com.atlassian.vcache.internal.BegunTransactionalActivityHandler;
4   import com.atlassian.vcache.internal.RequestContext;
5   import org.slf4j.Logger;
6   import org.slf4j.LoggerFactory;
7   
8   import java.util.HashMap;
9   import java.util.HashSet;
10  import java.util.Map;
11  import java.util.Set;
12  import java.util.concurrent.atomic.AtomicBoolean;
13  
14  import static java.util.Objects.requireNonNull;
15  
16  /**
17   * Default implementation of {@link TransactionControlManager}.
18   *
19   * @since 1.0.0
20   */
21  public class DefaultTransactionControlManager implements TransactionControlManager {
22      private static final Logger log = LoggerFactory.getLogger(DefaultTransactionControlManager.class);
23  
24      private final Object transactionControllersKey = new Object();
25      private final Object callbackKey = new Object();
26  
27      private final Instrumentor instrumentor;
28      private final BegunTransactionalActivityHandler begunTransactionalActivityHandler;
29  
30      public DefaultTransactionControlManager(Instrumentor instrumentor,
31                                              BegunTransactionalActivityHandler begunTransactionalActivityHandler) {
32          this.instrumentor = requireNonNull(instrumentor);
33          this.begunTransactionalActivityHandler = requireNonNull(begunTransactionalActivityHandler);
34      }
35  
36      @Override
37      public void registerTransactionalExternalCache(RequestContext requestContext,
38                                                     String cacheName,
39                                                     TransactionControl control) {
40          requestContext
41                  .computeIfAbsent(transactionControllersKey, HashMap::new)
42                  .computeIfAbsent(cacheName, x -> {
43                      log.trace("Registering {}", cacheName);
44                      return instrumentor.wrap(control, cacheName);
45                  });
46  
47          invokeCallbackIfNecessary(requestContext);
48      }
49  
50      @Override
51      public void syncAll(RequestContext requestContext) {
52          log.trace("Synchronising all caches");
53  
54          requestContext.<Map<String, TransactionControl>>get(transactionControllersKey)
55                  .ifPresent(txControls -> txControls.forEach((cacheName, transactionControl) -> {
56                      log.trace("Syncing {}", cacheName);
57                      transactionControl.transactionSync();
58                  }));
59          resetShouldInvokeCallback(requestContext);
60      }
61  
62      @Override
63      public Set<String> discardAll(RequestContext requestContext) {
64          log.trace("Discarding all caches");
65          final Set<String> discardedCacheNames = new HashSet<>();
66  
67          requestContext.<Map<String, TransactionControl>>get(transactionControllersKey)
68                  .ifPresent(txControls -> txControls.forEach((cacheName, transactionControl) -> {
69                      log.trace("Discarding {}", cacheName);
70                      if (transactionControl.transactionDiscard()) {
71                          discardedCacheNames.add(cacheName);
72                      }
73                  }));
74          resetShouldInvokeCallback(requestContext);
75  
76          return discardedCacheNames;
77      }
78  
79      private void invokeCallbackIfNecessary(RequestContext requestContext) {
80          if (getCallbackInvokedFlag(requestContext).compareAndSet(false, true)) {
81              begunTransactionalActivityHandler.onRequest(requestContext);
82          }
83      }
84  
85      private void resetShouldInvokeCallback(RequestContext requestContext) {
86          getCallbackInvokedFlag(requestContext).set(false);
87      }
88  
89      private AtomicBoolean getCallbackInvokedFlag(RequestContext requestContext) {
90          return requestContext.computeIfAbsent(callbackKey, () -> new AtomicBoolean(false));
91      }
92  }