View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
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   * Support class for {@link NamedLock} implementations providing reference counting.
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; // non-null only if diag enabled
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          if (diagnosticState != null) {
58              diagnosticState
59                      .computeIfAbsent(Thread.currentThread(), k -> new ArrayDeque<>())
60                      .push("shared");
61          }
62          return doLockShared(time, unit);
63      }
64  
65      protected abstract boolean doLockShared(long time, TimeUnit unit) throws InterruptedException;
66  
67      @Override
68      public boolean lockExclusively(long time, TimeUnit unit) throws InterruptedException {
69          if (diagnosticState != null) {
70              diagnosticState
71                      .computeIfAbsent(Thread.currentThread(), k -> new ArrayDeque<>())
72                      .push("exclusive");
73          }
74          return doLockExclusively(time, unit);
75      }
76  
77      protected abstract boolean doLockExclusively(long time, TimeUnit unit) throws InterruptedException;
78  
79      @Override
80      public void unlock() {
81          doUnlock();
82          if (diagnosticState != null) {
83              diagnosticState
84                      .computeIfAbsent(Thread.currentThread(), k -> new ArrayDeque<>())
85                      .pop();
86          }
87      }
88  
89      protected abstract void doUnlock();
90  
91      @Override
92      public void close() {
93          doClose();
94      }
95  
96      protected void doClose() {
97          factory.closeLock(name);
98      }
99  
100     /**
101      * Returns the diagnostic state (if collected) or empty map, never {@code null}.
102      *
103      * @since 1.9.11
104      */
105     public Map<Thread, Deque<String>> diagnosticState() {
106         if (diagnosticState != null) {
107             return diagnosticState;
108         } else {
109             return Collections.emptyMap();
110         }
111     }
112 
113     @Override
114     public String toString() {
115         return getClass().getSimpleName() + "{" + "name='" + name + '\'' + '}';
116     }
117 }