View Javadoc
1   package org.eclipse.aether.named.support;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *  http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import org.eclipse.aether.named.NamedLockFactory;
23  import org.slf4j.Logger;
24  import org.slf4j.LoggerFactory;
25  
26  import java.util.concurrent.ConcurrentHashMap;
27  import java.util.concurrent.ConcurrentMap;
28  import java.util.concurrent.atomic.AtomicBoolean;
29  import java.util.concurrent.atomic.AtomicInteger;
30  
31  /**
32   * Support class for {@link NamedLockFactory} implementations providing reference counting.
33   */
34  public abstract class NamedLockFactorySupport implements NamedLockFactory
35  {
36      protected final Logger logger = LoggerFactory.getLogger( getClass() );
37  
38      private final ConcurrentMap<String, NamedLockHolder> locks;
39  
40      public NamedLockFactorySupport()
41      {
42          this.locks = new ConcurrentHashMap<>();
43      }
44  
45      @Override
46      public NamedLockSupport getLock( final String name )
47      {
48          return locks.compute( name, ( k, v ) ->
49          {
50              if ( v == null )
51              {
52                  v = new NamedLockHolder( createLock( k ) );
53              }
54              v.incRef();
55              return v;
56          } ).namedLock;
57      }
58  
59      @Override
60      public void shutdown()
61      {
62          // override if needed
63      }
64  
65      public boolean closeLock( final NamedLockSupport lock )
66      {
67          AtomicBoolean destroyed = new AtomicBoolean( false );
68          locks.compute( lock.name(), ( k, v ) ->
69          {
70              if ( v != null && v.decRef() == 0 )
71              {
72                  destroyLock( v.namedLock );
73                  destroyed.set( true );
74                  return null;
75              }
76              return v;
77          } );
78          return destroyed.get();
79      }
80  
81  
82      @Override
83      protected void finalize() throws Throwable
84      {
85          try
86          {
87              if ( !locks.isEmpty() )
88              {
89                  // report leak
90                  logger.warn( "Lock leak, referenced locks still exist {}", locks );
91              }
92          }
93          finally
94          {
95              super.finalize();
96          }
97      }
98  
99      protected abstract NamedLockSupport createLock( final String name );
100 
101     protected void destroyLock( final NamedLockSupport lock )
102     {
103         // override if needed
104     }
105 
106     private static final class NamedLockHolder
107     {
108         private final NamedLockSupport namedLock;
109 
110         private final AtomicInteger referenceCount;
111 
112         private NamedLockHolder( NamedLockSupport namedLock )
113         {
114             this.namedLock = namedLock;
115             this.referenceCount = new AtomicInteger( 0 );
116         }
117 
118         private int incRef()
119         {
120             return referenceCount.incrementAndGet();
121         }
122 
123         private int decRef()
124         {
125             return referenceCount.decrementAndGet();
126         }
127 
128         @Override
129         public String toString()
130         {
131             return "[refCount=" + referenceCount.get() + ", lock=" + namedLock + "]";
132         }
133     }
134 }