    001// Copyright 2010 The Apache Software Foundation
    002//
    003// Licensed under the Apache License, Version 2.0 (the "License");
    004// you may not use this file except in compliance with the License.
    005// You may obtain a copy of the License at
    006//
    007// http://www.apache.org/licenses/LICENSE-2.0
    008//
    009// Unless required by applicable law or agreed to in writing, software
    010// distributed under the License is distributed on an "AS IS" BASIS,
    011// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    012// See the License for the specific language governing permissions and
    013// limitations under the License.
    014
    015package org.apache.tapestry5.ioc.services;
    016
    017import java.util.Objects;
    018import java.util.function.Consumer;
    019import java.util.function.Function;
    020import java.util.function.Supplier;
    021
    022/**
    023 * Provides access to per-thread (and, by extension, per-request) data, managed by the {@link PerthreadManager}.
    024 * A PerThreadValue stores a particular type of information.
    025 *
    026 * @see org.apache.tapestry5.ioc.services.PerthreadManager#createValue()
    027 * @since 5.2.0
    028 */
    029public interface PerThreadValue<T>
    030{
    031    /**
    032     * Is a value stored (even null)?
    033     */
    034    boolean exists();
    035
    036    /**
    037     * Reads the current per-thread value, or returns null if no value has been stored.
    038     */
    039    T get();
    040
    041    /**
    042     * Gets the current per-thread value if it exists (even if null), or the defaultValue
    043     * if no value has been stored.
    044     */
    045    T get(T defaultValue);
    046
    047    /**
    048     * Sets the current per-thread value, then returns that value.
    049     */
    050    T set(T newValue);
    051
    052    /**
    053     * If no value is currently stored (checked by {@link #exists()}), the value
    054     * provided by the supplier function is set and return.
    055     * Otherwise, the current value is returned.
    056     *
    057     * @param fn the value supplier function
    058     * @return The current (existing or computed) value
    059     * @throws NullPointerException if the supplier function is null
    060     * @since 5.8.3
    061     */
    062    default T computeIfAbsent(Supplier<? extends T> fn) {
    063        Objects.requireNonNull(fn);
    064        if (exists()) {
    065            return get();
    066        }
    067
    068        T newValue = fn.get();
    069        set(newValue);
    070
    071        return newValue;
    072    }
    073
    074    /**
    075     * If a value is currently stored (checked by {@link #exists()}), this value
    076     * is used to compute a new one with the given mapping function.
    077     * Otherwise, null is returned.
    078     *
    079     * @param fn the mapping function to compute the new value
    080     * @return The new computed value, or null if none was present
    081     * @throws NullPointerException if the mapping function is null
    082     * @since 5.8.3
    083     */
    084    default T computeIfPresent(Function<? super T, ? extends T> fn) {
    085        Objects.requireNonNull(fn);
    086        if (!exists()) {
    087            return null;
    088        }
    089
    090        T newValue = fn.apply(get());
    091        set(newValue);
    092
    093        return newValue;
    094    }
    095
    096    /**
    097     * Computes a new value with the help of the current one, which is returned.
    098     *
    099     * @param fn the mapping function to compute the new value
    100     * @return The new computed value
    101     * @throws NullPointerException if the mapping function is null
    102     * @since 5.8.3
    103     */
    104    default T compute(Function<? super T, ? extends T> fn) {
    105        Objects.requireNonNull(fn);
    106
    107        T newValue = fn.apply(get());
    108        set(newValue);
    109
    110        return newValue;
    111    }
    112
    113    /**
    114     * If a value is set, performs the given action with it, otherwise it
    115     * does nothing.
    116     *
    117     * @param action performed action if a value is set
    118     * @throws NullPointerException if the action is null
    119     * @since 5.8.3
    120     */
    121    default void ifSet(Consumer<? super T> action) {
    122        Objects.requireNonNull(action);
    123
    124        if (!exists()) {
    125            return;
    126        }
    127
    128        action.accept(get());
    129    }
    130}