Skip to content

Instantly share code, notes, and snippets.

@mathieuancelin
Created January 26, 2018 10:28
Show Gist options
  • Save mathieuancelin/58e134c597f75c909e2df0916a117da5 to your computer and use it in GitHub Desktop.
Save mathieuancelin/58e134c597f75c909e2df0916a117da5 to your computer and use it in GitHub Desktop.
package com.example.demo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.UUID;
import java.util.function.Function;
@ComponentScan
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
@RestController
@RequestMapping("/api")
public static class ApiController {
public AwesomeContext AwesomeAction(CallContext ctx) {
System.out.println("log before ... " + ctx.request.getRequestURI());
return new AwesomeContext(UUID.randomUUID().toString(), ctx);
}
@GetMapping("/hello")
public String home() {
return Actions.with(this::AwesomeAction).run(ctx -> {
System.out.println(ctx.innerCtx.request.getMethod() + " method on " + ctx.innerCtx.request.getRequestURI());
return "hello";
});
}
}
public static class AwesomeContext {
public final CallContext innerCtx;
public final String reqId;
public AwesomeContext(String reqId, CallContext ctx) {
this.reqId = reqId;
this.innerCtx = ctx;
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// API part
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@Component
static class Helper {
private static WebApplicationContext webApplicationContext;
static WebApplicationContext webApplicationContext() {
return webApplicationContext;
}
@Autowired
public void setWebApplicationContext(WebApplicationContext webApplicationContext) {
Helper.webApplicationContext = webApplicationContext;
}
}
public static class CallContext {
public final HttpServletRequest request;
public final HttpServletResponse response;
public final WebApplicationContext webApplicationContext;
public CallContext(HttpServletRequest request, HttpServletResponse response, WebApplicationContext webApplicationContext) {
this.request = request;
this.response = response;
this.webApplicationContext = webApplicationContext;
}
}
public static class ActionChain<In> {
private final Function<CallContext, In> chain;
public ActionChain(Function<CallContext, In> chain) {
this.chain = chain;
}
public <Ret> Ret run(Function<In, Ret> block) {
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
if (requestAttributes instanceof ServletRequestAttributes) {
ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) requestAttributes;
HttpServletRequest request = servletRequestAttributes.getRequest();
HttpServletResponse response = servletRequestAttributes.getResponse();
return block.apply(chain.apply(new CallContext(request, response, Helper.webApplicationContext())));
} else {
throw new RuntimeException("WTF ???");
}
}
}
public static class Actions {
public static <Ret> ActionChain<Ret> with(Function<CallContext, Ret> action) {
return new ActionChain<Ret>(action);
}
public static <Ret1, Ret2> ActionChain<Ret2> combine(
Function<CallContext, Ret1> action1,
Function<Ret1, Ret2> action2
) {
return new ActionChain<Ret2>(action1.andThen(action2));
}
public static <Ret1, Ret2, Ret3> ActionChain<Ret3> combine(
Function<CallContext, Ret1> action1,
Function<Ret1, Ret2> action2,
Function<Ret2, Ret3> action3
) {
return new ActionChain<Ret3>(action1.andThen(action2).andThen(action3));
}
public static <Ret1, Ret2, Ret3, Ret4> ActionChain<Ret4> combine(
Function<CallContext, Ret1> action1,
Function<Ret1, Ret2> action2,
Function<Ret2, Ret3> action3,
Function<Ret3, Ret4> action4
) {
return new ActionChain<Ret4>(action1.andThen(action2).andThen(action3).andThen(action4));
}
public static <Ret1, Ret2, Ret3, Ret4, Ret5> ActionChain<Ret5> combine(
Function<CallContext, Ret1> action1,
Function<Ret1, Ret2> action2,
Function<Ret2, Ret3> action3,
Function<Ret3, Ret4> action4,
Function<Ret4, Ret5> action5
) {
return new ActionChain<Ret5>(action1.andThen(action2).andThen(action3).andThen(action4).andThen(action5));
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment