1 package com.atlassian.vcache.internal.core;
2
3 import com.atlassian.vcache.internal.NameValidator;
4 import com.atlassian.vcache.internal.RequestContext;
5 import org.slf4j.Logger;
6 import org.slf4j.LoggerFactory;
7
8 import java.util.Optional;
9 import java.util.function.Supplier;
10
11 import static com.atlassian.vcache.internal.NameValidator.requireValidPartitionIdentifier;
12 import static java.util.Objects.requireNonNull;
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41 public class ThreadLocalRequestContextSupplier implements Supplier<RequestContext> {
42 private static final Logger log = LoggerFactory.getLogger(ThreadLocalRequestContextSupplier.class);
43 private final ThreadLocal<RequestContext> threadRequestContexts = new ThreadLocal<>();
44 private final Optional<Supplier<String>> lenientPartitionIdSupplier;
45
46 private ThreadLocalRequestContextSupplier(Optional<Supplier<String>> lenientPartitionIdSupplier) {
47 this.lenientPartitionIdSupplier = requireNonNull(lenientPartitionIdSupplier);
48 }
49
50
51
52
53 public static ThreadLocalRequestContextSupplier strictSupplier() {
54 return new ThreadLocalRequestContextSupplier(Optional.empty());
55 }
56
57
58
59
60
61
62 public static ThreadLocalRequestContextSupplier lenientSupplier(Supplier<String> partitionIdSupplier) {
63 log.warn("A lenient supplier has been created, TransactionalExternalCaches are now broken");
64 return new ThreadLocalRequestContextSupplier(Optional.of(partitionIdSupplier));
65 }
66
67 @Override
68 public RequestContext get() {
69 final RequestContext current = threadRequestContexts.get();
70 if (current == null) {
71 if (!lenientPartitionIdSupplier.isPresent()) {
72 log.error("Asked for request context when not initialised!");
73 throw new IllegalStateException("Thread has not been initialised.");
74 }
75
76 log.debug("Asked for request context when not initialised, returning a lenient one.");
77 return new LenientRequestContext();
78 }
79
80 return current;
81 }
82
83
84
85
86
87
88
89 public void initThread(String partitionId) {
90 final RequestContext current = threadRequestContexts.get();
91 if (current != null) {
92 log.error(
93 "Asked to initialise thread {} that is already initialised!",
94 Thread.currentThread().getName());
95 throw new IllegalStateException(
96 "Thread '" + Thread.currentThread().getName() + "' has already been initialised.");
97 }
98
99 log.trace("Initialise request context");
100 threadRequestContexts.set(new DefaultRequestContext(requireValidPartitionIdentifier(partitionId)));
101 }
102
103
104
105
106 public void clearThread() {
107 final RequestContext current = threadRequestContexts.get();
108 if (current == null) {
109 log.warn("Asked to clear a thread that is already clear!");
110 }
111
112 log.trace("Clear request context");
113 threadRequestContexts.remove();
114 }
115
116
117
118
119 private class LenientRequestContext implements RequestContext {
120 @Override
121 public String partitionIdentifier() {
122 return requireValidPartitionIdentifier(lenientPartitionIdSupplier.get().get());
123 }
124
125 @Override
126 public <T> T computeIfAbsent(Object key, Supplier<T> supplier) {
127 return supplier.get();
128 }
129
130 @Override
131 public <T> Optional<T> get(Object key) {
132 return Optional.empty();
133 }
134 }
135 }