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>
063 *   public class SimpleLogger {
064 *
065 *     private final StampedLockVisitor&lt;PrintStream&gt; 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) -&gt; ps.println(message));
073 *     }
074 *
075 *     public void log(byte[] buffer) {
076 *         lock.acceptWriteLocked((ps) -&gt; { ps.write(buffer); ps.println(); });
077 *     }
078 * </pre>
079 *
080 * @since 3.11
081 */
082public class LockingVisitors {
083
084    /**
085     * Wraps a domain object and a lock for access by lambdas.
086     *
087     * @param <O> the wrapped object type.
088     * @param <L> the wrapped lock type.
089     */
090    public static class LockVisitor<O, L> {
091
092        /**
093         * The lock object, untyped, since, for example {@link StampedLock} does not implement a locking interface in
094         * Java 8.
095         */
096        private final L lock;
097
098        /**
099         * The guarded object.
100         */
101        private final O object;
102
103        /**
104         * Supplies the read lock, usually from the lock object.
105         */
106        private final Supplier<Lock> readLockSupplier;
107
108        /**
109         * Supplies the write lock, usually from the lock object.
110         */
111        private final Supplier<Lock> writeLockSupplier;
112
113        /**
114         * Constructs an instance.
115         *
116         * @param object The object to guard.
117         * @param lock The locking object.
118         * @param readLockSupplier Supplies the read lock, usually from the lock object.
119         * @param writeLockSupplier Supplies the write lock, usually from the lock object.
120         */
121        protected LockVisitor(final O object, final L lock, final Supplier<Lock> readLockSupplier, final Supplier<Lock> writeLockSupplier) {
122            this.object = Objects.requireNonNull(object, "object");
123            this.lock = Objects.requireNonNull(lock, "lock");
124            this.readLockSupplier = Objects.requireNonNull(readLockSupplier, "readLockSupplier");
125            this.writeLockSupplier = Objects.requireNonNull(writeLockSupplier, "writeLockSupplier");
126        }
127
128        /**
129         * Provides read (shared, non-exclusive) access to the locked (hidden) object. More precisely, what the method
130         * will do (in the given order):
131         *
132         * <ol>
133         * <li>Obtain a read (shared) lock on the locked (hidden) object. The current thread may block, until such a
134         * lock is granted.</li>
135         * <li>Invokes the given {@link FailableConsumer consumer}, passing the locked object as the parameter.</li>
136         * <li>Release the lock, as soon as the consumers invocation is done. If the invocation results in an error, the
137         * lock will be released anyways.</li>
138         * </ol>
139         *
140         * @param consumer The consumer, which is being invoked to use the hidden object, which will be passed as the
141         *        consumers parameter.
142         * @see #acceptWriteLocked(FailableConsumer)
143         * @see #applyReadLocked(FailableFunction)
144         */
145        public void acceptReadLocked(final FailableConsumer<O, ?> consumer) {
146            lockAcceptUnlock(readLockSupplier, consumer);
147        }
148
149        /**
150         * Provides write (exclusive) access to the locked (hidden) object. More precisely, what the method will do (in
151         * the given order):
152         *
153         * <ol>
154         * <li>Obtain a write (shared) lock on the locked (hidden) object. The current thread may block, until such a
155         * lock is granted.</li>
156         * <li>Invokes the given {@link FailableConsumer consumer}, passing the locked object as the parameter.</li>
157         * <li>Release the lock, as soon as the consumers invocation is done. If the invocation results in an error, the
158         * lock will be released anyways.</li>
159         * </ol>
160         *
161         * @param consumer The consumer, which is being invoked to use the hidden object, which will be passed as the
162         *        consumers parameter.
163         * @see #acceptReadLocked(FailableConsumer)
164         * @see #applyWriteLocked(FailableFunction)
165         */
166        public void acceptWriteLocked(final FailableConsumer<O, ?> consumer) {
167            lockAcceptUnlock(writeLockSupplier, consumer);
168        }
169
170        /**
171         * Provides read (shared, non-exclusive) access to the locked (hidden) object for the purpose of computing a
172         * result object. More precisely, what the method will do (in the given order):
173         *
174         * <ol>
175         * <li>Obtain a read (shared) lock on the locked (hidden) object. The current thread may block, until such a
176         * lock is granted.</li>
177         * <li>Invokes the given {@link FailableFunction function}, passing the locked object as the parameter,
178         * receiving the functions result.</li>
179         * <li>Release the lock, as soon as the consumers invocation is done. If the invocation results in an error, the
180         * lock will be released anyways.</li>
181         * <li>Return the result object, that has been received from the functions invocation.</li>
182         * </ol>
183         * <p>
184         * <em>Example:</em> Consider that the hidden object is a list, and we wish to know the current size of the
185         * list. This might be achieved with the following:
186         * </p>
187         * <pre>
188         * private Lock&lt;List&lt;Object&gt;&gt; listLock;
189         *
190         * public int getCurrentListSize() {
191         *     final Integer sizeInteger = listLock.applyReadLocked((list) -&gt; Integer.valueOf(list.size));
192         *     return sizeInteger.intValue();
193         * }
194         * </pre>
195         *
196         * @param <T> The result type (both the functions, and this method's.)
197         * @param function The function, which is being invoked to compute the result. The function will receive the
198         *        hidden object.
199         * @return The result object, which has been returned by the functions invocation.
200         * @throws IllegalStateException The result object would be, in fact, the hidden object. This would extend
201         *         access to the hidden object beyond this methods lifetime and will therefore be prevented.
202         * @see #acceptReadLocked(FailableConsumer)
203         * @see #applyWriteLocked(FailableFunction)
204         */
205        public <T> T applyReadLocked(final FailableFunction<O, T, ?> function) {
206            return lockApplyUnlock(readLockSupplier, function);
207        }
208
209        /**
210         * Provides write (exclusive) access to the locked (hidden) object for the purpose of computing a result object.
211         * More precisely, what the method will do (in the given order):
212         *
213         * <ol>
214         * <li>Obtain a read (shared) lock on the locked (hidden) object. The current thread may block, until such a
215         * lock is granted.</li>
216         * <li>Invokes the given {@link FailableFunction function}, passing the locked object as the parameter,
217         * receiving the functions result.</li>
218         * <li>Release the lock, as soon as the consumers invocation is done. If the invocation results in an error, the
219         * lock will be released anyways.</li>
220         * <li>Return the result object, that has been received from the functions invocation.</li>
221         * </ol>
222         *
223         * @param <T> The result type (both the functions, and this method's.)
224         * @param function The function, which is being invoked to compute the result. The function will receive the
225         *        hidden object.
226         * @return The result object, which has been returned by the functions invocation.
227         * @throws IllegalStateException The result object would be, in fact, the hidden object. This would extend
228         *         access to the hidden object beyond this methods lifetime and will therefore be prevented.
229         * @see #acceptReadLocked(FailableConsumer)
230         * @see #applyWriteLocked(FailableFunction)
231         */
232        public <T> T applyWriteLocked(final FailableFunction<O, T, ?> function) {
233            return lockApplyUnlock(writeLockSupplier, function);
234        }
235
236        /**
237         * Gets the lock.
238         *
239         * @return the lock.
240         */
241        public L getLock() {
242            return lock;
243        }
244
245        /**
246         * Gets the guarded object.
247         *
248         * @return the object.
249         */
250        public O getObject() {
251            return object;
252        }
253
254        /**
255         * This method provides the default implementation for {@link #acceptReadLocked(FailableConsumer)}, and
256         * {@link #acceptWriteLocked(FailableConsumer)}.
257         *
258         * @param lockSupplier A supplier for the lock. (This provides, in fact, a long, because a {@link StampedLock} is used
259         *        internally.)
260         * @param consumer The consumer, which is to be given access to the locked (hidden) object, which will be passed
261         *        as a parameter.
262         * @see #acceptReadLocked(FailableConsumer)
263         * @see #acceptWriteLocked(FailableConsumer)
264         */
265        protected void lockAcceptUnlock(final Supplier<Lock> lockSupplier, final FailableConsumer<O, ?> consumer) {
266            final Lock lock = Objects.requireNonNull(Suppliers.get(lockSupplier), "lock");
267            lock.lock();
268            try {
269                if (consumer != null) {
270                    consumer.accept(object);
271                }
272            } catch (final Throwable t) {
273                throw Failable.rethrow(t);
274            } finally {
275                lock.unlock();
276            }
277        }
278
279        /**
280         * This method provides the actual implementation for {@link #applyReadLocked(FailableFunction)}, and
281         * {@link #applyWriteLocked(FailableFunction)}.
282         *
283         * @param <T> The result type (both the functions, and this method's.)
284         * @param lockSupplier A supplier for the lock. (This provides, in fact, a long, because a {@link StampedLock} is used
285         *        internally.)
286         * @param function The function, which is being invoked to compute the result object. This function will receive
287         *        the locked (hidden) object as a parameter.
288         * @return The result object, which has been returned by the functions invocation.
289         * @throws IllegalStateException The result object would be, in fact, the hidden object. This would extend
290         *         access to the hidden object beyond this methods lifetime and will therefore be prevented.
291         * @see #applyReadLocked(FailableFunction)
292         * @see #applyWriteLocked(FailableFunction)
293         */
294        protected <T> T lockApplyUnlock(final Supplier<Lock> lockSupplier, final FailableFunction<O, T, ?> function) {
295            final Lock lock = Objects.requireNonNull(Suppliers.get(lockSupplier), "lock");
296            lock.lock();
297            try {
298                return function.apply(object);
299            } catch (final Throwable t) {
300                throw Failable.rethrow(t);
301            } finally {
302                lock.unlock();
303            }
304        }
305
306    }
307
308    /**
309     * This class implements a wrapper for a locked (hidden) object, and provides the means to access it. The basic
310     * idea, is that the user code forsakes all references to the locked object, using only the wrapper object, and the
311     * accessor methods {@link #acceptReadLocked(FailableConsumer)}, {@link #acceptWriteLocked(FailableConsumer)},
312     * {@link #applyReadLocked(FailableFunction)}, and {@link #applyWriteLocked(FailableFunction)}. By doing so, the
313     * necessary protections are guaranteed.
314     *
315     * @param <O> The locked (hidden) objects type.
316     */
317    public static class ReadWriteLockVisitor<O> extends LockVisitor<O, ReadWriteLock> {
318
319        /**
320         * Creates a new instance with the given locked object. This constructor is supposed to be used for subclassing
321         * only. In general, it is suggested to use {@link LockingVisitors#stampedLockVisitor(Object)} instead.
322         *
323         * @param object The locked (hidden) object. The caller is supposed to drop all references to the locked object.
324         * @param readWriteLock the lock to use.
325         */
326        protected ReadWriteLockVisitor(final O object, final ReadWriteLock readWriteLock) {
327            super(object, readWriteLock, readWriteLock::readLock, readWriteLock::writeLock);
328        }
329    }
330
331    /**
332     * This class implements a wrapper for a locked (hidden) object, and provides the means to access it. The basic
333     * idea is that the user code forsakes all references to the locked object, using only the wrapper object, and the
334     * accessor methods {@link #acceptReadLocked(FailableConsumer)}, {@link #acceptWriteLocked(FailableConsumer)},
335     * {@link #applyReadLocked(FailableFunction)}, and {@link #applyWriteLocked(FailableFunction)}. By doing so, the
336     * necessary protections are guaranteed.
337     *
338     * @param <O> The locked (hidden) objects type.
339     */
340    public static class StampedLockVisitor<O> extends LockVisitor<O, StampedLock> {
341
342        /**
343         * Creates a new instance with the given locked object. This constructor is supposed to be used for subclassing
344         * only. In general, it is suggested to use {@link LockingVisitors#stampedLockVisitor(Object)} instead.
345         *
346         * @param object The locked (hidden) object. The caller is supposed to drop all references to the locked object.
347         * @param stampedLock the lock to use.
348         */
349        protected StampedLockVisitor(final O object, final StampedLock stampedLock) {
350            super(object, stampedLock, stampedLock::asReadLock, stampedLock::asWriteLock);
351        }
352    }
353
354    /**
355     * Creates a new instance of {@link ReadWriteLockVisitor} with the given (hidden) object and lock.
356     *
357     * @param <O> The locked objects type.
358     * @param object The locked (hidden) object.
359     * @param readWriteLock The lock to use.
360     * @return The created instance, a {@link StampedLockVisitor lock} for the given object.
361     * @since 3.13.0
362     */
363    public static <O> ReadWriteLockVisitor<O> create(final O object, final ReadWriteLock readWriteLock) {
364        return new LockingVisitors.ReadWriteLockVisitor<>(object, readWriteLock);
365    }
366
367    /**
368     * Creates a new instance of {@link ReadWriteLockVisitor} with the given (hidden) object.
369     *
370     * @param <O> The locked objects type.
371     * @param object The locked (hidden) object.
372     * @return The created instance, a {@link StampedLockVisitor lock} for the given object.
373     */
374    public static <O> ReadWriteLockVisitor<O> reentrantReadWriteLockVisitor(final O object) {
375        return create(object, new ReentrantReadWriteLock());
376    }
377
378    /**
379     * Creates a new instance of {@link StampedLockVisitor} with the given (hidden) object.
380     *
381     * @param <O> The locked objects type.
382     * @param object The locked (hidden) object.
383     * @return The created instance, a {@link StampedLockVisitor lock} for the given object.
384     */
385    public static <O> StampedLockVisitor<O> stampedLockVisitor(final O object) {
386        return new LockingVisitors.StampedLockVisitor<>(object, new StampedLock());
387    }
388
389    /**
390     * Make private in 4.0.
391     *
392     * @deprecated TODO Make private in 4.0.
393     */
394    @Deprecated
395    public LockingVisitors() {
396        // empty
397    }
398}