2424import java .util .concurrent .locks .StampedLock ;
2525import java .util .function .Supplier ;
2626
27+ import org .apache .commons .lang3 .builder .AbstractSupplier ;
2728import org .apache .commons .lang3 .function .Failable ;
2829import org .apache .commons .lang3 .function .FailableConsumer ;
2930import org .apache .commons .lang3 .function .FailableFunction ;
@@ -94,6 +95,103 @@ public class LockingVisitors {
9495 */
9596 public static class LockVisitor <O , L > {
9697
98+ /**
99+ * Builds {@link LockVisitor} instances.
100+ *
101+ * @param <O> the wrapped object type.
102+ * @param <L> the wrapped lock type.
103+ * @param <B> the builder type.
104+ * @since 3.18.0
105+ */
106+ public static class LVBuilder <O , L , B extends LVBuilder <O , L , B >> extends AbstractSupplier <LockVisitor <O , L >, B , RuntimeException > {
107+
108+ /**
109+ * The lock object, untyped, since, for example {@link StampedLock} does not implement a locking interface in
110+ * Java 8.
111+ */
112+ L lock ;
113+
114+ /**
115+ * The guarded object.
116+ */
117+ O object ;
118+
119+ /**
120+ * Supplies the read lock, usually from the lock object.
121+ */
122+ private Supplier <Lock > readLockSupplier ;
123+
124+ /**
125+ * Supplies the write lock, usually from the lock object.
126+ */
127+ private Supplier <Lock > writeLockSupplier ;
128+
129+ /**
130+ * Constructs a new instance.
131+ */
132+ public LVBuilder () {
133+ // empty
134+ }
135+
136+ @ Override
137+ public LockVisitor <O , L > get () {
138+ return new LockVisitor <>(this );
139+ }
140+
141+ Supplier <Lock > getReadLockSupplier () {
142+ return readLockSupplier ;
143+ }
144+
145+
146+ Supplier <Lock > getWriteLockSupplier () {
147+ return writeLockSupplier ;
148+ }
149+
150+ /**
151+ * Set the lock used from accept methods.
152+ *
153+ * @param lock the lock.
154+ * @return {@code this} instance.
155+ */
156+ public B setLock (final L lock ) {
157+ this .lock = lock ;
158+ return asThis ();
159+ }
160+
161+ /**
162+ * Set the resource.
163+ *
164+ * @param object the resource.
165+ * @return {@code this} instance.
166+ */
167+ public B setObject (final O object ) {
168+ this .object = object ;
169+ return asThis ();
170+ }
171+
172+ /**
173+ * Supplies the read lock.
174+ *
175+ * @param readLockSupplier Supplies the read lock.
176+ * @return {@code this} instance.
177+ */
178+ public B setReadLockSupplier (final Supplier <Lock > readLockSupplier ) {
179+ this .readLockSupplier = readLockSupplier ;
180+ return asThis ();
181+ }
182+
183+ /**
184+ * Supplies the write lock.
185+ *
186+ * @param writeLockSupplier Supplies the write lock.
187+ * @return {@code this} instance.
188+ */
189+ public B setWriteLockSupplier (final Supplier <Lock > writeLockSupplier ) {
190+ this .writeLockSupplier = writeLockSupplier ;
191+ return asThis ();
192+ }
193+ }
194+
97195 /**
98196 * The lock object, untyped, since, for example {@link StampedLock} does not implement a locking interface in
99197 * Java 8.
@@ -115,6 +213,18 @@ public static class LockVisitor<O, L> {
115213 */
116214 private final Supplier <Lock > writeLockSupplier ;
117215
216+ /**
217+ * Constructs an instance from a builder.
218+ *
219+ * @param builder The builder.
220+ */
221+ private LockVisitor (final LVBuilder <O , L , ?> builder ) {
222+ this .object = Objects .requireNonNull (builder .object , "object" );
223+ this .lock = Objects .requireNonNull (builder .lock , "lock" );
224+ this .readLockSupplier = Objects .requireNonNull (builder .readLockSupplier , "readLockSupplier" );
225+ this .writeLockSupplier = Objects .requireNonNull (builder .writeLockSupplier , "writeLockSupplier" );
226+ }
227+
118228 /**
119229 * Constructs an instance.
120230 *
@@ -316,6 +426,54 @@ protected <T> T lockApplyUnlock(final Supplier<Lock> lockSupplier, final Failabl
316426 */
317427 public static class ReadWriteLockVisitor <O > extends LockVisitor <O , ReadWriteLock > {
318428
429+ /**
430+ * Builds {@link LockVisitor} instances.
431+ *
432+ * @param <O> the wrapped object type.
433+ * @since 3.18.0
434+ */
435+ public static class Builder <O > extends LVBuilder <O , ReadWriteLock , Builder <O >> {
436+
437+ /**
438+ * Constructs a new instance.
439+ */
440+ public Builder () {
441+ // empty
442+ }
443+
444+ @ Override
445+ public ReadWriteLockVisitor <O > get () {
446+ return new ReadWriteLockVisitor <>(this );
447+ }
448+
449+ @ Override
450+ public Builder <O > setLock (final ReadWriteLock readWriteLock ) {
451+ setReadLockSupplier (readWriteLock ::readLock );
452+ setWriteLockSupplier (readWriteLock ::writeLock );
453+ return super .setLock (readWriteLock );
454+ }
455+ }
456+
457+ /**
458+ * Creates a new builder.
459+ *
460+ * @param <O> the wrapped object type.
461+ * @return a new builder.
462+ * @since 3.18.0
463+ */
464+ public static <O > Builder <O > builder () {
465+ return new Builder <>();
466+ }
467+
468+ /**
469+ * Constructs a new instance from a builder.
470+ *
471+ * @param builder a builder.
472+ */
473+ private ReadWriteLockVisitor (final Builder <O > builder ) {
474+ super (builder );
475+ }
476+
319477 /**
320478 * Creates a new instance with the given locked object. This constructor is supposed to be used for subclassing
321479 * only. In general, it is suggested to use {@link LockingVisitors#stampedLockVisitor(Object)} instead.
@@ -326,6 +484,7 @@ public static class ReadWriteLockVisitor<O> extends LockVisitor<O, ReadWriteLock
326484 protected ReadWriteLockVisitor (final O object , final ReadWriteLock readWriteLock ) {
327485 super (object , readWriteLock , readWriteLock ::readLock , readWriteLock ::writeLock );
328486 }
487+
329488 }
330489
331490 /**
@@ -340,6 +499,56 @@ protected ReadWriteLockVisitor(final O object, final ReadWriteLock readWriteLock
340499 */
341500 public static class ReentrantLockVisitor <O > extends LockVisitor <O , ReentrantLock > {
342501
502+ /**
503+ * Builds {@link LockVisitor} instances.
504+ *
505+ * @param <O> the wrapped object type.
506+ * @since 3.18.0
507+ */
508+ public static class Builder <O > extends LVBuilder <O , ReentrantLock , Builder <O >> {
509+
510+ /**
511+ * Constructs a new instance.
512+ */
513+ public Builder () {
514+ // empty
515+ }
516+
517+ @ Override
518+ public ReentrantLockVisitor <O > get () {
519+ return new ReentrantLockVisitor <>(this );
520+ }
521+
522+
523+ @ Override
524+ public Builder <O > setLock (final ReentrantLock reentrantLock ) {
525+ setReadLockSupplier (() -> reentrantLock );
526+ setWriteLockSupplier (() -> reentrantLock );
527+ return super .setLock (reentrantLock );
528+ }
529+ }
530+
531+ /**
532+ * Creates a new builder.
533+ *
534+ * @param <O> the wrapped object type.
535+ * @return a new builder.
536+ * @since 3.18.0
537+ */
538+ public static <O > Builder <O > builder () {
539+ return new Builder <>();
540+ }
541+
542+ /**
543+ * Constructs a new instance from a builder.
544+ *
545+ * @param builder a builder.
546+ */
547+ private ReentrantLockVisitor (final Builder <O > builder ) {
548+ super (builder );
549+ }
550+
551+
343552 /**
344553 * Creates a new instance with the given locked object. This constructor is supposed to be used for subclassing
345554 * only. In general, it is suggested to use {@link LockingVisitors#reentrantLockVisitor(Object)} instead.
@@ -363,6 +572,55 @@ protected ReentrantLockVisitor(final O object, final ReentrantLock reentrantLock
363572 */
364573 public static class StampedLockVisitor <O > extends LockVisitor <O , StampedLock > {
365574
575+ /**
576+ * Builds {@link LockVisitor} instances.
577+ *
578+ * @param <O> the wrapped object type.
579+ * @since 3.18.0
580+ */
581+ public static class Builder <O > extends LVBuilder <O , StampedLock , Builder <O >> {
582+
583+ /**
584+ * Constructs a new instance.
585+ */
586+ public Builder () {
587+ // empty
588+ }
589+
590+ @ Override
591+ public StampedLockVisitor <O > get () {
592+ return new StampedLockVisitor <>(this );
593+ }
594+
595+
596+ @ Override
597+ public Builder <O > setLock (final StampedLock stampedLock ) {
598+ setReadLockSupplier (stampedLock ::asReadLock );
599+ setWriteLockSupplier (stampedLock ::asWriteLock );
600+ return super .setLock (stampedLock );
601+ }
602+ }
603+
604+ /**
605+ * Creates a new builder.
606+ *
607+ * @param <O> the wrapped object type.
608+ * @return a new builder.
609+ * @since 3.18.0
610+ */
611+ public static <O > Builder <O > builder () {
612+ return new Builder <>();
613+ }
614+
615+ /**
616+ * Constructs a new instance from a builder.
617+ *
618+ * @param builder a builder.
619+ */
620+ private StampedLockVisitor (final Builder <O > builder ) {
621+ super (builder );
622+ }
623+
366624 /**
367625 * Creates a new instance with the given locked object. This constructor is supposed to be used for subclassing
368626 * only. In general, it is suggested to use {@link LockingVisitors#stampedLockVisitor(Object)} instead.
0 commit comments