package com.github.dakusui.actionunit.actions;

import com.github.dakusui.actionunit.core.Action;
import com.github.dakusui.actionunit.core.ActionSupport;
import com.github.dakusui.actionunit.exceptions.ActionException;

import java.util.Formatter;

import static com.github.dakusui.actionunit.core.ActionSupport.named;
import static java.util.Objects.requireNonNull;

public interface Attempt extends Action {
  @Override
  default void accept(Visitor visitor) {
    visitor.visit(this);
  }

  Action perform();

  Action recover();

  Action ensure();

  Class<? extends Throwable> targetExceptionClass();

  @Override
  default void formatTo(Formatter formatter, int flags, int width, int precision) {
    formatter.format("attempt");
  }

  class Builder extends Action.Builder<Attempt> {
    private       Class<? extends Throwable> targetExceptionClass = Exception.class;
    private final Action                     perform;
    private       Action                     recover              = Named.of("recover",
        Leaf.of(
            $ -> {
              if ($.wasExceptionThrown()) {
                throw ActionException.wrap($.thrownException());
              }
            }));
    private       Action                     ensure               = Named.of("ensure",
        ActionSupport.nop()
    );

    public Builder(Action perform) {
      this.perform = requireNonNull(perform);
    }

    public Builder recover(Class<? extends Throwable> targetExceptionClass, Action recover) {
      this.recover = Named.of("recover", requireNonNull(recover));
      this.targetExceptionClass = requireNonNull(targetExceptionClass);
      return this;
    }

    public Action ensure(Action ensure) {
      this.ensure = named("ensure", requireNonNull(ensure));
      return this.$();
    }

    public Attempt build() {
      return new Attempt() {

        @Override
        public Action perform() {
          return perform;
        }

        @Override
        public Action recover() {
          return recover;
        }

        public Class<? extends Throwable> targetExceptionClass() {
          return targetExceptionClass;
        }

        @Override
        public Action ensure() {
          return ensure;
        }
      };
    }
  }
}

@@ -148,16 +148,67 @@
 upport;%0A
+import com.github.dakusui.actionunit.core.Context;%0A
 import c
@@ -293,16 +293,121 @@
 matter;%0A
+import java.util.function.Consumer;%0A%0Aimport static com.github.dakusui.actionunit.core.ActionSupport.leaf;
 %0Aimport 
@@ -955,22 +955,16 @@
 private 
-      
 Class%3C? 
@@ -1047,36 +1047,16 @@
  Action 
-                    
 perform;
@@ -1072,61 +1072,22 @@
 ate 
-      
 Action 
-                    recover             
+recover
  = N
@@ -1134,17 +1134,27 @@
         
-$
+(Context $)
  -%3E %7B%0A  
@@ -1309,61 +1309,21 @@
 ate 
-      
 Action 
-                    ensure              
+ensure
  = N
@@ -1458,32 +1458,364 @@
 erform);%0A    %7D%0A%0A
+    public Builder recover(Class%3C? extends Throwable%3E targetExceptionClass, Consumer%3CThrowable%3E exceptionHandler) %7B%0A      this.recover = Named.of(%22recover%22, leaf(c -%3E %7B%0A        exceptionHandler.accept(c.thrownException());%0A      %7D));%0A      this.targetExceptionClass = requireNonNull(targetExceptionClass);%0A      return this;%0A    %7D%0A%0A
     public Build

Make it possible to use ContextConsumer in 'recover' clause. (#76)