1 /*
2 * JBoss, Home of Professional Open Source
3 * Copyright 2006, JBoss Inc., and individual contributors as indicated
4 * by the @authors tag. See the copyright.txt in the distribution for a
5 * full listing of individual contributors.
6 *
7 * This is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU Lesser General Public License as
9 * published by the Free Software Foundation; either version 2.1 of
10 * the License, or (at your option) any later version.
11 *
12 * This software is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this software; if not, write to the Free
19 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
21 */
22
23 package org.jboss.web.jsf.integration.injection;
24
25 import java.lang.reflect.Field;
26 import java.lang.reflect.InvocationTargetException;
27 import java.lang.reflect.Method;
28 import java.lang.reflect.Modifier;
29 import java.util.HashMap;
30 import java.util.Map;
31
32 import javax.annotation.PostConstruct;
33 import javax.annotation.PreDestroy;
34 import javax.annotation.Resource;
35 import javax.ejb.EJB;
36 import javax.naming.Context;
37 import javax.naming.InitialContext;
38 import javax.naming.NamingException;
39 import javax.persistence.PersistenceContext;
40 import javax.persistence.PersistenceUnit;
41 import javax.xml.ws.WebServiceRef;
42
43 import org.jboss.logging.Logger;
44
45 import com.sun.faces.spi.InjectionProvider;
46 import com.sun.faces.spi.InjectionProviderException;
47
48 /**
49 * Provides interface between JSF RI and Tomcat Catalina for injection of managed beans as
50 * per JSF 1.2 Spec section 5.4.
51 *
52 * @author Stan Silvert
53 * @author Fabien Carrion
54 * @author Remy Maucherat
55 */
56 public class JBossInjectionProvider implements InjectionProvider {
57 private static final Logger LOG = Logger.getLogger(JBossInjectionProvider.class);
58 private static final String NAMING_DISABLED = "Injection of naming resources into JSF managed beans disabled.";
59
60 private Context namingContext;
61
62 /**
63 * Uses the default naming context for injection of resources into managed beans.
64 */
65 public JBossInjectionProvider() {
66 try {
67 this.namingContext = new InitialContext();
68 } catch (Exception e) {
69 LOG.warn(NAMING_DISABLED, e);
70 }
71 }
72
73 /**
74 * This constructor allows a subclass to override the default naming
75 * context.
76 *
77 * @param namingContext The naming context to use for injection of managed beans.
78 * If this param is null then injection of resources will be
79 * disabled and JBoss will only call @PostConstruct and
80 * @PreDestroy methods.
81 */
82 protected JBossInjectionProvider(Context namingContext) {
83 if (namingContext == null) {
84 LOG.warn(NAMING_DISABLED);
85 }
86
87 this.namingContext = namingContext;
88 }
89
90 /**
91 * Call methods on a managed bean that are annotated with @PreDestroy.
92 */
93 public void invokePreDestroy(Object managedBean) throws InjectionProviderException {
94 try {
95 Method[] methods = managedBean.getClass().getDeclaredMethods();
96 Method preDestroy = null;
97 for (int i = 0; i < methods.length; i++) {
98 if (methods[i].isAnnotationPresent(PreDestroy.class)) {
99 if ((preDestroy != null)
100 || (methods[i].getParameterTypes().length != 0)
101 || (Modifier.isStatic(methods[i].getModifiers()))
102 || (methods[i].getExceptionTypes().length > 0)
103 || (!methods[i].getReturnType().getName().equals("void"))) {
104 throw new IllegalArgumentException("Invalid PreDestroy annotation");
105 }
106 preDestroy = methods[i];
107 }
108 }
109
110 // At the end the postconstruct annotated
111 // method is invoked
112 if (preDestroy != null) {
113 boolean accessibility = preDestroy.isAccessible();
114 preDestroy.setAccessible(true);
115 preDestroy.invoke(managedBean);
116 preDestroy.setAccessible(accessibility);
117 }
118 } catch (Exception e) {
119 LOG.error("PreDestroy failed on managed bean.", e);
120 }
121 }
122
123 /**
124 * Call methods on a managed bean that are annotated with @PostConstruct.
125 */
126 public void invokePostConstruct(Object managedBean) throws InjectionProviderException {
127 try {
128 Method[] methods = managedBean.getClass().getDeclaredMethods();
129 Method postConstruct = null;
130 for (int i = 0; i < methods.length; i++) {
131 if (methods[i].isAnnotationPresent(PostConstruct.class)) {
132 if ((postConstruct != null)
133 || (methods[i].getParameterTypes().length != 0)
134 || (Modifier.isStatic(methods[i].getModifiers()))
135 || (methods[i].getExceptionTypes().length > 0)
136 || (!methods[i].getReturnType().getName().equals("void"))) {
137 throw new IllegalArgumentException("Invalid PostConstruct annotation");
138 }
139 postConstruct = methods[i];
140 }
141 }
142
143 // At the end the postconstruct annotated
144 // method is invoked
145 if (postConstruct != null) {
146 boolean accessibility = postConstruct.isAccessible();
147 postConstruct.setAccessible(true);
148 postConstruct.invoke(managedBean);
149 postConstruct.setAccessible(accessibility);
150 }
151 } catch (Exception e) {
152 LOG.error("PostConstruct failed on managed bean.", e);
153 }
154 }
155
156 /**
157 * Inject naming resources into a managed bean and then call methods
158 * annotated with @PostConstruct.
159 */
160 public void inject(Object managedBean) throws InjectionProviderException {
161 if (this.namingContext != null) {
162 try {
163
164 // Initialize fields annotations
165 Field[] fields = managedBean.getClass().getDeclaredFields();
166 for (int i = 0; i < fields.length; i++) {
167 if (fields[i].isAnnotationPresent(Resource.class)) {
168 Resource annotation = (Resource) fields[i].getAnnotation(Resource.class);
169 lookupFieldResource(namingContext, managedBean, fields[i], annotation.name());
170 }
171 if (fields[i].isAnnotationPresent(EJB.class)) {
172 EJB annotation = (EJB) fields[i].getAnnotation(EJB.class);
173 lookupFieldResource(namingContext, managedBean, fields[i], annotation.name());
174 }
175 if (fields[i].isAnnotationPresent(WebServiceRef.class)) {
176 WebServiceRef annotation =
177 (WebServiceRef) fields[i].getAnnotation(WebServiceRef.class);
178 lookupFieldResource(namingContext, managedBean, fields[i], annotation.name());
179 }
180 if (fields[i].isAnnotationPresent(PersistenceContext.class)) {
181 PersistenceContext annotation =
182 (PersistenceContext) fields[i].getAnnotation(PersistenceContext.class);
183 lookupFieldResource(namingContext, managedBean, fields[i], annotation.name());
184 }
185 if (fields[i].isAnnotationPresent(PersistenceUnit.class)) {
186 PersistenceUnit annotation =
187 (PersistenceUnit) fields[i].getAnnotation(PersistenceUnit.class);
188 lookupFieldResource(namingContext, managedBean, fields[i], annotation.name());
189 }
190 }
191
192 // Initialize methods annotations
193 Method[] methods = managedBean.getClass().getDeclaredMethods();
194 for (int i = 0; i < methods.length; i++) {
195 if (methods[i].isAnnotationPresent(Resource.class)) {
196 Resource annotation = (Resource) methods[i].getAnnotation(Resource.class);
197 lookupMethodResource(namingContext, managedBean, methods[i], annotation.name());
198 }
199 if (methods[i].isAnnotationPresent(EJB.class)) {
200 EJB annotation = (EJB) methods[i].getAnnotation(EJB.class);
201 lookupMethodResource(namingContext, managedBean, methods[i], annotation.name());
202 }
203 if (methods[i].isAnnotationPresent(WebServiceRef.class)) {
204 WebServiceRef annotation =
205 (WebServiceRef) methods[i].getAnnotation(WebServiceRef.class);
206 lookupMethodResource(namingContext, managedBean, methods[i], annotation.name());
207 }
208 if (methods[i].isAnnotationPresent(PersistenceContext.class)) {
209 PersistenceContext annotation =
210 (PersistenceContext) methods[i].getAnnotation(PersistenceContext.class);
211 lookupMethodResource(namingContext, managedBean, methods[i], annotation.name());
212 }
213 if (methods[i].isAnnotationPresent(PersistenceUnit.class)) {
214 PersistenceUnit annotation =
215 (PersistenceUnit) methods[i].getAnnotation(PersistenceUnit.class);
216 lookupMethodResource(namingContext, managedBean, methods[i], annotation.name());
217 }
218 }
219
220 } catch (Exception e) {
221 LOG.error("Injection failed on managed bean.", e);
222 }
223 }
224
225 }
226
227 /**
228 * Inject resources in specified field.
229 */
230 protected static void lookupFieldResource(javax.naming.Context context,
231 Object instance, Field field, String name)
232 throws NamingException, IllegalAccessException {
233
234 Object lookedupResource = null;
235 boolean accessibility = false;
236
237 if ((name != null) &&
238 (name.length() > 0)) {
239 lookedupResource = context.lookup(name);
240 } else {
241 lookedupResource = context.lookup(instance.getClass().getName() + "/" + field.getName());
242 }
243
244 accessibility = field.isAccessible();
245 field.setAccessible(true);
246 field.set(instance, lookedupResource);
247 field.setAccessible(accessibility);
248 }
249
250
251 /**
252 * Inject resources in specified method.
253 */
254 protected static void lookupMethodResource(javax.naming.Context context,
255 Object instance, Method method, String name)
256 throws NamingException, IllegalAccessException, InvocationTargetException {
257
258 if (!method.getName().startsWith("set")
259 || method.getParameterTypes().length != 1
260 || !method.getReturnType().getName().equals("void")) {
261 throw new IllegalArgumentException("Invalid method resource injection annotation");
262 }
263
264 Object lookedupResource = null;
265 boolean accessibility = false;
266
267 if ((name != null) &&
268 (name.length() > 0)) {
269 lookedupResource = context.lookup(name);
270 } else {
271 lookedupResource =
272 context.lookup(instance.getClass().getName() + "/" + method.getName().substring(3));
273 }
274
275 accessibility = method.isAccessible();
276 method.setAccessible(true);
277 method.invoke(instance, lookedupResource);
278 method.setAccessible(accessibility);
279 }
280
281 }