/** * Copyright (c) 2015 Codetrails GmbH. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Marcel Bruch - initial API and implementation. */ package org.eclipse.recommenders.utils; import static java.util.Objects.requireNonNull; import static org.eclipse.recommenders.utils.Checks.ensureIsTrue; import java.util.Objects; @SuppressWarnings("unchecked") public abstract class Result<T> { public static final int OK = 0; public static final int ABSENT = -1; private static final Absent DEFAULT_ABSENT = new Absent(ABSENT, null); public static <T> Result<T> of(T reference) { return new Present<T>(requireNonNull(reference)); } public static <T> Result<T> fromNullable(@Nullable T nullableReference) { return nullableReference == null ? Result.<T>absent() : new Present<T>(nullableReference); } public static <T> Result<T> absent() { return (Result<T>) DEFAULT_ABSENT; } public static <T> Result<T> absent(int code) { return (Result<T>) new Absent(code, null); } public static <T> Result<T> absent(Throwable exception) { return (Result<T>) new Absent(ABSENT, exception); } public static <T> Result<T> absent(int code, Throwable exception) { return (Result<T>) new Absent(code, exception); } public abstract boolean isPresent(); public abstract boolean hasReason(); public abstract int getReason(); public abstract T get(); public abstract T or(T defaultValue); public abstract Result<Throwable> getException(); @Override public abstract boolean equals(@Nullable Object other); @Override public abstract int hashCode(); private static final class Present<T> extends Result<T> { private final T reference; private Present(T reference) { this.reference = reference; } @Override public boolean isPresent() { return true; } @Override public boolean hasReason() { return false; } @Override public T or(T defaultValue) { return reference; } @Override public T get() { return reference; } @Override public int getReason() { return OK; } @Override public Result<Throwable> getException() { return Result.absent(); } @Override public boolean equals(Object other) { if (this == other) { return true; } if (other == null) { return false; } if (getClass() != other.getClass()) { return false; } Present<?> that = (Present<?>) other; return Objects.equals(this.reference, that.reference); } @Override public int hashCode() { return Objects.hash(reference); } @Override public String toString() { return "Result.of(" + reference + ")"; } } private static final class Absent extends Result<Object> { private final int reason; private final Throwable exception; private Absent(int reason, @Nullable Throwable exception) { ensureIsTrue(reason != OK); this.reason = reason; this.exception = exception; } @Override public boolean isPresent() { return false; } @Override public boolean hasReason() { return reason != ABSENT; } @Override public Object or(Object defaultValue) { return defaultValue; } @Override public Object get() { throw Throws.throwIllegalStateException("cannot get() value from Absent"); } @Override public int getReason() { return reason; } @Override public Result<Throwable> getException() { return Result.fromNullable(exception); } @Override public boolean equals(Object other) { if (this == other) { return true; } if (other == null) { return false; } if (getClass() != other.getClass()) { return false; } Absent that = (Absent) other; return this.reason == that.reason && Objects.equals(this.exception, that.exception); } @Override public int hashCode() { return Objects.hash(reason, exception); } @Override public String toString() { return "Result.absent(" + reason + ", " + exception + ")"; } } }