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

functionalj.result.Result Maven / Gradle / Ivy

// ============================================================================
// Copyright (c) 2017-2019 Nawapunth Manusitthipol (NawaMan - http://nawaman.net).
// ----------------------------------------------------------------------------
// MIT License
// 
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
// 
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
// ============================================================================
package functionalj.result;

import static java.util.Arrays.asList;
import static java.util.Objects.requireNonNull;

import java.io.PrintStream;
import java.io.PrintWriter;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;

import functionalj.function.Func;
import functionalj.function.Func0;
import functionalj.function.Func1;
import functionalj.function.Func2;
import functionalj.function.Func3;
import functionalj.function.Func4;
import functionalj.function.Func5;
import functionalj.function.Func6;
import functionalj.function.FunctionInvocationException;
import functionalj.list.FuncList;
import functionalj.pipeable.Pipeable;
import functionalj.promise.HasPromise;
import functionalj.promise.Promise;
import functionalj.tuple.Tuple;
import functionalj.tuple.Tuple2;
import functionalj.validator.SimpleValidator;
import functionalj.validator.Validator;
import lombok.val;
import nullablej.nullable.Nullable;

public abstract class Result
        implements
            AsResult,
            Pipeable>,
            HasPromise,
            ResultMapAddOn,
            ResultChainAddOn,
            ResultFilterAddOn ,
            ResultPeekAddOn,
            ResultStatusAddOn {
    
    protected static  Func1 throwException() {
        return e -> { throw e; };
    }
    protected static  Func1 throwRuntimeException() {
        return e -> {
            if (e instanceof RuntimeException)
                throw e;
            throw new RuntimeException(e);
        };
    }
    protected static  Func1 returnException() {
        return e -> e;
    }
    protected  Func1> returnValueException() {
        return e -> newException(e);
    }
    protected static  Func1> returnValueNull() {
        return e -> Result.ofNull();
    }
    protected static  Func1 returnNull() {
        return e -> null;
    }
    protected static  Func1 returnFalse() {
        return e -> false;
    }
    protected static  Func1 returnTrue() {
        return e -> false;
    }
    
    @SuppressWarnings("rawtypes")
	private static final Result NULL = new ImmutableResult<>(null);
    
    /**
     * Returns the Null result.
     * 
     * @param    the data type of the result.
     * @return the Result containing null value.
     */
    public static  Result ofNull() {
        @SuppressWarnings("unchecked")
        val nullResult = (Result)NULL;
        return nullResult;
    }
    
    /**
     * Returns the NotExist result.
     * 
     * @param    the data type of the result.
     * @return the Result that is the result does not exist.
     */
    public static  Result ofNotExist() {
        @SuppressWarnings("unchecked")
        val notAvailableResult = (Result)Result.ofException(new ResultNotExistException());
        return notAvailableResult;
    }
    /**
     * Returns the NotExist result with message.
     * 
     * @param  message  the exception message.
     * @param        the data type of the result.
     * @return the Result that is the result is not available.
     */
    public static  Result ofNotExist(String message) {
        @SuppressWarnings("unchecked")
        val exceptionResult = (Result)Result.ofException(new ResultNotExistException(message, null));
        return exceptionResult;
    }
    /**
     * Returns the NotExist result with message and cause.
     * 
     * @param  message  the exception message.
     * @param  cause    the exception cause.
     * @param        the data type of the result.
     * @return the Result that is the result is not available.
     */
    public static  Result ofNotExist(String message, Exception cause) {
        @SuppressWarnings("unchecked")
        val exceptionResult = (Result)Result.ofException(new ResultNotExistException(message, cause));
        return exceptionResult;
    }
    
    /**
     * Returns the NoMore result.
     * 
     * @param    the data type of the result.
     * @return the Result that is the result does not exist.
     */
    public static  Result ofNoMore() {
        @SuppressWarnings("unchecked")
        val notAvailableResult = (Result)Result.ofException(new NoMoreResultException());
        return notAvailableResult;
    }
    /**
     * Returns the NoMore result with message.
     * 
     * @param  message  the exception message.
     * @param        the data type of the result.
     * @return the Result that is the result is not available.
     */
    public static  Result ofNoMore(String message) {
        @SuppressWarnings("unchecked")
        val exceptionResult = (Result)Result.ofException(new NoMoreResultException(message, null));
        return exceptionResult;
    }
    /**
     * Returns the NoMore result with message and cause.
     * 
     * @param  message  the exception message.
     * @param  cause    the exception cause.
     * @param        the data type of the result.
     * @return the Result that is the result is not available.
     */
    public static  Result ofNoMore(String message, Exception cause) {
        @SuppressWarnings("unchecked")
        val exceptionResult = (Result)Result.ofException(new NoMoreResultException(message, cause));
        return exceptionResult;
    }
    
    /**
     * Returns the NotReady result.
     * 
     * @param    the data type of the result.
     * @return the Result that is the result is not ready.
     */
    public static  Result ofNotReady() {
        @SuppressWarnings("unchecked")
        val notReady = (Result)Result.ofException(new ResultNotReadyException());
        return notReady;
    }
    /**
     * Returns the NotReady result with message.
     * 
     * @param  message  the exception message.
     * @param        the data type of the result.
     * @return the Result that is the result is not ready.
     */
    public static  Result ofNotReady(String message) {
        @SuppressWarnings("unchecked")
        val exceptionResult = (Result)Result.ofException(new ResultNotReadyException(message, null));
        return exceptionResult;
    }
    /**
     * Returns the NotReady result with message.
     * 
     * @param  message  the exception message.
     * @param  cause    the exception cause.
     * @param        the data type of the result.
     * @return the Result that is the result is not ready.
     */
    public static  Result ofNotReady(String message, Exception cause) {
        @SuppressWarnings("unchecked")
        val exceptionResult = (Result)Result.ofException(new ResultNotReadyException(message, cause));
        return exceptionResult;
    }
    
    /**
     * Returns the Cancelled result.
     * 
     * @param    the data type of the result.
     * @return the Result that is the result is cancelled.
     */
    public static  Result ofCancelled() {
        @SuppressWarnings("unchecked")
        val cancelledResult = (Result)Result.ofException(new ResultCancelledException());
        return cancelledResult;
    }
    /**
     * Returns the Cancelled result with message.
     * 
     * @param  message  the exception message.
     * @param         the data type of the result.
     * @return the Result that is the result is cancelled.
     */
    public static  Result ofCancelled(String message) {
        @SuppressWarnings("unchecked")
        val cancelledResult = (Result)Result.ofException(new ResultCancelledException(message, null));
        return cancelledResult;
    }
    /**
     * Returns the Cancelled result with message.
     * 
     * @param  message  the exception message.
     * @param  cause    the exception cause.
     * @param         the data type of the result.
     * @return the Result that is the result is cancelled.
     */
    public static  Result ofCancelled(String message, Exception cause) {
        @SuppressWarnings("unchecked")
        val cancelledResult = (Result)Result.ofException(new ResultCancelledException(message, cause));
        return cancelledResult;
    }
    
    /**
     * Returns the Invalid result with message.
     * 
     * @param  message  the exception message.
     * @param         the data type of the result.
     * @return the Result that is the result is invalid.
     */
    public static  Result ofInvalid(String message) {
        @SuppressWarnings("unchecked")
        val invalidResult = (Result)Result.ofException(new ValidationException(message, null));
        return invalidResult;
    }
    /**
     * Returns the Invalid result with message.
     * 
     * @param  message  the exception message.
     * @param  cause    the exception cause.
     * @param         the data type of the result.
     * @return the Result that is the result is invalid.
     */
    public static  Result ofInvalid(String message, Exception cause) {
        @SuppressWarnings("unchecked")
        val invalidResult = (Result)Result.ofException(new ValidationException(message, cause));
        return invalidResult;
    }
    
    public static  Result valueOf(D value) {
        if (value == null)
            return Result.ofNull();
        
        return new ImmutableResult(value, (Exception)null);
    }
    
    public static  Result from(Supplier supplier) {
        return of(Func0.of(supplier::get));
    }
    
    @SuppressWarnings({ "unchecked", "rawtypes" })
    public static  Result of(Func0 supplier) {
        try {
            if (supplier instanceof Func0)
                 return Result.valueOf((D)((Func0)supplier).applyUnsafe());
            else return Result.valueOf(supplier.get());
        } catch (FunctionInvocationException e) {
            val cause = e.getCause();
            if (cause instanceof Exception)
                 return Result.ofException((Exception)cause);
            else return Result.ofException(e);
        } catch (Exception e) {
            return Result.ofException(e);
        }
    }
    @SuppressWarnings({ "unchecked", "rawtypes" })
    public static  Result Try(Func0 supplier) {
        try {
            if (supplier instanceof Func0)
                 return Result.valueOf((D)((Func0)supplier).applyUnsafe());
            else return Result.valueOf(supplier.get());
        } catch (Exception e) {
            return Result.ofException(e);
        }
    }
    
    public static  Result ofException(String exceptionMsg) {
        return new ImmutableResult((D)null, new FunctionInvocationException(exceptionMsg));
    }
    
    public static  Result ofException(Exception exception) {
        return new ImmutableResult(null, (exception != null) ? exception : new FunctionInvocationException("Unknown reason."));
    }
    
    public static  Result ofResult(Result result) {
        if (result instanceof Result)
            return (Result)result;
        
        if (result == null)
            return Result.ofNull();
        
        val data = result.__valueData();
        
        @SuppressWarnings("unchecked")
        val value     = (data instanceof ExceptionHolder) ? null                                   : (D)data;
        val exception = (data instanceof ExceptionHolder) ? ((ExceptionHolder)data).getException() : null;
        if (exception != null)
            return Result.ofException(exception);
            
        return Result.valueOf(value);
    }
    
    public static  Result of(
            T1 value1,
            T2 value2,
            BiFunction merger) {
        return Result.of(Func0.of(()->{
            val value = Func.applyUnsafe(merger, value1, value2);
            return value;
        }));
    }
    
    public static  Result of(
            T1 value1,
            T2 value2,
            T3 value3,
            Func3 merger) {
        return Result.of(Func0.of(()->{
            val value = merger.applyUnsafe(value1, value2, value3);
            return value;
        }));
    }
    
    public static  Result of(
            T1 value1,
            T2 value2,
            T3 value3,
            T4 value4,
            Func4 merger) {
        return Result.of(Func0.of(()->{
            val value = merger.applyUnsafe(value1, value2, value3, value4);
            return value;
        }));
    }
    
    public static  Result of(
            T1 value1,
            T2 value2,
            T3 value3,
            T4 value4,
            T5 value5,
            Func5 merger) {
        return Result.of(Func0.of(()->{
            val value = merger.applyUnsafe(value1, value2, value3, value4, value5);
            return value;
        }));
    }
    
    public static  Result of(
            T1 value1,
            T2 value2,
            T3 value3,
            T4 value4,
            T5 value5,
            T6 value6,
            Func6 merger) {
        return Result.of(Func0.of(()->{
            val value = merger.applyUnsafe(value1, value2, value3, value4, value5, value6);
            return value;
        }));
    }
    
    public static  Result Do(Func0 supplier) {
        try {
            return Result.valueOf((D)supplier.applyUnsafe());
        } catch (Exception e) {
            return Result.ofException(e);
        }
    }
    
    public static  Result Do(
            Func0 supplier1,
            Func0 supplier2,
            Func2 merger) {
        return Result.ofResults(
                    Try(supplier1),
                    Try(supplier2),
                    merger
                );
    }
    
    public static  Result Do(
            Func0 supplier1,
            Func0 supplier2,
            Func0 supplier3,
            Func3 merger) {
        return Result.ofResults(
                    Try(supplier1),
                    Try(supplier2),
                    Try(supplier3),
                    merger
                );
    }
    
    public static  Result Do(
            Func0 supplier1,
            Func0 supplier2,
            Func0 supplier3,
            Func0 supplier4,
            Func4 merger) {
        return Result.ofResults(
                    Try(supplier1),
                    Try(supplier2),
                    Try(supplier3),
                    Try(supplier4),
                    merger
                );
    }
    
    public static  Result Do(
            Func0 supplier1,
            Func0 supplier2,
            Func0 supplier3,
            Func0 supplier4,
            Func0 supplier5,
            Func5 merger) {
        return Result.ofResults(
                    Try(supplier1),
                    Try(supplier2),
                    Try(supplier3),
                    Try(supplier4),
                    Try(supplier5),
                    merger
                );
    }
    
    public static  Result Do(
            Func0 supplier1,
            Func0 supplier2,
            Func0 supplier3,
            Func0 supplier4,
            Func0 supplier5,
            Func0 supplier6,
            Func6 merger) {
        return Result.ofResults(
                    Try(supplier1),
                    Try(supplier2),
                    Try(supplier3),
                    Try(supplier4),
                    Try(supplier5),
                    Try(supplier6),
                    merger
                );
    }
    
    public static  Result ofResults(
            HasResult result1,
            HasResult result2,
            BiFunction merger) {
        return Result.of(Func0.of(()->{
            val value1 = result1.getResult().orThrow();
            val value2 = result2.getResult().orThrow();
            val value = Func.applyUnsafe(merger, value1, value2);
            return value;
        }));
    }
    
    public static  Result ofResults(
            HasResult result1,
            HasResult result2,
            HasResult result3,
            Func3 merger) {
        return Result.of(Func0.of(()->{
            val value1 = result1.getResult().orThrow();
            val value2 = result2.getResult().orThrow();
            val value3 = result3.getResult().orThrow();
            val value = merger.applyUnsafe(value1, value2, value3);
            return value;
        }));
    }
    
    public static  Result ofResults(
            HasResult result1,
            HasResult result2,
            HasResult result3,
            HasResult result4,
            Func4 merger) {
        return Result.of(Func0.of(()->{
            val value1 = result1.getResult().orThrow();
            val value2 = result2.getResult().orThrow();
            val value3 = result3.getResult().orThrow();
            val value4 = result4.getResult().orThrow();
            val value = merger.applyUnsafe(value1, value2, value3, value4);
            return value;
        }));
    }
    
    public static  Result ofResults(
            HasResult result1,
            HasResult result2,
            HasResult result3,
            HasResult result4,
            HasResult result5,
            Func5 merger) {
        return Result.of(Func0.of(()->{
            val value1 = result1.getResult().orThrow();
            val value2 = result2.getResult().orThrow();
            val value3 = result3.getResult().orThrow();
            val value4 = result4.getResult().orThrow();
            val value5 = result5.getResult().orThrow();
            val value = merger.applyUnsafe(value1, value2, value3, value4, value5);
            return value;
        }));
    }
    
    public static  Result ofResults(
            HasResult result1,
            HasResult result2,
            HasResult result3,
            HasResult result4,
            HasResult result5,
            HasResult result6,
            Func6 merger) {
        return Result.of(Func0.of(()->{
            val value1 = result1.getResult().orThrow();
            val value2 = result2.getResult().orThrow();
            val value3 = result3.getResult().orThrow();
            val value4 = result4.getResult().orThrow();
            val value5 = result5.getResult().orThrow();
            val value6 = result6.getResult().orThrow();
            val value = merger.applyUnsafe(value1, value2, value3, value4, value5, value6);
            return value;
        }));
    }
    
    
    
    abstract Object __valueData();
    
    public Result or(Result anotherResult) {
        if (this.isPresent())
            return this;
        if (anotherResult.isPresent())
            return anotherResult;
        return this;
    }
    
    @SuppressWarnings("unchecked")
    protected  Result newException(Exception exception) {
        return (Result)Result.ofException(exception);
    }
    
    @SuppressWarnings("unchecked")
    public  T mapData(Func1 exceptionGet, Func2 processor) {
        try {
            val data      = __valueData();
            val isValue   = ((data == null) || !(data instanceof ExceptionHolder));
            val value     = isValue ? (DATA)data : null;
            val exception = isValue ? null       : ((ExceptionHolder)data).getException();
            assert !((value != null) && (exception != null));
            
            return processor.applyUnsafe(value, exception);
        } catch (Exception cause) {
            return exceptionGet.apply(cause);
        }
    }
    
    @SuppressWarnings("unchecked")
    public  Result mapValue(Func2> processor) {
        return new DerivedResult(this, org-> {
            try {
                val data      = org.__valueData();
                val isValue   = ((data == null) || !(data instanceof ExceptionHolder));
                val value     = isValue ? (DATA)data : null;
                val exception = isValue ? null       : ((ExceptionHolder)data).getException();
                assert !((value != null) && (exception != null));
                
                val newValue = processor.applyUnsafe(value, exception);
                return newValue;
            } catch (Exception cause) {
                return newException(cause);
            }
        });
    }
    
    public final DATA get() {
        return value();
    }
    public final DATA value() {
        return mapData(
                throwRuntimeException(),
                (value, exception) -> {
                    if (exception != null)
                        throw exception;
                    return value;
                }
        );
    }
    public final DATA getValue() {
    	return value();
    }
    
    public final Exception exception() {
        return mapData(
                returnNull(),
                (value, exception) -> {
                    if (exception != null)
                        return exception;
                    
                    return null;
                }
        );
    }
    public final Exception getException() {
    	return exception();
    }
    
    public final > T castTo(Class clzz) {
        return clzz.cast(this);
    }
    
    @Override
    public Result asResult() {
        return this;
    }
    
    public final Tuple2 toTuple() {
        return new Tuple2() {
            @Override public final DATA _1()      { return getValue();     }
            @Override public final Exception _2() { return getException(); }
        };
    }
    
    public final Optional toOptional() {
        return Optional.ofNullable(this.get());
    }
    public final Nullable toNullable() {
        return Nullable.of(this.get());
    }
    
    public final FuncList toList() {
        return FuncList.of(this.get());
    }
    
    @Override
    public Promise getPromise() {
        return mapData(
                Promise::ofException,
                (value, exception) -> {
                    return (exception == null)
                            ? Promise.of(value)
                            : Promise.ofException(exception);
                }
        );
    }
    
    @Override
    public final Result __data() throws Exception {
        return this;
    }
    
    @SuppressWarnings("unchecked")
    public final  Result map(Func1 mapper) {
        return mapValue(
                (value, exception) -> {
                    if (value == null)
                        return (Result)this;
                    
                    val newValue = mapper.applyUnsafe(value);
                    return Result.valueOf(newValue);
                }
        );
    }
    public final  Result as(Class onlyClass) {
        return filter(onlyClass::isInstance)
                .map (onlyClass::cast);
    }
    
    public final Result mapException(Func1 mapper) {
        return mapValue(
                (value, exception) -> {
                    if (exception == null)
                        return this;
                    
                    val newException = mapper.applyUnsafe(exception);
                    return newException(newException);
                }
        );
    }
    
    public final  Result mapWith(
            Func2 func, 
            Result operantResult) {
        return flatMap(data -> { 
            return operantResult.map(operant -> {
                return func.apply(data, operant);
            });
        });
    }
    
    @SuppressWarnings("unchecked")
    public final  Result flatMap(Func1> mapper) {
        return mapValue(
                (value, exception) -> {
                    if (value == null)
                        return (Result)this;
                    
                    val monad = (Result)mapper.applyUnsafe(value);
                    return monad;
                }
        );
    }
    
    public final Result filter(Predicate theCondition) {
        return mapValue(
                (value, exception) -> {
                    if (value != null) {
                        val isPass = theCondition.test(value);
                        if (!isPass)
                            return Result.ofNull();
                    }
                    return this;
                }
        );
    }
    
    public final Result peek(Consumer theConsumer) {
        return mapValue((value, exception) -> {
            if (value != null)
                theConsumer.accept(value);
            
            return this;
        });
    }
    
    public final Result forValue(Consumer theConsumer) {
        mapData(throwException(),
                (value, exception) -> {
                    if (value != null)
                        theConsumer.accept(value);
                    return null;
                });
        return this;
    }
    
    //== Status and check
    
    public ResultStatus getStatus() {
        return mapData(
                returnNull(),
                (value, exception) -> {
                    return ResultStatus.getStatus(value, exception);
                });
    }
    
    //== Validation ==
    
    //== TODO - Validate then accumulate.
    
    public final Result validateNotNull() {
        return mapData(
                returnValueException(),
                (value, exception)->{
                    if ((value == null) && (exception != null))
                        return newException(
                                new ValidationException(
                                        new NullPointerException()));
                    
                    return this;
                });
    }
    public final Result validateNotNull(String message) {
        return mapData(
                returnValueException(),
                (value, exception)->{
                    if ((value == null) && (exception != null))
                        return newException(
                                new ValidationException(message));
                    
                    return this;
                }
        );
    }
    public final Result validateUnavailable() {
        return mapData(
                returnValueException(),
                (value, exception)->{
                    if (exception instanceof ResultNotAvailableException)
                        return newException(new ValidationException(exception));
                
                    return this;
                }
        );
    }
    public final Result validateNotReady() {
        return mapData(
                returnValueException(),
                (value, exception)->{
                    if ((exception instanceof ResultNotAvailableException)
                     || (exception instanceof ResultNotReadyException))
                        return newException(new ValidationException(exception));
                    
                    return this;
                }
        );
    }
    public final Result validateResultCancelled() {
        return mapData(
                returnValueException(),
                (value, exception)->{
                    if (exception instanceof ResultCancelledException)
                        return newException(new ValidationException(exception));
                    
                    return this;
                }
        );
    }
    public final Result validateResultNotExist() {
        return mapData(
                returnValueException(),
                (value, exception)->{
                    if (exception instanceof ResultNotExistException)
                        return newException(new ValidationException(exception));
                    
                    return this;
                }
        );
    }
    public final Result validateNoMoreResult() {
        return mapData(
                returnValueException(),
                (value, exception)->{
                    if (exception instanceof NoMoreResultException)
                        return newException(new ValidationException(exception));
                    
                    return this;
                }
        );
    }
    
    @SuppressWarnings({ "unchecked", "rawtypes" })
    public final Result validate(String stringFormat, Predicate validChecker) {
        return mapData(
                returnValueException(),
                (value, exception)->{
                    if (value == null) 
                        return this;
                    try {
                        if (validChecker.test(value))
                            return this;
                        
                        val validationException = SimpleValidator.exceptionFor(stringFormat).apply(value, (Predicate)validChecker);
                        return (Result)newException(validationException);
                    } catch (Exception cause) {
                        val validationException = SimpleValidator.exceptionFor(stringFormat, cause).apply(value, (Predicate)validChecker);
                        return (Result)newException(validationException);
                    }
                }
        );
    }
    
    @SuppressWarnings({ "unchecked", "rawtypes" })
    public final  Result validate(String stringFormat, Func1 mapper, Predicate validChecker) {
        return mapData(
                returnValueException(),
                (value, exception)->{
                    if (value == null) 
                        return this;
                    try {
                        val target = mapper.applyUnsafe(value);
                        if (validChecker.test(target))
                            return this;
                        
                        val validationException = SimpleValidator.exceptionFor(stringFormat).apply(value, (Predicate)validChecker);
                        return (Result)newException(validationException);
                        
                    } catch (Exception cause) {
                        val validationException = SimpleValidator.exceptionFor(stringFormat, cause).apply(value, (Predicate)validChecker);
                        return (Result)newException(validationException);
                    }
                });
    }
    public final Result validate(Validator validator) {
        return mapData(
                returnValueException(),
                (value, exception)->{
                    if (value == null) 
                        return this;
                    
                    return validator.validate(value);
                });
    }
    
    @SafeVarargs
    public final Result>> validate(Validator ... validators) {
        return validate(asList(validators));
    }
    
    @SuppressWarnings("unchecked")
    public final Result>> validate(List> validators) {
        return (Result>>) mapData(
                e -> newException(new ResultNotAvailableException()),
                (value, exception)->{
                    if (exception != null)
                        return (Result>>)this;
                    
                    val exceptions = FuncList.from(validators)
                        .map   (validator -> validator.validate(value))
                        .filter(result    -> !result.isValue())
                        .map   (result    -> result.getException())
                        .map   (error     -> ValidationException.of(error));
                    return Result.valueOf(Tuple.of(value, exceptions));
                });
    }
    
    public final Result ensureNotNull() {
        return mapData(
                returnValueException(),
                (value, exception)->{
                    if (value != null)
                        return this;
                    if (exception != null)
                        return this;
                    
                    return newException(new NullPointerException());
                }
        );
    }
    
    // Alias of whenNotPresentUse
    public final Result otherwise(DATA elseValue) {
        return whenAbsentUse(elseValue);
    }
    
    // Alias of whenNotPresentGet
    public final Result otherwiseGet(Supplier elseSupplier) {
        return whenAbsentGet(elseSupplier);
    }
    
    public final DATA orNull() {
        return orElse(null);
    }
    
    public final DATA orElse(DATA elseValue) {
        return mapData(
                __ -> elseValue,
                (value, exception)->{
                    if (value != null)
                        return value;
                    
                    return elseValue;
                }
        );
    }
    
    public final DATA orElseGet(Supplier elseSupplier) {
        return orGet(elseSupplier);
    }
    public final DATA orGet(Supplier elseSupplier) {
        return mapData(
                __ -> null,
                (value, exception)->{
                    if (value != null)
                        return value;
                    
                    return elseSupplier.get();
                }
        );
    }
    public final DATA orApply(Func1 elseMapper) {
        return mapData(
                __ -> null,
                (value, exception)->{
                    if (value != null)
                        return value;
                    
                    return elseMapper.apply(exception);
                }
        );
    }
    
    public final DATA orThrow() throws Exception {
        return mapData(
                throwException(),
                (value, exception)->{
                    if (exception == null)
                        return value;
                    
                    throw exception;
                }
        );
    }
    public final DATA orThrowRuntimeException() {
        return mapData(
                throwRuntimeException(),
                (value, exception)->{
                    if (exception == null)
                        return value;
                    
                    throw exception;
                }
        );
    }
    public final  DATA orThrow(Func1 toException) 
            throws EXCEPTION {
        return mapData(
                e -> { throw toException.applyUnsafe(e); },
                (value, exception)->{
                    if (exception == null)
                        return value;
                    
                    throw exception;
                }
        );
    }
    public final  
            DATA orThrowRuntimeException(Function toRuntimeException) {
        return mapData(
                e -> {
                    val exception = toRuntimeException.apply(e);
                    if (exception instanceof RuntimeException)
                        throw (RuntimeException)exception;
                    throw new RuntimeException(exception);
                },
                (value, exception)->{
                    if (exception == null)
                        return value;
                    
                    throw exception;
                }
        );
    }
    
    public final Result printException() {
        return printException(System.err);
    }
    
    public final Result printException(PrintStream printStream) {
        return mapValue(
                (value, exception)->{
                    exception.printStackTrace(printStream);
                    
                    return this;
                }
        );
    }
    
    public final Result printException(PrintWriter printWriter) {
        return mapValue(
                (value, exception)->{
                    exception.printStackTrace(printWriter);
                    
                    return this;
                }
                );
    }
    
    @Override
    public final int hashCode() {
        return Objects.hash(__valueData());
    }
    @SuppressWarnings("rawtypes")
    @Override
    public final boolean equals(Object obj) {
        if (!(obj instanceof Result))
            return false;
        
        return Objects.equals(__valueData(), ((Result)obj).__valueData());
    }
    @Override
    public final String toString() {
        @SuppressWarnings("rawtypes")
        val clss = (Class)this.getClass();
        val clssName = ((clss == ImmutableResult.class) || (clss == DerivedResult.class))
                ? "Result"
                : clss.getSimpleName();
        return clssName
              + mapData(
                e -> ":{ Exception: " + e  + " }",
                (value, exception) -> {
                    val msg = ((exception != null) && (exception.getMessage() != null)) ? ": " + exception.getMessage() : "";
                    if (exception == null)
                        return ":{ Value: "     + value      + " }";
                    else if (exception instanceof NoMoreResultException)
                        return ":{ NoMoreResult" + msg + " }";
                    else if (exception instanceof ResultCancelledException)
                        return ":{ Cancelled" + msg + " }";
                    else if (exception instanceof ResultNotReadyException)
                        return ":{ NotReady" + msg + " }";
                    else if (exception instanceof ResultNotExistException)
                        return ":{ NotExist" + msg + " }";
                    else if (exception instanceof ResultNotAvailableException)
                        return ":{ NotAvailable" + msg + " }";
                    else if (exception instanceof ValidationException)
                         return ":{ Invalid" + msg + " }";
                    else return ":{ Exception: " + exception  + " }";
                });
    }
    
    //== Internal ==
    
    public final static class ExceptionHolder {
        private final Exception exception;
        ExceptionHolder(Exception exception) {
            this.exception = requireNonNull(exception);
        }
        public final Exception getException() {
            return exception;
        }
        
        @Override
        public String toString() {
            return "ExceptionHolder [exception=" + exception + "]";
        }
        @Override
        public int hashCode() {
            final int prime = 31;
            int result = 1;
            result = prime * result + ((exception == null) ? 0 : exception.hashCode());
            return result;
        }
        @Override
        public boolean equals(Object obj) {
            if (this == obj)
                return true;
            if (obj == null)
                return false;
            if (getClass() != obj.getClass())
                return false;
            ExceptionHolder other = (ExceptionHolder) obj;
            if (exception == null) {
                if (other.exception != null)
                    return false;
            } else if (!exception.equals(other.exception))
                return false;
            return true;
        }
    }
    
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy