1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.kuali.rice.core.util;
18
19 import java.beans.PropertyDescriptor;
20 import java.lang.reflect.AccessibleObject;
21 import java.lang.reflect.Field;
22 import java.lang.reflect.InvocationTargetException;
23 import java.lang.reflect.Method;
24 import java.util.HashMap;
25 import java.util.LinkedList;
26 import java.util.List;
27 import java.util.Map;
28
29 import javax.xml.namespace.QName;
30
31 import org.apache.commons.lang.StringUtils;
32 import org.apache.log4j.Logger;
33 import org.kuali.rice.core.config.ConfigContext;
34 import org.kuali.rice.core.resourceloader.GlobalResourceLoader;
35 import org.kuali.rice.core.resourceloader.ResourceLoader;
36 import org.springframework.beans.BeanUtils;
37 import org.springframework.beans.BeansException;
38 import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter;
39 import org.springframework.util.ReflectionUtils;
40
41
42
43
44
45
46
47
48
49
50
51 public class GRLServiceInjectionPostProcessor extends InstantiationAwareBeanPostProcessorAdapter {
52 private static final Logger LOG = Logger.getLogger(GRLServiceInjectionPostProcessor.class);
53
54
55 private Map<Class<?>, List<AnnotatedMember>> classMetadata = new HashMap<Class<?>, List<AnnotatedMember>>();
56
57 @Override
58 public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
59 List<AnnotatedMember> metadata = findClassMetadata(bean.getClass());
60 for (AnnotatedMember member: metadata) {
61 Object value = member.read(bean);
62 if (value == null) {
63 Object newValue = lookupRiceService(member.service);
64 if (newValue != null) {
65
66 member.inject(bean, newValue);
67 }
68 }
69 }
70 return super.postProcessBeforeInitialization(bean, beanName);
71 }
72
73
74 protected Object lookupRiceService(RiceService annotation) {
75 String resourceLoader = annotation.resourceLoader();
76 String name = annotation.name();
77
78 ResourceLoader rl;
79
80
81 if (StringUtils.isEmpty(resourceLoader)) {
82 LOG.error("Using global resource loader");
83 rl = GlobalResourceLoader.getResourceLoader();
84 if (rl == null) {
85
86 throw new RuntimeException("Global resource loader could not be obtained");
87 }
88 } else {
89 QName rlName = QName.valueOf(resourceLoader);
90
91 if (StringUtils.isBlank(rlName.getNamespaceURI())) {
92
93 rlName = new QName(ConfigContext.getCurrentContextConfig().getServiceNamespace(), rlName.getLocalPart());
94 }
95 rl = GlobalResourceLoader.getResourceLoader(rlName);
96 if (rl == null) {
97 throw new RuntimeException("Named resource loader not found: " + resourceLoader);
98 }
99 }
100
101 LOG.error("Looking up service for injection: " + name);
102 return rl.getService(QName.valueOf(name));
103 }
104
105
106
107
108
109
110
111 private synchronized List<AnnotatedMember> findClassMetadata(Class<? extends Object> clazz) {
112 List<AnnotatedMember> metadata = classMetadata.get(clazz);
113 if (metadata == null) {
114 final List<AnnotatedMember> newMetadata = new LinkedList<AnnotatedMember>();
115
116 ReflectionUtils.doWithFields(clazz, new ReflectionUtils.FieldCallback() {
117 public void doWith(Field f) throws IllegalArgumentException, IllegalAccessException {
118 addIfPresent(newMetadata, f);
119 }
120 });
121
122
123
124 ReflectionUtils.doWithMethods(clazz, new ReflectionUtils.MethodCallback() {
125 public void doWith(Method m) throws IllegalArgumentException, IllegalAccessException {
126 addIfPresent(newMetadata, m);
127 }
128 });
129
130 metadata = newMetadata;
131 classMetadata.put(clazz, metadata);
132 }
133 return metadata;
134 }
135
136
137
138
139
140
141
142 private void addIfPresent(List<AnnotatedMember> metadata, AccessibleObject ao) {
143 RiceService annotation = ao.getAnnotation(RiceService.class);
144 if (annotation != null) {
145 metadata.add(new AnnotatedMember(ao, annotation));
146 }
147 }
148
149
150
151
152 private final class AnnotatedMember {
153 private final AccessibleObject member;
154 private final RiceService service;
155
156 public AnnotatedMember(AccessibleObject member, RiceService service) {
157 this.member = member;
158 this.service = service;
159
160 if (service.name() == null) {
161 throw new IllegalArgumentException("Service name must be specified in RiceService annotation");
162 }
163 }
164
165 public Object read(Object instance) {
166
167
168
169 try {
170 if (!member.isAccessible()) {
171 member.setAccessible(true);
172 }
173 if (member instanceof Field) {
174 return ((Field) member).get(instance);
175 }
176 else if (member instanceof Method) {
177 PropertyDescriptor pd = BeanUtils.findPropertyForMethod((Method) member);
178 if (pd == null) {
179 throw new IllegalArgumentException("Annotated was found on a method that did not resolve to a bean property: " + member);
180 }
181 Method getter = pd.getReadMethod();
182 if (getter == null) {
183
184
185 return null;
186
187 }
188 return getter.invoke(instance, (Object[]) null);
189 }
190 else {
191 throw new IllegalArgumentException("Cannot read unknown AccessibleObject type " + member);
192 }
193 }
194 catch (IllegalAccessException ex) {
195 throw new IllegalArgumentException("Cannot inject member " + member, ex);
196 }
197 catch (InvocationTargetException ex) {
198
199 throw new IllegalArgumentException("Attempt to inject setter method " + member +
200 " resulted in an exception", ex);
201 }
202 }
203
204 public void inject(Object instance, Object value) {
205 try {
206 if (!member.isAccessible()) {
207 member.setAccessible(true);
208 }
209 if (member instanceof Field) {
210 ((Field) member).set(instance, value);
211 }
212 else if (member instanceof Method) {
213 PropertyDescriptor pd = BeanUtils.findPropertyForMethod((Method) member);
214 if (pd == null) {
215 throw new IllegalArgumentException("Annotated was found on a method that did not resolve to a bean property: " + member);
216 }
217 Method setter = pd.getWriteMethod();
218 if (setter == null) {
219 throw new IllegalArgumentException("No setter found for property " + pd.getName());
220 }
221 setter.invoke(instance, value);
222 }
223 else {
224 throw new IllegalArgumentException("Cannot inject unknown AccessibleObject type " + member);
225 }
226 }
227 catch (IllegalAccessException ex) {
228 throw new IllegalArgumentException("Cannot inject member " + member, ex);
229 }
230 catch (InvocationTargetException ex) {
231
232 throw new IllegalArgumentException("Attempt to inject setter method " + member +
233 " resulted in an exception", ex);
234 }
235 }
236 }
237 }