1   /**
2    * Copyright (c) 2000-2008 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.lock.model.impl.LockImpl;
30  import com.liferay.portal.kernel.util.ConcurrentHashSet;
31  
32  import java.util.Iterator;
33  import java.util.Map;
34  import java.util.Set;
35  import java.util.concurrent.ConcurrentHashMap;
36  
37  /**
38   * <a href="LockPool.java.html"><b><i>View Source</i></b></a>
39   *
40   * @author Brian Wing Shun Chan
41   *
42   */
43  public class LockPool {
44  
45      public static void clear() {
46          _instance._clear();
47      }
48  
49      public static Lock getLock(String className, Comparable<?> pk)
50          throws ExpiredLockException, NoSuchLockException {
51  
52          return _instance._getLock(className, pk);
53      }
54  
55      public static Set<Lock> getLocksByCompanyId(long companyId) {
56          Set<Lock> locksByCompanyId = _instance._getLocksByCompanyId(companyId);
57  
58          Iterator<Lock> itr = locksByCompanyId.iterator();
59  
60          while (itr.hasNext()) {
61              Lock lock = itr.next();
62  
63              if (lock.isExpired()) {
64                  itr.remove();
65  
66                  _instance._getLocks(
67                      lock.getClassName(), lock.getPrimaryKey()).remove(lock);
68                  _instance._getLocksByUserId(lock.getUserId()).remove(lock);
69              }
70          }
71  
72          return locksByCompanyId;
73      }
74  
75      public static Set<Lock> getLocksByUserId(long userId) {
76          Set<Lock> locksByUserId = _instance._getLocksByUserId(userId);
77  
78          Iterator<Lock> itr = locksByUserId.iterator();
79  
80          while (itr.hasNext()) {
81              Lock lock = itr.next();
82  
83              if (lock.isExpired()) {
84                  itr.remove();
85  
86                  _instance._getLocks(
87                      lock.getClassName(), lock.getPrimaryKey()).remove(lock);
88                  _instance._getLocksByCompanyId(
89                      lock.getCompanyId()).remove(lock);
90              }
91          }
92  
93          return locksByUserId;
94      }
95  
96      public static boolean hasLock(
97          String className, Comparable<?> pk, long userId) {
98  
99          return _instance._hasLock(className, pk, userId);
100     }
101 
102     public static boolean isLocked(String className, Comparable<?> pk) {
103         return _instance._isLocked(className, pk);
104     }
105 
106     public static void lock(
107             String className, Comparable<?> pk, long companyId, long userId,
108             long expirationTime)
109         throws DuplicateLockException {
110 
111         _instance._lock(className, pk, companyId, userId, expirationTime);
112     }
113 
114     public static void unlock(String className, Comparable<?> pk) {
115         _instance._unlock(className, pk);
116     }
117 
118     private LockPool() {
119         _locksByClassName =
120             new ConcurrentHashMap<String, Map<Comparable<?>, Lock>>();
121         _locksByCompanyId = new ConcurrentHashMap<Long, Set<Lock>>();
122         _locksByUserId = new ConcurrentHashMap<Long, Set<Lock>>();
123     }
124 
125     private void _clear() {
126         _locksByClassName.clear();
127         _locksByCompanyId.clear();
128         _locksByUserId.clear();
129     }
130 
131     private Lock _getLock(String className, Comparable<?> pk)
132         throws ExpiredLockException, NoSuchLockException {
133 
134         Map<Comparable<?>, Lock> locksByPK = _getLocks(className, pk);
135 
136         Lock lock = locksByPK.get(pk);
137 
138         if (lock == null) {
139             throw new NoSuchLockException();
140         }
141         else if (lock.isExpired()) {
142             _unlock(className, pk);
143 
144             throw new ExpiredLockException();
145         }
146 
147         return lock;
148     }
149 
150     private Map<Comparable<?>, Lock> _getLocks(
151         String className, Comparable<?> pk) {
152 
153         Map<Comparable<?>, Lock> locksByPK = _locksByClassName.get(className);
154 
155         if (locksByPK == null) {
156             locksByPK = new ConcurrentHashMap<Comparable<?>, Lock>();
157 
158             _locksByClassName.put(className, locksByPK);
159         }
160 
161         return locksByPK;
162     }
163 
164     private Set<Lock> _getLocksByCompanyId(long companyId) {
165         Set<Lock> set = _locksByCompanyId.get(companyId);
166 
167         if (set == null) {
168             set = new ConcurrentHashSet<Lock>();
169 
170             _locksByCompanyId.put(companyId, set);
171         }
172 
173         return set;
174     }
175 
176     private Set<Lock> _getLocksByUserId(long userId) {
177         Set<Lock> set = _locksByUserId.get(userId);
178 
179         if (set == null) {
180             set = new ConcurrentHashSet<Lock>();
181 
182             _locksByUserId.put(userId, set);
183         }
184 
185         return set;
186     }
187 
188     private boolean _hasLock(String className, Comparable<?> pk, long userId) {
189         try {
190             Lock lock = _getLock(className, pk);
191 
192             if (lock.getUserId() == userId) {
193                 return true;
194             }
195         }
196         catch (ExpiredLockException ele) {
197         }
198         catch (NoSuchLockException nsle) {
199         }
200 
201         return false;
202     }
203 
204     private boolean _isLocked(String className, Comparable<?> pk) {
205         try {
206             _getLock(className, pk);
207 
208             return true;
209         }
210         catch (ExpiredLockException ele) {
211         }
212         catch (NoSuchLockException nsle) {
213         }
214 
215         return false;
216     }
217 
218     private void _lock(
219             String className, Comparable<?> pk, long companyId, long userId,
220             long expirationTime)
221         throws DuplicateLockException {
222 
223         Map<Comparable<?>, Lock> locksByPK = _getLocks(className, pk);
224 
225         Lock lock = locksByPK.get(pk);
226 
227         if (lock != null && lock.isExpired()) {
228             _unlock(className, pk);
229 
230             lock = null;
231         }
232         else if ((lock != null) && (lock.getUserId() != userId)) {
233             throw new DuplicateLockException(lock);
234         }
235 
236         if (lock == null) {
237             lock = new LockImpl(
238                 className, pk, companyId, userId, expirationTime);
239 
240             locksByPK.put(pk, lock);
241 
242             _getLocksByCompanyId(companyId).add(lock);
243             _getLocksByUserId(userId).add(lock);
244         }
245         else {
246             lock.setExpirationTime(expirationTime);
247         }
248     }
249 
250     private void _unlock(String className, Comparable<?> pk) {
251         Map<Comparable<?>, Lock> locksByPK = _getLocks(className, pk);
252 
253         Lock lock = locksByPK.remove(pk);
254 
255         if (lock != null) {
256             _getLocksByCompanyId(lock.getCompanyId()).remove(lock);
257             _getLocksByUserId(lock.getUserId()).remove(lock);
258         }
259     }
260 
261     private static LockPool _instance = new LockPool();
262 
263     private Map<String, Map<Comparable<?>, Lock>> _locksByClassName;
264     private Map<Long, Set<Lock>> _locksByCompanyId;
265     private Map<Long, Set<Lock>> _locksByUserId;
266 
267 }