KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*
2  * The Apache Software License, Version 1.1
3  *
4  *
5  * Copyright (c) 2001-2003 The Apache Software Foundation. All rights
6  * reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  * notice, this list of conditions and the following disclaimer in
17  * the documentation and/or other materials provided with the
18  * distribution.
19  *
20  * 3. The end-user documentation included with the redistribution,
21  * if any, must include the following acknowledgment:
22  * "This product includes software developed by the
23  * Apache Software Foundation (http://www.apache.org/)."
24  * Alternately, this acknowledgment may appear in the software itself,
25  * if and wherever such third-party acknowledgments normally appear.
26  *
27  * 4. The names "Axis" and "Apache Software Foundation" must
28  * not be used to endorse or promote products derived from this
29  * software without prior written permission. For written
30  * permission, please contact apache@apache.org.
31  *
32  * 5. Products derived from this software may not be called "Apache",
33  * nor may "Apache" appear in their name, without prior written
34  * permission of the Apache Software Foundation.
35  *
36  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39  * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
40  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
41  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
42  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
43  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
44  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
45  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
46  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47  * SUCH DAMAGE.
48  * ====================================================================
49  *
50  * This software consists of voluntary contributions made by many
51  * individuals on behalf of the Apache Software Foundation. For more
52  * information on the Apache Software Foundation, please see
53  * <http://www.apache.org/>.
54  */

55
56 package org.jboss.axis.providers.java;
57
58 import org.jboss.axis.AxisFault;
59 import org.jboss.axis.Handler;
60 import org.jboss.axis.MessageContext;
61 import org.jboss.axis.handlers.soap.SOAPService;
62 import org.jboss.axis.utils.ClassUtils;
63 import org.jboss.axis.utils.Messages;
64 import org.jboss.logging.Logger;
65
66 import javax.naming.Context JavaDoc;
67 import javax.naming.InitialContext JavaDoc;
68 import java.lang.reflect.Method JavaDoc;
69 import java.util.Properties JavaDoc;
70
71 /**
72  * A basic EJB Provider
73  *
74  * @author Carl Woolf (cwoolf@macromedia.com)
75  * @author Tom Jordahl (tomj@macromedia.com)
76  * @author Cédric Chabanois (cchabanois@ifrance.com)
77  */

78 public class EJBProvider extends RPCProvider
79 {
80    private static Logger log = Logger.getLogger(EJBProvider.class.getName());
81
82    public static final String JavaDoc OPTION_BEANNAME = "beanJndiName";
83    public static final String JavaDoc OPTION_HOMEINTERFACENAME = "homeInterfaceName";
84    public static final String JavaDoc OPTION_REMOTEINTERFACENAME = "remoteInterfaceName";
85    public static final String JavaDoc OPTION_LOCALHOMEINTERFACENAME = "localHomeInterfaceName";
86    public static final String JavaDoc OPTION_LOCALINTERFACENAME = "localInterfaceName";
87
88
89    public static final String JavaDoc jndiContextClass = "jndiContextClass";
90    public static final String JavaDoc jndiURL = "jndiURL";
91    public static final String JavaDoc jndiUsername = "jndiUser";
92    public static final String JavaDoc jndiPassword = "jndiPassword";
93
94    protected static final Class JavaDoc[] empty_class_array = new Class JavaDoc[0];
95    protected static final Object JavaDoc[] empty_object_array = new Object JavaDoc[0];
96
97    private static InitialContext JavaDoc cached_context = null;
98
99    ///////////////////////////////////////////////////////////////
100
///////////////////////////////////////////////////////////////
101
/////// Default methods from JavaProvider ancestor, overridden
102
/////// for ejbeans
103
///////////////////////////////////////////////////////////////
104
///////////////////////////////////////////////////////////////
105

106    /**
107     * Return a object which implements the service.
108     *
109     * @param msgContext the message context
110     * @param clsName The JNDI name of the EJB home class
111     * @return an object that implements the service
112     */

113    protected Object JavaDoc makeNewServiceObject(MessageContext msgContext,
114                                          String JavaDoc clsName)
115            throws Exception JavaDoc
116    {
117       String JavaDoc remoteHomeName = getStrOption(OPTION_HOMEINTERFACENAME,
118               msgContext.getService());
119       String JavaDoc localHomeName = getStrOption(OPTION_LOCALHOMEINTERFACENAME,
120               msgContext.getService());
121       String JavaDoc homeName = (remoteHomeName != null ? remoteHomeName : localHomeName);
122
123       if (homeName == null)
124       {
125          // cannot find both remote home and local home
126
throw new AxisFault(Messages.getMessage("noOption00",
127                  OPTION_HOMEINTERFACENAME,
128                  msgContext.getTargetService()));
129       }
130
131       // Load the Home class name given in the config file
132
Class JavaDoc homeClass = ClassUtils.forName(homeName, true, msgContext.getClassLoader());
133
134       // we create either the ejb using either the RemoteHome or LocalHome object
135
if (remoteHomeName != null)
136          return createRemoteEJB(msgContext, clsName, homeClass);
137       else
138          return createLocalEJB(msgContext, clsName, homeClass);
139    }
140
141    /**
142     * Create an EJB using a remote home object
143     *
144     * @param msgContext the message context
145     * @param beanJndiName The JNDI name of the EJB remote home class
146     * @param homeClass the class of the home interface
147     * @return an EJB
148     */

149    private Object JavaDoc createRemoteEJB(MessageContext msgContext,
150                                   String JavaDoc beanJndiName,
151                                   Class JavaDoc homeClass)
152            throws Exception JavaDoc
153    {
154       // Get the EJB Home object from JNDI
155
Object JavaDoc ejbHome = getEJBHome(msgContext.getService(),
156               msgContext, beanJndiName);
157       Object JavaDoc ehome = javax.rmi.PortableRemoteObject.narrow(ejbHome, homeClass);
158
159       // Invoke the create method of the ejbHome class without actually
160
// touching any EJB classes (i.e. no cast to EJBHome)
161
Method JavaDoc createMethod = homeClass.getMethod("create", empty_class_array);
162       Object JavaDoc result = createMethod.invoke(ehome, empty_object_array);
163
164       return result;
165    }
166
167    /**
168     * Create an EJB using a local home object
169     *
170     * @param msgContext the message context
171     * @param beanJndiName The JNDI name of the EJB local home class
172     * @param homeClass the class of the home interface
173     * @return an EJB
174     */

175    private Object JavaDoc createLocalEJB(MessageContext msgContext,
176                                  String JavaDoc beanJndiName,
177                                  Class JavaDoc homeClass)
178            throws Exception JavaDoc
179    {
180       // Get the EJB Home object from JNDI
181
Object JavaDoc ejbHome = getEJBHome(msgContext.getService(),
182               msgContext, beanJndiName);
183
184       // the home object is a local home object
185
Object JavaDoc ehome;
186       if (homeClass.isInstance(ejbHome))
187          ehome = ejbHome;
188       else
189          throw new ClassCastException JavaDoc(Messages.getMessage("badEjbHomeType"));
190
191       // Invoke the create method of the ejbHome class without actually
192
// touching any EJB classes (i.e. no cast to EJBLocalHome)
193
Method JavaDoc createMethod = homeClass.getMethod("create", empty_class_array);
194       Object JavaDoc result = createMethod.invoke(ehome, empty_object_array);
195
196       return result;
197    }
198
199    /**
200     * Tells if the ejb that will be used to handle this service is a remote
201     * one
202     */

203    private boolean isRemoteEjb(SOAPService service)
204    {
205       return getStrOption(OPTION_HOMEINTERFACENAME, service) != null;
206    }
207
208    /**
209     * Tells if the ejb that will be used to handle this service is a local
210     * one
211     */

212    private boolean isLocalEjb(SOAPService service)
213    {
214       return (!isRemoteEjb(service)) &&
215               (getStrOption(OPTION_LOCALHOMEINTERFACENAME, service) != null);
216    }
217
218
219    /**
220     * Return the option in the configuration that contains the service class
221     * name. In the EJB case, it is the JNDI name of the bean.
222     */

223    protected String JavaDoc getServiceClassNameOptionName()
224    {
225       return OPTION_BEANNAME;
226    }
227
228    /**
229     * Get a String option by looking first in the service options,
230     * and then at the Handler's options. This allows defaults to be
231     * specified at the provider level, and then overriden for particular
232     * services.
233     *
234     * @param optionName the option to retrieve
235     * @return String the value of the option or null if not found in
236     * either scope
237     */

238    protected String JavaDoc getStrOption(String JavaDoc optionName, Handler service)
239    {
240       String JavaDoc value = null;
241       if (service != null)
242          value = (String JavaDoc)service.getOption(optionName);
243       if (value == null)
244          value = (String JavaDoc)getOption(optionName);
245       return value;
246    }
247
248    /**
249     * Get the remote interface of an ejb from its home class.
250     * This function can only be used for remote ejbs
251     *
252     * @param beanJndiName the jndi name of the ejb
253     * @param service the soap service
254     * @param msgContext the message context (can be null)
255     */

256    private Class JavaDoc getRemoteInterfaceClassFromHome(String JavaDoc beanJndiName,
257                                                  SOAPService service,
258                                                  MessageContext msgContext)
259            throws Exception JavaDoc
260    {
261       // Get the EJB Home object from JNDI
262
Object JavaDoc ejbHome = getEJBHome(service, msgContext, beanJndiName);
263
264       String JavaDoc homeName = getStrOption(OPTION_HOMEINTERFACENAME,
265               service);
266       if (homeName == null)
267          throw new AxisFault(Messages.getMessage("noOption00",
268                  OPTION_HOMEINTERFACENAME,
269                  service.getName()));
270
271       // Load the Home class name given in the config file
272
ClassLoader JavaDoc cl = (msgContext != null) ?
273               msgContext.getClassLoader() :
274               Thread.currentThread().getContextClassLoader();
275       Class JavaDoc homeClass = ClassUtils.forName(homeName, true, cl);
276
277
278       // Make sure the object we got back from JNDI is the same type
279
// as the what is specified in the config file
280
Object JavaDoc ehome = javax.rmi.PortableRemoteObject.narrow(ejbHome, homeClass);
281
282       // This code requires the use of ejb.jar, so we do the stuff below
283
// EJBHome ejbHome = (EJBHome) ehome;
284
// EJBMetaData meta = ejbHome.getEJBMetaData();
285
// Class interfaceClass = meta.getRemoteInterfaceClass();
286

287       // Invoke the getEJBMetaData method of the ejbHome class without
288
// actually touching any EJB classes (i.e. no cast to EJBHome)
289
Method JavaDoc getEJBMetaData =
290               homeClass.getMethod("getEJBMetaData", empty_class_array);
291       Object JavaDoc metaData = getEJBMetaData.invoke(ehome, empty_object_array);
292       Method JavaDoc getRemoteInterfaceClass =
293               metaData.getClass().getMethod("getRemoteInterfaceClass",
294                       empty_class_array);
295       return (Class JavaDoc)getRemoteInterfaceClass.invoke(metaData,
296               empty_object_array);
297    }
298
299
300    /**
301     * Get the class description for the EJB Remote or Local Interface,
302     * which is what we are interested in exposing to the world (i.e. in WSDL).
303     *
304     * @param msgContext the message context (can be null)
305     * @param beanJndiName the JNDI name of the EJB
306     * @return the class info of the EJB remote or local interface
307     */

308    protected Class JavaDoc getServiceClass(String JavaDoc beanJndiName,
309                                    SOAPService service,
310                                    MessageContext msgContext)
311            throws AxisFault
312    {
313       Class JavaDoc interfaceClass = null;
314
315       try
316       {
317          // First try to get the interface class from the configuation
318
// Note that we don't verify that remote remoteInterfaceName is used for
319
// remote ejb and localInterfaceName for local ejb. Should we ?
320
String JavaDoc remoteInterfaceName =
321                  getStrOption(OPTION_REMOTEINTERFACENAME, service);
322          String JavaDoc localInterfaceName =
323                  getStrOption(OPTION_LOCALINTERFACENAME, service);
324          String JavaDoc interfaceName = (remoteInterfaceName != null ? remoteInterfaceName : localInterfaceName);
325
326          if (interfaceName != null)
327          {
328             ClassLoader JavaDoc cl = (msgContext != null) ?
329                     msgContext.getClassLoader() :
330                     Thread.currentThread().getContextClassLoader();
331             interfaceClass = ClassUtils.forName(interfaceName,
332                     true,
333                     cl);
334          }
335          else
336          {
337             // cannot get the interface name from the configuration, we get
338
// it from the EJB Home (if remote)
339
if (isRemoteEjb(service))
340             {
341                String JavaDoc remoteHomeName = getStrOption(OPTION_HOMEINTERFACENAME,
342                        service);
343                interfaceClass = getRemoteInterfaceClassFromHome(beanJndiName,
344                        service,
345                        msgContext);
346             }
347             else if (isLocalEjb(service))
348             {
349                // we cannot get the local interface from the local ejb home
350
// localInterfaceName is mandatory for local ejbs
351
throw new AxisFault(Messages.getMessage("noOption00",
352                        OPTION_LOCALINTERFACENAME,
353                        service.getName()));
354             }
355             else
356             {
357                // neither a local ejb or a remote one ...
358
throw new AxisFault(Messages.getMessage("noOption00",
359                        OPTION_HOMEINTERFACENAME,
360                        service.getName()));
361             }
362          }
363       }
364       catch (Exception JavaDoc e)
365       {
366          throw AxisFault.makeFault(e);
367       }
368
369       // got it, return it
370
return interfaceClass;
371    }
372
373    /**
374     * Common routine to do the JNDI lookup on the Home interface object
375     * username and password for jndi lookup are got from the configuration or from
376     * the messageContext if not found in the configuration
377     */

378    private Object JavaDoc getEJBHome(SOAPService serviceHandler,
379                              MessageContext msgContext,
380                              String JavaDoc beanJndiName)
381            throws AxisFault
382    {
383       Object JavaDoc ejbHome = null;
384
385       // Set up an InitialContext and use it get the beanJndiName from JNDI
386
try
387       {
388          Properties JavaDoc properties = null;
389
390          // collect all the properties we need to access JNDI:
391
// username, password, factoryclass, contextUrl
392

393          // username
394
String JavaDoc username = getStrOption(jndiUsername, serviceHandler);
395          if ((username == null) && (msgContext != null))
396             username = msgContext.getUsername();
397          if (username != null)
398          {
399             if (properties == null)
400                properties = new Properties JavaDoc();
401             properties.setProperty(Context.SECURITY_PRINCIPAL, username);
402          }
403
404          // password
405
String JavaDoc password = getStrOption(jndiPassword, serviceHandler);
406          if ((password == null) && (msgContext != null))
407             password = msgContext.getPassword();
408          if (password != null)
409          {
410             if (properties == null)
411                properties = new Properties JavaDoc();
412             properties.setProperty(Context.SECURITY_CREDENTIALS, password);
413          }
414
415          // factory class
416
String JavaDoc factoryClass = getStrOption(jndiContextClass, serviceHandler);
417          if (factoryClass != null)
418          {
419             if (properties == null)
420                properties = new Properties JavaDoc();
421             properties.setProperty(Context.INITIAL_CONTEXT_FACTORY, factoryClass);
422          }
423
424          // contextUrl
425
String JavaDoc contextUrl = getStrOption(jndiURL, serviceHandler);
426          if (contextUrl != null)
427          {
428             if (properties == null)
429                properties = new Properties JavaDoc();
430             properties.setProperty(Context.PROVIDER_URL, contextUrl);
431          }
432
433          // get context using these properties
434
InitialContext JavaDoc context = getContext(properties);
435
436          // if we didn't get a context, fail
437
if (context == null)
438             throw new AxisFault(Messages.getMessage("cannotCreateInitialContext00"));
439
440          ejbHome = getEJBHome(context, beanJndiName);
441
442          if (ejbHome == null)
443             throw new AxisFault(Messages.getMessage("cannotFindJNDIHome00", beanJndiName));
444       }
445               // Should probably catch javax.naming.NameNotFoundException here
446
catch (Exception JavaDoc exception)
447       {
448          log.info(Messages.getMessage("toAxisFault00"), exception);
449          throw AxisFault.makeFault(exception);
450       }
451
452       return ejbHome;
453    }
454
455    protected InitialContext JavaDoc getCachedContext()
456            throws javax.naming.NamingException JavaDoc
457    {
458       if (cached_context == null)
459          cached_context = new InitialContext JavaDoc();
460       return cached_context;
461    }
462
463
464    protected InitialContext JavaDoc getContext(Properties JavaDoc properties)
465            throws AxisFault, javax.naming.NamingException JavaDoc
466    {
467       // if we got any stuff from the configuration file
468
// create a new context using these properties
469
// otherwise, we get a default context and cache it for next time
470
return ((properties == null)
471               ? getCachedContext()
472               : new InitialContext JavaDoc(properties));
473    }
474
475    protected Object JavaDoc getEJBHome(InitialContext JavaDoc context, String JavaDoc beanJndiName)
476            throws AxisFault, javax.naming.NamingException JavaDoc
477    {
478       // Do the JNDI lookup
479
return context.lookup(beanJndiName);
480    }
481
482    /**
483     * Fill in a service description with the correct impl class
484     * and typemapping set.
485     */

486 // public void initServiceDesc(SOAPService service, MessageContext msgContext)
487
// throws AxisFault
488
// {
489
// // the service class used to fill service description is the EJB Remote/Local Interface
490
// // we add EJBObject and EJBLocalObject as stop classes because we
491
// // don't want any of their methods in the wsdl ...
492
// ServiceDesc serviceDescription = service.getServiceDescription();
493
// ArrayList stopClasses = serviceDescription.getStopClasses();
494
// if (stopClasses == null)
495
// stopClasses = new ArrayList();
496
// stopClasses.add("javax.ejb.EJBObject");
497
// stopClasses.add("javax.ejb.EJBLocalObject");
498
// serviceDescription.setStopClasses(stopClasses);
499
// super.initServiceDesc(service,msgContext);
500
// }
501

502 }
503
Popular Tags