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

ratpack.exec.internal.DefaultSuccessPromise Maven / Gradle / Ivy

There is a newer version: 2.0.0-rc-1
Show newest version
/*
 * Copyright 2014 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package ratpack.exec.internal;

import ratpack.exec.*;
import ratpack.func.Action;
import ratpack.func.Function;
import ratpack.func.NoArgAction;
import ratpack.func.Predicate;
import ratpack.util.internal.InternalRatpackError;

import java.util.Objects;
import java.util.function.Consumer;
import java.util.function.Supplier;

import static ratpack.func.Action.ignoreArg;

public class DefaultSuccessPromise implements SuccessPromise {

  private final Supplier executionSupplier;
  private final Consumer> fulfillment;
  private final Action errorHandler;

  public DefaultSuccessPromise(Supplier executionSupplier, Consumer> fulfillment, Action errorHandler) {
    this.executionSupplier = executionSupplier;
    this.fulfillment = fulfillment;
    this.errorHandler = errorHandler;
  }

  @Override
  public void then(final Action then) {
    final ExecutionBacking executionBacking = executionSupplier.get();
    try {
      doThen(new UserActionFulfiller(executionBacking, then));
    } catch (ExecutionException e) {
      throw e;
    } catch (Exception e) {
      throw new InternalRatpackError("failed to add promise resume action", e);
    }
  }

  private void doThen(final Fulfiller fulfiller) {
    fulfillment.accept(fulfiller);
  }

  @Override
  public  DefaultPromise map(final Function transformer) {
    return new DefaultPromise<>(executionSupplier, downstream -> DefaultSuccessPromise.this.doThen(new Transform(downstream, transformer) {
      @Override
      protected void onSuccess(O transformed) {
        downstream.success(transformed);
      }
    }));
  }

  @Override
  public  Promise flatMap(final Function> transformer) {
    return new DefaultPromise<>(executionSupplier, downstream -> DefaultSuccessPromise.this.doThen(new Transform, O>(downstream, transformer) {
      @Override
      protected void onSuccess(Promise transformed) {
        transformed.onError(downstream::error).then(downstream::success);
      }
    }));
  }

  @Override
  public Promise route(final Predicate predicate, final Action fulfillment) {
    return new DefaultPromise<>(executionSupplier, downstream -> doThen(new Step(downstream) {
      @Override
      public void success(T value) {
        boolean apply;
        try {
          apply = predicate.apply(value);
        } catch (Throwable e) {
          error(e);
          return;
        }

        if (apply) {
          try {
            fulfillment.execute(value);
          } catch (Throwable e) {
            error(e);
          }
        } else {
          downstream.success(value);
        }
      }
    }));
  }

  @Override
  public Promise onNull(final NoArgAction onNull) {
    return route(Objects::isNull, ignoreArg(onNull));
  }

  private abstract class Step implements Fulfiller {
    protected final Fulfiller downstream;

    public Step(Fulfiller downstream) {
      this.downstream = downstream;
    }

    @Override
    public void error(Throwable throwable) {
      try {
        errorHandler.execute(throwable);
      } catch (Throwable e) {
        downstream.error(e);
      }
    }
  }

  private class PassThru implements Fulfiller {
    protected final Fulfiller downstream;

    public PassThru(Fulfiller downstream) {
      this.downstream = downstream;
    }

    @Override
    public void error(Throwable throwable) {
      try {
        errorHandler.execute(throwable);
      } catch (Throwable e) {
        downstream.error(e);
      }
    }

    @Override
    public void success(T value) {
      downstream.success(value);
    }
  }

  @Override
  public  Promise blockingMap(final Function transformer) {
    return flatMap(new Function>() {
      @Override
      public Promise apply(final T t) throws Exception {
        return executionSupplier.get().getExecution().getControl().blocking(() -> transformer.apply(t));
      }
    });
  }

  @Override
  public Promise cache() {
    return new CachingPromise<>(fulfillment, executionSupplier, errorHandler);
  }

  @Override
  public Promise onYield(Runnable onYield) {
    return new DefaultPromise<>(executionSupplier, downstream -> {
      try {
        onYield.run();
      } catch (Throwable e) {
        downstream.error(e);
        return;
      }
      fulfillment.accept(downstream);
    });
  }

  @Override
  public Promise defer(Action releaser) {
    return new DefaultPromise<>(executionSupplier, downstream -> {
      ExecutionBacking executionBacking = executionSupplier.get();
      executionBacking.streamSubscribe((streamHandle) -> {
        try {
          releaser.execute((Runnable) () ->
              streamHandle.complete(() -> fulfillment.accept(downstream))
          );
        } catch (Throwable t) {
          downstream.error(t);
        }
      });
    });
  }

  @Override
  public Promise wiretap(Action> listener) {
    return new DefaultPromise<>(executionSupplier, downstream -> doThen(new Step(downstream) {
      @Override
      public void success(T value) {
        try {
          listener.execute(Result.success(value));
        } catch (Throwable t) {
          error(t);
          return;
        }

        downstream.success(value);
      }

      @Override
      public void error(Throwable throwable) {
        try {
          listener.execute(Result.failure(throwable));
        } catch (Throwable t) {
          t.addSuppressed(throwable);
          super.error(t);
          return;
        }

        super.error(throwable);
      }
    }));
  }

  @Override
  public Promise throttled(Throttle throttle) {
    return throttle.throttle(new DefaultPromise<>(executionSupplier, downstream -> doThen(new PassThru(downstream))));
  }

  private abstract class Transform extends Step {
    private final Function function;

    public Transform(Fulfiller downstream, Function function) {
      super(downstream);
      this.function = function;
    }

    @Override
    public void success(T value) {
      I transformed;
      try {
        transformed = function.apply(value);
      } catch (Throwable e) {
        downstream.error(e);
        return;
      }

      onSuccess(transformed);
    }

    protected abstract void onSuccess(I transformed);
  }

  private class UserActionFulfiller implements Fulfiller {
    private final ExecutionBacking executionBacking;
    private final Action then;

    public UserActionFulfiller(ExecutionBacking executionBacking, Action then) {
      this.executionBacking = executionBacking;
      this.then = then;
    }

    @Override
    public void error(final Throwable throwable) {
      try {
        errorHandler.execute(throwable);
      } catch (Throwable errorHandlerThrown) {
        executionBacking.streamSubscribe(h -> h.complete(() -> {
          throw errorHandlerThrown;
        }));
      }
    }

    @Override
    public void success(final T value) {
      try {
        then.execute(value);
      } catch (Throwable throwable) {
        executionBacking.streamSubscribe(h -> h.complete(() -> {
          throw throwable;
        }));
      }
    }
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy