View Javadoc

1   package com.atlassian.vcache.internal.core.service;
2   
3   import com.atlassian.marshalling.api.MarshallingException;
4   import com.atlassian.vcache.ExternalCache;
5   import com.atlassian.vcache.ExternalCacheException;
6   import com.atlassian.vcache.internal.ExternalCacheExceptionListener;
7   import com.atlassian.vcache.internal.core.VCacheCoreUtils;
8   import org.slf4j.Logger;
9   
10  import java.time.Duration;
11  import java.util.concurrent.Callable;
12  import java.util.concurrent.CompletableFuture;
13  import java.util.concurrent.CompletionStage;
14  import java.util.concurrent.ExecutionException;
15  import java.util.function.Consumer;
16  
17  import static com.atlassian.vcache.ExternalCacheException.Reason.MARSHALLER_FAILURE;
18  import static com.atlassian.vcache.ExternalCacheException.Reason.UNCLASSIFIED_FAILURE;
19  import static com.atlassian.vcache.internal.NameValidator.requireValidCacheName;
20  import static com.atlassian.vcache.internal.core.VCacheCoreUtils.failed;
21  import static java.util.Objects.requireNonNull;
22  
23  /**
24   * Provides common operations for {@link ExternalCache} instances.
25   *
26   * @param <V> the value type
27   * @since 1.0.0
28   */
29  public abstract class AbstractExternalCache<V> implements ExternalCache<V> {
30      protected final String name;
31      protected final Duration lockTimeout;
32      private ExternalCacheExceptionListener externalCacheExceptionListener;
33  
34      protected AbstractExternalCache(String name,
35                                      Duration lockTimeout,
36                                      ExternalCacheExceptionListener externalCacheExceptionListener) {
37          this.name = requireValidCacheName(name);
38          this.lockTimeout = requireNonNull(lockTimeout);
39          this.externalCacheExceptionListener = requireNonNull(externalCacheExceptionListener);
40      }
41  
42      /**
43       * Returns the cache context for the current request.
44       *
45       * @return the cache context for the current request.
46       */
47      protected abstract AbstractExternalCacheRequestContext<V> ensureCacheContext();
48  
49      /**
50       * Returns the logging instance for the implementation class.
51       *
52       * @return the logging instance for the implementation class.
53       */
54      protected abstract Logger getLogger();
55  
56      /**
57       * Maps a generic {@link Exception} to a corresponding {@link ExternalCacheException}.
58       */
59      protected abstract ExternalCacheException mapException(Exception ex);
60  
61      @Override
62      public final String getName() {
63          return name;
64      }
65  
66      /**
67       * Performs a transaction and handles all the standard exceptions that may occur.
68       *
69       * @param txn the transaction the perform
70       * @param <T> the return type
71       * @return A {@link CompletionStage} representing the outcome of performing the transaction.
72       */
73      protected <T> CompletionStage<T> perform(Callable<T> txn) {
74          return perform(txn, (i) -> {
75          });
76      }
77  
78      /**
79       * Performs a transaction and handles all the standard exceptions that may occur.
80       *
81       * @param txn            the transaction the perform
82       * @param successHandler called if the <tt>txn</tt> is successful
83       * @param <T>            the return type
84       * @return A {@link CompletionStage} representing the outcome of performing the transaction.
85       */
86      protected <T> CompletionStage<T> perform(Callable<T> txn, Consumer<T> successHandler) {
87          final ExternalCacheException exception;
88          try {
89              final T outcome = txn.call();
90              successHandler.accept(outcome);
91              return VCacheCoreUtils.successful(outcome);
92          } catch (MarshallingException ex) {
93              exception = new ExternalCacheException(MARSHALLER_FAILURE, ex);
94          } catch (ExecutionException | InterruptedException ex) {
95              exception = new ExternalCacheException(UNCLASSIFIED_FAILURE, ex);
96          } catch (ExternalCacheException ece) {
97              exception = ece;
98          } catch (Exception ex) {
99              exception = mapException(ex);
100         }
101 
102         externalCacheExceptionListener.onThrow(getName(), exception);
103         return failed(new CompletableFuture<>(), exception);
104     }
105 }