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.concurrent.ConcurrentHashMap;
22  import java.util.concurrent.ConcurrentMap;
23  import java.util.concurrent.atomic.AtomicInteger;
24  
25  import org.eclipse.aether.named.NamedLockFactory;
26  import org.slf4j.Logger;
27  import org.slf4j.LoggerFactory;
28  
29  import static java.util.Objects.requireNonNull;
30  
31  /**
32   * Support class for {@link NamedLockFactory} implementations providing reference counting.
33   */
34  public abstract class NamedLockFactorySupport implements NamedLockFactory {
35      protected final Logger logger = LoggerFactory.getLogger(getClass());
36  
37      private final ConcurrentMap<String, NamedLockHolder> locks;
38  
39      public NamedLockFactorySupport() {
40          this.locks = new ConcurrentHashMap<>();
41      }
42  
43      @Override
44      public NamedLockSupport getLock(final String name) {
45          return locks.compute(name, (k, v) -> {
46                      if (v == null) {
47                          v = new NamedLockHolder(createLock(k));
48                      }
49                      v.incRef();
50                      return v;
51                  })
52                  .namedLock;
53      }
54  
55      @Override
56      public void shutdown() {
57          // override if needed
58      }
59  
60      public void closeLock(final String name) {
61          locks.compute(name, (k, v) -> {
62              if (v != null && v.decRef() == 0) {
63                  destroyLock(v.namedLock.name());
64                  return null;
65              }
66              return v;
67          });
68      }
69  
70      /**
71       * Implementations shall create and return {@link NamedLockSupport} for given {@code name}, this method must never
72       * return {@code null}.
73       */
74      protected abstract NamedLockSupport createLock(String name);
75  
76      /**
77       * Implementation may override this (empty) method to perform some sort of implementation specific cleanup for
78       * given lock name. Invoked when reference count for given name drops to zero and named lock was removed.
79       */
80      protected void destroyLock(final String name) {
81          // override if needed
82      }
83  
84      private static final class NamedLockHolder {
85          private final NamedLockSupport namedLock;
86  
87          private final AtomicInteger referenceCount;
88  
89          private NamedLockHolder(final NamedLockSupport namedLock) {
90              this.namedLock = requireNonNull(namedLock);
91              this.referenceCount = new AtomicInteger(0);
92          }
93  
94          private int incRef() {
95              return referenceCount.incrementAndGet();
96          }
97  
98          private int decRef() {
99              return referenceCount.decrementAndGet();
100         }
101 
102         @Override
103         public String toString() {
104             return "[refCount=" + referenceCount.get() + ", lock=" + namedLock + "]";
105         }
106     }
107 }