package com.ziffit.autoconfigure.spring.concurrency;

import com.google.common.base.Throwables;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.concurrent.Executor;
import java.util.concurrent.ForkJoinPool;

@Configuration
@EnableAsync
public class AsyncConfiguration implements AsyncConfigurer {

    private static final Logger logger = LogManager.getLogger();

    private ConcurrencyProperties concurrencyProperties;

    public AsyncConfiguration(ConcurrencyProperties concurrencyProperties) {
        this.concurrencyProperties = concurrencyProperties;
    }

    @Override
    public Executor getAsyncExecutor() {
        return new ForkJoinPool(concurrencyProperties.getAsyncThreadPoolSize());
    }

    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return (e, method, parameters) -> logger.error(buildExceptionMessage(e, method, parameters));
    }

    private String buildExceptionMessage(Throwable e, Method method, Object... parameters) {
        StringBuilder exceptionMessage = new StringBuilder();
        exceptionMessage.append("==============Uncaught Async Exception==============");
        exceptionMessage.append(System.lineSeparator());
        exceptionMessage.append("Error message: [").append(Throwables.getStackTraceAsString(e)).append("]");
        exceptionMessage.append(System.lineSeparator());
        exceptionMessage.append("Method name: [").append(method.getName()).append("]");
        exceptionMessage.append(System.lineSeparator());
        Arrays.stream(parameters).forEach(parameter -> exceptionMessage
            .append("Calling parameter: [").append(parameter).append("]").append(System.lineSeparator()));
        return exceptionMessage.toString();
    }
}

@@ -89,16 +89,79 @@
 wables;%0A
+import com.google.common.util.concurrent.ThreadFactoryBuilder;%0A
 import o
@@ -192,24 +192,24 @@
 LogManager;%0A
-
 import org.a
@@ -498,16 +498,169 @@
 leAsync;
+%0Aimport org.springframework.scheduling.concurrent.ThreadPoolExecutorFactoryBean;%0Aimport org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
 %0A%0Aimport
@@ -749,16 +749,55 @@
 ecutor;%0A
+import java.util.concurrent.Executors;%0A
 import j
@@ -1256,79 +1256,357 @@
     
-return new ForkJoinPool(concurrencyProperties.getAsyncThreadPoolSize())
+ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();%0A        executor.setCorePoolSize(concurrencyProperties.getAsyncThreadPoolSize() / 2);%0A        executor.setMaxPoolSize(concurrencyProperties.getAsyncThreadPoolSize());%0A        executor.setThreadNamePrefix(%22Spring-Async-Executor-%22);%0A        executor.initialize();%0A        return executor
 ;%0A  

Switch to a more appropriate executor for async HTTP requests.