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;
> +        }
> +    }
> +}
> 

Reply via email to