All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.phantomthief.util.MoreSuppliers Maven / Gradle / Ivy

There is a newer version: 0.1.55
Show newest version
package com.github.phantomthief.util;

import static com.google.common.base.Preconditions.checkNotNull;
import static java.util.Optional.empty;
import static java.util.Optional.ofNullable;

import java.io.Serializable;
import java.util.Optional;
import java.util.function.Function;
import java.util.function.Supplier;

/**
 * @author w.vela
 */
public final class MoreSuppliers {

    public static  CloseableSupplier lazy(Supplier delegate) {
        return lazy(delegate, true);
    }

    public static  CloseableSupplier lazy(Supplier delegate, boolean resetAfterClose) {
        if (delegate instanceof CloseableSupplier) {
            return (CloseableSupplier) delegate;
        } else {
            return new CloseableSupplier<>(checkNotNull(delegate), resetAfterClose);
        }
    }

    public static  CloseableThrowableSupplier lazyEx(ThrowableSupplier delegate) {
        return lazyEx(delegate, true);
    }

    public static  CloseableThrowableSupplier lazyEx(ThrowableSupplier delegate,
            boolean resetAfterClose) {
        if (delegate instanceof CloseableThrowableSupplier) {
            return (CloseableThrowableSupplier) delegate;
        } else {
            return new CloseableThrowableSupplier<>(checkNotNull(delegate), resetAfterClose);
        }
    }

    public static  Supplier asyncLazy(Supplier delegate, Supplier pendingSupplier,
            String threadName) {
        return new AsyncSupplier<>(delegate, pendingSupplier, threadName);
    }

    public static  Supplier asyncLazy(Supplier delegate, String threadName) {
        return asyncLazy(delegate, () -> null, threadName);
    }

    public static  Supplier asyncLazy(Supplier delegate) {
        return asyncLazy(delegate, null);
    }

    public static class CloseableSupplier implements Supplier, Serializable {

        private static final long serialVersionUID = 0L;
        private final Supplier delegate;
        private final boolean resetAfterClose;
        private volatile transient boolean initialized;
        private transient T value;

        private CloseableSupplier(Supplier delegate, boolean resetAfterClose) {
            this.delegate = delegate;
            this.resetAfterClose = resetAfterClose;
        }

        public T get() {
            if (!(this.initialized)) {
                synchronized (this) {
                    if (!(this.initialized)) {
                        T t = this.delegate.get();
                        this.value = t;
                        this.initialized = true;
                        return t;
                    }
                }
            }
            return this.value;
        }

        public boolean isInitialized() {
            return initialized;
        }

        public  void ifPresent(ThrowableConsumer consumer) throws X {
            synchronized (this) {
                if (initialized && this.value != null) {
                    consumer.accept(this.value);
                }
            }
        }

        public  Optional map(Function mapper) {
            checkNotNull(mapper);
            synchronized (this) {
                if (initialized && this.value != null) {
                    return ofNullable(mapper.apply(value));
                } else {
                    return empty();
                }
            }
        }

        public void tryClose() {
            tryClose(i -> { });
        }

        public  void tryClose(ThrowableConsumer close) throws X {
            synchronized (this) {
                if (initialized) {
                    close.accept(value);
                    if (resetAfterClose) {
                        this.value = null;
                        initialized = false;
                    }
                }
            }
        }

        public String toString() {
            if (initialized) {
                return "MoreSuppliers.lazy(" + get() + ")";
            } else {
                return "MoreSuppliers.lazy(" + this.delegate + ")";
            }
        }
    }


    public static class CloseableThrowableSupplier
            implements ThrowableSupplier, Serializable {

        private static final long serialVersionUID = 0L;
        private final ThrowableSupplier delegate;
        private final boolean resetAfterClose;
        private volatile transient boolean initialized;
        private transient T value;

        private CloseableThrowableSupplier(ThrowableSupplier delegate, boolean resetAfterClose) {
            this.delegate = delegate;
            this.resetAfterClose = resetAfterClose;
        }

        public T get() throws X {
            if (!(this.initialized)) {
                synchronized (this) {
                    if (!(this.initialized)) {
                        T t = this.delegate.get();
                        this.value = t;
                        this.initialized = true;
                        return t;
                    }
                }
            }
            return this.value;
        }

        public boolean isInitialized() {
            return initialized;
        }

        public  void ifPresent(ThrowableConsumer consumer) throws X2 {
            synchronized (this) {
                if (initialized && this.value != null) {
                    consumer.accept(this.value);
                }
            }
        }

        public  Optional map(Function mapper) {
            checkNotNull(mapper);
            synchronized (this) {
                if (initialized && this.value != null) {
                    return ofNullable(mapper.apply(value));
                } else {
                    return empty();
                }
            }
        }

        public void tryClose() {
            tryClose(i -> { });
        }

        public  void tryClose(ThrowableConsumer close) throws X2 {
            synchronized (this) {
                if (initialized) {
                    close.accept(value);
                    if (resetAfterClose) {
                        this.value = null;
                        initialized = false;
                    }
                }
            }
        }

        public String toString() {
            if (initialized) {
                try {
                    return "MoreSuppliers.lazy(" + get() + ")";
                } catch (Throwable x) {
                    throw new RuntimeException(x);
                }
            } else {
                return "MoreSuppliers.lazy(" + this.delegate + ")";
            }
        }
    }

    public static final class AsyncSupplier implements Supplier {

        private final String initThreadName;
        private final Supplier innerSupplier;
        private final Supplier pendingSupplier;

        private volatile T value;

        private volatile boolean inited;
        private volatile boolean initing;

        AsyncSupplier(Supplier innerSupplier, Supplier pendingSupplier,
                String initThreadName) {
            this.initThreadName = initThreadName;
            this.innerSupplier = checkNotNull(innerSupplier);
            this.pendingSupplier = checkNotNull(pendingSupplier);
        }

        @Override
        public T get() {
            if (inited) {
                return value;
            }
            if (initing) {
                return pendingSupplier.get();
            }
            synchronized (this) {
                if (inited) {
                    return value;
                }
                if (initing) {
                    return pendingSupplier.get();
                }
                initing = true;
                Runnable initWithTry = () -> {
                    try {
                        value = innerSupplier.get();
                        inited = true;
                        initing = false;
                    } catch (Throwable e) {
                        initing = false;
                        throw e;
                    }
                };
                if (initThreadName == null) {
                    new Thread(initWithTry).start();
                } else {
                    new Thread(initWithTry, initThreadName).start();
                }
            }
            if (inited) {
                return value;
            } else {
                return pendingSupplier.get();
            }
        }
    }
}