View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *     http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.transaction.locking;
18  
19  import java.util.concurrent.TimeUnit;
20  
21  /**
22   * Default implementation of the {@link HierarchicalLockManager}.
23   * 
24   * <p>
25   * It splits the path into segments and non-exclusively locks each segment
26   * beginning from the root. The final segment - which is supposed to be the
27   * resource to be locked itself - can either be locked exclusively or
28   * non-exclusively. Too choose between the two, provide the flag in
29   * {@link #lockInHierarchy(Object, String, boolean)}.
30   * 
31   * <p>
32   * This implementation needs an ordinary {@link LockManager lock manager} that
33   * it delegates all locking calls to.
34   * 
35   * <p>
36   * This implementation is <em>thread-safe</em>.
37   */
38  public class DefaultHierarchicalLockManager<M> implements HierarchicalLockManager<Object, M> {
39  
40      private final String rootPath;
41  
42      private final LockManager<Object, M> lm;
43  
44      public DefaultHierarchicalLockManager(String rootPath, LockManager<Object, M> lm) {
45          this.rootPath = rootPath;
46          this.lm = lm;
47      }
48  
49      public void lockInHierarchy(M resourceManager, String path, boolean exclusive)
50              throws LockException {
51          // strip off root path
52          // TODO misses sane checks
53          if (!path.startsWith(rootPath)) {
54              throw new LockException("Could not lock a path (" + path
55                      + ") that is not under the rootPath (" + rootPath + ")");
56          }
57          String relativePath = path.substring(rootPath.length());
58  
59          // this is the root path we want to lock
60          if (relativePath.length() == 0) {
61              lock(resourceManager, "/", exclusive);
62              return;
63          }
64  
65          // always read lock root
66          lock(resourceManager, "/", false);
67  
68          String[] segments = relativePath.split("\\\\");
69          StringBuffer currentPath = new StringBuffer(relativePath.length());
70          // for root path
71          currentPath.append('/');
72  
73          // skip first segment which is just empty
74          for (int i = 1; i < segments.length; i++) {
75              String segment = segments[i];
76  
77              currentPath.append(segment).append('/');
78              String key = currentPath.toString();
79  
80              if (i == segments.length - 1) {
81                  // this is the resource itself
82                  lock(resourceManager, key, exclusive);
83              } else {
84                  // this is one of the parent path segments
85                  lock(resourceManager, key, false);
86              }
87          }
88      }
89  
90      public void endWork() {
91          lm.endWork();
92      }
93  
94      public void lock(M managedResource, Object key, boolean exclusive) throws LockException {
95          lm.lock(managedResource, key, exclusive);
96      }
97  
98      public void startWork(long timeout, TimeUnit unit) {
99          lm.startWork(timeout, unit);
100 
101     }
102 
103     public boolean tryLock(M managedResource, Object key, boolean exclusive) {
104         return lm.tryLock(managedResource, key, exclusive);
105     }
106 }