1/*
2 * Copyright 2002-2012 the original author or authors.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package org.springframework.scheduling.aspectj;
18
19import java.util.concurrent.Callable;
20import java.util.concurrent.Executor;
21import java.util.concurrent.Future;
22
23import org.aspectj.lang.reflect.MethodSignature;
24
25import org.springframework.aop.interceptor.AsyncExecutionAspectSupport;
26import org.springframework.core.task.AsyncTaskExecutor;
27
28/**
29 * Abstract aspect that routes selected methods asynchronously.
30 *
31 * <p>This aspect needs to be injected with an implementation of
32 * {@link Executor} to activate it for a specific thread pool.
33 * Otherwise it will simply delegate all calls synchronously.
34 *
35 * @author Ramnivas Laddad
36 * @author Juergen Hoeller
37 * @author Chris Beams
38 * @since 3.0.5
39 */
40public abstract aspect AbstractAsyncExecutionAspect extends AsyncExecutionAspectSupport {
41
42	/**
43	 * Create an {@code AnnotationAsyncExecutionAspect} with a {@code null} default
44	 * executor, which should instead be set via {@code #aspectOf} and
45	 * {@link #setExecutor(Executor)}.
46	 */
47	public AbstractAsyncExecutionAspect() {
48		super(null);
49	}
50
51	/**
52	 * Apply around advice to methods matching the {@link #asyncMethod()} pointcut,
53	 * submit the actual calling of the method to the correct task executor and return
54	 * immediately to the caller.
55	 * @return {@link Future} if the original method returns {@code Future}; {@code null}
56	 * otherwise.
57	 */
58	Object around() : asyncMethod() {
59		MethodSignature methodSignature = (MethodSignature) thisJoinPointStaticPart.getSignature();
60		AsyncTaskExecutor executor = determineAsyncExecutor(methodSignature.getMethod());
61		if (executor == null) {
62			return proceed();
63		}
64		Callable<Object> callable = new Callable<Object>() {
65			public Object call() throws Exception {
66				Object result = proceed();
67				if (result instanceof Future) {
68					return ((Future<?>) result).get();
69				}
70				return null;
71			}};
72		Future<?> result = executor.submit(callable);
73		if (Future.class.isAssignableFrom(methodSignature.getReturnType())) {
74			return result;
75		}
76		else {
77			return null;
78		}
79	}
80
81	/**
82	 * Return the set of joinpoints at which async advice should be applied.
83	 */
84	public abstract pointcut asyncMethod();
85
86}
87