1 | /** |
2 | * Licensed to jclouds, Inc. (jclouds) under one or more |
3 | * contributor license agreements. See the NOTICE file |
4 | * distributed with this work for additional information |
5 | * regarding copyright ownership. jclouds licenses this file |
6 | * to you under the Apache License, Version 2.0 (the |
7 | * "License"); you may not use this file except in compliance |
8 | * with the License. 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, |
13 | * software distributed under the License is distributed on an |
14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
15 | * KIND, either express or implied. See the License for the |
16 | * specific language governing permissions and limitations |
17 | * under the License. |
18 | */ |
19 | package org.jclouds.rest.internal; |
20 | |
21 | import static com.google.common.collect.Sets.difference; |
22 | import static org.jclouds.rest.internal.RestAnnotationProcessor.delegationMap; |
23 | import static org.jclouds.rest.internal.RestAnnotationProcessor.getHttpMethods; |
24 | import static org.jclouds.rest.internal.RestAnnotationProcessor.methodToIndexOfParamToBinderParamAnnotation; |
25 | import static org.jclouds.rest.internal.RestAnnotationProcessor.methodToIndexOfParamToEndpointAnnotations; |
26 | import static org.jclouds.rest.internal.RestAnnotationProcessor.methodToIndexOfParamToEndpointParamAnnotations; |
27 | import static org.jclouds.rest.internal.RestAnnotationProcessor.methodToIndexOfParamToFormParamAnnotations; |
28 | import static org.jclouds.rest.internal.RestAnnotationProcessor.methodToIndexOfParamToHeaderParamAnnotations; |
29 | import static org.jclouds.rest.internal.RestAnnotationProcessor.methodToIndexOfParamToMatrixParamAnnotations; |
30 | import static org.jclouds.rest.internal.RestAnnotationProcessor.methodToIndexOfParamToParamParserAnnotations; |
31 | import static org.jclouds.rest.internal.RestAnnotationProcessor.methodToIndexOfParamToPartParamAnnotations; |
32 | import static org.jclouds.rest.internal.RestAnnotationProcessor.methodToIndexOfParamToPathParamAnnotations; |
33 | import static org.jclouds.rest.internal.RestAnnotationProcessor.methodToIndexOfParamToPostParamAnnotations; |
34 | import static org.jclouds.rest.internal.RestAnnotationProcessor.methodToIndexOfParamToQueryParamAnnotations; |
35 | import static org.jclouds.rest.internal.RestAnnotationProcessor.methodToIndexOfParamToWrapWithAnnotation; |
36 | import static org.jclouds.rest.internal.RestAnnotationProcessor.methodToIndexesOfOptions; |
37 | |
38 | import java.lang.reflect.Method; |
39 | import java.util.concurrent.ExecutionException; |
40 | |
41 | import javax.annotation.Resource; |
42 | import javax.inject.Named; |
43 | import javax.inject.Singleton; |
44 | import javax.ws.rs.Path; |
45 | import javax.ws.rs.PathParam; |
46 | |
47 | import org.jclouds.http.HttpRequest; |
48 | import org.jclouds.logging.Logger; |
49 | import org.jclouds.rest.annotations.Delegate; |
50 | import org.jclouds.rest.internal.RestAnnotationProcessor.MethodKey; |
51 | |
52 | import com.google.common.cache.CacheLoader; |
53 | import com.google.common.collect.ImmutableSet; |
54 | import com.google.common.collect.Multimap; |
55 | import com.google.inject.Inject; |
56 | import com.google.inject.Injector; |
57 | import com.google.inject.Key; |
58 | import com.google.inject.Provides; |
59 | |
60 | /** |
61 | * seeds the annotation cache |
62 | * |
63 | * @author Adrian Cole |
64 | */ |
65 | |
66 | @Singleton |
67 | public class SeedAnnotationCache extends CacheLoader<Class<?>, Boolean> { |
68 | @Resource |
69 | protected Logger logger = Logger.NULL; |
70 | |
71 | protected final Multimap<String, String> constants; |
72 | protected final Injector injector; |
73 | |
74 | @Inject |
75 | public SeedAnnotationCache(Injector injector, @Named("CONSTANTS") Multimap<String, String> constants) { |
76 | this.injector = injector; |
77 | this.constants = constants; |
78 | } |
79 | |
80 | public void bindConstant(Method method) { |
81 | String key = method.getAnnotation(PathParam.class).value(); |
82 | String value = injector.getInstance(Key.get(String.class, method.getAnnotation(Named.class))); |
83 | constants.put(key, value); |
84 | } |
85 | |
86 | @Override |
87 | public Boolean load(Class<?> declaring) throws ExecutionException { |
88 | for (Method method : difference(ImmutableSet.copyOf(declaring.getMethods()), ImmutableSet.copyOf(Object.class |
89 | .getMethods()))) { |
90 | if (isHttpMethod(method) || method.isAnnotationPresent(Delegate.class)) { |
91 | for (int index = 0; index < method.getParameterTypes().length; index++) { |
92 | methodToIndexOfParamToBinderParamAnnotation.get(method).get(index); |
93 | methodToIndexOfParamToWrapWithAnnotation.get(method).get(index); |
94 | methodToIndexOfParamToHeaderParamAnnotations.get(method).get(index); |
95 | methodToIndexOfParamToMatrixParamAnnotations.get(method).get(index); |
96 | methodToIndexOfParamToFormParamAnnotations.get(method).get(index); |
97 | methodToIndexOfParamToQueryParamAnnotations.get(method).get(index); |
98 | methodToIndexOfParamToEndpointAnnotations.get(method).get(index); |
99 | methodToIndexOfParamToEndpointParamAnnotations.get(method).get(index); |
100 | methodToIndexOfParamToPathParamAnnotations.get(method).get(index); |
101 | methodToIndexOfParamToPostParamAnnotations.get(method).get(index); |
102 | methodToIndexOfParamToParamParserAnnotations.get(method).get(index); |
103 | methodToIndexOfParamToPartParamAnnotations.get(method).get(index); |
104 | methodToIndexesOfOptions.get(method); |
105 | } |
106 | delegationMap.put(new MethodKey(method), method); |
107 | } else if (isConstantDeclaration(method)) { |
108 | bindConstant(method); |
109 | } else if (!method.getDeclaringClass().equals(declaring)) { |
110 | logger.trace("skipping potentially overridden method %s", method); |
111 | } else if (method.isAnnotationPresent(Provides.class)) { |
112 | logger.trace("skipping provider method %s", method); |
113 | } else { |
114 | logger.trace("Method is not annotated as either http or constant: %s", method); |
115 | } |
116 | } |
117 | return true; |
118 | } |
119 | |
120 | public static boolean isHttpMethod(Method method) { |
121 | return method.isAnnotationPresent(Path.class) || getHttpMethods(method) != null |
122 | || ImmutableSet.copyOf(method.getParameterTypes()).contains(HttpRequest.class); |
123 | } |
124 | |
125 | public static boolean isConstantDeclaration(Method method) { |
126 | return method.isAnnotationPresent(PathParam.class) && method.isAnnotationPresent(Named.class); |
127 | } |
128 | } |