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 lockFactory 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> lockFactory) {
90 final Function<D, ManagedLock> lockFunction = fromSupplier(managedLockFactory(lockFactory));
91 return managedFactory(weakMemoizer(lockFunction), stripeFunction);
92 }
93
94 /**
95 * Convenience method that simply calls
96 * {@link #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 #weakManagedLockFactory(Function, Supplier)
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 * @see #weakManagedLockFactory(Function, Supplier)
117 */
118 public static @NotNull
119 <T> Function<T, ManagedLock> weakManagedLockFactory() {
120 return weakManagedLockFactory(Functions.<T> identity());
121 }
122
123 /**
124 * Create a {@link Function} for resolving {@link ManagedLock.ReadWrite
125 * managed read-write locks}. The particular lock is resolved using a
126 * striping {@link Function} that is used look up a lock instance. This
127 * allows for a finite set of locks to be used even if the set of T is
128 * essentially unbounded. The locks are stored using weak references so
129 * infrequently accessed locks should not use excess memory.
130 *
131 * @param <T> the type of the thing used to look up locks
132 * @param <D> the type used to map lock instances
133 * @param stripeFunction to convert the input to the thing used to look up
134 * the individual locks
135 * @param lockFactory the factory for creating the individual locks
136 * @return a new {@link Function} that provides
137 * {@link ManagedLock.ReadWrite} instances that stores created instances
138 * with weak references.
139 */
140 public static @NotNull
141 <T, D> Function<T, ManagedLock.ReadWrite> weakReadWriteManagedLockFactory(final @NotNull Function<T, D> stripeFunction,
142 final @NotNull Supplier<ReadWriteLock> lockFactory) {
143 notNull("stripeFunction", stripeFunction);
144 final Function<D, ReadWrite> readWriteManagedLockFactory = fromSupplier(managedReadWriteLockFactory(lockFactory));
145 final WeakMemoizer<D, ManagedLock.ReadWrite> locks = weakMemoizer(readWriteManagedLockFactory);
146 return new Function<T, ManagedLock.ReadWrite>() {
147 public ManagedLock.ReadWrite get(final T input) {
148 return locks.get(stripeFunction.get(input));
149 };
150 };
151 }
152
153 /**
154 * A convenience method for calling
155 * {@link #weakReadWriteManagedLockFactory(Function, Supplier)} that uses
156 * default {@link ReentrantReadWriteLock locks}
157 *
158 * @param <T> the type of the thing used to look up locks
159 * @param <D> the type used to map lock instances
160 * @param stripeFunction
161 * @return a new {@link Function} that provides
162 * {@link ManagedLock.ReadWrite} instances that stores created instances
163 * with weak references.
164 */
165 public static @NotNull
166 <T, D> Function<T, ManagedLock.ReadWrite> weakReadWriteManagedLockFactory(final Function<T, D> stripeFunction) {
167 return weakReadWriteManagedLockFactory(stripeFunction, readWriteLockFactory());
168 }
169
170 /**
171 * A convenience method for calling
172 * {@link #weakReadWriteManagedLockFactory(Function)} that uses the
173 * {@link Functions#identity() identity function} for striping, essentially
174 * meaning that unique input will have its own lock.
175 *
176 * @param <T> the type of the thing used to look up locks
177 * @return a new {@link Function} that provides the appropriate
178 * {@link ReadWrite} for the argument {@link ManagedLock.ReadWrite}
179 * instances that stores created instances with weak references.
180 */
181 public static @NotNull
182 <T> Function<T, ManagedLock.ReadWrite> weakReadWriteManagedLockFactory() {
183 return weakReadWriteManagedLockFactory(Functions.<T> identity());
184 }
185
186 /**
187 * A {@link Supplier} of {@link ReentrantLock locks}.
188 *
189 * @return lock factory
190 */
191 static @NotNull
192 Supplier<Lock> lockFactory() {
193 return new Supplier<Lock>() {
194 public Lock get() {
195 return new ReentrantLock();
196 }
197 };
198 }
199
200 /**
201 * A {@link Supplier} of {@link ReentrantReadWriteLock read write locks}.
202 *
203 * @return lock factory
204 */
205 static @NotNull
206 Supplier<ReadWriteLock> readWriteLockFactory() {
207 return new Supplier<ReadWriteLock>() {
208 public ReadWriteLock get() {
209 return new ReentrantReadWriteLock();
210 }
211 };
212 }
213
214 /**
215 * A {@link Supplier} of {@link ManagedLock managed locks}.
216 *
217 * @return lock factory
218 */
219 static @NotNull
220 Supplier<ManagedLock> managedLockFactory(final @NotNull Supplier<Lock> supplier) {
221 notNull("supplier", supplier);
222 return new Supplier<ManagedLock>() {
223 public ManagedLock get() {
224 return new ManagedLockImpl(supplier.get());
225 }
226 };
227 }
228
229 /**
230 * A {@link Supplier} of {@link ManagedLock.ReadWrite managed read write
231 * locks}.
232 *
233 * @return lock factory
234 */
235 static @NotNull
236 Supplier<ManagedLock.ReadWrite> managedReadWriteLockFactory(final @NotNull Supplier<ReadWriteLock> supplier) {
237 notNull("supplier", supplier);
238 return new Supplier<ManagedLock.ReadWrite>() {
239 public ManagedLock.ReadWrite get() {
240 return new ReadWriteManagedLock(supplier.get());
241 }
242 };
243 }
244
245 /**
246 * Implement {@link ReadWrite}
247 */
248 static class ReadWriteManagedLock implements ManagedLock.ReadWrite {
249 private final ManagedLock read;
250 private final ManagedLock write;
251
252 ReadWriteManagedLock(final ReadWriteLock lock) {
253 notNull("lock", lock);
254 read = new ManagedLockImpl(lock.readLock());
255 write = new ManagedLockImpl(lock.writeLock());
256 }
257
258 public ManagedLock read() {
259 return read;
260 }
261
262 public ManagedLock write() {
263 return write;
264 }
265 }
266
267 static class ManagedFactory<T, D> implements Function<T, ManagedLock> {
268 static final <T, D> ManagedFactory<T, D> managedFactory(final Function<D, ManagedLock> lockResolver, final Function<T, D> stripeFunction) {
269 return new ManagedFactory<T, D>(lockResolver, stripeFunction);
270 }
271
272 private final Function<D, ManagedLock> lockResolver;
273 private final Function<T, D> stripeFunction;
274
275 ManagedFactory(final Function<D, ManagedLock> lockResolver, final Function<T, D> stripeFunction) {
276 this.lockResolver = notNull("lockResolver", lockResolver);
277 this.stripeFunction = notNull("stripeFunction", stripeFunction);
278 }
279
280 public ManagedLock get(final T descriptor) {
281 return lockResolver.get(stripeFunction.get(descriptor));
282 };
283 }
284
285 /**
286 * Default implementation of {@link ManagedLock}
287 *
288 * @param <T> the input type
289 * @param <D> the type used for the internal lock resolution.
290 */
291 static class ManagedLockImpl implements ManagedLock {
292 private final Lock lock;
293
294 ManagedLockImpl(final @NotNull Lock lock) {
295 this.lock = notNull("lock", lock);
296 }
297
298 public <R> R withLock(final Supplier<R> supplier) {
299 lock.lock();
300 try {
301 return supplier.get();
302 } finally {
303 lock.unlock();
304 }
305 }
306
307 public <R> R withLock(final Callable<R> callable) throws Exception {
308 lock.lock();
309 try {
310 return callable.call();
311 } finally {
312 lock.unlock();
313 }
314 }
315
316 public void withLock(final Runnable runnable) {
317 lock.lock();
318 try {
319 runnable.run();
320 } finally {
321 lock.unlock();
322 }
323 }
324 }
325
326 // /CLOVER:OFF
327 private ManagedLocks() {
328 throw new AssertionError("cannot instantiate!");
329 }
330 // /CLOVER:ON
331 }