FileDocCategorySizeDatePackage
JavaProvider.javaAPI DocApache Axis 1.419116Sat Apr 22 18:57:28 BST 2006org.apache.axis.providers.java

JavaProvider

public abstract class JavaProvider extends org.apache.axis.providers.BasicProvider
Base class for Java dispatching. Fetches various fields out of envelope, looks up service object (possibly using session state), and delegates envelope body processing to subclass via abstract processMessage method.
author
Doug Davis (dug@us.ibm.com)
author
Carl Woolf (cwoolf@macromedia.com)

Fields Summary
protected static Log
log
protected static Log
entLog
public static final String
OPTION_CLASSNAME
public static final String
OPTION_ALLOWEDMETHODS
public static final String
OPTION_SCOPE
Constructors Summary
Methods Summary
private java.lang.StringgetAllowedMethods(org.apache.axis.Handler service)

        String val = (String)service.getOption(OPTION_ALLOWEDMETHODS);
        if (val == null || val.length() == 0) {
            // Try the old option for backwards-compatibility
            val = (String)service.getOption("methodName");
        }
        return val;
    
private java.lang.ObjectgetApplicationScopedObject(org.apache.axis.MessageContext msgContext, java.lang.String serviceName, java.lang.String clsName, javax.xml.rpc.holders.IntHolder scopeHolder)

        AxisEngine engine = msgContext.getAxisEngine();
        Session appSession = engine.getApplicationSession();
        if (appSession != null) {
            return getSessionServiceObject(appSession, serviceName,
                                           msgContext, clsName);
        } else {
            // was no application session - log an error and
            // treat as request scope
            log.error(Messages.getMessage("noAppSession"));
            scopeHolder.value = Scope.DEFAULT.getValue();
            return getNewServiceObject(msgContext, clsName);
        }
    
private java.lang.ObjectgetNewServiceObject(org.apache.axis.MessageContext msgContext, java.lang.String clsName)
Return a new service object which, if it implements the ServiceLifecycle interface, has been init()ed.

param
msgContext the MessageContext
param
clsName the name of the class to instantiate
return
an initialized service object

        Object serviceObject = makeNewServiceObject(msgContext, clsName);
        if (serviceObject != null &&
                serviceObject instanceof ServiceLifecycle) {
            ((ServiceLifecycle)serviceObject).init(
                  msgContext.getProperty(Constants.MC_SERVLET_ENDPOINT_CONTEXT));
        }
        return serviceObject;
    
protected java.lang.ClassgetServiceClass(java.lang.String clsName, org.apache.axis.handlers.soap.SOAPService service, org.apache.axis.MessageContext msgContext)
Returns the Class info about the service class.

        ClassLoader cl = null;
        Class serviceClass = null;
        AxisEngine engine = service.getEngine();

        // If we have a message context, use that to get classloader
        // otherwise get the current threads classloader
        if (msgContext != null) {
            cl = msgContext.getClassLoader();
        } else {
            cl = Thread.currentThread().getContextClassLoader();
        }

        // If we have an engine, use its class cache
        if (engine != null) {
            ClassCache cache     = engine.getClassCache();
            try {
                JavaClass jc = cache.lookup(clsName, cl);
                serviceClass = jc.getJavaClass();
            } catch (ClassNotFoundException e) {
                log.error(Messages.getMessage("exception00"), e);
                throw new AxisFault(Messages.getMessage("noClassForService00", clsName), e);
            }
        } else {
            // if no engine, we don't have a cache, use Class.forName instead.
            try {
                serviceClass = ClassUtils.forName(clsName, true, cl);
            } catch (ClassNotFoundException e) {
                log.error(Messages.getMessage("exception00"), e);
                throw new AxisFault(Messages.getMessage("noClassForService00", clsName), e);
            }
        }
        return serviceClass;
    
protected java.lang.StringgetServiceClassName(org.apache.axis.Handler service)
Return the class name of the service

        return (String) service.getOption( getServiceClassNameOptionName() );
    
protected java.lang.StringgetServiceClassNameOptionName()
Return the option in the configuration that contains the service class name

        return OPTION_CLASSNAME;
    
public java.lang.ObjectgetServiceObject(org.apache.axis.MessageContext msgContext, org.apache.axis.Handler service, java.lang.String clsName, javax.xml.rpc.holders.IntHolder scopeHolder)
Get the service object whose method actually provides the service. May look up in session table.


                         
        
                                     
                                     
                                     
         
    
        String serviceName = msgContext.getService().getName();

        // scope can be "Request", "Session", "Application", "Factory"
        Scope scope = Scope.getScope((String)service.getOption(OPTION_SCOPE), Scope.DEFAULT);

        scopeHolder.value = scope.getValue();

        if (scope == Scope.REQUEST) {
            // make a one-off
            return getNewServiceObject(msgContext, clsName);
        } else if (scope == Scope.SESSION) {
            // What do we do if serviceName is null at this point???
            if (serviceName == null)
                serviceName = msgContext.getService().toString();

            // look in incoming session
            Session session = msgContext.getSession();
            if (session != null) {
                return getSessionServiceObject(session, serviceName,
                                               msgContext, clsName);
            } else {
                // was no incoming session, sigh, treat as request scope
                scopeHolder.value = Scope.DEFAULT.getValue();
                return getNewServiceObject(msgContext, clsName);
            }
        } else if (scope == Scope.APPLICATION) {
            // MUST be AxisEngine here!
            return getApplicationScopedObject(msgContext, serviceName, clsName, scopeHolder);
        } else if (scope == Scope.FACTORY) {
            String objectID = msgContext.getStrProp("objectID");
            if (objectID == null) {
                return getApplicationScopedObject(msgContext, serviceName, clsName, scopeHolder);
            }
            SOAPService svc = (SOAPService)service;
            Object ret = svc.serviceObjects.get(objectID);
            if (ret == null) {
                throw new AxisFault("NoSuchObject", null, null, null);
            }
            return ret;
        }

        // NOTREACHED
        return null;
    
private java.lang.ObjectgetSessionServiceObject(org.apache.axis.session.Session session, java.lang.String serviceName, org.apache.axis.MessageContext msgContext, java.lang.String clsName)
Get a service object from a session. Handles threading / locking issues when multiple threads might be accessing the same session object, and ensures only one thread gets to create the service object if there isn't one already.

        Object obj = null;
        boolean makeNewObject = false;

        // This is a little tricky.
        synchronized (session.getLockObject()) {
            // store service objects in session, indexed by class name
            obj = session.get(serviceName);

            // If nothing there, put in a placeholder object so
            // other threads wait for us to create the real
            // service object.
            if (obj == null) {
                obj = new LockObject();
                makeNewObject = true;
                session.set(serviceName, obj);
                msgContext.getService().addSession(session);
            }
        }

        // OK, we DEFINITELY have something in obj at this point.  Either
        // it's the service object or it's a LockObject (ours or someone
        // else's).

        if (LockObject.class == obj.getClass()) {
            LockObject lock = (LockObject)obj;

            // If we were the lucky thread who got to install the
            // placeholder, create a new service object and install it
            // instead, then notify anyone waiting on the LockObject.
            if (makeNewObject) {
                try {
                  obj = getNewServiceObject(msgContext, clsName);
                  session.set(serviceName, obj);
                  msgContext.getService().addSession(session);
                } catch(final Exception e) {
                    session.remove(serviceName);
                    throw e;
                } finally {
                  lock.complete();
                }
            } else {
                // It's someone else's LockObject, so wait around until
                // it's completed.
                lock.waitUntilComplete();

                // Now we are guaranteed there is a service object in the
                // session, so this next part doesn't need syncing
                obj = session.get(serviceName);
            }
        }

        return obj;
    
public voidinitServiceDesc(org.apache.axis.handlers.soap.SOAPService service, org.apache.axis.MessageContext msgContext)
Fill in a service description with the correct impl class and typemapping set. This uses methods that can be overridden by other providers (like the EJBProvider) to get the class from the right place.

        // Set up the Implementation class for the service

        String clsName = getServiceClassName(service);
        if (clsName == null) {
            throw new AxisFault(Messages.getMessage("noServiceClass"));
        }
        Class cls = getServiceClass(clsName, service, msgContext);
        JavaServiceDesc serviceDescription = (JavaServiceDesc)service.getServiceDescription();

        // And the allowed methods, if necessary
        if (serviceDescription.getAllowedMethods() == null && service != null) {
            String allowedMethods = getAllowedMethods(service);
            if (allowedMethods != null && !"*".equals(allowedMethods)) {
                ArrayList methodList = new ArrayList();
                StringTokenizer tokenizer = new StringTokenizer(allowedMethods, " ,");
                while (tokenizer.hasMoreTokens()) {
                    methodList.add(tokenizer.nextToken());
                }
                serviceDescription.setAllowedMethods(methodList);
            }
        }

        serviceDescription.loadServiceDescByIntrospection(cls);
    
public voidinvoke(org.apache.axis.MessageContext msgContext)
Invoke the message by obtaining various common fields, looking up the service object (via getServiceObject), and actually processing the message (via processMessage).

        if (log.isDebugEnabled())
            log.debug("Enter: JavaProvider::invoke (" + this + ")");

        /* Find the service we're invoking so we can grab it's options */
        /***************************************************************/
        String serviceName = msgContext.getTargetService();
        Handler service = msgContext.getService();

        /* Now get the service (RPC) specific info  */
        /********************************************/
        String  clsName    = getServiceClassName(service);

        if ((clsName == null) || clsName.equals("")) {
            throw new AxisFault("Server.NoClassForService",
                Messages.getMessage("noOption00", getServiceClassNameOptionName(), serviceName),
                null, null);
        }

        IntHolder scope   = new IntHolder();
        Object serviceObject = null;

        try {
            serviceObject = getServiceObject(msgContext, service, clsName, scope);

            SOAPEnvelope   resEnv = null;

            // If there IS a response message AND this is a one-way operation,
            // we delete the response message here.  Note that this might
            // cause confusing results in some cases - i.e. nothing fails,
            // but your response headers don't go anywhere either.  It might
            // be nice if in the future there was a way to detect an error
            // when trying to install a response message in a MessageContext
            // associated with a one-way operation....
            OperationDesc operation = msgContext.getOperation();
            if (operation != null &&
                    OperationType.ONE_WAY.equals(operation.getMep())) {
                msgContext.setResponseMessage(null);
            } else {
                Message        resMsg  = msgContext.getResponseMessage();

                // If we didn't have a response message, make sure we set one up
                // with the appropriate versions of SOAP and Schema
                if (resMsg == null) {
                    resEnv  = new SOAPEnvelope(msgContext.getSOAPConstants(),
                                               msgContext.getSchemaVersion());
                    
                    resMsg = new Message(resEnv);
                    String encoding = XMLUtils.getEncoding(msgContext);
                    resMsg.setProperty(SOAPMessage.CHARACTER_SET_ENCODING, encoding);
                    msgContext.setResponseMessage( resMsg );
                } else {
                    resEnv  = resMsg.getSOAPEnvelope();
                }
            }
            
            Message        reqMsg  = msgContext.getRequestMessage();
            SOAPEnvelope   reqEnv  = reqMsg.getSOAPEnvelope();

            processMessage(msgContext, reqEnv, resEnv, serviceObject);
        } catch( SAXException exp ) {
            entLog.debug( Messages.getMessage("toAxisFault00"), exp);
            Exception real = exp.getException();
            if (real == null) {
                real = exp;
            }
            throw AxisFault.makeFault(real);
        } catch( Exception exp ) {
            entLog.debug( Messages.getMessage("toAxisFault00"), exp);
            AxisFault fault = AxisFault.makeFault(exp);
            //make a note if this was a runtime fault, for better logging
            if (exp instanceof RuntimeException) {
                fault.addFaultDetail(Constants.QNAME_FAULTDETAIL_RUNTIMEEXCEPTION,
                        "true");
            }
            throw fault;
        } finally {
            // If this is a request scoped service object which implements
            // ServiceLifecycle, let it know that it's being destroyed now.
            if (serviceObject != null  &&
                scope.value == Scope.REQUEST.getValue() &&
                serviceObject instanceof ServiceLifecycle)
            {
                ((ServiceLifecycle)serviceObject).destroy();
            }
        }

        if (log.isDebugEnabled())
            log.debug("Exit: JavaProvider::invoke (" + this + ")");
    
protected java.lang.ObjectmakeNewServiceObject(org.apache.axis.MessageContext msgContext, java.lang.String clsName)
Default java service object comes from simply instantiating the class wrapped in jc

        ClassLoader cl     = msgContext.getClassLoader();
        ClassCache cache   = msgContext.getAxisEngine().getClassCache();
        JavaClass  jc      = cache.lookup(clsName, cl);

        return jc.getJavaClass().newInstance();
    
public abstract voidprocessMessage(org.apache.axis.MessageContext msgContext, org.apache.axis.message.SOAPEnvelope reqEnv, org.apache.axis.message.SOAPEnvelope resEnv, java.lang.Object obj)
Process the current message. Side-effect resEnv to create return value.

param
msgContext self-explanatory
param
reqEnv the request envelope
param
resEnv the response envelope
param
obj the service object itself