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