io.baratine.service.Result Maven / Gradle / Ivy
/*
* Copyright (c) 1998-2015 Caucho Technology -- all rights reserved
*
* This file is part of Baratine(TM)(TM)
*
* Each copy or derived work must preserve the copyright notice and this
* notice unmodified.
*
* Baratine is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Baratine is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
* of NON-INFRINGEMENT. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License
* along with Baratine; if not, write to the
*
* Free Software Foundation, Inc.
* 59 Temple Place, Suite 330
* Boston, MA 02111-1307 USA
*
* @author Scott Ferguson
*/
package io.baratine.service;
import java.util.List;
import java.util.Objects;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
import io.baratine.function.TriConsumer;
import io.baratine.service.ResultImpl.AdapterMake;
import io.baratine.service.ResultImpl.ChainResult;
import io.baratine.service.ResultImpl.ChainResultAsync;
import io.baratine.service.ResultImpl.ChainResultFun;
import io.baratine.service.ResultImpl.ChainResultFunExn;
import io.baratine.service.ResultImpl.ChainResultFunFuture;
import io.baratine.service.ResultImpl.ChainResultFunFutureExn;
import io.baratine.service.ResultImpl.ResultJoinBuilder;
/**
* The Result callback for async service calls has a primary result filled by
* complete(value)
and an exception return filled by
* fail(exception)
*
* Since Result is designed as a lambda @FunctionalInterface interface,
* clients can use simple lambda expressions to process the results.
*
* For services that call other services, Results can be chained to simplify
* return value processing.
*
* Result resembles java.nio.channels.CompletionHandler
,
* but does not require an attribute.
*
*
*
* Sample client usage:
*
* ServiceManager manager = ServiceManager.create().start();
*
* MyService service = manager.service(new MyServiceImpl())
* .as(MyService.class);
*
* // JDK8 lambda for handle callback
* service.hello((x,e)->System.out.println("Result: " + x));
*
* // JDK8 lambda with builder
* service.hello(Result.onFail(e->System.out.println("Exception: " + e))
* .onOk(x->System.out.println("Result: " + x));
* // Explicit result
* service.hello(new MyHelloResult());
*
* // result chaining with function
* service.hello(result.of(x->"[" + x + "]"));
*
* // result chaining with consumer
* service.hello(result.of((x,r)->r.ok("[" + x + "]")));
*
* // result fork/join
* Result.Fork<String,String> fork = result.fork();
* service1.hello(fork.branch());
* service2.hello(fork.branch());
* fork.onFail((x,e,r)->r.ok("fork-fail: " + x + " " + e));
* fork.join((x,r)->r.ok("fork-result: " + x));
* ...
* public class MyResultHandler implements Result <MyDomainObject> {
* ...
* @Override
* public void handle(MyDomainObject value, Throwable exn)
{
if (exn != null) {
exn.printStackTrace();
return;
}
* map.put(value.name, value.value);
*
* store.add(value);
* }
*
*
* Sample service usage:
*
* void hello(Result<String> result)
* {
* result.ok("Hello, world");
* }
*
*
* Chaining:
*
* void doRouter(Result<String> result)
* {
* HelloService hello = ...;
*
* hello.hello(result.of(x->"Hello: " + x));
* }
*
*
*/
@FunctionalInterface
public interface Result
{
/**
* Client handler for result values. The result will either contain
* a value or a failure exception, but not both.
*
* The service will call ok
or fail
. The client
* will receive a handle callback.
*
* Service:
*
* void hello(Result<String> result)
* {
* result.ok("Hello, world");
* }
*
*
* Client:
*
* hello.hello((x,e)->System.out.println("Hello: " + x + " " + e));
*
*
* @param value the result value
* @param fail the result failure exception
*/
void handle(T value, Throwable fail)
throws Exception;
/**
* Completes the Result with its value. Services call complete to finish
* the response.
*
* Service:
*
* void hello(Result<String> result)
* {
* result.ok("Hello, world");
* }
*
*
* Client:
*
* hello.hello((x,e)->System.out.println("Hello: " + x));
*
*
* @param result the result value
*/
default void ok(T result)
{
try {
handle(result, null);
} catch (Exception e) {
fail(e);
}
}
/**
* Fails the Result with an exception. The exception will be passed to
* the calling client.
*
* @param exn the exception
*/
default void fail(Throwable exn)
{
try {
handle(null, exn);
} catch (Exception e) {
throw new ServiceExceptionExecution(e);
}
}
/**
* Create an empty Result that ignores the complete
.
*/
static Result ignore()
{
return ResultImpl.Ignore.create();
}
/**
* Creates a chained result.
*
*
* void myMiddle(Result<String> result)
* {
* MyLeafService leaf = ...;
*
* leaf.myLeaf(result.of());
* }
*
*/
default Result of()
{
return of(x->x);
}
/**
* Creates a composed result that will receive its completed value from
* a function. The function's value will become the
* result's complete value.
*
*
* void myMiddle(Result<String> result)
* {
* MyLeafService leaf = ...;
*
* leaf.myLeaf(result.of(v->"Leaf: " + v));
* }
*
*/
default Result of(Function fun)
{
if (isFuture()) {
return new ChainResultFunFuture(this, fun);
}
else {
return new ChainResultFun(this, fun);
}
}
/**
* Creates a composed result that will receive its completed value from
* a function. The function's value will become the
* result's complete value.
*
*
* void myMiddle(Result<String> result)
* {
* MyLeafService leaf = ...;
*
* leaf.myLeaf(result.of(v->"Leaf: " + v,
* (e,r)->{ e.printStackTrace(); r.fail(e); }));
* }
*
*/
default Result of(Function fun,
BiConsumer> exnHandler)
{
if (isFuture()) {
return new ChainResultFunFutureExn(this, fun, exnHandler);
}
else {
return new ChainResultFunExn(this, fun, exnHandler);
}
}
/**
* Creates a chained result for calling an internal
* service from another service. The lambda expression will complete
* the original result.
*
*
* void myMiddle(Result<String> result)
* {
* MyLeafService leaf = ...;
*
* leaf.myLeaf(result.of((v,r)->r.complete("Leaf: " + v)));
* }
*
*/
default Result of(BiConsumer> consumer)
{
if (isFuture()) {
return new ChainResultAsync(this, consumer);
}
else {
return new ChainResult(this, consumer);
}
}
/**
* Creates a Result as a pair of lambda consumers, one to process normal
* results, and one to handle exceptions.
*
*
* hello.hello(Result.of(e->System.out.println("exception: " + e))
* .onOk(x->System.out.println("result: " + x));
*
*
*
* @param result a consumer to handle a normal result value.
* @param exn a consumer to handle an exception result
*
* @return the constructed Result
*/
static Result of(Consumer result, Consumer exn)
{
return new AdapterMake(result, exn);
}
static Result onOk(Consumer consumer)
{
Objects.requireNonNull(consumer);
return new ResultImpl.ResultBuilder<>(consumer, null);
}
static Builder onFail(Consumer fail)
{
Objects.requireNonNull(fail);
return new ResultImpl.ResultBuilder<>(null, fail);
}
interface Builder
{
Result onOk(Consumer consumer);
}
/**
*
* Result.Fork<String,String> fork = result.fork();
*
* service1.hello(fork.branch());
* service2.hello(fork.branch());
*
* fork.join(x->System.out.println("Fork: " + x));
*
*
* @return fork/join builder
*/
default Fork fork()
{
return new ResultJoinBuilder<>(this);
}
//
// internal methods for managing future results
//
default boolean isFuture()
{
return false;
}
default void completeFuture(T value)
{
throw new IllegalStateException(getClass().getName());
}
default void completeFuture(Result result, U value)
{
throw new IllegalStateException(getClass().getName());
}
public interface Fork
{
Result branch();
Fork fail(TriConsumer,List,Result> fails);
void join(Function,T> combiner);
void join(BiConsumer,Result> combiner);
}
abstract public class Wrapper implements Result
{
private final Result _next;
protected Wrapper(Result next)
{
Objects.requireNonNull(next);
_next = next;
}
@Override
public boolean isFuture()
{
return _next.isFuture();
}
abstract public void ok(T value);
@Override
public void completeFuture(Result result, V value)
{
_next.completeFuture(result, value);
}
@Override
public void completeFuture(T value)
{
ok(value);
}
public final void handle(T value, Throwable exn)
{
throw new UnsupportedOperationException(getClass().getName());
}
@Override
public void fail(Throwable exn)
{
delegate().fail(exn);
}
protected Result delegate()
{
return _next;
}
@Override
public String toString()
{
return getClass().getSimpleName() + "[" + delegate() + "]";
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy