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 }