/** * Start concurrent request processing and execute the given task with an * {@link #setTaskExecutor(AsyncTaskExecutor) AsyncTaskExecutor}. The result * from the task execution is saved and the request dispatched in order to * resume processing of that result. If the task raises an Exception then * the saved result will be the raised Exception. * @param callable a unit of work to be executed asynchronously * @param processingContext additional context to save that can be accessed * via {@link #getConcurrentResultContext()} * @throws Exception if concurrent processing failed to start * @see #getConcurrentResult() * @see #getConcurrentResultContext() */ @SuppressWarnings({"unchecked", "rawtypes"}) public void startCallableProcessing(Callable<?> callable, Object... processingContext) throws Exception { Assert.notNull(callable, "Callable must not be null"); startCallableProcessing(new WebAsyncTask(callable), processingContext); }
@Override public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception { if (returnValue == null) { mavContainer.setRequestHandled(true); return; } Callable<?> callable = (Callable<?>) returnValue; WebAsyncUtils.getAsyncManager(webRequest).startCallableProcessing(callable, mavContainer); }
@Override public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception { if (returnValue == null) { mavContainer.setRequestHandled(true); return; } WebAsyncTask<?> webAsyncTask = (WebAsyncTask<?>) returnValue; if (this.beanFactory != null) { webAsyncTask.setBeanFactory(this.beanFactory); } WebAsyncUtils.getAsyncManager(webRequest).startCallableProcessing(webAsyncTask, mavContainer); }
@Test public void startCallableProcessingNullInput() throws Exception { try { this.asyncManager.startCallableProcessing((Callable<?>) null); fail("Expected exception"); } catch (IllegalArgumentException ex) { assertEquals("Callable must not be null", ex.getMessage()); } }
@SuppressWarnings("unchecked") @Test public void startCallableProcessingTimeoutAndCheckThreadInterrupted() throws Exception { StubCallable callable = new StubCallable(); Future future = mock(Future.class); AsyncTaskExecutor executor = mock(AsyncTaskExecutor.class); when(executor.submit(any(Runnable.class))).thenReturn(future); this.asyncManager.setTaskExecutor(executor); this.asyncManager.startCallableProcessing(callable); this.asyncWebRequest.onTimeout(ASYNC_EVENT); assertTrue(this.asyncManager.hasConcurrentResult()); verify(future).cancel(true); verifyNoMoreInteractions(future); }
@Test public void startAsyncProcessingWithoutAsyncWebRequest() throws Exception { WebAsyncManager manager = WebAsyncUtils.getAsyncManager(new MockHttpServletRequest()); try { manager.startCallableProcessing(new StubCallable(1)); fail("Expected exception"); } catch (IllegalStateException ex) { assertEquals("AsyncWebRequest must not be null", ex.getMessage()); } try { manager.startDeferredResultProcessing(new DeferredResult<String>()); fail("Expected exception"); } catch (IllegalStateException ex) { assertEquals("AsyncWebRequest must not be null", ex.getMessage()); } }
@Test public void startCallableProcessingPreProcessException() throws Exception { Callable<Object> task = new StubCallable(21); Exception exception = new Exception(); CallableProcessingInterceptor interceptor = mock(CallableProcessingInterceptor.class); willThrow(exception).given(interceptor).preProcess(this.asyncWebRequest, task); setupDefaultAsyncScenario(); this.asyncManager.registerCallableInterceptor("interceptor", interceptor); this.asyncManager.startCallableProcessing(task); assertTrue(this.asyncManager.hasConcurrentResult()); assertEquals(exception, this.asyncManager.getConcurrentResult()); verifyDefaultAsyncScenario(); verify(interceptor).beforeConcurrentHandling(this.asyncWebRequest, task); }
@Test public void startCallableProcessingCallableException() throws Exception { Exception concurrentResult = new Exception(); Callable<Object> task = new StubCallable(concurrentResult); CallableProcessingInterceptor interceptor = mock(CallableProcessingInterceptor.class); setupDefaultAsyncScenario(); this.asyncManager.registerCallableInterceptor("interceptor", interceptor); this.asyncManager.startCallableProcessing(task); assertTrue(this.asyncManager.hasConcurrentResult()); assertEquals(concurrentResult, this.asyncManager.getConcurrentResult()); verifyDefaultAsyncScenario(); verify(interceptor).beforeConcurrentHandling(this.asyncWebRequest, task); verify(interceptor).preProcess(this.asyncWebRequest, task); verify(interceptor).postProcess(this.asyncWebRequest, task, concurrentResult); }
@Test public void startCallableProcessingAfterException() throws Exception { StubCallable callable = new StubCallable(); Exception exception = new Exception(); CallableProcessingInterceptor interceptor = mock(CallableProcessingInterceptor.class); Exception e = new Exception(); given(interceptor.handleError(this.asyncWebRequest, callable, e)).willThrow(exception); this.asyncManager.registerCallableInterceptor("errorInterceptor", interceptor); this.asyncManager.startCallableProcessing(callable); AsyncEvent event = new AsyncEvent(new MockAsyncContext(this.servletRequest, this.servletResponse), e); this.asyncWebRequest.onError(event); assertTrue(this.asyncManager.hasConcurrentResult()); assertEquals(exception, this.asyncManager.getConcurrentResult()); assertEquals("/test", ((MockAsyncContext) this.servletRequest.getAsyncContext()).getDispatchedPath()); verify(interceptor).beforeConcurrentHandling(this.asyncWebRequest, callable); }
@Test public void startCallableProcessingAfterTimeoutException() throws Exception { StubCallable callable = new StubCallable(); Exception exception = new Exception(); CallableProcessingInterceptor interceptor = mock(CallableProcessingInterceptor.class); given(interceptor.handleTimeout(this.asyncWebRequest, callable)).willThrow(exception); this.asyncManager.registerCallableInterceptor("timeoutInterceptor", interceptor); this.asyncManager.startCallableProcessing(callable); this.asyncWebRequest.onTimeout(ASYNC_EVENT); assertTrue(this.asyncManager.hasConcurrentResult()); assertEquals(exception, this.asyncManager.getConcurrentResult()); assertEquals("/test", ((MockAsyncContext) this.servletRequest.getAsyncContext()).getDispatchedPath()); verify(interceptor).beforeConcurrentHandling(this.asyncWebRequest, callable); }
@Test public void startCallableProcessingTimeoutAndComplete() throws Exception { StubCallable callable = new StubCallable(); CallableProcessingInterceptor interceptor = mock(CallableProcessingInterceptor.class); given(interceptor.handleTimeout(this.asyncWebRequest, callable)).willReturn(RESULT_NONE); this.asyncManager.registerCallableInterceptor("interceptor", interceptor); this.asyncManager.startCallableProcessing(callable); this.asyncWebRequest.onTimeout(ASYNC_EVENT); this.asyncWebRequest.onComplete(ASYNC_EVENT); assertTrue(this.asyncManager.hasConcurrentResult()); assertEquals(AsyncRequestTimeoutException.class, this.asyncManager.getConcurrentResult().getClass()); verify(interceptor).beforeConcurrentHandling(this.asyncWebRequest, callable); verify(interceptor).afterCompletion(this.asyncWebRequest, callable); }
@Test public void startCallableProcessingErrorAndResumeThroughCallback() throws Exception { StubCallable callable = new StubCallable(); WebAsyncTask<Object> webAsyncTask = new WebAsyncTask<>(callable); webAsyncTask.onError(new Callable<Object>() { @Override public Object call() throws Exception { return 7; } }); this.asyncManager.startCallableProcessing(webAsyncTask); Exception e = new Exception(); AsyncEvent event = new AsyncEvent(new MockAsyncContext(this.servletRequest, this.servletResponse), e); this.asyncWebRequest.onError(event); assertTrue(this.asyncManager.hasConcurrentResult()); assertEquals(7, this.asyncManager.getConcurrentResult()); assertEquals("/test", ((MockAsyncContext) this.servletRequest.getAsyncContext()).getDispatchedPath()); }
@Test public void startCallableProcessingPostProcessException() throws Exception { Callable<Object> task = new StubCallable(21); Exception exception = new Exception(); CallableProcessingInterceptor interceptor = mock(CallableProcessingInterceptor.class); willThrow(exception).given(interceptor).postProcess(this.asyncWebRequest, task, 21); setupDefaultAsyncScenario(); this.asyncManager.registerCallableInterceptor("interceptor", interceptor); this.asyncManager.startCallableProcessing(task); assertTrue(this.asyncManager.hasConcurrentResult()); assertEquals(exception, this.asyncManager.getConcurrentResult()); verifyDefaultAsyncScenario(); verify(interceptor).beforeConcurrentHandling(this.asyncWebRequest, task); verify(interceptor).preProcess(this.asyncWebRequest, task); }
@Test public void startCallableProcessingTimeoutAndResumeThroughCallback() throws Exception { StubCallable callable = new StubCallable(); WebAsyncTask<Object> webAsyncTask = new WebAsyncTask<>(callable); webAsyncTask.onTimeout(new Callable<Object>() { @Override public Object call() throws Exception { return 7; } }); this.asyncManager.startCallableProcessing(webAsyncTask); this.asyncWebRequest.onTimeout(ASYNC_EVENT); assertTrue(this.asyncManager.hasConcurrentResult()); assertEquals(7, this.asyncManager.getConcurrentResult()); assertEquals("/test", ((MockAsyncContext) this.servletRequest.getAsyncContext()).getDispatchedPath()); }
@Test public void startCallableProcessingErrorAndResumeThroughInterceptor() throws Exception { StubCallable callable = new StubCallable(); CallableProcessingInterceptor interceptor = mock(CallableProcessingInterceptor.class); Exception e = new Exception(); given(interceptor.handleError(this.asyncWebRequest, callable, e)).willReturn(22); this.asyncManager.registerCallableInterceptor("errorInterceptor", interceptor); this.asyncManager.startCallableProcessing(callable); AsyncEvent event = new AsyncEvent(new MockAsyncContext(this.servletRequest, this.servletResponse), e); this.asyncWebRequest.onError(event); assertTrue(this.asyncManager.hasConcurrentResult()); assertEquals(22, this.asyncManager.getConcurrentResult()); assertEquals("/test", ((MockAsyncContext) this.servletRequest.getAsyncContext()).getDispatchedPath()); verify(interceptor).beforeConcurrentHandling(this.asyncWebRequest, callable); }
@Test public void startCallableProcessingErrorAndComplete() throws Exception { StubCallable callable = new StubCallable(); CallableProcessingInterceptor interceptor = mock(CallableProcessingInterceptor.class); Exception e = new Exception(); given(interceptor.handleError(this.asyncWebRequest, callable, e)).willReturn(RESULT_NONE); this.asyncManager.registerCallableInterceptor("interceptor", interceptor); this.asyncManager.startCallableProcessing(callable); AsyncEvent event = new AsyncEvent(new MockAsyncContext(this.servletRequest, this.servletResponse), e); this.asyncWebRequest.onError(event); this.asyncWebRequest.onComplete(event); assertTrue(this.asyncManager.hasConcurrentResult()); assertEquals(e, this.asyncManager.getConcurrentResult()); verify(interceptor).beforeConcurrentHandling(this.asyncWebRequest, callable); verify(interceptor).afterCompletion(this.asyncWebRequest, callable); }
@SuppressWarnings("unchecked") @Test public void startCallableProcessingBeforeConcurrentHandlingException() throws Exception { Callable<Object> task = new StubCallable(21); Exception exception = new Exception(); CallableProcessingInterceptor interceptor = mock(CallableProcessingInterceptor.class); willThrow(exception).given(interceptor).beforeConcurrentHandling(this.asyncWebRequest, task); this.asyncManager.registerCallableInterceptor("interceptor", interceptor); try { this.asyncManager.startCallableProcessing(task); fail("Expected Exception"); } catch (Exception ex) { assertEquals(exception, ex); } assertFalse(this.asyncManager.hasConcurrentResult()); verify(this.asyncWebRequest).addTimeoutHandler(notNull()); verify(this.asyncWebRequest).addErrorHandler(notNull()); verify(this.asyncWebRequest).addCompletionHandler(notNull()); }
@Test public void startCallableProcessing() throws Exception { int concurrentResult = 21; Callable<Object> task = new StubCallable(concurrentResult); CallableProcessingInterceptor interceptor = mock(CallableProcessingInterceptor.class); setupDefaultAsyncScenario(); this.asyncManager.registerCallableInterceptor("interceptor", interceptor); this.asyncManager.startCallableProcessing(task); assertTrue(this.asyncManager.hasConcurrentResult()); assertEquals(concurrentResult, this.asyncManager.getConcurrentResult()); verifyDefaultAsyncScenario(); verify(interceptor).beforeConcurrentHandling(this.asyncWebRequest, task); verify(interceptor).preProcess(this.asyncWebRequest, task); verify(interceptor).postProcess(this.asyncWebRequest, task, concurrentResult); }
@Test public void startCallableProcessingTimeoutAndResumeThroughInterceptor() throws Exception { StubCallable callable = new StubCallable(); CallableProcessingInterceptor interceptor = mock(CallableProcessingInterceptor.class); given(interceptor.handleTimeout(this.asyncWebRequest, callable)).willReturn(22); this.asyncManager.registerCallableInterceptor("timeoutInterceptor", interceptor); this.asyncManager.startCallableProcessing(callable); this.asyncWebRequest.onTimeout(ASYNC_EVENT); assertTrue(this.asyncManager.hasConcurrentResult()); assertEquals(22, this.asyncManager.getConcurrentResult()); assertEquals("/test", ((MockAsyncContext) this.servletRequest.getAsyncContext()).getDispatchedPath()); verify(interceptor).beforeConcurrentHandling(this.asyncWebRequest, callable); }
@SuppressWarnings("unchecked") @Test public void startCallableProcessingWithAsyncTask() throws Exception { AsyncTaskExecutor executor = mock(AsyncTaskExecutor.class); given(this.asyncWebRequest.getNativeRequest(HttpServletRequest.class)).willReturn(this.servletRequest); WebAsyncTask<Object> asyncTask = new WebAsyncTask<>(1000L, executor, mock(Callable.class)); this.asyncManager.startCallableProcessing(asyncTask); verify(executor).submit((Runnable) notNull()); verify(this.asyncWebRequest).setTimeout(1000L); verify(this.asyncWebRequest).addTimeoutHandler(any(Runnable.class)); verify(this.asyncWebRequest).addErrorHandler(any(Consumer.class)); verify(this.asyncWebRequest).addCompletionHandler(any(Runnable.class)); verify(this.asyncWebRequest).startAsync(); }