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 *      https://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.ReentrantLock;
023import java.util.concurrent.locks.ReentrantReadWriteLock;
024import java.util.concurrent.locks.StampedLock;
025import java.util.function.Supplier;
026
027import org.apache.commons.lang3.builder.AbstractSupplier;
028import org.apache.commons.lang3.function.Failable;
029import org.apache.commons.lang3.function.FailableConsumer;
030import org.apache.commons.lang3.function.FailableFunction;
031import org.apache.commons.lang3.function.Suppliers;
032
033/**
034 * Combines the monitor and visitor pattern to work with {@link Lock}s as an alternative to synchronization.
035 * <p>
036 * The read and write methods use the locks supplied by the visitor. A {@link ReentrantLockVisitor} uses one exclusive lock for both methods.
037 * A {@link ReadWriteLockVisitor} uses the underlying read and write locks, while a {@link StampedLockVisitor} uses its read and write
038 * {@link Lock} views. Read operations may run concurrently only when the supplied lock supports shared reads.
039 * </p>
040 * <p>
041 * For example, to use this class with a {@link ReentrantLock}:
042 * </p>
043 * <ol>
044 * <li>In single threaded mode, call {@link #reentrantLockVisitor(Object)}, passing the object to protect. This creates a
045 * {@link LockingVisitors.ReentrantLockVisitor}
046 * </li>
047 * <li>To access the protected object, create a {@link FailableConsumer} lambda. The consumer will receive the object as a parameter while the visitor holds the
048 * lock. Then call
049 * {@link LockingVisitors.LockVisitor#acceptReadLocked(FailableConsumer)}, or
050 * {@link LockingVisitors.LockVisitor#acceptWriteLocked(FailableConsumer)}, passing the consumer.
051 * </li>
052 * <li>Alternatively, to receive a result object, use a {@link FailableFunction} lambda. To have the function executed, call
053 * {@link LockingVisitors.LockVisitor#applyReadLocked(FailableFunction)}, or
054 * {@link LockingVisitors.LockVisitor#applyWriteLocked(FailableFunction)}.
055 * </li>
056 * </ol>
057 * <p>
058 * Example 1: A thread safe logger class using a {@link ReentrantLockVisitor}.
059 * </p>
060 *
061 * <pre>{@code
062 *   public class SimpleLogger1 {
063 *
064 *     private final ReentrantLockVisitor<PrintStream> lock;
065 *     private final PrintStream ps;
066 *
067 *     public SimpleLogger(OutputStream out) {
068 *         ps = new PrintStream(out);
069 *         lock = LockingVisitors.reentrantLockVisitor(ps);
070 *     }
071 *
072 *     public void log(String message) {
073 *         lock.acceptWriteLocked(ps -> ps.println(message));
074 *     }
075 *
076 *     public void log(byte[] buffer) {
077 *         lock.acceptWriteLocked(ps -> { ps.write(buffer); ps.println(); });
078 *     }
079 * }
080 * }
081 * </pre>
082 *
083 * <p>
084 * Example 2: A thread safe logger class using a {@link ReadWriteLockVisitor}.
085 * </p>
086 *
087 * <pre>{@code
088 *   public class SimpleLogger2 {
089 *
090 *     private final ReadWriteLockVisitor<PrintStream> lock;
091 *     private final PrintStream ps;
092 *
093 *     public SimpleLogger(OutputStream out) {
094 *         ps = new PrintStream(out);
095 *         lock = LockingVisitors.readWriteLockVisitor(ps);
096 *     }
097 *
098 *     public void log(String message) {
099 *         lock.acceptWriteLocked(ps -> ps.println(message));
100 *     }
101 *
102 *     public void log(byte[] buffer) {
103 *         lock.acceptWriteLocked(ps -> { ps.write(buffer); ps.println(); });
104 *     }
105 * }
106 * }
107 * </pre>
108 *
109 * <p>
110 * Example 3: A thread safe logger class using a {@link StampedLock}.
111 * </p>
112 *
113 * <pre>{@code
114 *   public class SimpleLogger3 {
115 *
116 *     private final StampedLockVisitor<PrintStream> lock;
117 *     private final PrintStream ps;
118 *
119 *     public SimpleLogger(OutputStream out) {
120 *         ps = new PrintStream(out);
121 *         lock = LockingVisitors.stampedLockVisitor(ps);
122 *     }
123 *
124 *     public void log(String message) {
125 *         lock.acceptWriteLocked(ps -> ps.println(message));
126 *     }
127 *
128 *     public void log(byte[] buffer) {
129 *         lock.acceptWriteLocked(ps -> { ps.write(buffer); ps.println(); });
130 *     }
131 * }
132 * }
133 * </pre>
134 *
135 * @since 3.11
136 */
137public class LockingVisitors {
138
139    /**
140     * Wraps a domain object and a lock for access by lambdas.
141     *
142     * @param <O> The wrapped object type.
143     * @param <L> The wrapped lock type.
144     * @see LockingVisitors
145     */
146    public static class LockVisitor<O, L> {
147
148        /**
149         * Builds {@link LockVisitor} instances.
150         *
151         * @param <O> The wrapped object type.
152         * @param <L> The wrapped lock type.
153         * @param <B> The builder type.
154         * @since 3.18.0
155         */
156        public static class LVBuilder<O, L, B extends LVBuilder<O, L, B>> extends AbstractSupplier<LockVisitor<O, L>, B, RuntimeException> {
157
158            /**
159             * The underlying lock object. Its type varies because {@link StampedLock} does not implement {@link Lock} or
160             * {@link ReadWriteLock}.
161             */
162            L lock;
163
164            /**
165             * The guarded object.
166             */
167            O object;
168
169            /**
170             * Supplies the lock used by read methods.
171             */
172            private Supplier<Lock> readLockSupplier;
173
174            /**
175             * Supplies the lock used by write methods.
176             */
177            private Supplier<Lock> writeLockSupplier;
178
179            /**
180             * Constructs a new instance.
181             */
182            public LVBuilder() {
183                // empty
184            }
185
186            @Override
187            public LockVisitor<O, L> get() {
188                return new LockVisitor<>(this);
189            }
190
191            Supplier<Lock> getReadLockSupplier() {
192                return readLockSupplier;
193            }
194
195
196            Supplier<Lock> getWriteLockSupplier() {
197                return writeLockSupplier;
198            }
199
200            /**
201             * Sets the underlying lock returned by {@link LockVisitor#getLock()}.
202             *
203             * @param lock The lock.
204             * @return {@code this} instance.
205             */
206            public B setLock(final L lock) {
207                this.lock = lock;
208                return asThis();
209            }
210
211            /**
212             * Sets the resource.
213             *
214             * @param object The resource.
215             * @return {@code this} instance.
216             */
217            public B setObject(final O object) {
218                this.object = object;
219                return asThis();
220            }
221
222            /**
223             * Sets the supplier of the lock used by read methods.
224             *
225             * @param readLockSupplier Supplies the read lock.
226             * @return {@code this} instance.
227             */
228            public B setReadLockSupplier(final Supplier<Lock> readLockSupplier) {
229                this.readLockSupplier = readLockSupplier;
230                return asThis();
231            }
232
233            /**
234             * Sets the supplier of the lock used by write methods.
235             *
236             * @param writeLockSupplier Supplies the write lock.
237             * @return {@code this} instance.
238             */
239            public B setWriteLockSupplier(final Supplier<Lock> writeLockSupplier) {
240                this.writeLockSupplier = writeLockSupplier;
241                return asThis();
242            }
243        }
244
245        /**
246         * The underlying lock object. Its type varies because {@link StampedLock} does not implement {@link Lock} or
247         * {@link ReadWriteLock}.
248         */
249        private final L lock;
250
251        /**
252         * The guarded object.
253         */
254        private final O object;
255
256        /**
257         * Supplies the lock used by read methods.
258         */
259        private final Supplier<Lock> readLockSupplier;
260
261        /**
262         * Supplies the lock used by write methods.
263         */
264        private final Supplier<Lock> writeLockSupplier;
265
266        /**
267         * Constructs an instance from a builder.
268         *
269         * @param builder The builder.
270         */
271        private LockVisitor(final LVBuilder<O, L, ?> builder) {
272            this.object = Objects.requireNonNull(builder.object, "object");
273            this.lock = Objects.requireNonNull(builder.lock, "lock");
274            this.readLockSupplier = Objects.requireNonNull(builder.readLockSupplier, "readLockSupplier");
275            this.writeLockSupplier = Objects.requireNonNull(builder.writeLockSupplier, "writeLockSupplier");
276        }
277
278        /**
279         * Constructs an instance.
280         *
281         * @param object The object to guard.
282         * @param lock The locking object.
283         * @param readLockSupplier Supplies the lock used by read methods.
284         * @param writeLockSupplier Supplies the lock used by write methods.
285         */
286        protected LockVisitor(final O object, final L lock, final Supplier<Lock> readLockSupplier, final Supplier<Lock> writeLockSupplier) {
287            this.object = Objects.requireNonNull(object, "object");
288            this.lock = Objects.requireNonNull(lock, "lock");
289            this.readLockSupplier = Objects.requireNonNull(readLockSupplier, "readLockSupplier");
290            this.writeLockSupplier = Objects.requireNonNull(writeLockSupplier, "writeLockSupplier");
291        }
292
293        /**
294         * Invokes the consumer while holding the lock supplied for read operations.
295         * The lock is released in a {@code finally} block after the consumer returns or throws. Whether other readers can proceed concurrently depends on the
296         * supplied lock.
297         *
298         * @param consumer The consumer of the guarded object.
299         * @see #acceptWriteLocked(FailableConsumer)
300         * @see #applyReadLocked(FailableFunction)
301         */
302        public void acceptReadLocked(final FailableConsumer<O, ?> consumer) {
303            lockAcceptUnlock(readLockSupplier, consumer);
304        }
305
306        /**
307         * Invokes the consumer while holding the lock supplied for write operations.
308         * The lock is released in a {@code finally} block after the consumer returns or throws.
309         *
310         * @param consumer The consumer of the guarded object.
311         * @see #acceptReadLocked(FailableConsumer)
312         * @see #applyWriteLocked(FailableFunction)
313         */
314        public void acceptWriteLocked(final FailableConsumer<O, ?> consumer) {
315            lockAcceptUnlock(writeLockSupplier, consumer);
316        }
317
318        /**
319         * Applies the function while holding the lock supplied for read operations.
320         * The lock is released in a {@code finally} block after the function returns or throws. Whether other readers can proceed concurrently depends on the
321         * supplied lock.
322         *
323         * @param <T> The result type.
324         * @param function The function applied to the guarded object.
325         * @return The function result.
326         * @throws NullPointerException Thrown if the lock supplier is null or returns null.
327         * @see #acceptReadLocked(FailableConsumer)
328         * @see #applyWriteLocked(FailableFunction)
329         */
330        public <T> T applyReadLocked(final FailableFunction<O, T, ?> function) {
331            return lockApplyUnlock(readLockSupplier, function);
332        }
333
334        /**
335         * Applies the function while holding the lock supplied for write operations.
336         * The lock is released in a {@code finally} block after the function returns or throws.
337         *
338         * @param <T> The result type.
339         * @param function The function applied to the guarded object.
340         * @return The function result.
341         * @throws NullPointerException Thrown if the lock supplier is null or returns null.
342         * @see #acceptWriteLocked(FailableConsumer)
343         * @see #applyReadLocked(FailableFunction)
344         */
345        public <T> T applyWriteLocked(final FailableFunction<O, T, ?> function) {
346            return lockApplyUnlock(writeLockSupplier, function);
347        }
348
349        /**
350         * Gets the lock.
351         *
352         * @return The lock.
353         */
354        public L getLock() {
355            return lock;
356        }
357
358        /**
359         * Gets the guarded object.
360         *
361         * @return The object.
362         */
363        public O getObject() {
364            return object;
365        }
366
367        /**
368         * Implements {@link #acceptReadLocked(FailableConsumer)} and
369         * {@link #acceptWriteLocked(FailableConsumer)}.
370         *
371         * @param lockSupplier Supplies the {@link Lock} to acquire and release, including a {@link StampedLock} view.
372         * @param consumer The consumer of the guarded object.
373         * @see #acceptReadLocked(FailableConsumer)
374         * @see #acceptWriteLocked(FailableConsumer)
375         */
376        protected void lockAcceptUnlock(final Supplier<Lock> lockSupplier, final FailableConsumer<O, ?> consumer) {
377            final Lock lock = Objects.requireNonNull(Suppliers.get(lockSupplier), "lock");
378            lock.lock();
379            try {
380                Failable.accept(consumer, object);
381            } finally {
382                lock.unlock();
383            }
384        }
385
386        /**
387         * Implements {@link #applyReadLocked(FailableFunction)} and
388         * {@link #applyWriteLocked(FailableFunction)}.
389         *
390         * @param <T> The result type.
391         * @param lockSupplier Supplies the {@link Lock} to acquire and release, including a {@link StampedLock} view.
392         * @param function The function applied to the guarded object.
393         * @return The function result.
394         * @throws NullPointerException Thrown if the lock supplier is null or returns null.
395         * @see #applyReadLocked(FailableFunction)
396         * @see #applyWriteLocked(FailableFunction)
397         */
398        protected <T> T lockApplyUnlock(final Supplier<Lock> lockSupplier, final FailableFunction<O, T, ?> function) {
399            final Lock lock = Objects.requireNonNull(Suppliers.get(lockSupplier), "lock");
400            lock.lock();
401            try {
402                return Failable.apply(function, object);
403            } finally {
404                lock.unlock();
405            }
406        }
407
408    }
409
410    /**
411     * Wraps a {@link ReadWriteLock} and object to protect. Read methods use {@link ReadWriteLock#readLock()}, and write methods use
412     * {@link ReadWriteLock#writeLock()}. To access the object, use the methods {@link #acceptReadLocked(FailableConsumer)},
413     * {@link #acceptWriteLocked(FailableConsumer)}, {@link #applyReadLocked(FailableFunction)}, and {@link #applyWriteLocked(FailableFunction)}. The visitor
414     * holds the lock while the consumer or function is called.
415     *
416     * @param <O> The type of the object to protect.
417     * @see LockingVisitors#create(Object, ReadWriteLock)
418     */
419    public static class ReadWriteLockVisitor<O> extends LockVisitor<O, ReadWriteLock> {
420
421        /**
422         * Builds {@link LockVisitor} instances.
423         *
424         * @param <O> The wrapped object type.
425         * @since 3.18.0
426         */
427        public static class Builder<O> extends LVBuilder<O, ReadWriteLock, Builder<O>> {
428
429            /**
430             * Constructs a new instance.
431             */
432            public Builder() {
433                // empty
434            }
435
436            @Override
437            public ReadWriteLockVisitor<O> get() {
438                return new ReadWriteLockVisitor<>(this);
439            }
440
441            @Override
442            public Builder<O> setLock(final ReadWriteLock readWriteLock) {
443                setReadLockSupplier(readWriteLock::readLock);
444                setWriteLockSupplier(readWriteLock::writeLock);
445                return super.setLock(readWriteLock);
446            }
447        }
448
449        /**
450         * Creates a new builder.
451         *
452         * @param <O> The wrapped object type.
453         * @return A new builder.
454         * @since 3.18.0
455         */
456        public static <O> Builder<O> builder() {
457            return new Builder<>();
458        }
459
460        /**
461         * Constructs a new instance from a builder.
462         *
463         * @param builder A builder.
464         */
465        private ReadWriteLockVisitor(final Builder<O> builder) {
466            super(builder);
467        }
468
469        /**
470         * Creates a new instance with the given object and lock.
471         *
472         * @param object The object to protect. The caller is supposed to drop all references to the locked object.
473         * @param readWriteLock The lock to use.
474         * @see LockingVisitors
475         */
476        protected ReadWriteLockVisitor(final O object, final ReadWriteLock readWriteLock) {
477            super(object, readWriteLock, readWriteLock::readLock, readWriteLock::writeLock);
478        }
479
480    }
481
482    /**
483     * Wraps a {@link ReentrantLock} and object to protect. Both read and write methods acquire the same exclusive lock.
484     * To access the object, use the methods {@link #acceptReadLocked(FailableConsumer)},
485     * {@link #acceptWriteLocked(FailableConsumer)}, {@link #applyReadLocked(FailableFunction)}, and {@link #applyWriteLocked(FailableFunction)}. The visitor
486     * holds the lock while the consumer or function is called.
487     *
488     * @param <O> The type of the object to protect.
489     * @see LockingVisitors#reentrantLockVisitor(Object)
490     * @since 3.18.0
491     */
492    public static class ReentrantLockVisitor<O> extends LockVisitor<O, ReentrantLock> {
493
494        /**
495         * Builds {@link LockVisitor} instances.
496         *
497         * @param <O> The wrapped object type.
498         * @since 3.18.0
499         */
500        public static class Builder<O> extends LVBuilder<O, ReentrantLock, Builder<O>> {
501
502            /**
503             * Constructs a new instance.
504             */
505            public Builder() {
506                // empty
507            }
508
509            @Override
510            public ReentrantLockVisitor<O> get() {
511                return new ReentrantLockVisitor<>(this);
512            }
513
514
515            @Override
516            public Builder<O> setLock(final ReentrantLock reentrantLock) {
517                setReadLockSupplier(() -> reentrantLock);
518                setWriteLockSupplier(() -> reentrantLock);
519                return super.setLock(reentrantLock);
520            }
521        }
522
523        /**
524         * Creates a new builder.
525         *
526         * @param <O> The wrapped object type.
527         * @return A new builder.
528         * @since 3.18.0
529         */
530        public static <O> Builder<O> builder() {
531            return new Builder<>();
532        }
533
534        /**
535         * Constructs a new instance from a builder.
536         *
537         * @param builder A builder.
538         */
539        private ReentrantLockVisitor(final Builder<O> builder) {
540            super(builder);
541        }
542
543
544        /**
545         * Creates a new instance with the given object and lock.
546         * <p>
547         * This visitor uses the given {@link ReentrantLock} for both read and write methods; both acquire it exclusively.
548         * </p>
549         *
550         * @param object The object to protect. The caller is supposed to drop all references to the locked object.
551         * @param reentrantLock The lock to use.
552         * @see LockingVisitors
553         */
554        protected ReentrantLockVisitor(final O object, final ReentrantLock reentrantLock) {
555            super(object, reentrantLock, () -> reentrantLock, () -> reentrantLock);
556        }
557    }
558
559    /**
560     * Wraps a {@link StampedLock} and object to protect. Read methods use {@link StampedLock#asReadLock()}, and write methods use
561     * {@link StampedLock#asWriteLock()}. To access the object, use the methods {@link #acceptReadLocked(FailableConsumer)},
562     * {@link #acceptWriteLocked(FailableConsumer)}, {@link #applyReadLocked(FailableFunction)}, and {@link #applyWriteLocked(FailableFunction)}. The visitor
563     * holds the lock while the consumer or function is called.
564     *
565     * @param <O> The type of the object to protect.
566     * @see LockingVisitors#stampedLockVisitor(Object)
567     */
568    public static class StampedLockVisitor<O> extends LockVisitor<O, StampedLock> {
569
570        /**
571         * Builds {@link LockVisitor} instances.
572         *
573         * @param <O> The wrapped object type.
574         * @since 3.18.0
575         */
576        public static class Builder<O> extends LVBuilder<O, StampedLock, Builder<O>> {
577
578            /**
579             * Constructs a new instance.
580             */
581            public Builder() {
582                // empty
583            }
584
585            @Override
586            public StampedLockVisitor<O> get() {
587                return new StampedLockVisitor<>(this);
588            }
589
590
591            @Override
592            public Builder<O> setLock(final StampedLock stampedLock) {
593                setReadLockSupplier(stampedLock::asReadLock);
594                setWriteLockSupplier(stampedLock::asWriteLock);
595                return super.setLock(stampedLock);
596            }
597        }
598
599        /**
600         * Creates a new builder.
601         *
602         * @param <O> The wrapped object type.
603         * @return A new builder.
604         * @since 3.18.0
605         */
606        public static <O> Builder<O> builder() {
607            return new Builder<>();
608        }
609
610        /**
611         * Constructs a new instance from a builder.
612         *
613         * @param builder A builder.
614         */
615        private StampedLockVisitor(final Builder<O> builder) {
616            super(builder);
617        }
618
619        /**
620         * Creates a new instance with the given object and lock.
621         *
622         * @param object The object to protect. The caller is supposed to drop all references to the locked object.
623         * @param stampedLock The lock to use.
624         * @see LockingVisitors
625         */
626        protected StampedLockVisitor(final O object, final StampedLock stampedLock) {
627            super(object, stampedLock, stampedLock::asReadLock, stampedLock::asWriteLock);
628        }
629    }
630
631    /**
632     * Creates a new instance of {@link ReadWriteLockVisitor} with the given object and lock.
633     *
634     * @param <O> The type of the object to protect.
635     * @param object The object to protect.
636     * @param readWriteLock The lock to use.
637     * @return A new {@link ReadWriteLockVisitor}.
638     * @see LockingVisitors
639     * @since 3.13.0
640     */
641    public static <O> ReadWriteLockVisitor<O> create(final O object, final ReadWriteLock readWriteLock) {
642        return new LockingVisitors.ReadWriteLockVisitor<>(object, readWriteLock);
643    }
644
645    /**
646     * Creates a new instance of {@link ReentrantLockVisitor} with the given object and lock.
647     *
648     * @param <O> The type of the object to protect.
649     * @param object The object to protect.
650     * @param reentrantLock The lock to use.
651     * @return A new {@link ReentrantLockVisitor}.
652     * @see LockingVisitors
653     * @since 3.18.0
654     */
655    public static <O> ReentrantLockVisitor<O> create(final O object, final ReentrantLock reentrantLock) {
656        return new LockingVisitors.ReentrantLockVisitor<>(object, reentrantLock);
657    }
658
659    /**
660     * Creates a new instance of {@link ReentrantLockVisitor} with the given object.
661     *
662     * @param <O> The type of the object to protect.
663     * @param object The object to protect.
664     * @return A new {@link ReentrantLockVisitor}.
665     * @see LockingVisitors
666     * @since 3.18.0
667     */
668    public static <O> ReentrantLockVisitor<O> reentrantLockVisitor(final O object) {
669        return create(object, new ReentrantLock());
670    }
671
672    /**
673     * Creates a new instance of {@link ReadWriteLockVisitor} with the given object.
674     *
675     * @param <O> The type of the object to protect.
676     * @param object The object to protect.
677     * @return A new {@link ReadWriteLockVisitor}.
678     * @see LockingVisitors
679     */
680    public static <O> ReadWriteLockVisitor<O> reentrantReadWriteLockVisitor(final O object) {
681        return create(object, new ReentrantReadWriteLock());
682    }
683
684    /**
685     * Creates a new instance of {@link StampedLockVisitor} with the given object.
686     *
687     * @param <O> The type of the object to protect.
688     * @param object The object to protect.
689     * @return A new {@link StampedLockVisitor}.
690     * @see LockingVisitors
691     */
692    public static <O> StampedLockVisitor<O> stampedLockVisitor(final O object) {
693        return new LockingVisitors.StampedLockVisitor<>(object, new StampedLock());
694    }
695
696    /**
697     * Make private in 4.0.
698     *
699     * @see LockingVisitors
700     * @deprecated TODO Make private in 4.0.
701     */
702    @Deprecated
703    public LockingVisitors() {
704        // empty
705    }
706}