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