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 java.util.ArrayDeque;
23  import java.util.Deque;
24  import java.util.concurrent.TimeUnit;
25  import java.util.concurrent.locks.ReadWriteLock;
26  
27  /**
28   * Named lock support implementation that is using {@link ReadWriteLock} instances. The adapted lock MUST SUPPORT
29   * reentrancy, non re-entrant locks will NOT work. It is the responsibility of an adapting lock, to ensure that
30   * above lock requirement stands.
31   */
32  public class ReadWriteLockNamedLock extends NamedLockSupport
33  {
34      private enum Step
35      {
36          /**
37           * Step when {@link ReadWriteLock#readLock()} was locked
38           */
39          SHARED,
40  
41          /**
42           * Step when {@link ReadWriteLock#writeLock()} was locked
43           */
44          EXCLUSIVE
45      }
46  
47      private final ThreadLocal<Deque<Step>> threadSteps;
48  
49      private final ReadWriteLock readWriteLock;
50  
51      public ReadWriteLockNamedLock( final String name, final NamedLockFactorySupport factory,
52                                     final ReadWriteLock readWriteLock )
53      {
54          super( name, factory );
55          this.threadSteps = ThreadLocal.withInitial( ArrayDeque::new );
56          this.readWriteLock = readWriteLock;
57      }
58  
59      @Override
60      public boolean lockShared( final long time, final TimeUnit unit ) throws InterruptedException
61      {
62          Deque<Step> steps = threadSteps.get();
63          if ( readWriteLock.readLock().tryLock( time, unit ) )
64          {
65              steps.push( Step.SHARED );
66              return true;
67          }
68          return false;
69      }
70  
71      @Override
72      public boolean lockExclusively( final long time, final TimeUnit unit ) throws InterruptedException
73      {
74          Deque<Step> steps = threadSteps.get();
75          if ( !steps.isEmpty() )
76          { // we already own shared or exclusive lock
77              if ( !steps.contains( Step.EXCLUSIVE ) )
78              {
79                  return false; // Lock upgrade not supported
80              }
81          }
82          if ( readWriteLock.writeLock().tryLock( time, unit ) )
83          {
84              steps.push( Step.EXCLUSIVE );
85              return true;
86          }
87          return false;
88      }
89  
90      @Override
91      public void unlock()
92      {
93          Deque<Step> steps = threadSteps.get();
94          if ( steps.isEmpty() )
95          {
96              throw new IllegalStateException( "Wrong API usage: unlock w/o lock" );
97          }
98          Step step = steps.pop();
99          if ( Step.SHARED == step )
100         {
101             readWriteLock.readLock().unlock();
102         }
103         else if ( Step.EXCLUSIVE == step )
104         {
105             readWriteLock.writeLock().unlock();
106         }
107     }
108 }