Matt, I received 3 emails regarding this lazy stuff being back ported. Is there a related issue for this? With the volume of emails I am getting I may have missed it but I would like to understand, Furthermore, in none of these commit emails did I see a changes file listed? How can I know why you did this without that and user’s won’t either since it won’t appear in the release notes.
Note that while I would like to avoid back porting from 3.x if it is being done to resolve a bug then I am fine with that. But if this is just a random “improvement” please don’t. Ralph > On Nov 3, 2023, at 4:22 PM, mattsic...@apache.org wrote: > > 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 <mattsic...@apache.org> > 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; > + } > + } > +} >