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 private static final boolean DIAGNOSTIC_ENABLED = Boolean.getBoolean("aether.named.diagnostic.enabled");
44
45 protected final Logger logger = LoggerFactory.getLogger(getClass());
46
47 private final ConcurrentMap<String, NamedLockHolder> locks;
48
49 private final boolean diagnosticEnabled;
50
51 public NamedLockFactorySupport() {
52 this(DIAGNOSTIC_ENABLED);
53 }
54
55 public NamedLockFactorySupport(boolean diagnosticEnabled) {
56 this.locks = new ConcurrentHashMap<>();
57 this.diagnosticEnabled = diagnosticEnabled;
58 }
59
60
61
62
63
64
65 public boolean isDiagnosticEnabled() {
66 return diagnosticEnabled;
67 }
68
69 @Override
70 public NamedLockSupport getLock(final String name) {
71 return locks.compute(name, (k, v) -> {
72 if (v == null) {
73 v = new NamedLockHolder(createLock(k));
74 }
75 v.incRef();
76 return v;
77 })
78 .namedLock;
79 }
80
81 @Override
82 public void shutdown() {
83
84 }
85
86 @Override
87 public <E extends Throwable> E onFailure(E failure) {
88 if (isDiagnosticEnabled()) {
89 Map<String, NamedLockHolder> locks = new HashMap<>(this.locks);
90 int activeLocks = locks.size();
91 logger.info("Diagnostic dump of lock factory");
92 logger.info("===============================");
93 logger.info("Implementation: {}", getClass().getName());
94 logger.info("Active locks: {}", activeLocks);
95 logger.info("");
96 if (activeLocks > 0) {
97 for (Map.Entry<String, NamedLockHolder> entry : locks.entrySet()) {
98 String name = entry.getKey();
99 int refCount = entry.getValue().referenceCount.get();
100 NamedLockSupport lock = entry.getValue().namedLock;
101 logger.info("Name: {}", name);
102 logger.info("RefCount: {}", refCount);
103 Map<Thread, Deque<String>> diag = lock.diagnosticState();
104 diag.forEach((key, value) -> logger.info(" {} -> {}", key, value));
105 }
106 logger.info("");
107 }
108 }
109 return failure;
110 }
111
112 public void closeLock(final String name) {
113 locks.compute(name, (k, v) -> {
114 if (v != null && v.decRef() == 0) {
115 destroyLock(v.namedLock.name());
116 return null;
117 }
118 return v;
119 });
120 }
121
122
123
124
125
126 protected abstract NamedLockSupport createLock(String name);
127
128
129
130
131
132 protected void destroyLock(final String name) {
133
134 }
135
136 private static final class NamedLockHolder {
137 private final NamedLockSupport namedLock;
138
139 private final AtomicInteger referenceCount;
140
141 private NamedLockHolder(final NamedLockSupport namedLock) {
142 this.namedLock = requireNonNull(namedLock);
143 this.referenceCount = new AtomicInteger(0);
144 }
145
146 private int incRef() {
147 return referenceCount.incrementAndGet();
148 }
149
150 private int decRef() {
151 return referenceCount.decrementAndGet();
152 }
153
154 @Override
155 public String toString() {
156 return "[refCount=" + referenceCount.get() + ", lock=" + namedLock + "]";
157 }
158 }
159 }