FileDocCategorySizeDatePackage
EJBProvider.javaAPI DocApache Axis 1.419730Sat Apr 22 18:57:26 BST 2006org.apache.axis.providers.java

EJBProvider

public class EJBProvider extends RPCProvider
A basic EJB Provider
author
Carl Woolf (cwoolf@macromedia.com)
author
Tom Jordahl (tomj@macromedia.com)
author
C?dric Chabanois (cchabanois@ifrance.com)

Fields Summary
protected static Log
log
protected static Log
entLog
public static final String
OPTION_BEANNAME
public static final String
OPTION_HOMEINTERFACENAME
public static final String
OPTION_REMOTEINTERFACENAME
public static final String
OPTION_LOCALHOMEINTERFACENAME
public static final String
OPTION_LOCALINTERFACENAME
public static final String
jndiContextClass
public static final String
jndiURL
public static final String
jndiUsername
public static final String
jndiPassword
protected static final Class[]
empty_class_array
protected static final Object[]
empty_object_array
private static InitialContext
cached_context
Constructors Summary
Methods Summary
private java.lang.ObjectcreateLocalEJB(org.apache.axis.MessageContext msgContext, java.lang.String beanJndiName, java.lang.Class homeClass)
Create an EJB using a local home object

param
msgContext the message context
param
beanJndiName The JNDI name of the EJB local home class
param
homeClass the class of the home interface
return
an EJB

        // Get the EJB Home object from JNDI 
        Object ejbHome = getEJBHome(msgContext.getService(),
                                    msgContext, beanJndiName);

        // the home object is a local home object
        Object ehome;
        if (homeClass.isInstance(ejbHome))
          ehome = ejbHome;
        else
          throw new ClassCastException(
                  Messages.getMessage("badEjbHomeType"));
          
        // Invoke the create method of the ejbHome class without actually
        // touching any EJB classes (i.e. no cast to EJBLocalHome)
        Method createMethod = homeClass.getMethod("create", empty_class_array);
        Object result = createMethod.invoke(ehome, empty_object_array);
                               
        return result;
    
private java.lang.ObjectcreateRemoteEJB(org.apache.axis.MessageContext msgContext, java.lang.String beanJndiName, java.lang.Class homeClass)
Create an EJB using a remote home object

param
msgContext the message context
param
beanJndiName The JNDI name of the EJB remote home class
param
homeClass the class of the home interface
return
an EJB

        // Get the EJB Home object from JNDI 
        Object ejbHome = getEJBHome(msgContext.getService(),
                                    msgContext, beanJndiName);
        Object ehome = javax.rmi.PortableRemoteObject.narrow(ejbHome, homeClass);

        // Invoke the create method of the ejbHome class without actually
        // touching any EJB classes (i.e. no cast to EJBHome)
        Method createMethod = homeClass.getMethod("create", empty_class_array);
        Object result = createMethod.invoke(ehome, empty_object_array);
        
        return result;        
    
protected javax.naming.InitialContextgetCachedContext()

        if (cached_context == null)
            cached_context = new InitialContext();
        return cached_context;
    
private java.lang.ThrowablegetCause(java.lang.Throwable original)
Get the cause of an exception, using reflection so that it still works under JDK 1.3

param
original the original exception
return
the cause of the exception, or the given exception if the cause cannot be discovered.

        try {
            Method method = original.getClass().getMethod("getCause", null);
            Throwable cause = (Throwable) method.invoke(original, null);
            if (cause != null) {
                return cause;
            }
        } catch (NoSuchMethodException nsme) {
            // ignore, this occurs under JDK 1.3 
        } catch (Throwable t) {
        }
        return original;
    
protected javax.naming.InitialContextgetContext(java.util.Properties properties)

        // if we got any stuff from the configuration file
        // create a new context using these properties 
        // otherwise, we get a default context and cache it for next time
        return ((properties == null)
                ? getCachedContext()
                : new InitialContext(properties));
    
private java.lang.ObjectgetEJBHome(org.apache.axis.handlers.soap.SOAPService serviceHandler, org.apache.axis.MessageContext msgContext, java.lang.String beanJndiName)
Common routine to do the JNDI lookup on the Home interface object username and password for jndi lookup are got from the configuration or from the messageContext if not found in the configuration

        Object ejbHome = null;
        
        // Set up an InitialContext and use it get the beanJndiName from JNDI
        try {
            Properties properties = null;

            // collect all the properties we need to access JNDI:
            // username, password, factoryclass, contextUrl

            // username
            String username = getStrOption(jndiUsername, serviceHandler);
            if ((username == null) && (msgContext != null))
               username = msgContext.getUsername();
            if (username != null) {
                if (properties == null)
                    properties = new Properties();
                properties.setProperty(Context.SECURITY_PRINCIPAL, username);
            }

            // password
            String password = getStrOption(jndiPassword, serviceHandler);
            if ((password == null) && (msgContext != null))
                password = msgContext.getPassword();
            if (password != null) {
                if (properties == null)
                    properties = new Properties();
                properties.setProperty(Context.SECURITY_CREDENTIALS, password);
            }

            // factory class
            String factoryClass = getStrOption(jndiContextClass, serviceHandler);
            if (factoryClass != null) {
                if (properties == null)
                    properties = new Properties();
                properties.setProperty(Context.INITIAL_CONTEXT_FACTORY, factoryClass);
            }

            // contextUrl
            String contextUrl = getStrOption(jndiURL, serviceHandler);
            if (contextUrl != null) {
                if (properties == null)
                    properties = new Properties();
                properties.setProperty(Context.PROVIDER_URL, contextUrl);
            }

            // get context using these properties 
            InitialContext context = getContext(properties);

            // if we didn't get a context, fail
            if (context == null)
                throw new AxisFault( Messages.getMessage("cannotCreateInitialContext00"));
            
            ejbHome = getEJBHome(context, beanJndiName);

            if (ejbHome == null)
                throw new AxisFault( Messages.getMessage("cannotFindJNDIHome00",beanJndiName));
        }
        // Should probably catch javax.naming.NameNotFoundException here 
        catch (Exception exception) {
            entLog.info(Messages.getMessage("toAxisFault00"), exception);
            throw AxisFault.makeFault(exception);
        }

        return ejbHome;
    
protected java.lang.ObjectgetEJBHome(javax.naming.InitialContext context, java.lang.String beanJndiName)

        // Do the JNDI lookup
        return context.lookup(beanJndiName);
    
private java.lang.ClassgetRemoteInterfaceClassFromHome(java.lang.String beanJndiName, org.apache.axis.handlers.soap.SOAPService service, org.apache.axis.MessageContext msgContext)
Get the remote interface of an ejb from its home class. This function can only be used for remote ejbs

param
beanJndiName the jndi name of the ejb
param
service the soap service
param
msgContext the message context (can be null)

        // Get the EJB Home object from JNDI
        Object ejbHome = getEJBHome(service, msgContext, beanJndiName);

        String homeName = getStrOption(OPTION_HOMEINTERFACENAME,
                                       service);
        if (homeName == null)
            throw new AxisFault(
                    Messages.getMessage("noOption00",
                                        OPTION_HOMEINTERFACENAME,
                                        service.getName()));

        // Load the Home class name given in the config file
        ClassLoader cl = (msgContext != null) ?
                msgContext.getClassLoader() :
                Thread.currentThread().getContextClassLoader();
        Class homeClass = ClassUtils.forName(homeName, true, cl);


        // Make sure the object we got back from JNDI is the same type
        // as the what is specified in the config file
        Object ehome = javax.rmi.PortableRemoteObject.narrow(ejbHome, homeClass);

        // This code requires the use of ejb.jar, so we do the stuff below
        //   EJBHome ejbHome = (EJBHome) ehome;
        //   EJBMetaData meta = ejbHome.getEJBMetaData();
        //   Class interfaceClass = meta.getRemoteInterfaceClass();

        // Invoke the getEJBMetaData method of the ejbHome class without
        // actually touching any EJB classes (i.e. no cast to EJBHome)
        Method getEJBMetaData =
                homeClass.getMethod("getEJBMetaData", empty_class_array);
        Object metaData = getEJBMetaData.invoke(ehome, empty_object_array);
        Method getRemoteInterfaceClass =
                metaData.getClass().getMethod("getRemoteInterfaceClass",
                                                  empty_class_array);
        return (Class) getRemoteInterfaceClass.invoke(metaData,
                                                       empty_object_array);
    
protected java.lang.ClassgetServiceClass(java.lang.String beanJndiName, org.apache.axis.handlers.soap.SOAPService service, org.apache.axis.MessageContext msgContext)
Get the class description for the EJB Remote or Local Interface, which is what we are interested in exposing to the world (i.e. in WSDL).

param
msgContext the message context (can be null)
param
beanJndiName the JNDI name of the EJB
return
the class info of the EJB remote or local interface

        Class interfaceClass = null;
        
        try {
            // First try to get the interface class from the configuation
            // Note that we don't verify that remote remoteInterfaceName is used for
            // remote ejb and localInterfaceName for local ejb. Should we ?
            String remoteInterfaceName = 
                    getStrOption(OPTION_REMOTEINTERFACENAME, service);
            String localInterfaceName = 
                    getStrOption(OPTION_LOCALINTERFACENAME, service);
            String interfaceName = (remoteInterfaceName != null ? remoteInterfaceName : localInterfaceName);

            if(interfaceName != null){
                ClassLoader cl = (msgContext != null) ?
                        msgContext.getClassLoader() :
                        Thread.currentThread().getContextClassLoader();
                interfaceClass = ClassUtils.forName(interfaceName,
                                                    true,
                                                    cl);
            } 
            else
            {
                // cannot get the interface name from the configuration, we get
                // it from the EJB Home (if remote)
                if (isRemoteEjb(service)) {
                    interfaceClass = getRemoteInterfaceClassFromHome(beanJndiName,
                                                                     service,
                                                                     msgContext);
                }
                else 
                if (isLocalEjb(service)) {
                    // we cannot get the local interface from the local ejb home
                    // localInterfaceName is mandatory for local ejbs
                    throw new AxisFault(
                            Messages.getMessage("noOption00", 
                                                OPTION_LOCALINTERFACENAME, 
                                                service.getName()));
                }
                else
                {
                    // neither a local ejb or a remote one ...
                    throw new AxisFault(Messages.getMessage("noOption00", 
                                                OPTION_HOMEINTERFACENAME,
                                                service.getName()));
                }
            }
        } catch (Exception e) {
            throw AxisFault.makeFault(e);
        }

        // got it, return it
       return interfaceClass;
    
protected java.lang.StringgetServiceClassNameOptionName()
Return the option in the configuration that contains the service class name. In the EJB case, it is the JNDI name of the bean.

        return OPTION_BEANNAME;
    
protected java.lang.StringgetStrOption(java.lang.String optionName, org.apache.axis.Handler service)
Get a String option by looking first in the service options, and then at the Handler's options. This allows defaults to be specified at the provider level, and then overriden for particular services.

param
optionName the option to retrieve
return
String the value of the option or null if not found in either scope

        String value = null;
        if (service != null)
            value = (String)service.getOption(optionName);
        if (value == null)
            value = (String)getOption(optionName);
        return value;
    
protected java.lang.ObjectinvokeMethod(org.apache.axis.MessageContext msgContext, java.lang.reflect.Method method, java.lang.Object obj, java.lang.Object[] argValues)
Override the default implementation such that we can include special handling for {@link java.rmi.ServerException}.

Converts {@link java.rmi.ServerException} exceptions to {@link InvocationTargetException} exceptions with the same cause. This allows the axis framework to create a SOAP fault.

see
org.apache.axis.providers.java.RPCProvider#invokeMethod(org.apache.axis.MessageContext, java.lang.reflect.Method, java.lang.Object, java.lang.Object[])

        try {
            return super.invokeMethod(msgContext, method, obj, argValues);
        } catch (InvocationTargetException ite) {
            Throwable cause = getCause(ite);
            if (cause instanceof java.rmi.ServerException) {
                throw new InvocationTargetException(getCause(cause));
            }
            throw ite;
        }
    
private booleanisLocalEjb(org.apache.axis.handlers.soap.SOAPService service)
Tells if the ejb that will be used to handle this service is a local one

        return (!isRemoteEjb(service)) && 
          (getStrOption(OPTION_LOCALHOMEINTERFACENAME,service) != null);
    
private booleanisRemoteEjb(org.apache.axis.handlers.soap.SOAPService service)
Tells if the ejb that will be used to handle this service is a remote one

        return getStrOption(OPTION_HOMEINTERFACENAME,service) != null; 
    
protected java.lang.ObjectmakeNewServiceObject(org.apache.axis.MessageContext msgContext, java.lang.String clsName)
Return a object which implements the service.

param
msgContext the message context
param
clsName The JNDI name of the EJB home class
return
an object that implements the service


    ///////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////
    /////// Default methods from JavaProvider ancestor, overridden
    ///////   for ejbeans
    ///////////////////////////////////////////////////////////////
    ///////////////////////////////////////////////////////////////

                                       
       
                                            
         
    
        String remoteHomeName = getStrOption(OPTION_HOMEINTERFACENAME, 
                                                msgContext.getService());
        String localHomeName = getStrOption(OPTION_LOCALHOMEINTERFACENAME, 
                                                msgContext.getService());
        String homeName = (remoteHomeName != null ? remoteHomeName:localHomeName);

        if (homeName == null) {
            // cannot find both remote home and local home  
            throw new AxisFault(
                Messages.getMessage("noOption00", 
                                    OPTION_HOMEINTERFACENAME, 
                                    msgContext.getTargetService()));
        }
                                                        
        // Load the Home class name given in the config file
        Class homeClass = ClassUtils.forName(homeName, true, msgContext.getClassLoader());

        // we create either the ejb using either the RemoteHome or LocalHome object
        if (remoteHomeName != null)
            return createRemoteEJB(msgContext, clsName, homeClass);
        else 
            return createLocalEJB(msgContext, clsName, homeClass);