// Path: cachedfield/src/main/java/com/byoutline/cachedfield/internal/DefaultExecutors.java
// public final class DefaultExecutors {
// 
//     public static Executor createDefaultStateListenerExecutor() {
//         // Execute on same thread.
//         return new Executor() {
//             @Override
//             public void execute(Runnable command) {
//                 command.run();
//             }
//         };
//     }
// 
//     public static ExecutorService createDefaultValueGetterExecutor() {
//         return Executors.newCachedThreadPool();
//     }
// }
// 
// Path: cachedfield/src/main/java/com/byoutline/cachedfield/internal/StubErrorListener.java
// public class StubErrorListener implements ErrorListener {
// 
//     @Override
//     public void valueLoadingFailed(Exception ex) {
//         // ignore
//     }
// }
// 
// Path: cachedfield/src/main/java/com/byoutline/cachedfield/internal/VoidArgumentFactory.java
// public final class VoidArgumentFactory {
// 
//     private VoidArgumentFactory() {
//     }
// 
//     public static <RETURN_TYPE> ProviderWithArg<RETURN_TYPE, Void> addVoidArg(
//             @Nonnull final Provider<RETURN_TYPE> valueGetter) {
//         return new ProviderWithArg<RETURN_TYPE, Void>() {
// 
//             @Override
//             public RETURN_TYPE get(Void arg) {
//                 return valueGetter.get();
//             }
//         };
//     }
// 
//     public static <RETURN_TYPE> SuccessListenerWithArg<RETURN_TYPE, Void> addVoidArg(
//             @Nonnull final SuccessListener<RETURN_TYPE> successHandler) {
//         return new SuccessListenerWithArg<RETURN_TYPE, Void>() {
// 
//             @Override
//             public void valueLoaded(RETURN_TYPE value, Void arg) {
//                 successHandler.valueLoaded(value);
//             }
//         };
//     }
// 
//     public static <RETURN_TYPE> ErrorListenerWithArg<Void> addVoidArg(
//             @Nonnull final ErrorListener errorHandler) {
//         return new ErrorListenerWithArg<Void>() {
// 
//             @Override
//             public void valueLoadingFailed(Exception ex, Void arg) {
//                 errorHandler.valueLoadingFailed(ex);
//             }
//         };
//     }
// 
//     public static <RETURN_TYPE> DbWriterWithArg<RETURN_TYPE, Void> addVoidArg(
//             @Nonnull final DbWriter<RETURN_TYPE> dbWriter) {
//         return new DbWriterWithArg<RETURN_TYPE, Void>() {
// 
//             @Override
//             public void saveToDb(RETURN_TYPE value, Void arg) {
//                 dbWriter.saveToDb(value);
//             }
//         };
//     }
// }


import com.byoutline.cachedfield.internal.DefaultExecutors;
import com.byoutline.cachedfield.internal.StubErrorListener;
import com.byoutline.cachedfield.internal.VoidArgumentFactory;
import javax.annotation.Nonnull;
import javax.inject.Provider;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
package com.byoutline.cachedfield;



/**
 * Default implementation of {@link CachedField}. Loads value on separate thread
 * and informs listeners on success and error.
 *
 * @param <RETURN_TYPE> Type of value to be cached
 * @author Sebastian Kacprzak <sebastian.kacprzak at byoutline.com>
 */
public class CachedFieldImpl<RETURN_TYPE> implements CachedField<RETURN_TYPE> {

    private final CachedFieldWithArgImpl<RETURN_TYPE, Void> delegate;

    /**
     * Constructor for situation that we are not interested in failures, only in
     * successfully calculated values.
     *
     * @param sessionProvider Provider that returns String unique for current
     *                        session. When session changes cached value will be dropped.
     * @param valueGetter     Provider that synchronously calculates/fetches value
     *                        and returns it.
     * @param successListener Listener that will be informed when value is
     *                        successfully calculated.
     */
    public CachedFieldImpl(@Nonnull Provider<String> sessionProvider,
                           @Nonnull Provider<RETURN_TYPE> valueGetter,
                           @Nonnull SuccessListener<RETURN_TYPE> successListener) {
        this(sessionProvider, valueGetter, successListener, new StubErrorListener());
    }

    /**
     * @param sessionProvider Provider that returns String unique for current
     *                        session. When session changes cached value will be dropped.
     * @param valueGetter     Provider that synchronously calculates/fetches value
     *                        and returns it.
     * @param successHandler  Listener that will be informed when value is
     *                        successfully calculated.
     * @param errorHandler    Listener that will be be informed when calculation of
     *                        value fails.
     */
    public CachedFieldImpl(@Nonnull Provider<String> sessionProvider,
                           @Nonnull Provider<RETURN_TYPE> valueGetter,
                           @Nonnull SuccessListener<RETURN_TYPE> successHandler,
                           @Nonnull ErrorListener errorHandler) {
        this(sessionProvider, valueGetter, successHandler, errorHandler,
                DefaultExecutors.createDefaultValueGetterExecutor(),
                DefaultExecutors.createDefaultStateListenerExecutor());
    }

    public CachedFieldImpl(@Nonnull Provider<String> sessionProvider,
                           @Nonnull Provider<RETURN_TYPE> valueGetter,
                           @Nonnull SuccessListener<RETURN_TYPE> successHandler,
                           @Nonnull ErrorListener errorHandler,
                           @Nonnull ExecutorService valueGetterExecutor,
                           @Nonnull Executor stateListenerExecutor) {
        ProviderWithArg<RETURN_TYPE, Void> valueGetterWithArg = VoidArgumentFactory.addVoidArg(valueGetter);
// Path: cachedfield/src/main/java/com/byoutline/cachedfield/internal/DefaultExecutors.java
// public final class DefaultExecutors {
// 
//     public static Executor createDefaultStateListenerExecutor() {
//         // Execute on same thread.
//         return new Executor() {
//             @Override
//             public void execute(Runnable command) {
//                 command.run();
//             }
//         };
//     }
// 
//     public static ExecutorService createDefaultValueGetterExecutor() {
//         return Executors.newCachedThreadPool();
//     }
// }
// 
// Path: cachedfield/src/main/java/com/byoutline/cachedfield/internal/StubErrorListener.java
// public class StubErrorListener implements ErrorListener {
// 
//     @Override
//     public void valueLoadingFailed(Exception ex) {
//         // ignore
//     }
// }
// 
// Path: cachedfield/src/main/java/com/byoutline/cachedfield/internal/VoidArgumentFactory.java
// public final class VoidArgumentFactory {
// 
//     private VoidArgumentFactory() {
//     }
// 
//     public static <RETURN_TYPE> ProviderWithArg<RETURN_TYPE, Void> addVoidArg(
//             @Nonnull final Provider<RETURN_TYPE> valueGetter) {
//         return new ProviderWithArg<RETURN_TYPE, Void>() {
// 
//             @Override
//             public RETURN_TYPE get(Void arg) {
//                 return valueGetter.get();
//             }
//         };
//     }
// 
//     public static <RETURN_TYPE> SuccessListenerWithArg<RETURN_TYPE, Void> addVoidArg(
//             @Nonnull final SuccessListener<RETURN_TYPE> successHandler) {
//         return new SuccessListenerWithArg<RETURN_TYPE, Void>() {
// 
//             @Override
//             public void valueLoaded(RETURN_TYPE value, Void arg) {
//                 successHandler.valueLoaded(value);
//             }
//         };
//     }
// 
//     public static <RETURN_TYPE> ErrorListenerWithArg<Void> addVoidArg(
//             @Nonnull final ErrorListener errorHandler) {
//         return new ErrorListenerWithArg<Void>() {
// 
//             @Override
//             public void valueLoadingFailed(Exception ex, Void arg) {
//                 errorHandler.valueLoadingFailed(ex);
//             }
//         };
//     }
// 
//     public static <RETURN_TYPE> DbWriterWithArg<RETURN_TYPE, Void> addVoidArg(
//             @Nonnull final DbWriter<RETURN_TYPE> dbWriter) {
//         return new DbWriterWithArg<RETURN_TYPE, Void>() {
// 
//             @Override
//             public void saveToDb(RETURN_TYPE value, Void arg) {
//                 dbWriter.saveToDb(value);
//             }
//         };
//     }
// }


// Path: cachedfield/src/main/java/com/byoutline/cachedfield/CachedFieldImpl.java
import com.byoutline.cachedfield.internal.DefaultExecutors;
import com.byoutline.cachedfield.internal.StubErrorListener;
import com.byoutline.cachedfield.internal.VoidArgumentFactory;
import javax.annotation.Nonnull;
import javax.inject.Provider;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;

package com.byoutline.cachedfield;



/**
 * Default implementation of {@link CachedField}. Loads value on separate thread
 * and informs listeners on success and error.
 *
 * @param <RETURN_TYPE> Type of value to be cached
 * @author Sebastian Kacprzak <sebastian.kacprzak at byoutline.com>
 */
public class CachedFieldImpl<RETURN_TYPE> implements CachedField<RETURN_TYPE> {

    private final CachedFieldWithArgImpl<RETURN_TYPE, Void> delegate;

    /**
     * Constructor for situation that we are not interested in failures, only in
     * successfully calculated values.
     *
     * @param sessionProvider Provider that returns String unique for current
     *                        session. When session changes cached value will be dropped.
     * @param valueGetter     Provider that synchronously calculates/fetches value
     *                        and returns it.
     * @param successListener Listener that will be informed when value is
     *                        successfully calculated.
     */
    public CachedFieldImpl(@Nonnull Provider<String> sessionProvider,
                           @Nonnull Provider<RETURN_TYPE> valueGetter,
                           @Nonnull SuccessListener<RETURN_TYPE> successListener) {
        this(sessionProvider, valueGetter, successListener, new StubErrorListener());
    }

    /**
     * @param sessionProvider Provider that returns String unique for current
     *                        session. When session changes cached value will be dropped.
     * @param valueGetter     Provider that synchronously calculates/fetches value
     *                        and returns it.
     * @param successHandler  Listener that will be informed when value is
     *                        successfully calculated.
     * @param errorHandler    Listener that will be be informed when calculation of
     *                        value fails.
     */
    public CachedFieldImpl(@Nonnull Provider<String> sessionProvider,
                           @Nonnull Provider<RETURN_TYPE> valueGetter,
                           @Nonnull SuccessListener<RETURN_TYPE> successHandler,
                           @Nonnull ErrorListener errorHandler) {
        this(sessionProvider, valueGetter, successHandler, errorHandler,
                DefaultExecutors.createDefaultValueGetterExecutor(),
                DefaultExecutors.createDefaultStateListenerExecutor());
    }

    public CachedFieldImpl(@Nonnull Provider<String> sessionProvider,
                           @Nonnull Provider<RETURN_TYPE> valueGetter,
                           @Nonnull SuccessListener<RETURN_TYPE> successHandler,
                           @Nonnull ErrorListener errorHandler,
                           @Nonnull ExecutorService valueGetterExecutor,
                           @Nonnull Executor stateListenerExecutor) {
        ProviderWithArg<RETURN_TYPE, Void> valueGetterWithArg = VoidArgumentFactory.addVoidArg(valueGetter);
        SuccessListenerWithArg<RETURN_TYPE, Void> success = VoidArgumentFactory.addVoidArg(successHandler);