How to call #Service method from #Component - java

I have a component that I would like to call a service method from. When I try to call nothing happens. The service method is completablefuture method that calls a rest api. Could this have anything to do with it?
I've tried calling it from different classes and it works. Only this class is an issue.
Snippet of the class I'm calling it from:
#Component
#Scope("prototype")
public class Reader{
///and other variable declarations used
#Autowired
private AsyncServices aService;
public void StartAsync() throws InterruptedException, IOException{
Runnable task = new Runnable() {
#Override
public void run() {
try {
StartInventory();
} catch (Exception ex) {
System.out.print("start inventory thread could not start:
"+ex.getLocalizedMessage());}
}
};
Runnable task2 = new Runnable() {
#Override
public void run() {
try {
StartTCPClient();
} catch (Exception ex) {
System.out.print("start tcpclient thread could not start: "+ex.getMessage());
}
}
};
tcpClientThread = new Thread(task2, "TCPClientThread");
tcpClientThread.setDaemon(true);
tcpClientThread.start();
inventoryThread = new Thread(task, "InventoryThread");
inventoryThread.setDaemon(true);
inventoryThread.start();
public void StartInventory() throws InterruptedException, ExecutionException, ParseException{
......
//calling the method in #service class
aService.findVehicle(rfidtag);
}
code for service:
#Service
public class AsyncServices {
private final RestTemplate appRestTemplate;
#Autowired
public AsyncServices(RestTemplateBuilder builder){
this.appRestTemplate=builder.build();
}
#Async
#Transactional
public CompletableFuture<BmwvehicleTest> findVehicle(String rfidtag) throws InterruptedException{
log.info("trying to find a vehicle test by rfidtag"+ rfidtag);
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
HttpEntity <BmwvehicleTest> entity = new HttpEntity <BmwvehicleTest>(headers);
BmwvehicleTest results=appRestTemplate.exchange("http://localhost/tag/"+rfidtag, HttpMethod.GET, entity, BmwvehicleTest.class).getBody();
return CompletableFuture.completedFuture(results);
}
I expect to be able to get the result from the service method which is getting results from a rest api.

Related

How to unit test asynchronous code made synchronous using CountdownLatch

Below is the class I want to test :
SomeClass.java
public void SomeClass {
final CountDownLatch latch = new CountDownLatch(1);
int result;
registerCallbackWithService(new MyCallback());
public int callToExternalService(){
//Do some stuff and make service call
latch.await();
return result;
}
class MyCallback implements ServiceCallback {
#Override
public void onResult(final int res) {
//do something
result = res;
latch.countdown();
}
}
}
The callback MyCallback was registered earlier before invoking callToExternalService().
If I write a simple test to just mock the service call made in callToExternalService(), the test keeps on running infinitely because of latch.await().
How can I test the logic in callToExternalService() as well as in onResult() ?
I modified by code to expose the callback that I am registering using a package-protected function as below :
public void SomeClass {
private final CountDownLatch latch = new CountDownLatch(1);
private int result;
registerCallback(new MyCallback());
public int callToExternalService(){
//Do some stuff and make service call
latch.await();
return result;
}
private class MyCallback implements ServiceCallback {
#Override
public void onResult(final int res) {
//do something
result = res;
latch.countdown();
}
}
protected registerCallback(ServiceCallback callback) {
registerCallbackWithService(callback);
}
}
Now, for testing I do my testing by creating a new class SomeClassTest extends SomeClass and do my testing using an instance of this class. In SomeClassTest all I do is override registerCallback() to access the callback instance that is being registered.
public class ServiceTest {
private ServiceCallback mServiceCallback;
class SomeClassTest extends SomeClass {
#Override
registerCallback(ServiceCallback callback) {
mServiceCallback = callback;
super.registerCallback(callback);
}
}
}
Now all I have to do it using doAnswer, invoke the callback upon service request which results in the execution of latch.countdown() on the same latch reference that is put on await just after making the service request.
SomeClassTest someClassInstance = new SomeClassTest();
doAnswer(new Answer() {
#Override
public Object answer(InvocationOnMock invocationOnMock) throws Throwable {
mServiceVCallback.onResult(int_I_want_to_test_for)
return null;
}
}).when(someClassInstance).service_request_before_latch_await();
int response = someClassInstance.callToExternalService();
assertEquals(response, expected_response);

Spring boot Non Controller Exceptions Handling - Centralized Exception Handling

Is there a way to create a centralized exception handling mechanism in spring boot. I have a custom exception that I am throwing from multiple #Component classes and I would like it to be caught in one class/handler.
This is NOT a REST API or Controller triggered call. I tried #ControllerAdvice with #ExceptionHandler. but no luck. Example below to shows what I am trying to achieve. Method Handle is not triggering. I am using spring boot v2.1.1
CustomException
public class CustomException extends RuntimeException {
public CustomException(String errorMessage, Throwable err) {
super(errorMessage, err);
}
}
Handler
#ControllerAdvice
public class CatchCustomException {
#ExceptionHandler(value = CustomException.class )
public void handle (CustomException e)
{
System.out.println(e.getMessage());
}
}
Component Class
#Component
#EnableScheduling
public class HandlingExample {
#Scheduled(fixedRate = 3000)
public void method1(){
throw new CustomException("Method1++++", new Exception());
}
#Scheduled(fixedRate = 1000)
public void method2(){
throw new CustomException("Method2----", new Exception());
}
}
spring have many error handlers in different context, for your case, you should handle the error exception with #Schedule, so you can create a TaskScheduler by your own
#Bean
public TaskScheduler taskScheduler() {
ScheduledExecutorService localExecutor = Executors.newSingleThreadScheduledExecutor();
ConcurrentTaskScheduler taskScheduler = new ConcurrentTaskScheduler(localExecutor);
taskScheduler.setErrorHandler(new YourErrorHandler());
return taskScheduler;
}
public class YourErrorHandler implements ErrorHandler {
#Override
public void handleError(Throwable t) {
// TODO Auto-generated method stub
}
}

How to implement Runnable in Spring Framework for writing to a database

I am new to Spring and I wish to implement threads. I have tried the conventional Java run() method to send a database writing task to the thread. However, this causes a NullPointerException every time I am calling the database dao or service query within the run() method. If I place the query in the constructor then it works.
I think possibly I am not able to instantiate the dao/service variable in runnable?
public class TestThread implements Runnable{
#Autowired
public CarService carService;
public TestThread(List<Car> listcar) {
List<Car> listcar = new ArrayList<Car>();
//This works here
listcar = new java.util.ArrayList<Car>(carService.findAllServices(0, 10000));
for(int i=0;i<listcar.size();i++) {
System.out.println("The all car services in runnable constructor"+listcar.get(i).getName());
}
}
public void run() {
try {
runrun();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//This does not work
public void runrun() throws Exception {
List<Car> listcar = new ArrayList<Car>();
listcar = new java.util.ArrayList<Car>(carService.findAllServices(0, 10000));
for(int i=0;i<listcar.size();i++) {
System.out.println("The all car services in run method "+listcar.get(i).getName());
}
}
}
TestThreadCallController.java:
#Controller
public class TestThreadCallController {
#RequestMapping(value = "/upload", method = RequestMethod.POST)
public #ResponseBody void FindyourCarService() throws IOException{
TestThread th=new TestThread(listcar);
new Thread(th).start();
ApplicationContext context = new ClassPathXmlApplicationContext("test-Thread.xml");
TestThread th1 = (TestThread) context.getBean("TestThread");
new Thread(th1).start();
}
}
test-Thread.xml
bean initialization code:
<bean id="TestThread" class="com.test.thread.domain.TestThread">
</bean>
Yeah, agree, bad idea doing this manually. Let Spring do it. Put a service for the DB behind A Spring Integration gateway & return a Future. boom. done. #Async works - but its more fun to play with SI.

how to test method that starts new thread which may fail due to operating system

I have an application built upon Spring Boot. There is simple controller with a method which creates new Thread and starts it. However a runnable executes unix command (nc) (used ProcessBuilder for that). Thus when I'm runnning it on the windows I get exceptions from started thread. Indeed it can not run unix program. Now I would like to write a test for this controller, but I'm wondering is it possible and reasonable. I was thinking about changing behaviour of runnable task just for testing, although I don't know how can it be done. Thanks for any help and other ideas/solutions for this case.
Controller:
#Controller
public class TaskController {
ThreadFactory threadFactory = new ThreadFactoryBuilder().setNameFormat(task-%d").build();
#RequestMapping(value = "/startTask")
public #ResponseBody ResponseEntity<String> startTask() {
Runnable runnable= new Task();
threadFactory.newThread(runnable).start();
return new ResponseEntity<String>("Task started", HttpStatus.ACCEPTED);
}
}
Task:
public class Task implements Runnable {
#Override
public void run() {
// start unix process
}
}
Application class:
#ComponentScan
#EnableAutoConfiguration
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Integration Test:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = Application.class)
#WebAppConfiguration
#IntegrationTest("server.port=0")
#DirtiesContext
public class ApplicationTest {
#Value("${local.server.port}")
private int port;
#Test
public void shouldStartTask() throws Exception {
// when
ResponseEntity<String> entity = new TestRestTemplate().getForEntity("http://localhost:" + this.port + "/startTask", String.class);
// then
assertThat(entity.getStatusCode()).isSameAs(HttpStatus.ACCEPTED);
}
}
You might find it easier to test your program if you the extract the processing logic of your application (which does things using threads) from your controller logic, placing the processing logic in a separate service layer, which your controller delegates to. Design the service layer to have an API that is easy to unit test, by providing methods for accessing its current state, not just for performing actions. Use dependency injection to connect your controller to your service layer.
So, something like this:
public interface Service
{
// Sets this.wasTaskStarted() == true
void startTask();
boolean wasTaskStarted();
void awaitCompletionOfTask();
}
#Controller
public class TaskController {
private final Service service;
#Autowired
public TaskController(Service service) {
this.service = service;
}
#RequestMapping(value = "/startTask")
public #ResponseBody ResponseEntity<String> startTask() {
service.startTask();
return new ResponseEntity<String>("Task started", HttpStatus.ACCEPTED);
}
}
public ServiceImpl implements Service {
private final ThreadFactor threadFactory = new ....;
private Thread taskTread;
#Override
public synchronized void startTask() {
if (taskTread == null) {
taskTread = threadFactory.newThread(new Task());
taskTread.start();
notifyAll();
}
// else already started
}
#Override
public synchronized boolean wasTaskStarted() {
return taskTread != null;
}
#Override
public synchronized void awaitCompletionOfTask() {
while (taskTread == null) {
wait();
}
taskTread.join();
}
}
To test that your controller starts a task, you just need to test that Service.wasTaskStarted() is true after calling TaskController.startTask().
You also have to test your service layer:
public class ServiceImplTest
{
#Test
public void testStartTask() {
final ServiceImpl service = new ServiceImpl(....);
service.startTask();
assert(service.wasTastStarted());
}
#Test
public void testRunTask() {
final ServiceImpl service = new ServiceImpl(....);
service.startTask();
service.awaitCompletionOfTask();
// Add assertions here to test that the task did what it ought to do
}
}
Thanks for the suggestion. You just opened my mind and I changed the design a bit. I resigned from an integration test. From business point of view, I don't need to check whether task has been started or even completed. Now it looks as follows:
Controller:
#Controller
public class TaskController {
private ThreadService threadService;
#Autowired
public TaskController (ThreadService threadService) {
this.threadService= threadService;
}
#RequestMapping(value = "/startTask")
public #ResponseBody ResponseEntity<String> startTask() {
// some conditions here which I would like to test
threadService.startNewThread(new Task());
return new ResponseEntity<String>("Task started", HttpStatus.ACCEPTED);
}
}
Task:
public class Task implements Runnable {
#Override
public void run() {
// start unix process
}
}
Thread service:
#Component
public class ThreadService {
ThreadFactory threadFactory = new ThreadFactoryBuilder().setNameFormat("task-%d").build();
public void startNewThread(Runnnable task) {
threadFactory.newThread(task).start();
}
}
And I decided to unit test my controller, stubbing ThreadService with mockito:
#RunWith(MockitoJUnitRunner.class)
public class TaskControllerTest {
#Mock
ThreadService threadService;
#InjectMocks
private TaskController objectUnderTest;
#Test
public void shouldStartTask() throws FileNotFoundException {
// when
ResponseEntity<String> response = objectUnderTest.startTask();
// then
assertThat(response.getStatusCode()).isSameAs(HttpStatus.ACCEPTED);
// more assertions
}

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;
}
}
}

Categories