1 /**
2 * Copyright 2008 Atlassian Pty Ltd
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 package com.atlassian.util.concurrent;
18
19 import static com.atlassian.util.concurrent.Assertions.notNull;
20 import static com.atlassian.util.concurrent.Functions.fromSupplier;
21 import static com.atlassian.util.concurrent.ManagedLocks.ManagedFactory.managedFactory;
22 import static com.atlassian.util.concurrent.WeakMemoizer.weakMemoizer;
23
24 import java.util.concurrent.Callable;
25 import java.util.concurrent.locks.Lock;
26 import java.util.concurrent.locks.ReadWriteLock;
27 import java.util.concurrent.locks.ReentrantLock;
28 import java.util.concurrent.locks.ReentrantReadWriteLock;
29
30 import com.atlassian.util.concurrent.ManagedLock.ReadWrite;
31
32 /**
33 * Static factory for producing {@link ManagedLock} and {@link ReadWrite}
34 * instances. Also contains factory methods for getting striping functions for
35 * these as well.
36 * <p>
37 * All Parameters and returns values do no allow nulls. All supplied
38 * {@link Function functions} should not allow null values are permit null
39 * returns.
40 * <p>
41 * Several methods take stripe functions. These functions should return the same
42 * value for the life of their input, ie they should be based on immutable
43 * properties of the input value - otherwise the stripe function might point to
44 * a different lock depending on the state of the input.
45 *
46 * @since 0.0.7
47 */
48 public class ManagedLocks {
49 /**
50 * Get a {@link ManagedLock} that manages the supplied {@link Lock}.
51 *
52 * @param lock the lock to use.
53 * @return a managed lock
54 */
55 public static @NotNull
56 ManagedLock manage(final @NotNull Lock lock) {
57 return new ManagedLockImpl(lock);
58 }
59
60 /**
61 * Get a {@link ManagedLock.ReadWrite} that manages the supplied
62 * {@link ReadWriteLock}.
63 *
64 * @param lock the lock to use.
65 * @return a managed read write lock
66 */
67 public static @NotNull
68 ManagedLock.ReadWrite manageReadWrite(final @NotNull ReadWriteLock lock) {
69 return new ReadWriteManagedLock(lock);
70 }
71
72 /**
73 * Create a {@link Function} for resolving {@link ManagedLock managed locks}
74 * . The particular lock is resolved using a striping {@link Function} that
75 * is used look up a lock instance. This allows for a finite set of locks to
76 * be used even if the set of T is essentially unbounded. The locks are
77 * stored using weak references so infrequently accessed locks should not
78 * use excess memory.
79 *
80 * @param <T> the type of the thing used to look up locks
81 * @param <D> the type used to map lock instances
82 * @param stripeFunction to convert the input to the thing used to look up
83 * the individual locks
84 * @param the factory for creating the individual locks
85 * @return a new {@link Function} that provides {@link ManagedLock}
86 * instances that stores created instances with weak references.
87 */
88 public static @NotNull
89 <T, D> Function<T, ManagedLock> weakManagedLockFactory(final @NotNull Function<T, D> stripeFunction, final @NotNull Supplier<Lock> lockSupplier) {
90 final Function<D, ManagedLock> lockFactory = fromSupplier(managedLockFactory(lockSupplier));
91 return managedFactory(weakMemoizer(lockFactory), stripeFunction);
92 }
93
94 /**
95 * Convenience method that simply calls
96 * {@link ManagedLocks#weakManagedLockFactory(Function, Supplier)} with the
97 * {@link #lockFactory() default lock factory}.
98 *
99 * @param <T> the type of the thing used to look up locks
100 * @param <D> the type used to map lock instances
101 * @param stripeFunction to convert Ts to Ds.
102 * @see ManagedLocks#weakLockManager(Function, int)
103 */
104 public static @NotNull
105 <T, D> Function<T, ManagedLock> weakManagedLockFactory(final @NotNull Function<T, D> stripeFunction) {
106 return weakManagedLockFactory(stripeFunction, lockFactory());
107 }
108
109 /**
110 * Convenience method that calls
111 * {@link ManagedLocks#weakManagedLockFactory(Function)} using the
112 * {@link Functions#identity() identity function} for striping, essentially
113 * meaning that unique input will have its own lock.
114 *
115 * @param <T> the type of the thing used to look up locks
116 * @param <D> the type used to map lock instances
117 * @param stripeFunction to convert Ts to Ds.
118 * @see ManagedLocks#weakLockManager(Function, int)
119 */
120 public static @NotNull
121 <T> Function<T, ManagedLock> weakManagedLockFactory() {
122 return weakManagedLockFactory(Functions.<T> identity());
123 }
124
125 /**
126 * Create a {@link Function} for resolving {@link ManagedLock.ReadWrite
127 * managed read-write locks}. The particular lock is resolved using a
128 * striping {@link Function} that is used look up a lock instance. This
129 * allows for a finite set of locks to be used even if the set of T is
130 * essentially unbounded. The locks are stored using weak references so
131 * infrequently accessed locks should not use excess memory.
132 *
133 * @param <T> the type of the thing used to look up locks
134 * @param <D> the type used to map lock instances
135 * @param stripeFunction to convert the input to the thing used to look up
136 * the individual locks
137 * @param the factory for creating the individual locks
138 * @return a new {@link Function} that provides
139 * {@link ManagedLock.ReadWrite} instances that stores created instances
140 * with weak references.
141 */
142 public static @NotNull
143 <T, D> Function<T, ManagedLock.ReadWrite> weakReadWriteManagedLockFactory(final @NotNull Function<T, D> stripeFunction,
144 final @NotNull Supplier<ReadWriteLock> lockSupplier) {
145 notNull("stripeFunction", stripeFunction);
146 final Function<D, ReadWrite> readWriteManagedLockFactory = fromSupplier(managedReadWriteLockFactory(lockSupplier));
147 final WeakMemoizer<D, ManagedLock.ReadWrite> locks = weakMemoizer(readWriteManagedLockFactory);
148 return new Function<T, ManagedLock.ReadWrite>() {
149 public ManagedLock.ReadWrite get(final T input) {
150 return locks.get(stripeFunction.get(input));
151 };
152 };
153 }
154
155 /**
156 * A convenience method for calling
157 * {@link #weakReadWriteManagedLockFactory(Function, Supplier)} that uses
158 * default {@link ReentrantReadWriteLock locks}
159 *
160 * @param <T> the type of the thing used to look up locks
161 * @param <D> the type used to map lock instances
162 * @param stripeFunction
163 * @return a new {@link Function} that provides
164 * {@link ManagedLock.ReadWrite} instances that stores created instances
165 * with weak references.
166 */
167 public static @NotNull
168 <T, D> Function<T, ManagedLock.ReadWrite> weakReadWriteManagedLockFactory(final Function<T, D> stripeFunction) {
169 return weakReadWriteManagedLockFactory(stripeFunction, readWriteLockFactory());
170 }
171
172 /**
173 * A convenience method for calling
174 * {@link #weakReadWriteManagedLockFactory(Function)} that uses the
175 * {@link Functions#identity() identity function} for striping, essentially
176 * meaning that unique input will have its own lock.
177 *
178 * @param <T> the type of the thing used to look up locks
179 * @param <D> the type used to map lock instances
180 * @return a new {@link Function} that provides
181 * {@link ManagedLock.ReadWrite} instances that stores created instances
182 * with weak references.
183 */
184 public static @NotNull
185 <T> Function<T, ManagedLock.ReadWrite> weakReadWriteManagedLockFactory() {
186 return weakReadWriteManagedLockFactory(Functions.<T> identity());
187 }
188
189 /**
190 * A {@link Supplier} of {@link ReentrantLock locks}.
191 *
192 * @return lock factory
193 */
194 static @NotNull
195 Supplier<Lock> lockFactory() {
196 return new Supplier<Lock>() {
197 public Lock get() {
198 return new ReentrantLock();
199 }
200 };
201 }
202
203 /**
204 * A {@link Supplier} of {@link ReentrantReadWriteLock read write locks}.
205 *
206 * @return lock factory
207 */
208 static @NotNull
209 Supplier<ReadWriteLock> readWriteLockFactory() {
210 return new Supplier<ReadWriteLock>() {
211 public ReadWriteLock get() {
212 return new ReentrantReadWriteLock();
213 }
214 };
215 }
216
217 /**
218 * A {@link Supplier} of {@link ManagedLock managed locks}.
219 *
220 * @return lock factory
221 */
222 static @NotNull
223 Supplier<ManagedLock> managedLockFactory(final @NotNull Supplier<Lock> supplier) {
224 notNull("supplier", supplier);
225 return new Supplier<ManagedLock>() {
226 public ManagedLock get() {
227 return new ManagedLockImpl(supplier.get());
228 }
229 };
230 }
231
232 /**
233 * A {@link Supplier} of {@link ManagedLock.ReadWrite managed read write
234 * locks}.
235 *
236 * @return lock factory
237 */
238 static @NotNull
239 Supplier<ManagedLock.ReadWrite> managedReadWriteLockFactory(final @NotNull Supplier<ReadWriteLock> supplier) {
240 notNull("supplier", supplier);
241 return new Supplier<ManagedLock.ReadWrite>() {
242 public ManagedLock.ReadWrite get() {
243 return new ReadWriteManagedLock(supplier.get());
244 }
245 };
246 }
247
248 /**
249 * Implement {@link ReadWrite}
250 */
251 static class ReadWriteManagedLock implements ManagedLock.ReadWrite {
252 private final ManagedLock read;
253 private final ManagedLock write;
254
255 ReadWriteManagedLock(final ReadWriteLock lock) {
256 notNull("lock", lock);
257 read = new ManagedLockImpl(lock.readLock());
258 write = new ManagedLockImpl(lock.writeLock());
259 }
260
261 public ManagedLock read() {
262 return read;
263 }
264
265 public ManagedLock write() {
266 return write;
267 }
268 }
269
270 static class ManagedFactory<T, D> implements Function<T, ManagedLock> {
271 static final <T, D> ManagedFactory<T, D> managedFactory(final Function<D, ManagedLock> lockResolver, final Function<T, D> stripeFunction) {
272 return new ManagedFactory<T, D>(lockResolver, stripeFunction);
273 }
274
275 private final Function<D, ManagedLock> lockResolver;
276 private final Function<T, D> stripeFunction;
277
278 ManagedFactory(final Function<D, ManagedLock> lockResolver, final Function<T, D> stripeFunction) {
279 this.lockResolver = notNull("lockResolver", lockResolver);
280 this.stripeFunction = notNull("stripeFunction", stripeFunction);
281 }
282
283 public ManagedLock get(final T descriptor) {
284 return lockResolver.get(stripeFunction.get(descriptor));
285 };
286 }
287
288 /**
289 * Default implementation of {@link ManagedLock}
290 *
291 * @param <T> the input type
292 * @param <D> the type used for the internal lock resolution.
293 */
294 static class ManagedLockImpl implements ManagedLock {
295 private final Lock lock;
296
297 ManagedLockImpl(final @NotNull Lock lock) {
298 this.lock = notNull("lock", lock);
299 }
300
301 public <R> R withLock(final Supplier<R> supplier) {
302 lock.lock();
303 try {
304 return supplier.get();
305 } finally {
306 lock.unlock();
307 }
308 }
309
310 public <R> R withLock(final Callable<R> callable) throws Exception {
311 lock.lock();
312 try {
313 return callable.call();
314 } finally {
315 lock.unlock();
316 }
317 }
318
319 public void withLock(final Runnable runnable) {
320 lock.lock();
321 try {
322 runnable.run();
323 } finally {
324 lock.unlock();
325 }
326 }
327 }
328
329 // /CLOVER:OFF
330 private ManagedLocks() {
331 throw new AssertionError("cannot instantiate!");
332 }
333 // /CLOVER:ON
334 }