KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > axis > providers > java > EJBProvider


1 /*
2  * Copyright 2001-2004 The Apache Software Foundation.
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
17 package org.apache.axis.providers.java;
18
19 import java.lang.reflect.Method JavaDoc;
20 import java.lang.reflect.InvocationTargetException JavaDoc;
21 import java.util.Properties JavaDoc;
22
23 import javax.naming.Context JavaDoc;
24 import javax.naming.InitialContext JavaDoc;
25
26 import org.apache.axis.AxisFault;
27 import org.apache.axis.Constants;
28 import org.apache.axis.Handler;
29 import org.apache.axis.MessageContext;
30 import org.apache.axis.components.logger.LogFactory;
31 import org.apache.axis.handlers.soap.SOAPService;
32 import org.apache.axis.utils.ClassUtils;
33 import org.apache.axis.utils.Messages;
34 import org.apache.commons.logging.Log;
35
36 /**
37  * A basic EJB Provider
38  *
39  * @author Carl Woolf (cwoolf@macromedia.com)
40  * @author Tom Jordahl (tomj@macromedia.com)
41  * @author C?dric Chabanois (cchabanois@ifrance.com)
42  */

43 public class EJBProvider extends RPCProvider
44 {
45     protected static Log log =
46         LogFactory.getLog(EJBProvider.class.getName());
47
48     // The enterprise category is for stuff that an enterprise product might
49
// want to track, but in a simple environment (like the AXIS build) would
50
// be nothing more than a nuisance.
51
protected static Log entLog =
52         LogFactory.getLog(Constants.ENTERPRISE_LOG_CATEGORY);
53
54     public static final String JavaDoc OPTION_BEANNAME = "beanJndiName";
55     public static final String JavaDoc OPTION_HOMEINTERFACENAME = "homeInterfaceName";
56     public static final String JavaDoc OPTION_REMOTEINTERFACENAME = "remoteInterfaceName";
57     public static final String JavaDoc OPTION_LOCALHOMEINTERFACENAME = "localHomeInterfaceName";
58     public static final String JavaDoc OPTION_LOCALINTERFACENAME = "localInterfaceName";
59     
60     
61     public static final String JavaDoc jndiContextClass = "jndiContextClass";
62     public static final String JavaDoc jndiURL = "jndiURL";
63     public static final String JavaDoc jndiUsername = "jndiUser";
64     public static final String JavaDoc jndiPassword = "jndiPassword";
65     
66     protected static final Class JavaDoc[] empty_class_array = new Class JavaDoc[0];
67     protected static final Object JavaDoc[] empty_object_array = new Object JavaDoc[0];
68     
69     private static InitialContext JavaDoc cached_context = null;
70
71     ///////////////////////////////////////////////////////////////
72
///////////////////////////////////////////////////////////////
73
/////// Default methods from JavaProvider ancestor, overridden
74
/////// for ejbeans
75
///////////////////////////////////////////////////////////////
76
///////////////////////////////////////////////////////////////
77

78     /**
79      * Return a object which implements the service.
80      *
81      * @param msgContext the message context
82      * @param clsName The JNDI name of the EJB home class
83      * @return an object that implements the service
84      */

85     protected Object JavaDoc makeNewServiceObject(MessageContext msgContext,
86                                            String JavaDoc clsName)
87         throws Exception JavaDoc
88     {
89         String JavaDoc remoteHomeName = getStrOption(OPTION_HOMEINTERFACENAME,
90                                                 msgContext.getService());
91         String JavaDoc localHomeName = getStrOption(OPTION_LOCALHOMEINTERFACENAME,
92                                                 msgContext.getService());
93         String JavaDoc homeName = (remoteHomeName != null ? remoteHomeName:localHomeName);
94
95         if (homeName == null) {
96             // cannot find both remote home and local home
97
throw new AxisFault(
98                 Messages.getMessage("noOption00",
99                                     OPTION_HOMEINTERFACENAME,
100                                     msgContext.getTargetService()));
101         }
102                                                         
103         // Load the Home class name given in the config file
104
Class JavaDoc homeClass = ClassUtils.forName(homeName, true, msgContext.getClassLoader());
105
106         // we create either the ejb using either the RemoteHome or LocalHome object
107
if (remoteHomeName != null)
108             return createRemoteEJB(msgContext, clsName, homeClass);
109         else
110             return createLocalEJB(msgContext, clsName, homeClass);
111     }
112
113     /**
114      * Create an EJB using a remote home object
115      *
116      * @param msgContext the message context
117      * @param beanJndiName The JNDI name of the EJB remote home class
118      * @param homeClass the class of the home interface
119      * @return an EJB
120      */

121     private Object JavaDoc createRemoteEJB(MessageContext msgContext,
122                                     String JavaDoc beanJndiName,
123                                     Class JavaDoc homeClass)
124         throws Exception JavaDoc
125     {
126         // Get the EJB Home object from JNDI
127
Object JavaDoc ejbHome = getEJBHome(msgContext.getService(),
128                                     msgContext, beanJndiName);
129         Object JavaDoc ehome = javax.rmi.PortableRemoteObject.narrow(ejbHome, homeClass);
130
131         // Invoke the create method of the ejbHome class without actually
132
// touching any EJB classes (i.e. no cast to EJBHome)
133
Method JavaDoc createMethod = homeClass.getMethod("create", empty_class_array);
134         Object JavaDoc result = createMethod.invoke(ehome, empty_object_array);
135         
136         return result;
137     }
138
139     /**
140      * Create an EJB using a local home object
141      *
142      * @param msgContext the message context
143      * @param beanJndiName The JNDI name of the EJB local home class
144      * @param homeClass the class of the home interface
145      * @return an EJB
146      */

147     private Object JavaDoc createLocalEJB(MessageContext msgContext,
148                                    String JavaDoc beanJndiName,
149                                    Class JavaDoc homeClass)
150         throws Exception JavaDoc
151     {
152         // Get the EJB Home object from JNDI
153
Object JavaDoc ejbHome = getEJBHome(msgContext.getService(),
154                                     msgContext, beanJndiName);
155
156         // the home object is a local home object
157
Object JavaDoc ehome;
158         if (homeClass.isInstance(ejbHome))
159           ehome = ejbHome;
160         else
161           throw new ClassCastException JavaDoc(
162                   Messages.getMessage("badEjbHomeType"));
163           
164         // Invoke the create method of the ejbHome class without actually
165
// touching any EJB classes (i.e. no cast to EJBLocalHome)
166
Method JavaDoc createMethod = homeClass.getMethod("create", empty_class_array);
167         Object JavaDoc result = createMethod.invoke(ehome, empty_object_array);
168                                
169         return result;
170     }
171
172     /**
173      * Tells if the ejb that will be used to handle this service is a remote
174      * one
175      */

176     private boolean isRemoteEjb(SOAPService service)
177     {
178         return getStrOption(OPTION_HOMEINTERFACENAME,service) != null;
179     }
180
181     /**
182      * Tells if the ejb that will be used to handle this service is a local
183      * one
184      */

185     private boolean isLocalEjb(SOAPService service)
186     {
187         return (!isRemoteEjb(service)) &&
188           (getStrOption(OPTION_LOCALHOMEINTERFACENAME,service) != null);
189     }
190
191
192     /**
193      * Return the option in the configuration that contains the service class
194      * name. In the EJB case, it is the JNDI name of the bean.
195      */

196     protected String JavaDoc getServiceClassNameOptionName()
197     {
198         return OPTION_BEANNAME;
199     }
200
201     /**
202      * Get a String option by looking first in the service options,
203      * and then at the Handler's options. This allows defaults to be
204      * specified at the provider level, and then overriden for particular
205      * services.
206      *
207      * @param optionName the option to retrieve
208      * @return String the value of the option or null if not found in
209      * either scope
210      */

211     protected String JavaDoc getStrOption(String JavaDoc optionName, Handler service)
212     {
213         String JavaDoc value = null;
214         if (service != null)
215             value = (String JavaDoc)service.getOption(optionName);
216         if (value == null)
217             value = (String JavaDoc)getOption(optionName);
218         return value;
219     }
220
221     /**
222      * Get the remote interface of an ejb from its home class.
223      * This function can only be used for remote ejbs
224      *
225      * @param beanJndiName the jndi name of the ejb
226      * @param service the soap service
227      * @param msgContext the message context (can be null)
228      */

229     private Class JavaDoc getRemoteInterfaceClassFromHome(String JavaDoc beanJndiName,
230                                                    SOAPService service,
231                                                    MessageContext msgContext)
232         throws Exception JavaDoc
233     {
234         // Get the EJB Home object from JNDI
235
Object JavaDoc ejbHome = getEJBHome(service, msgContext, beanJndiName);
236
237         String JavaDoc homeName = getStrOption(OPTION_HOMEINTERFACENAME,
238                                        service);
239         if (homeName == null)
240             throw new AxisFault(
241                     Messages.getMessage("noOption00",
242                                         OPTION_HOMEINTERFACENAME,
243                                         service.getName()));
244
245         // Load the Home class name given in the config file
246
ClassLoader JavaDoc cl = (msgContext != null) ?
247                 msgContext.getClassLoader() :
248                 Thread.currentThread().getContextClassLoader();
249         Class JavaDoc homeClass = ClassUtils.forName(homeName, true, cl);
250
251
252         // Make sure the object we got back from JNDI is the same type
253
// as the what is specified in the config file
254
Object JavaDoc ehome = javax.rmi.PortableRemoteObject.narrow(ejbHome, homeClass);
255
256         // This code requires the use of ejb.jar, so we do the stuff below
257
// EJBHome ejbHome = (EJBHome) ehome;
258
// EJBMetaData meta = ejbHome.getEJBMetaData();
259
// Class interfaceClass = meta.getRemoteInterfaceClass();
260

261         // Invoke the getEJBMetaData method of the ejbHome class without
262
// actually touching any EJB classes (i.e. no cast to EJBHome)
263
Method JavaDoc getEJBMetaData =
264                 homeClass.getMethod("getEJBMetaData", empty_class_array);
265         Object JavaDoc metaData = getEJBMetaData.invoke(ehome, empty_object_array);
266         Method JavaDoc getRemoteInterfaceClass =
267                 metaData.getClass().getMethod("getRemoteInterfaceClass",
268                                                   empty_class_array);
269         return (Class JavaDoc) getRemoteInterfaceClass.invoke(metaData,
270                                                        empty_object_array);
271     }
272
273     
274     /**
275      * Get the class description for the EJB Remote or Local Interface,
276      * which is what we are interested in exposing to the world (i.e. in WSDL).
277      *
278      * @param msgContext the message context (can be null)
279      * @param beanJndiName the JNDI name of the EJB
280      * @return the class info of the EJB remote or local interface
281      */

282     protected Class JavaDoc getServiceClass(String JavaDoc beanJndiName,
283                                     SOAPService service,
284                                     MessageContext msgContext)
285         throws AxisFault
286     {
287         Class JavaDoc interfaceClass = null;
288         
289         try {
290             // First try to get the interface class from the configuation
291
// Note that we don't verify that remote remoteInterfaceName is used for
292
// remote ejb and localInterfaceName for local ejb. Should we ?
293
String JavaDoc remoteInterfaceName =
294                     getStrOption(OPTION_REMOTEINTERFACENAME, service);
295             String JavaDoc localInterfaceName =
296                     getStrOption(OPTION_LOCALINTERFACENAME, service);
297             String JavaDoc interfaceName = (remoteInterfaceName != null ? remoteInterfaceName : localInterfaceName);
298
299             if(interfaceName != null){
300                 ClassLoader JavaDoc cl = (msgContext != null) ?
301                         msgContext.getClassLoader() :
302                         Thread.currentThread().getContextClassLoader();
303                 interfaceClass = ClassUtils.forName(interfaceName,
304                                                     true,
305                                                     cl);
306             }
307             else
308             {
309                 // cannot get the interface name from the configuration, we get
310
// it from the EJB Home (if remote)
311
if (isRemoteEjb(service)) {
312                     interfaceClass = getRemoteInterfaceClassFromHome(beanJndiName,
313                                                                      service,
314                                                                      msgContext);
315                 }
316                 else
317                 if (isLocalEjb(service)) {
318                     // we cannot get the local interface from the local ejb home
319
// localInterfaceName is mandatory for local ejbs
320
throw new AxisFault(
321                             Messages.getMessage("noOption00",
322                                                 OPTION_LOCALINTERFACENAME,
323                                                 service.getName()));
324                 }
325                 else
326                 {
327                     // neither a local ejb or a remote one ...
328
throw new AxisFault(Messages.getMessage("noOption00",
329                                                 OPTION_HOMEINTERFACENAME,
330                                                 service.getName()));
331                 }
332             }
333         } catch (Exception JavaDoc e) {
334             throw AxisFault.makeFault(e);
335         }
336
337         // got it, return it
338
return interfaceClass;
339     }
340
341     /**
342      * Common routine to do the JNDI lookup on the Home interface object
343      * username and password for jndi lookup are got from the configuration or from
344      * the messageContext if not found in the configuration
345      */

346     private Object JavaDoc getEJBHome(SOAPService serviceHandler,
347                               MessageContext msgContext,
348                               String JavaDoc beanJndiName)
349         throws AxisFault
350     {
351         Object JavaDoc ejbHome = null;
352         
353         // Set up an InitialContext and use it get the beanJndiName from JNDI
354
try {
355             Properties JavaDoc properties = null;
356
357             // collect all the properties we need to access JNDI:
358
// username, password, factoryclass, contextUrl
359

360             // username
361
String JavaDoc username = getStrOption(jndiUsername, serviceHandler);
362             if ((username == null) && (msgContext != null))
363                username = msgContext.getUsername();
364             if (username != null) {
365                 if (properties == null)
366                     properties = new Properties JavaDoc();
367                 properties.setProperty(Context.SECURITY_PRINCIPAL, username);
368             }
369
370             // password
371
String JavaDoc password = getStrOption(jndiPassword, serviceHandler);
372             if ((password == null) && (msgContext != null))
373                 password = msgContext.getPassword();
374             if (password != null) {
375                 if (properties == null)
376                     properties = new Properties JavaDoc();
377                 properties.setProperty(Context.SECURITY_CREDENTIALS, password);
378             }
379
380             // factory class
381
String JavaDoc factoryClass = getStrOption(jndiContextClass, serviceHandler);
382             if (factoryClass != null) {
383                 if (properties == null)
384                     properties = new Properties JavaDoc();
385                 properties.setProperty(Context.INITIAL_CONTEXT_FACTORY, factoryClass);
386             }
387
388             // contextUrl
389
String JavaDoc contextUrl = getStrOption(jndiURL, serviceHandler);
390             if (contextUrl != null) {
391                 if (properties == null)
392                     properties = new Properties JavaDoc();
393                 properties.setProperty(Context.PROVIDER_URL, contextUrl);
394             }
395
396             // get context using these properties
397
InitialContext JavaDoc context = getContext(properties);
398
399             // if we didn't get a context, fail
400
if (context == null)
401                 throw new AxisFault( Messages.getMessage("cannotCreateInitialContext00"));
402             
403             ejbHome = getEJBHome(context, beanJndiName);
404
405             if (ejbHome == null)
406                 throw new AxisFault( Messages.getMessage("cannotFindJNDIHome00",beanJndiName));
407         }
408         // Should probably catch javax.naming.NameNotFoundException here
409
catch (Exception JavaDoc exception) {
410             entLog.info(Messages.getMessage("toAxisFault00"), exception);
411             throw AxisFault.makeFault(exception);
412         }
413
414         return ejbHome;
415     }
416     
417     protected InitialContext JavaDoc getCachedContext()
418         throws javax.naming.NamingException JavaDoc
419     {
420         if (cached_context == null)
421             cached_context = new InitialContext JavaDoc();
422         return cached_context;
423     }
424         
425
426     protected InitialContext JavaDoc getContext(Properties JavaDoc properties)
427         throws AxisFault, javax.naming.NamingException JavaDoc
428     {
429         // if we got any stuff from the configuration file
430
// create a new context using these properties
431
// otherwise, we get a default context and cache it for next time
432
return ((properties == null)
433                 ? getCachedContext()
434                 : new InitialContext JavaDoc(properties));
435     }
436
437     protected Object JavaDoc getEJBHome(InitialContext JavaDoc context, String JavaDoc beanJndiName)
438         throws AxisFault, javax.naming.NamingException JavaDoc
439     {
440         // Do the JNDI lookup
441
return context.lookup(beanJndiName);
442     }
443
444     /**
445      * Override the default implementation such that we can include
446      * special handling for {@link java.rmi.ServerException}.
447      * <p/>
448      * Converts {@link java.rmi.ServerException} exceptions to
449      * {@link InvocationTargetException} exceptions with the same cause.
450      * This allows the axis framework to create a SOAP fault.
451      * </p>
452      *
453      * @see org.apache.axis.providers.java.RPCProvider#invokeMethod(org.apache.axis.MessageContext, java.lang.reflect.Method, java.lang.Object, java.lang.Object[])
454      */

455     protected Object JavaDoc invokeMethod(MessageContext msgContext, Method JavaDoc method,
456                                   Object JavaDoc obj, Object JavaDoc[] argValues)
457             throws Exception JavaDoc {
458         try {
459             return super.invokeMethod(msgContext, method, obj, argValues);
460         } catch (InvocationTargetException JavaDoc ite) {
461             Throwable JavaDoc cause = getCause(ite);
462             if (cause instanceof java.rmi.ServerException JavaDoc) {
463                 throw new InvocationTargetException JavaDoc(getCause(cause));
464             }
465             throw ite;
466         }
467     }
468
469     /**
470      * Get the cause of an exception, using reflection so that
471      * it still works under JDK 1.3
472      *
473      * @param original the original exception
474      * @return the cause of the exception, or the given exception if the cause cannot be discovered.
475      */

476     private Throwable JavaDoc getCause(Throwable JavaDoc original) {
477         try {
478             Method JavaDoc method = original.getClass().getMethod("getCause", null);
479             Throwable JavaDoc cause = (Throwable JavaDoc) method.invoke(original, null);
480             if (cause != null) {
481                 return cause;
482             }
483         } catch (NoSuchMethodException JavaDoc nsme) {
484             // ignore, this occurs under JDK 1.3
485
} catch (Throwable JavaDoc t) {
486         }
487         return original;
488     }
489 }
490
Popular Tags