1   /**
2    * Copyright (c) 2000-2009 Liferay, Inc. All rights reserved.
3    *
4    * The contents of this file are subject to the terms of the Liferay Enterprise
5    * Subscription License ("License"). You may not use this file except in
6    * compliance with the License. You can obtain a copy of the License by
7    * contacting Liferay, Inc. See the License for the specific language governing
8    * permissions and limitations under the License, including but not limited to
9    * distribution rights of the Software.
10   *
11   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
12   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
14   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
15   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
16   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
17   * SOFTWARE.
18   */
19  
20  package com.liferay.lock.util;
21  
22  import com.liferay.lock.DuplicateLockException;
23  import com.liferay.lock.ExpiredLockException;
24  import com.liferay.lock.NoSuchLockException;
25  import com.liferay.lock.model.Lock;
26  import com.liferay.portal.kernel.uuid.PortalUUIDUtil;
27  
28  import java.util.Map;
29  import java.util.concurrent.ConcurrentHashMap;
30  
31  /**
32   * <a href="LockPool.java.html"><b><i>View Source</i></b></a>
33   *
34   * @author Brian Wing Shun Chan
35   * @author Alexander Chow
36   *
37   */
38  public class LockPool {
39  
40      public static void clear() {
41          _instance._clear();
42      }
43  
44      public static Lock getLock(String className, Comparable<?> pk)
45          throws ExpiredLockException, NoSuchLockException {
46  
47          return _instance._getLock(className, pk);
48      }
49  
50      public static boolean hasLock(
51          String className, Comparable<?> pk, long userId) {
52  
53          return _instance._hasLock(className, pk, userId);
54      }
55  
56      public static boolean isLocked(String className, Comparable<?> pk) {
57          return _instance._isLocked(className, pk);
58      }
59  
60      public static Lock lock(
61              String className, Comparable<?> pk, long userId, String owner,
62              long expirationTime)
63          throws DuplicateLockException {
64  
65          return _instance._lock(className, pk, userId, owner, expirationTime);
66      }
67  
68      public static Lock refresh(String uuid, long expirationTime)
69          throws NoSuchLockException {
70  
71          return _instance._refresh(uuid, expirationTime);
72      }
73  
74      public static void unlock(String className, Comparable<?> pk) {
75          _instance._unlock(className, pk);
76      }
77  
78      private LockPool() {
79          _locksByClassName =
80              new ConcurrentHashMap<String, Map<Comparable<?>, Lock>>();
81          _lockByUuid = new ConcurrentHashMap<String, Lock>();
82      }
83  
84      private void _clear() {
85          _locksByClassName.clear();
86          _lockByUuid.clear();
87      }
88  
89      private Lock _getLock(String className, Comparable<?> pk)
90          throws ExpiredLockException, NoSuchLockException {
91  
92          Map<Comparable<?>, Lock> locksByPK = _getLocks(className);
93  
94          Lock lock = locksByPK.get(pk);
95  
96          if (lock == null) {
97              throw new NoSuchLockException();
98          }
99          else if (lock.isExpired()) {
100             _unlock(className, pk);
101 
102             throw new ExpiredLockException();
103         }
104 
105         return lock;
106     }
107 
108     private Map<Comparable<?>, Lock> _getLocks(String className) {
109         Map<Comparable<?>, Lock> locksByPK = _locksByClassName.get(className);
110 
111         if (locksByPK == null) {
112             locksByPK = new ConcurrentHashMap<Comparable<?>, Lock>();
113 
114             _locksByClassName.put(className, locksByPK);
115         }
116 
117         return locksByPK;
118     }
119 
120     private boolean _hasLock(String className, Comparable<?> pk, long userId) {
121         try {
122             Lock lock = _getLock(className, pk);
123 
124             if (lock.getUserId() == userId) {
125                 return true;
126             }
127         }
128         catch (ExpiredLockException ele) {
129         }
130         catch (NoSuchLockException nsle) {
131         }
132 
133         return false;
134     }
135 
136     private boolean _isLocked(String className, Comparable<?> pk) {
137         try {
138             _getLock(className, pk);
139 
140             return true;
141         }
142         catch (ExpiredLockException ele) {
143         }
144         catch (NoSuchLockException nsle) {
145         }
146 
147         return false;
148     }
149 
150     private Lock _lock(
151             String className, Comparable<?> pk, long userId, String owner,
152             long expirationTime)
153         throws DuplicateLockException {
154 
155         Map<Comparable<?>, Lock> locksByPK = _getLocks(className);
156 
157         Lock lock = locksByPK.get(pk);
158 
159         if (lock != null) {
160             if (lock.isExpired()) {
161                 _unlock(className, pk);
162 
163                 lock = null;
164             }
165             else if (!lock.getOwner().equals(owner)) {
166                 throw new DuplicateLockException(lock);
167             }
168         }
169 
170         if (lock == null) {
171             String uuid = PortalUUIDUtil.generate();
172 
173             lock = new Lock(uuid, className, pk, userId, owner, expirationTime);
174 
175             locksByPK.put(pk, lock);
176 
177             _lockByUuid.put(uuid, lock);
178         }
179         else {
180             lock.setExpirationTime(expirationTime);
181         }
182 
183         return lock;
184     }
185 
186     private Lock _refresh(String uuid, long expirationTime)
187         throws NoSuchLockException {
188 
189         Lock lock = _lockByUuid.get(uuid);
190 
191         if (lock != null) {
192             lock.setExpirationTime(expirationTime);
193 
194             return lock;
195         }
196 
197         throw new NoSuchLockException();
198     }
199 
200     private void _unlock(String className, Comparable<?> pk) {
201         Map<Comparable<?>, Lock> locksByPK = _getLocks(className);
202 
203         Lock lock = locksByPK.remove(pk);
204 
205         if (lock != null) {
206             _lockByUuid.remove(lock.getUuid());
207         }
208     }
209 
210     private static LockPool _instance = new LockPool();
211 
212     private Map<String, Map<Comparable<?>, Lock>> _locksByClassName;
213     private Map<String, Lock> _lockByUuid;
214 
215 }