View Javadoc
1   /*
2    * AutoDAO - Generic DAO on steroids implementation for Java.
3    *
4    * Copyright 2008-2012  Marat Radchenko <slonopotamus@users.sourceforge.net>
5    *
6    * Licensed under the Apache License, Version 2.0 (the "License");
7    * you may not use this file except in compliance with the License.
8    * You may obtain a copy of the License at
9    *
10   * http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  package net.sf.autodao.impl;
19  
20  import java.lang.annotation.Annotation;
21  import java.lang.reflect.Method;
22  import java.util.ArrayList;
23  import java.util.Collection;
24  import java.util.HashMap;
25  import java.util.List;
26  import java.util.Map;
27  
28  import net.sf.autodao.Finder;
29  import net.sf.autodao.Named;
30  import net.sf.autodao.QueryArgumentTransformer;
31  import org.aopalliance.intercept.MethodInterceptor;
32  import org.aopalliance.intercept.MethodInvocation;
33  import org.jetbrains.annotations.NotNull;
34  import org.jetbrains.annotations.Nullable;
35  import org.springframework.core.annotation.AnnotationUtils;
36  import org.springframework.transaction.interceptor.TransactionAspectSupport;
37  
38  /**
39   * Intercepts finder DAO calls and calls execute*Finder methods on dao.
40   *
41   * <p>NOT FOR PUBLIC USE.
42   */
43  final class FinderIntroductionInterceptor extends TransactionAspectSupport implements MethodInterceptor {
44  
45    @NotNull
46    private final Map<Class<?>, QueryArgumentTransformer<?, ?>> transformers;
47  
48    FinderIntroductionInterceptor(@NotNull final Map<Class<?>, QueryArgumentTransformer<?, ?>> transformers) {
49      this.transformers = transformers;
50    }
51  
52    /** {@inheritDoc} */
53    @Override
54    public Object invoke(@NotNull final MethodInvocation invocation) throws Throwable {
55      final Method method = invocation.getMethod();
56      final Finder finder = AnnotationUtils.getAnnotation(method, Finder.class);
57  
58      if (finder == null)
59        return invocation.proceed();
60  
61      final Object[] arguments = invocation.getArguments();
62      final Integer[] limit = new Integer[1];
63      final Integer[] offset = new Integer[1];
64      final List<Object> queryArgs = new ArrayList<>(arguments.length);
65      final Map<String, Object> namedArgs = new HashMap<>(arguments.length);
66      Utils.visitMethodParameters(method, new Utils.ParameterCallback() {
67        @Override
68        public void visit(final int index, @NotNull final Class<?> type, @NotNull final Annotation[] annotations) {
69          boolean processed = false;
70          final Object arg = arguments[index];
71          if (Utils.getLimit(annotations) != null) {
72            limit[0] = (Integer) arg;
73            processed = true;
74          }
75  
76          if (Utils.getOffset(annotations) != null) {
77            offset[0] = (Integer) arg;
78            processed = true;
79          }
80  
81          if (processed)
82            return;
83  
84          final Object queryArg = transformArg(arg, method.getParameterTypes()[index]);
85          final Named named = Utils.getNamed(annotations);
86          if (named == null) {
87            queryArgs.add(queryArg);
88          } else {
89            namedArgs.put(named.value(), queryArg);
90          }
91        }
92      });
93  
94      final FinderExecutor dao = (FinderExecutor) invocation.getThis();
95      if (Collection.class.isAssignableFrom(invocation.getMethod().getReturnType())) {
96        final List<Object> data;
97        if (namedArgs.isEmpty()) {
98          data = dao.executeListFinder(method, queryArgs.toArray(new Object[queryArgs.size()]), limit[0], offset[0]);
99        } else {
100         data = dao.executeListFinder(method, namedArgs, limit[0], offset[0]);
101       }
102       return convertResult(finder, data);
103     } else {
104       if (namedArgs.isEmpty()) {
105         return dao.executeSingleFinder(method, arguments);
106       } else {
107         return dao.executeSingleFinder(method, namedArgs);
108       }
109     }
110   }
111 
112   @SuppressWarnings({ "unchecked", "rawtypes" })
113   @Nullable
114   private Object transformArg(@Nullable final Object arg, @NotNull final Class<?> declaredArgType) {
115     if (arg == null)
116       return null;
117 
118     final QueryArgumentTransformer transformer = transformers.get(declaredArgType);
119     if (transformer == null)
120       return arg;
121 
122     return transformer.transform(arg);
123   }
124 
125   @SuppressWarnings({ "unchecked", "rawtypes" })
126   private static Object convertResult(final Finder finder, final List<Object> data) throws Exception {
127     final Class<? extends Collection> returnAs = finder.returnAs();
128     if (returnAs == List.class)
129       return data;
130 
131     final Collection<Object> result = returnAs.newInstance();
132     result.addAll(data);
133     return result;
134   }
135 }