Spring WebFlux. How to add specific logic after controller call? - java

I have the next RestController:
#PostMapping("/play")
public Mono<PlayResponse> play(#RequestBody String body) {
//business logic here;
}
And I wanna add some additional logic after the controller call. For example, I want to add to my application some modes logic:
timeout mode - after the successful call, the response will wait until timeout happens
long answer mode - after the successful call, the response will wait a particular amount of ms
failure mode - after the successful call, the response will answer with FORBIDDEN code
etc.
I'm trying to achieve that through WebFilter:
#Component
public class OutgoingFilter implements WebFilter {
Mode mode = new TimeoutMode();
#NonNull
#Override
public Mono<Void> filter(#NonNull final ServerWebExchange exchange, final WebFilterChain chain) {
return chain.filter(exchange)
.doOnNext(this::onNext)
.map(this::onMap)
.doFinally(this::onFinally);
}
private Void onMap(final Void unused) {
mode.run();
return unused;
}
private void onNext(final Void unused) {
mode.run();
}
private void onFinally(final SignalType signalType) {
mode.run();
}
}
As you can see, I've tried onMap, doOnNext andonFinally methods and none of them seem not working.
Is it the right way to use WebFilter there? Maybe I'm doing something wrong?
How can I implement such logic in the Spring WebFlux application?
Update
There is my Mode interface:
public interface Mode {
void run() throws Forbidden;
}
Implementations:
public class Fail implements Mode {
#Override
public void run() throws Forbidden {
throw new Forbidden("Fail mode enabled");
}
}
public class Wait implements Mode {
private final int ms;
public Wait() {
this(0);
}
public Wait(final int ms) {
this.ms = ms;
}
#Override
public void run() throws Forbidden {
sleep();
}
private void sleep() {
try {
Thread.sleep(ms);
} catch (InterruptedException e) {
throw new IllegalStateException(e);
}
}
}
But the implementations aren't final. I will change them to a reactive style if it's needed.

Related

Java reactor how to properly start async cancellable sideeffect

I'm trying to write something using reactor which I know how to write using completable futures. I'm getting "Calling subscribe in non-blocking scope" warning in it.
My goal is to call turnOn() with a timeout which should call turnOff() after the timeout. If turnOn() is called again it should cancel the old timeout and wait for a new timeout.
How should I do this? I could do a hibrate and use CompletableFuture for the timeout but reactor's api is just a bit easier.
this test works as expected:
public class TimeoutTest {
Service service;
#BeforeEach
public void setUp() {
service = mock(Service.class);
}
CompletableFuture<Void> turnOffFuture = null;
#DisplayName("Should timeout on turnOn with timeout")
#Test
public void timeoutCompletableFuture() throws InterruptedException {
turnOn(Duration.ofMillis(100)).join();
verify(service).turnOn();
verify(service,never()).turnOff();
Thread.sleep(1000);
verify(service).turnOff();
}
private interface Service{
void turnOn();
void turnOff();
}
public void cancelTimeout() {
if (turnOffFuture != null)
turnOffFuture.cancel(false);
turnOffFuture = null;
}
public CompletableFuture<Void> turnOn(Duration timeout) {
CompletableFuture<Void> turnOnFuture = turnOn();
cancelTimeout();
turnOffFuture = turnOnFuture.thenRun(() -> delay(timeout))
.thenRun(this::turnOff);
return turnOnFuture;
}
private void delay(Duration duration) {
try {
Thread.sleep(BigDecimal.valueOf(duration.getSeconds())
.scaleByPowerOfTen(3)
.add(BigDecimal.valueOf(duration.getNano(), 6))
.intValue());
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
private CompletableFuture<Void> turnOn() {
return CompletableFuture.runAsync(() -> service.turnOn());
}
private CompletableFuture<Void> turnOff() {
return CompletableFuture.runAsync(() -> service.turnOff());
}
}
but my reactor code does not.
public class TimeoutMonoTest {
Service service;
#BeforeEach
public void setUp() {
service = mock(Service.class);
}
Disposable turnOffDisposable = null;
#DisplayName("Should timeout on turnOn with timeout")
#Test
public void timeoutMono() throws InterruptedException {
turnOn(Duration.ofMillis(100)).block(Duration.ofMillis(10));
verify(service).turnOn();
verify(service, never()).turnOff();
Thread.sleep(1000);
verify(service).turnOff();
}
private interface Service {
void turnOn();
void turnOff();
}
public void cancelTimeout() {
if (turnOffDisposable != null)
turnOffDisposable.dispose();
turnOffDisposable = null;
}
public Mono<Void> turnOn(Duration timeout) {
Mono<Void> turnOnFuture = turnOn();
cancelTimeout();
turnOffDisposable = turnOnFuture.delayElement(timeout)
.subscribe(it -> this.turnOff());
return turnOnFuture;
}
private Mono<Void> turnOn() {
service.turnOn();
return Mono.just("not empty but mapped to void").then();
}
private Mono<Void> turnOff() {
service.turnOff();
return Mono.just("not empty but mapped to void").then();
}
}
The problem lies in the mapping to void mono's in the turnOn() and turnOff() methods. They do not actually get a "next" signal, just a "success" signal.
The fix is simply to change the turnOn method to:
public Mono<Void> turnOn(Duration timeout) {
cancelTimeout();
Mono<Void> turnOnMono = turnOn();
turnOffDisposable = turnOnMono.delayElement(timeout)
.then(turnOff())
.subscribe();
return turnOn();
}

RxJava2 batch items

I've a continuously generated log stream i.e a method which get called whenever a new log is available in the system. I don't want to process the log every time it is generated(because logs are generated every milliseconds or so).
I want to collect logs which are emitted over a period of time let say 5 seconds and then process them in batch.
How can I achieve this using rxjava.
I've tried something like
private static void logResults(LogData logData) {
Observable.create((ObservableOnSubscribe<LogData>) e -> {
e.onNext(logData);
}).buffer(5, TimeUnit.SECONDS).subscribeWith(new DisposableObserver<List<LogData>>() {
#Override
public void onNext(List<LogData> logData) {
System.out.print(logData.toString()));
}
#Override
public void onError(Throwable e) {
}
#Override
public void onComplete() {
}
});
}
/**
This method get called every time when new log is there
*/
public static void logGenerated(LogData log) {
logResults(log);
}
You need to create a flow that stays active across multiple calls to logResults. The simplest way is to use a static PublishSubject:
private static final Subject<LogData> subject =
PublishSubject.<LogData>create(); // .toSerialized();
private static final Disposable logProcessing =
subject.buffer(5, TimeUnit.SECONDS)
.subscribeWith(new DisposableObserver<List<LogData>>() {
#Override
public void onNext(List<LogData> logData) {
System.out.print(logData.toString()));
}
#Override
public void onError(Throwable e) {
}
#Override
public void onComplete() {
}
});
private static void logResults(LogData logData) {
subject.onNext(logData);
}
/**
* This method get called every time when new log is there
*/
public static void logGenerated(LogData log) {
logResults(log);
}

GWT - synchronous return of a method

Ok, there isn't synchronous call in GWT.
But if i have something like this:
class XXX {
Config c=new Config();
c.doSomething();
}
and the class Config
public class Config {
private static HashMap<String,String> map;
public Config(){
final ServerProxyAsync serverProxy= GWT.create(ServerProxy.class);
serverProxy.getParameters(new AsyncCallback<HashMap<String,String>>() {
#Override
public void onFailure(Throwable caught) {
System.out.println("getParameters: FAILED!");
map=null;
}
#Override
public void onSuccess(HashMap<String, String> result) {
System.out.println("getParameters: OK!");
map=result;
// RETURN NOW!!!!
}
});
}
if the asynchronous call doesn't terminate I can't do doSomething(), because sometime the method is invoked before the map is initialized.
Is there a way?
How about doSomething() in onSuccess() ?
You can't use synchronous call in GWT.Even though you made it somehowits not a good practise
When you need this you have to do the stuff in the onSuccess(); of your RPC call .
So, the best idea is to simply use the asynchronous method and continue execution via the callbacks provided.You will end up with a much better user experience, and a more professional appearing
application.
Just extends your Config class to take a Runnable or a Callback. Something like this:
public class Config {
private static HashMap<String,String> map;
private final Runnable callback;
public Config(Runnable callback){
this.run = run;
final ServerProxyAsync serverProxy= GWT.create(ServerProxy.class);
serverProxy.getParameters(new AsyncCallback<HashMap<String,String>>() {
#Override
public void onFailure(Throwable caught) {
System.out.println("getParameters: FAILED!");
map=null;
}
#Override
public void onSuccess(HashMap<String, String> result) {
System.out.println("getParameters: OK!");
map=result;
callback.run();
}
});
}
}
Then you can use it like this:
class XXX {
final Runnable callback = new Runnable() {
#Override
public void run() {
dosomething1();
}
};
Config c=new Config(callback);
}

Spring Async Uncaught Exception handler

#Override
#Async
public void asyncExceptionTest() {
int i=1/0;
}
How can I log this using Spring Async framework without having to put try catch around every async method? It doesn't seem to pass to the DefaultUncaughtExceptionHandler like normal.
#Async methods can be configured with a custom Executor to log any thrown exceptions.
The following code implements this pattern. Any method tagged with #Async will use the Executor returned by the method public Executor getAsyncExecutor(). This returns the HandlingExecutor which takes care of all logging (in this case it just prints the word "CAUGHT!" but you can replace with logging.
#Configuration
#EnableAsync
public class ExampleConfig implements AsyncConfigurer {
#Bean
public Runnable testExec() {
return new TestExec();
}
#Override
public Executor getAsyncExecutor() {
final ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(7);
executor.setMaxPoolSize(42);
executor.setQueueCapacity(11);
executor.setThreadNamePrefix("MyExecutor-");
executor.initialize();
return new HandlingExecutor(executor);
}
}
public class HandlingExecutor implements AsyncTaskExecutor {
private AsyncTaskExecutor executor;
public HandlingExecutor(AsyncTaskExecutor executor) {
this.executor = executor;
}
#Override
public void execute(Runnable task) {
executor.execute(task);
}
#Override
public void execute(Runnable task, long startTimeout) {
executor.execute(createWrappedRunnable(task), startTimeout);
}
#Override
public Future<?> submit(Runnable task) {
return executor.submit(createWrappedRunnable(task));
}
#Override
public <T> Future<T> submit(final Callable<T> task) {
return executor.submit(createCallable(task));
}
private <T> Callable<T> createCallable(final Callable<T> task) {
return new Callable<T>() {
#Override
public T call() throws Exception {
try {
return task.call();
} catch (Exception e) {
handle(e);
throw e;
}
}
};
}
private Runnable createWrappedRunnable(final Runnable task) {
return new Runnable() {
#Override
public void run() {
try {
task.run();
} catch (Exception e) {
handle(e);
}
}
};
}
private void handle(Exception e) {
System.out.println("CAUGHT!");
}
}
Update: Since Spring 4.1
Since Spring 4.1 It is possible to have an AsyncUncaughtExceptionHandler for #Async void methods.
Spring Reference Doc, Chapter 34.4.5 Exception management with #Async
... With a void return type however, the exception is uncaught and cannot be transmitted. For those cases, an AsyncUncaughtExceptionHandler can be provided to handle such exceptions.
By default, the exception is simply logged. A custom AsyncUncaughtExceptionHandler can be defined via AsyncConfigurer or the task:annotation-driven XML element.
(This feature was introduced after DD raised an impovement request: https://jira.spring.io/browse/SPR-8995 , see comments of this answer)
Before Spring 4.1
Looks like an missing feature how to handle exceptions of an void returning #Async Method. (I can not find any hint in the reference or java doc)
What I can imagine of an solution: Try to use AspectJ to write some kind of wrapper arround all #Async methods that log the exceptions.
For the log term, I would recommend to create an freature request in the spring bug tracker.
First off all, you should create a custom exception handler class like following;
#Component
public class AsyncExceptionHandler implements AsyncUncaughtExceptionHandler {
private final Logger logger = LoggerFactory.getLogger(AsyncExceptionHandler.class);
#Override
public void handleUncaughtException(Throwable ex, Method method, Object... params) {
logger.error("Unexpected asynchronous exception at : "
+ method.getDeclaringClass().getName() + "." + method.getName(), ex);
}
}
After that, you should set your customized exception handler class in your configuration like following;
#Configuration
#EnableAsync
public class AsyncConfig extends AsyncConfigurerSupport {
#Autowired
private AsyncExceptionHandler asyncExceptionHandler;
#Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return asyncExceptionHandler;
}
}
Note : Injectable exception handler is an option. You can create a new instance for every exception. My advice is using Injection for exception handler class, because spring's default scope is singleton so there is no need to create new instance for every exception.
You can use standard Spring AOP approach
#Aspect
#Component
#Slf4j
public class AsyncHandler {
#Around("#annotation(org.springframework.scheduling.annotation.Async)")
private Object handle(ProceedingJoinPoint pjp) throws Throwable {
try {
Object retVal = pjp.proceed();
return retVal;
} catch (Throwable e) {
log.error("in ASYNC, method: " + pjp.getSignature().toLongString() + ", args: " + AppStringUtils.transformToWellFormattedJsonString(pjp.getArgs()) + ", exception: "+ e, e);
throw e;
}
}
}

Custom Callback Handler

I am trying to understand mechanism of callback handler. How is the handle() method invoked? Can anybody give an example of usage of custom callback handler (other than those used in Login Modules of JASS or so) in non Swing application?
Define an interface to handle the callback.
public interface ServiceListener<T> {
void callback(T result);
}
Define a method that takes ServiceListener as parameter and returns void.
Public void runInBackground(ServiceListener listener) {
...code that runs in the background...
listener.callback(...data to return to caller...);
}
And you can now do this from your main code:
runInBackground(new ServiceListener() {
#Override
public void callback(..returned data...) {
...Do stuff with returned data...
}
});
This is a basic example for requesting data from a webserver using the AsyncTask from an Android application.
First define the async class. Note that the constructor takes a listener which we use to publish the result once ready.
public class Webservice extends AsyncTask<String, Void, String> {
private DialogListener dialogListener;
public Webservice(final DialogListener dialogListener) {
this.dialogListener = dialogListener;
}
#Override
protected String doInBackground(final String... strings) {
// We cant trigger onComplete here as we are not on the GUI thread!
return "";
}
protected void onPostExecute(final String result) {
dialogListener.onComplete(result);
}
}
Basic server class for handling various network communications:
public class Server {
public void queryServer(final String url, final DialogListener service) {
// Simulate slow network...
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Webservice(service).execute(url);
}
}
We can now use this code inside our activity without having to worry how long the call takes as it is not going to halt the GUI as it is executed async.
Server s = new Server();
// Async server call.
s.queryServer("http://onto.dk/actions/searchEvents.jsp?minLatE6=55640596&minLngE6=12078516&maxLatE6=55642654&maxLngE6=12081948", new DialogListener() {
#Override
public void onComplete(final String result) {
toast("complete");
}
#Override
public void onError() {
toast("error");
}
});

Categories