001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.commons.lang3.concurrent.locks;
018
019import java.util.Objects;
020import java.util.concurrent.locks.Lock;
021import java.util.concurrent.locks.ReadWriteLock;
022import java.util.concurrent.locks.ReentrantReadWriteLock;
023import java.util.concurrent.locks.StampedLock;
024import java.util.function.Supplier;
025
026import org.apache.commons.lang3.function.Failable;
027import org.apache.commons.lang3.function.FailableConsumer;
028import org.apache.commons.lang3.function.FailableFunction;
029import org.apache.commons.lang3.function.Suppliers;
030
031/**
032 * Combines the monitor and visitor pattern to work with {@link java.util.concurrent.locks.Lock locked objects}. Locked
033 * objects are an alternative to synchronization. This, on Wikipedia, is known as the Visitor pattern
034 * (https://en.wikipedia.org/wiki/Visitor_pattern), and from the "Gang of Four" "Design Patterns" book's Visitor pattern
035 * [Gamma, E., Helm, R., & Johnson, R. (1998). Visitor. In Design patterns elements of reusable object oriented software (pp. 331-344). Reading: Addison Wesley.].
036 *
037 * <p>
038 * Locking is preferable, if there is a distinction between read access (multiple threads may have read access
039 * concurrently), and write access (only one thread may have write access at any given time). In comparison,
040 * synchronization doesn't support read access, because synchronized access is exclusive.
041 * </p>
042 * <p>
043 * Using this class is fairly straightforward:
044 * </p>
045 * <ol>
046 * <li>While still in single thread mode, create an instance of {@link LockingVisitors.StampedLockVisitor} by calling
047 * {@link #stampedLockVisitor(Object)}, passing the object which needs to be locked. Discard all references to the
048 * locked object. Instead, use references to the lock.</li>
049 * <li>If you want to access the locked object, create a {@link FailableConsumer}. The consumer will receive the locked
050 * object as a parameter. For convenience, the consumer may be implemented as a Lambda. Then invoke
051 * {@link LockingVisitors.StampedLockVisitor#acceptReadLocked(FailableConsumer)}, or
052 * {@link LockingVisitors.StampedLockVisitor#acceptWriteLocked(FailableConsumer)}, passing the consumer.</li>
053 * <li>As an alternative, if you need to produce a result object, you may use a {@link FailableFunction}. This function
054 * may also be implemented as a Lambda. To have the function executed, invoke
055 * {@link LockingVisitors.StampedLockVisitor#applyReadLocked(FailableFunction)}, or
056 * {@link LockingVisitors.StampedLockVisitor#applyWriteLocked(FailableFunction)}.</li>
057 * </ol>
058 * <p>
059 * Example: A thread safe logger class.
060 * </p>
061 *
062 * <pre>{@code
063 *   public class SimpleLogger {
064 *
065 *     private final StampedLockVisitor<PrintStream> lock;
066 *
067 *     public SimpleLogger(OutputStream out) {
068 *         lock = LockingVisitors.stampedLockVisitor(new PrintStream(out));
069 *     }
070 *
071 *     public void log(String message) {
072 *         lock.acceptWriteLocked(ps -> ps.println(message));
073 *     }
074 *
075 *     public void log(byte[] buffer) {
076 *         lock.acceptWriteLocked(ps -> { ps.write(buffer); ps.println(); });
077 *     }
078 * }
079 * }
080 * </pre>
081 *
082 * @since 3.11
083 */
084public class LockingVisitors {
085
086    /**
087     * Wraps a domain object and a lock for access by lambdas.
088     *
089     * @param <O> the wrapped object type.
090     * @param <L> the wrapped lock type.
091     */
092    public static class LockVisitor<O, L> {
093
094        /**
095         * The lock object, untyped, since, for example {@link StampedLock} does not implement a locking interface in
096         * Java 8.
097         */
098        private final L lock;
099
100        /**
101         * The guarded object.
102         */
103        private final O object;
104
105        /**
106         * Supplies the read lock, usually from the lock object.
107         */
108        private final Supplier<Lock> readLockSupplier;
109
110        /**
111         * Supplies the write lock, usually from the lock object.
112         */
113        private final Supplier<Lock> writeLockSupplier;
114
115        /**
116         * Constructs an instance.
117         *
118         * @param object The object to guard.
119         * @param lock The locking object.
120         * @param readLockSupplier Supplies the read lock, usually from the lock object.
121         * @param writeLockSupplier Supplies the write lock, usually from the lock object.
122         */
123        protected LockVisitor(final O object, final L lock, final Supplier<Lock> readLockSupplier, final Supplier<Lock> writeLockSupplier) {
124            this.object = Objects.requireNonNull(object, "object");
125            this.lock = Objects.requireNonNull(lock, "lock");
126            this.readLockSupplier = Objects.requireNonNull(readLockSupplier, "readLockSupplier");
127            this.writeLockSupplier = Objects.requireNonNull(writeLockSupplier, "writeLockSupplier");
128        }
129
130        /**
131         * Provides read (shared, non-exclusive) access to the locked (hidden) object. More precisely, what the method
132         * will do (in the given order):
133         *
134         * <ol>
135         * <li>Obtain a read (shared) lock on the locked (hidden) object. The current thread may block, until such a
136         * lock is granted.</li>
137         * <li>Invokes the given {@link FailableConsumer consumer}, passing the locked object as the parameter.</li>
138         * <li>Release the lock, as soon as the consumers invocation is done. If the invocation results in an error, the
139         * lock will be released anyways.</li>
140         * </ol>
141         *
142         * @param consumer The consumer, which is being invoked to use the hidden object, which will be passed as the
143         *        consumers parameter.
144         * @see #acceptWriteLocked(FailableConsumer)
145         * @see #applyReadLocked(FailableFunction)
146         */
147        public void acceptReadLocked(final FailableConsumer<O, ?> consumer) {
148            lockAcceptUnlock(readLockSupplier, consumer);
149        }
150
151        /**
152         * Provides write (exclusive) access to the locked (hidden) object. More precisely, what the method will do (in
153         * the given order):
154         *
155         * <ol>
156         * <li>Obtain a write (shared) lock on the locked (hidden) object. The current thread may block, until such a
157         * lock is granted.</li>
158         * <li>Invokes the given {@link FailableConsumer consumer}, passing the locked object as the parameter.</li>
159         * <li>Release the lock, as soon as the consumers invocation is done. If the invocation results in an error, the
160         * lock will be released anyways.</li>
161         * </ol>
162         *
163         * @param consumer The consumer, which is being invoked to use the hidden object, which will be passed as the
164         *        consumers parameter.
165         * @see #acceptReadLocked(FailableConsumer)
166         * @see #applyWriteLocked(FailableFunction)
167         */
168        public void acceptWriteLocked(final FailableConsumer<O, ?> consumer) {
169            lockAcceptUnlock(writeLockSupplier, consumer);
170        }
171
172        /**
173         * Provides read (shared, non-exclusive) access to the locked (hidden) object for the purpose of computing a
174         * result object. More precisely, what the method will do (in the given order):
175         *
176         * <ol>
177         * <li>Obtain a read (shared) lock on the locked (hidden) object. The current thread may block, until such a
178         * lock is granted.</li>
179         * <li>Invokes the given {@link FailableFunction function}, passing the locked object as the parameter,
180         * receiving the functions result.</li>
181         * <li>Release the lock, as soon as the consumers invocation is done. If the invocation results in an error, the
182         * lock will be released anyways.</li>
183         * <li>Return the result object, that has been received from the functions invocation.</li>
184         * </ol>
185         * <p>
186         * <em>Example:</em> Consider that the hidden object is a list, and we wish to know the current size of the
187         * list. This might be achieved with the following:
188         * </p>
189         * <pre>{@code
190         * private Lock<List<Object>> listLock;
191         *
192         * public int getCurrentListSize() {
193         *     final Integer sizeInteger = listLock.applyReadLocked(list -> Integer.valueOf(list.size));
194         *     return sizeInteger.intValue();
195         * }
196         * }
197         * </pre>
198         *
199         * @param <T> The result type (both the functions, and this method's.)
200         * @param function The function, which is being invoked to compute the result. The function will receive the
201         *        hidden object.
202         * @return The result object, which has been returned by the functions invocation.
203         * @throws IllegalStateException The result object would be, in fact, the hidden object. This would extend
204         *         access to the hidden object beyond this methods lifetime and will therefore be prevented.
205         * @see #acceptReadLocked(FailableConsumer)
206         * @see #applyWriteLocked(FailableFunction)
207         */
208        public <T> T applyReadLocked(final FailableFunction<O, T, ?> function) {
209            return lockApplyUnlock(readLockSupplier, function);
210        }
211
212        /**
213         * Provides write (exclusive) access to the locked (hidden) object for the purpose of computing a result object.
214         * More precisely, what the method will do (in the given order):
215         *
216         * <ol>
217         * <li>Obtain a read (shared) lock on the locked (hidden) object. The current thread may block, until such a
218         * lock is granted.</li>
219         * <li>Invokes the given {@link FailableFunction function}, passing the locked object as the parameter,
220         * receiving the functions result.</li>
221         * <li>Release the lock, as soon as the consumers invocation is done. If the invocation results in an error, the
222         * lock will be released anyways.</li>
223         * <li>Return the result object, that has been received from the functions invocation.</li>
224         * </ol>
225         *
226         * @param <T> The result type (both the functions, and this method's.)
227         * @param function The function, which is being invoked to compute the result. The function will receive the
228         *        hidden object.
229         * @return The result object, which has been returned by the functions invocation.
230         * @throws IllegalStateException The result object would be, in fact, the hidden object. This would extend
231         *         access to the hidden object beyond this methods lifetime and will therefore be prevented.
232         * @see #acceptReadLocked(FailableConsumer)
233         * @see #applyWriteLocked(FailableFunction)
234         */
235        public <T> T applyWriteLocked(final FailableFunction<O, T, ?> function) {
236            return lockApplyUnlock(writeLockSupplier, function);
237        }
238
239        /**
240         * Gets the lock.
241         *
242         * @return the lock.
243         */
244        public L getLock() {
245            return lock;
246        }
247
248        /**
249         * Gets the guarded object.
250         *
251         * @return the object.
252         */
253        public O getObject() {
254            return object;
255        }
256
257        /**
258         * This method provides the default implementation for {@link #acceptReadLocked(FailableConsumer)}, and
259         * {@link #acceptWriteLocked(FailableConsumer)}.
260         *
261         * @param lockSupplier A supplier for the lock. (This provides, in fact, a long, because a {@link StampedLock} is used
262         *        internally.)
263         * @param consumer The consumer, which is to be given access to the locked (hidden) object, which will be passed
264         *        as a parameter.
265         * @see #acceptReadLocked(FailableConsumer)
266         * @see #acceptWriteLocked(FailableConsumer)
267         */
268        protected void lockAcceptUnlock(final Supplier<Lock> lockSupplier, final FailableConsumer<O, ?> consumer) {
269            final Lock lock = Objects.requireNonNull(Suppliers.get(lockSupplier), "lock");
270            lock.lock();
271            try {
272                if (consumer != null) {
273                    consumer.accept(object);
274                }
275            } catch (final Throwable t) {
276                throw Failable.rethrow(t);
277            } finally {
278                lock.unlock();
279            }
280        }
281
282        /**
283         * This method provides the actual implementation for {@link #applyReadLocked(FailableFunction)}, and
284         * {@link #applyWriteLocked(FailableFunction)}.
285         *
286         * @param <T> The result type (both the functions, and this method's.)
287         * @param lockSupplier A supplier for the lock. (This provides, in fact, a long, because a {@link StampedLock} is used
288         *        internally.)
289         * @param function The function, which is being invoked to compute the result object. This function will receive
290         *        the locked (hidden) object as a parameter.
291         * @return The result object, which has been returned by the functions invocation.
292         * @throws IllegalStateException The result object would be, in fact, the hidden object. This would extend
293         *         access to the hidden object beyond this methods lifetime and will therefore be prevented.
294         * @see #applyReadLocked(FailableFunction)
295         * @see #applyWriteLocked(FailableFunction)
296         */
297        protected <T> T lockApplyUnlock(final Supplier<Lock> lockSupplier, final FailableFunction<O, T, ?> function) {
298            final Lock lock = Objects.requireNonNull(Suppliers.get(lockSupplier), "lock");
299            lock.lock();
300            try {
301                return function.apply(object);
302            } catch (final Throwable t) {
303                throw Failable.rethrow(t);
304            } finally {
305                lock.unlock();
306            }
307        }
308
309    }
310
311    /**
312     * This class implements a wrapper for a locked (hidden) object, and provides the means to access it. The basic
313     * idea, is that the user code forsakes all references to the locked object, using only the wrapper object, and the
314     * accessor methods {@link #acceptReadLocked(FailableConsumer)}, {@link #acceptWriteLocked(FailableConsumer)},
315     * {@link #applyReadLocked(FailableFunction)}, and {@link #applyWriteLocked(FailableFunction)}. By doing so, the
316     * necessary protections are guaranteed.
317     *
318     * @param <O> The locked (hidden) objects type.
319     */
320    public static class ReadWriteLockVisitor<O> extends LockVisitor<O, ReadWriteLock> {
321
322        /**
323         * Creates a new instance with the given locked object. This constructor is supposed to be used for subclassing
324         * only. In general, it is suggested to use {@link LockingVisitors#stampedLockVisitor(Object)} instead.
325         *
326         * @param object The locked (hidden) object. The caller is supposed to drop all references to the locked object.
327         * @param readWriteLock the lock to use.
328         */
329        protected ReadWriteLockVisitor(final O object, final ReadWriteLock readWriteLock) {
330            super(object, readWriteLock, readWriteLock::readLock, readWriteLock::writeLock);
331        }
332    }
333
334    /**
335     * This class implements a wrapper for a locked (hidden) object, and provides the means to access it. The basic
336     * idea is that the user code forsakes all references to the locked object, using only the wrapper object, and the
337     * accessor methods {@link #acceptReadLocked(FailableConsumer)}, {@link #acceptWriteLocked(FailableConsumer)},
338     * {@link #applyReadLocked(FailableFunction)}, and {@link #applyWriteLocked(FailableFunction)}. By doing so, the
339     * necessary protections are guaranteed.
340     *
341     * @param <O> The locked (hidden) objects type.
342     */
343    public static class StampedLockVisitor<O> extends LockVisitor<O, StampedLock> {
344
345        /**
346         * Creates a new instance with the given locked object. This constructor is supposed to be used for subclassing
347         * only. In general, it is suggested to use {@link LockingVisitors#stampedLockVisitor(Object)} instead.
348         *
349         * @param object The locked (hidden) object. The caller is supposed to drop all references to the locked object.
350         * @param stampedLock the lock to use.
351         */
352        protected StampedLockVisitor(final O object, final StampedLock stampedLock) {
353            super(object, stampedLock, stampedLock::asReadLock, stampedLock::asWriteLock);
354        }
355    }
356
357    /**
358     * Creates a new instance of {@link ReadWriteLockVisitor} with the given (hidden) object and lock.
359     *
360     * @param <O> The locked objects type.
361     * @param object The locked (hidden) object.
362     * @param readWriteLock The lock to use.
363     * @return The created instance, a {@link StampedLockVisitor lock} for the given object.
364     * @since 3.13.0
365     */
366    public static <O> ReadWriteLockVisitor<O> create(final O object, final ReadWriteLock readWriteLock) {
367        return new LockingVisitors.ReadWriteLockVisitor<>(object, readWriteLock);
368    }
369
370    /**
371     * Creates a new instance of {@link ReadWriteLockVisitor} with the given (hidden) object.
372     *
373     * @param <O> The locked objects type.
374     * @param object The locked (hidden) object.
375     * @return The created instance, a {@link StampedLockVisitor lock} for the given object.
376     */
377    public static <O> ReadWriteLockVisitor<O> reentrantReadWriteLockVisitor(final O object) {
378        return create(object, new ReentrantReadWriteLock());
379    }
380
381    /**
382     * Creates a new instance of {@link StampedLockVisitor} with the given (hidden) object.
383     *
384     * @param <O> The locked objects type.
385     * @param object The locked (hidden) object.
386     * @return The created instance, a {@link StampedLockVisitor lock} for the given object.
387     */
388    public static <O> StampedLockVisitor<O> stampedLockVisitor(final O object) {
389        return new LockingVisitors.StampedLockVisitor<>(object, new StampedLock());
390    }
391
392    /**
393     * Make private in 4.0.
394     *
395     * @deprecated TODO Make private in 4.0.
396     */
397    @Deprecated
398    public LockingVisitors() {
399        // empty
400    }
401}