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.ArrayDeque;
22  import java.util.Collections;
23  import java.util.Deque;
24  import java.util.Map;
25  import java.util.concurrent.ConcurrentHashMap;
26  import java.util.concurrent.TimeUnit;
27  
28  import org.eclipse.aether.named.NamedLock;
29  import org.slf4j.Logger;
30  import org.slf4j.LoggerFactory;
31  
32  
33  
34  
35  public abstract class NamedLockSupport implements NamedLock {
36      protected final Logger logger = LoggerFactory.getLogger(getClass());
37  
38      private final String name;
39  
40      private final NamedLockFactorySupport factory;
41  
42      private final ConcurrentHashMap<Thread, Deque<String>> diagnosticState; 
43  
44      public NamedLockSupport(final String name, final NamedLockFactorySupport factory) {
45          this.name = name;
46          this.factory = factory;
47          this.diagnosticState = factory.isDiagnosticEnabled() ? new ConcurrentHashMap<>() : null;
48      }
49  
50      @Override
51      public String name() {
52          return name;
53      }
54  
55      @Override
56      public boolean lockShared(long time, TimeUnit unit) throws InterruptedException {
57          Deque<String> steps = null;
58          if (diagnosticState != null) {
59              steps = diagnosticState.computeIfAbsent(Thread.currentThread(), k -> new ArrayDeque<>());
60          }
61          if (steps != null) {
62              steps.push("wait-shared");
63          }
64          boolean result = doLockShared(time, unit);
65          if (steps != null) {
66              steps.pop();
67              if (result) {
68                  steps.push("shared");
69              }
70          }
71          return result;
72      }
73  
74      protected abstract boolean doLockShared(long time, TimeUnit unit) throws InterruptedException;
75  
76      @Override
77      public boolean lockExclusively(long time, TimeUnit unit) throws InterruptedException {
78          Deque<String> steps = null;
79          if (diagnosticState != null) {
80              steps = diagnosticState.computeIfAbsent(Thread.currentThread(), k -> new ArrayDeque<>());
81          }
82          if (steps != null) {
83              steps.push("wait-exclusive");
84          }
85          boolean result = doLockExclusively(time, unit);
86          if (steps != null) {
87              steps.pop();
88              if (result) {
89                  steps.push("exclusive");
90              }
91          }
92          return result;
93      }
94  
95      protected abstract boolean doLockExclusively(long time, TimeUnit unit) throws InterruptedException;
96  
97      @Override
98      public void unlock() {
99          doUnlock();
100         if (diagnosticState != null) {
101             diagnosticState
102                     .computeIfAbsent(Thread.currentThread(), k -> new ArrayDeque<>())
103                     .pop();
104         }
105     }
106 
107     protected abstract void doUnlock();
108 
109     @Override
110     public void close() {
111         doClose();
112     }
113 
114     protected void doClose() {
115         factory.closeLock(name);
116     }
117 
118     
119 
120 
121 
122 
123     public Map<Thread, Deque<String>> diagnosticState() {
124         if (diagnosticState != null) {
125             return diagnosticState;
126         } else {
127             return Collections.emptyMap();
128         }
129     }
130 
131     @Override
132     public String toString() {
133         return getClass().getSimpleName() + "{" + "name='" + name + '\'' + '}';
134     }
135 }