View Javadoc

1   package com.atlassian.vcache;
2   
3   import com.atlassian.marshalling.jdk.JavaSerializationMarshalling;
4   
5   import javax.annotation.PostConstruct;
6   import java.time.Duration;
7   import java.util.Map;
8   import java.util.Optional;
9   import java.util.Set;
10  import java.util.concurrent.CompletionStage;
11  import java.util.function.Function;
12  import java.util.stream.Collectors;
13  
14  import static com.atlassian.vcache.VCacheUtils.fold;
15  
16  /**
17   * Sample usage of a ExternalCache.
18   */
19  public class ExternalSample {
20      private static Long valueMapper(String key) {
21          switch (key) {
22              case "currentCount":
23                  return 42L;
24              case "licensedCount":
25                  return 666L;
26              default:
27                  throw new IllegalArgumentException("Unknown key: " + key);
28          }
29      }
30  
31      private static final Function<Set<String>, Map<String, Long>> VALUE_FACTORY = keys ->
32              keys.stream().collect(Collectors.toMap(key -> key, ExternalSample::valueMapper));
33  
34      private final DirectExternalCache<Long> cache;
35  
36      public ExternalSample(VCacheFactory factory) {
37          final ExternalCacheSettings settings = new ExternalCacheSettingsBuilder().
38                  defaultTtl(Duration.ofSeconds(666)).
39                  dataChangeRateHint(ChangeRate.HIGH_CHANGE).
40                  entryCountHint(42).
41                  entryGrowthRateHint(ChangeRate.LOW_CHANGE).
42                  build();
43  
44          cache = factory.getDirectExternalCache(
45                  "mycache",
46                  JavaSerializationMarshalling.pair(Long.TYPE),
47                  settings);
48      }
49  
50      @PostConstruct
51      void init() {
52          // Would not normally do this
53          cache.put("licensedCount", 88L, PutPolicy.ADD_ONLY);
54          cache.put("currentCount", 12L, PutPolicy.ADD_ONLY).whenComplete((b, ex) -> {
55              if (ex != null) {
56                  // log warning
57              } else {
58                  // log whether added
59              }
60          });
61      }
62  
63      public boolean addUser() {
64          final CompletionStage<Map<String, Optional<IdentifiedValue<Long>>>> getOp =
65                  cache.getBulkIdentified("currentCount", "licensedCount");
66  
67          final CompletionStage<Boolean> outcome = getOp.handle((currentValues, t) -> {
68  
69              if (t != null) {
70                  // Deal with it
71                  return false;
72              }
73  
74              // Check have values
75              if (!currentValues.get("currentCount").isPresent() || !currentValues.get("licensedCount").isPresent()) {
76                  // Deal with it
77                  return false;
78              }
79  
80              // Check have spare room
81              if (currentValues.get("currentCount").get().value() < currentValues.get("licensedCount").get().value()) {
82                  // Deal with it
83                  return false;
84              }
85  
86              // Increment and update
87              final Long newCount = currentValues.get("currentCount").get().value() + 1;
88  
89              CompletionStage<Boolean> replaceOp =
90                      cache.replaceIf("currentCount", currentValues.get("currentCount").get().identifier(), newCount);
91  
92              return fold(replaceOp,
93                      success -> false,
94                      failure -> false
95              );
96          });
97  
98          return outcome.toCompletableFuture().join();
99      }
100 
101     public Long spareLicenses() {
102         final CompletionStage<Map<String, Long>> cached = cache.getBulk(VALUE_FACTORY, "currentCount", "licensedCount");
103 
104         return fold(cached,
105                 m -> m.get("licensedCount") - m.get("currentCount"),
106                 err -> -1L);
107     }
108 }