1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.aether.named.support;
20
21 import java.util.Deque;
22 import java.util.HashMap;
23 import java.util.Map;
24 import java.util.concurrent.ConcurrentHashMap;
25 import java.util.concurrent.ConcurrentMap;
26 import java.util.concurrent.atomic.AtomicInteger;
27
28 import org.eclipse.aether.named.NamedLockFactory;
29 import org.slf4j.Logger;
30 import org.slf4j.LoggerFactory;
31
32 import static java.util.Objects.requireNonNull;
33
34
35
36
37 public abstract class NamedLockFactorySupport implements NamedLockFactory {
38
39
40
41
42
43
44
45
46 public static final String SYSTEM_PROP_DIAGNOSTIC_ENABLED = "aether.named.diagnostic.enabled";
47
48 private static final boolean DIAGNOSTIC_ENABLED = Boolean.getBoolean(SYSTEM_PROP_DIAGNOSTIC_ENABLED);
49
50 protected final Logger logger = LoggerFactory.getLogger(getClass());
51
52 private final ConcurrentMap<String, NamedLockHolder> locks;
53
54 private final boolean diagnosticEnabled;
55
56 public NamedLockFactorySupport() {
57 this(DIAGNOSTIC_ENABLED);
58 }
59
60 public NamedLockFactorySupport(boolean diagnosticEnabled) {
61 this.locks = new ConcurrentHashMap<>();
62 this.diagnosticEnabled = diagnosticEnabled;
63 }
64
65
66
67
68
69
70 public boolean isDiagnosticEnabled() {
71 return diagnosticEnabled;
72 }
73
74 @Override
75 public NamedLockSupport getLock(final String name) {
76 return locks.compute(name, (k, v) -> {
77 if (v == null) {
78 v = new NamedLockHolder(createLock(k));
79 }
80 v.incRef();
81 return v;
82 })
83 .namedLock;
84 }
85
86 @Override
87 public void shutdown() {
88
89 }
90
91 @Override
92 public <E extends Throwable> E onFailure(E failure) {
93 if (isDiagnosticEnabled()) {
94 Map<String, NamedLockHolder> locks = new HashMap<>(this.locks);
95 int activeLocks = locks.size();
96 logger.info("Diagnostic dump of lock factory");
97 logger.info("===============================");
98 logger.info("Implementation: {}", getClass().getName());
99 logger.info("Active locks: {}", activeLocks);
100 logger.info("");
101 if (activeLocks > 0) {
102 for (Map.Entry<String, NamedLockHolder> entry : locks.entrySet()) {
103 String name = entry.getKey();
104 int refCount = entry.getValue().referenceCount.get();
105 NamedLockSupport lock = entry.getValue().namedLock;
106 logger.info("Name: {}", name);
107 logger.info("RefCount: {}", refCount);
108 Map<Thread, Deque<String>> diag = lock.diagnosticState();
109 diag.forEach((key, value) -> logger.info(" {} -> {}", key, value));
110 }
111 logger.info("");
112 }
113 }
114 return failure;
115 }
116
117 public void closeLock(final String name) {
118 locks.compute(name, (k, v) -> {
119 if (v != null && v.decRef() == 0) {
120 destroyLock(v.namedLock.name());
121 return null;
122 }
123 return v;
124 });
125 }
126
127
128
129
130
131 protected abstract NamedLockSupport createLock(String name);
132
133
134
135
136
137 protected void destroyLock(final String name) {
138
139 }
140
141 private static final class NamedLockHolder {
142 private final NamedLockSupport namedLock;
143
144 private final AtomicInteger referenceCount;
145
146 private NamedLockHolder(final NamedLockSupport namedLock) {
147 this.namedLock = requireNonNull(namedLock);
148 this.referenceCount = new AtomicInteger(0);
149 }
150
151 private int incRef() {
152 return referenceCount.incrementAndGet();
153 }
154
155 private int decRef() {
156 return referenceCount.decrementAndGet();
157 }
158
159 @Override
160 public String toString() {
161 return "[refCount=" + referenceCount.get() + ", lock=" + namedLock + "]";
162 }
163 }
164 }