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.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              long expirationTime)
66          throws DuplicateLockException {
67  
68          return _instance._lock(className, pk, userId, owner, expirationTime);
69      }
70  
71      public static Lock refresh(String uuid, long expirationTime)
72          throws NoSuchLockException {
73  
74          return _instance._refresh(uuid, expirationTime);
75      }
76  
77      public static void unlock(String className, Comparable<?> pk) {
78          _instance._unlock(className, pk);
79      }
80  
81      private LockPool() {
82          _locksByClassName =
83              new ConcurrentHashMap<String, Map<Comparable<?>, Lock>>();
84          _lockByUuid = new ConcurrentHashMap<String, Lock>();
85      }
86  
87      private void _clear() {
88          _locksByClassName.clear();
89          _lockByUuid.clear();
90      }
91  
92      private Lock _getLock(String className, Comparable<?> pk)
93          throws ExpiredLockException, NoSuchLockException {
94  
95          Map<Comparable<?>, Lock> locksByPK = _getLocks(className);
96  
97          Lock lock = locksByPK.get(pk);
98  
99          if (lock == null) {
100             throw new NoSuchLockException();
101         }
102         else if (lock.isExpired()) {
103             _unlock(className, pk);
104 
105             throw new ExpiredLockException();
106         }
107 
108         return lock;
109     }
110 
111     private Map<Comparable<?>, Lock> _getLocks(String className) {
112         Map<Comparable<?>, Lock> locksByPK = _locksByClassName.get(className);
113 
114         if (locksByPK == null) {
115             locksByPK = new ConcurrentHashMap<Comparable<?>, Lock>();
116 
117             _locksByClassName.put(className, locksByPK);
118         }
119 
120         return locksByPK;
121     }
122 
123     private boolean _hasLock(String className, Comparable<?> pk, long userId) {
124         try {
125             Lock lock = _getLock(className, pk);
126 
127             if (lock.getUserId() == userId) {
128                 return true;
129             }
130         }
131         catch (ExpiredLockException ele) {
132         }
133         catch (NoSuchLockException nsle) {
134         }
135 
136         return false;
137     }
138 
139     private boolean _isLocked(String className, Comparable<?> pk) {
140         try {
141             _getLock(className, pk);
142 
143             return true;
144         }
145         catch (ExpiredLockException ele) {
146         }
147         catch (NoSuchLockException nsle) {
148         }
149 
150         return false;
151     }
152 
153     private Lock _lock(
154             String className, Comparable<?> pk, long userId, String owner,
155             long expirationTime)
156         throws DuplicateLockException {
157 
158         Map<Comparable<?>, Lock> locksByPK = _getLocks(className);
159 
160         Lock lock = locksByPK.get(pk);
161 
162         if (lock != null) {
163             if (lock.isExpired()) {
164                 _unlock(className, pk);
165 
166                 lock = null;
167             }
168             else if (!lock.getOwner().equals(owner)) {
169                 throw new DuplicateLockException(lock);
170             }
171         }
172 
173         if (lock == null) {
174             String uuid = PortalUUIDUtil.generate();
175 
176             lock = new Lock(uuid, className, pk, userId, owner, expirationTime);
177 
178             locksByPK.put(pk, lock);
179 
180             _lockByUuid.put(uuid, lock);
181         }
182         else {
183             lock.setExpirationTime(expirationTime);
184         }
185 
186         return lock;
187     }
188 
189     private Lock _refresh(String uuid, long expirationTime)
190         throws NoSuchLockException {
191 
192         Lock lock = _lockByUuid.get(uuid);
193 
194         if (lock != null) {
195             lock.setExpirationTime(expirationTime);
196 
197             return lock;
198         }
199 
200         throw new NoSuchLockException();
201     }
202 
203     private void _unlock(String className, Comparable<?> pk) {
204         Map<Comparable<?>, Lock> locksByPK = _getLocks(className);
205 
206         Lock lock = locksByPK.remove(pk);
207 
208         if (lock != null) {
209             _lockByUuid.remove(lock.getUuid());
210         }
211     }
212 
213     private static LockPool _instance = new LockPool();
214 
215     private Map<String, Map<Comparable<?>, Lock>> _locksByClassName;
216     private Map<String, Lock> _lockByUuid;
217 
218 }