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