This is an automated email from the ASF dual-hosted git repository.
mattsicker pushed a commit to branch 2.x
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git
The following commit(s) were added to refs/heads/2.x by this push:
new 4243f7cfce Backport Lazy util
4243f7cfce is described below
commit 4243f7cfceae535c898b863ada75417c0e4217fc
Author: Matt Sicker <[email protected]>
AuthorDate: Fri Nov 3 18:18:10 2023 -0500
Backport Lazy util
---
.../java/org/apache/logging/log4j/util/Lazy.java | 93 +++++++++++
.../org/apache/logging/log4j/util/LazyBoolean.java | 66 ++++++++
.../org/apache/logging/log4j/util/LazyUtil.java | 171 +++++++++++++++++++++
3 files changed, 330 insertions(+)
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/util/Lazy.java
b/log4j-api/src/main/java/org/apache/logging/log4j/util/Lazy.java
new file mode 100644
index 0000000000..2e0d84b3ce
--- /dev/null
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/Lazy.java
@@ -0,0 +1,93 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.logging.log4j.util;
+
+import java.util.Objects;
+import java.util.function.Function;
+import java.util.function.Supplier;
+
+/**
+ * Provides a lazily-initialized value from a {@code Supplier<T>}.
+ *
+ * @param <T> type of value
+ */
+public interface Lazy<T> extends Supplier<T> {
+ /**
+ * Returns the value held by this lazy. This may cause the value to
initialize if it hasn't been already.
+ */
+ T value();
+
+ /**
+ * Returns the value held by this lazy. This may cause the value to
initialize if it hasn't been already.
+ */
+ @Override
+ default T get() {
+ return value();
+ }
+
+ /**
+ * Creates a new lazy value derived from this lazy value using the
provided value mapping function.
+ */
+ default <R> Lazy<R> map(final Function<? super T, ? extends R> function) {
+ return lazy(() -> function.apply(value()));
+ }
+
+ /**
+ * Indicates whether this lazy value has been initialized.
+ */
+ boolean isInitialized();
+
+ /**
+ * Sets this lazy value to the provided value.
+ *
+ * @throws UnsupportedOperationException if this type of lazy value cannot
be updated
+ */
+ void set(final T newValue);
+
+ /**
+ * Creates a strict lazy value using the provided Supplier. The supplier
is guaranteed to only be invoked by at
+ * most one thread, and all threads will see the same published value when
this returns.
+ */
+ static <T> Lazy<T> lazy(final Supplier<T> supplier) {
+ Objects.requireNonNull(supplier);
+ return new LazyUtil.SafeLazy<>(supplier);
+ }
+
+ /**
+ * Creates a lazy value using the provided constant value.
+ */
+ static <T> Lazy<T> value(final T value) {
+ return new LazyUtil.Constant<>(value);
+ }
+
+ /**
+ * Creates a lazy value using a weak reference to the provided value.
+ */
+ static <T> Lazy<T> weak(final T value) {
+ return new LazyUtil.WeakConstant<>(value);
+ }
+
+ /**
+ * Creates a pure lazy value using the provided Supplier to initialize the
value. The supplier may be invoked more
+ * than once, and the return value should be a purely computed value as
the result may be a different instance
+ * each time. This is useful for building cache tables and other pure
computations.
+ */
+ static <T> Lazy<T> pure(final Supplier<T> supplier) {
+ Objects.requireNonNull(supplier);
+ return new LazyUtil.PureLazy<>(supplier);
+ }
+}
diff --git
a/log4j-api/src/main/java/org/apache/logging/log4j/util/LazyBoolean.java
b/log4j-api/src/main/java/org/apache/logging/log4j/util/LazyBoolean.java
new file mode 100644
index 0000000000..26db8639de
--- /dev/null
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/LazyBoolean.java
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.logging.log4j.util;
+
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.function.BooleanSupplier;
+
+public class LazyBoolean implements BooleanSupplier {
+ private final BooleanSupplier supplier;
+ private final Lock lock = new ReentrantLock();
+ private volatile boolean initialized;
+ private volatile boolean value;
+
+ public LazyBoolean(final BooleanSupplier supplier) {
+ this.supplier = supplier;
+ }
+
+ @Override
+ public boolean getAsBoolean() {
+ boolean uninitialized = !initialized;
+ boolean value = this.value;
+ if (uninitialized) {
+ lock.lock();
+ try {
+ uninitialized = !initialized;
+ if (uninitialized) {
+ this.value = value = supplier.getAsBoolean();
+ initialized = true;
+ }
+ } finally {
+ lock.unlock();
+ }
+ }
+ return value;
+ }
+
+ public void setAsBoolean(final boolean b) {
+ lock.lock();
+ try {
+ initialized = false;
+ value = b;
+ initialized = true;
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ public void reset() {
+ initialized = false;
+ }
+}
diff --git
a/log4j-api/src/main/java/org/apache/logging/log4j/util/LazyUtil.java
b/log4j-api/src/main/java/org/apache/logging/log4j/util/LazyUtil.java
new file mode 100644
index 0000000000..8b0b8c7a29
--- /dev/null
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/LazyUtil.java
@@ -0,0 +1,171 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.logging.log4j.util;
+
+import java.lang.ref.WeakReference;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.function.Supplier;
+
+final class LazyUtil {
+ private static final Object NULL = new Object() {
+ @Override
+ public String toString() {
+ return "null";
+ }
+ };
+
+ static Object wrapNull(final Object value) {
+ return value == null ? NULL : value;
+ }
+
+ static <T> T unwrapNull(final Object value) {
+ return value == NULL ? null : Cast.cast(value);
+ }
+
+ static class Constant<T> implements Lazy<T> {
+ private final T value;
+
+ Constant(final T value) {
+ this.value = value;
+ }
+
+ @Override
+ public T value() {
+ return value;
+ }
+
+ @Override
+ public boolean isInitialized() {
+ return true;
+ }
+
+ @Override
+ public void set(final T newValue) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String toString() {
+ return String.valueOf(value);
+ }
+ }
+
+ static class WeakConstant<T> implements Lazy<T> {
+ private final WeakReference<T> reference;
+
+ WeakConstant(final T value) {
+ reference = new WeakReference<>(value);
+ }
+
+ @Override
+ public T value() {
+ return reference.get();
+ }
+
+ @Override
+ public boolean isInitialized() {
+ return true;
+ }
+
+ @Override
+ public void set(final T newValue) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String toString() {
+ return String.valueOf(value());
+ }
+ }
+
+ static class SafeLazy<T> implements Lazy<T> {
+ private final Lock lock = new ReentrantLock();
+ private final Supplier<T> supplier;
+ private volatile Object value;
+
+ SafeLazy(final Supplier<T> supplier) {
+ this.supplier = supplier;
+ }
+
+ @Override
+ public T value() {
+ Object value = this.value;
+ if (value == null) {
+ lock.lock();
+ try {
+ value = this.value;
+ if (value == null) {
+ value = supplier.get();
+ this.value = wrapNull(value);
+ }
+ } finally {
+ lock.unlock();
+ }
+ }
+ return unwrapNull(value);
+ }
+
+ @Override
+ public void set(final T newValue) {
+ value = newValue;
+ }
+
+ public void reset() {
+ value = null;
+ }
+
+ @Override
+ public boolean isInitialized() {
+ return value != null;
+ }
+
+ @Override
+ public String toString() {
+ return isInitialized() ? String.valueOf(value) : "Lazy value not
initialized";
+ }
+ }
+
+ static class PureLazy<T> implements Lazy<T> {
+ private final Supplier<T> supplier;
+ private Object value;
+
+ public PureLazy(final Supplier<T> supplier) {
+ this.supplier = supplier;
+ }
+
+ @Override
+ public T value() {
+ Object value = this.value;
+ if (value == null) {
+ value = supplier.get();
+ this.value = wrapNull(value);
+ }
+ return unwrapNull(value);
+ }
+
+ @Override
+ public boolean isInitialized() {
+ return value != null;
+ }
+
+ @Override
+ public void set(final T newValue) {
+ value = newValue;
+ }
+ }
+}