Package com.sun.enterprise.webservice

Source Code of com.sun.enterprise.webservice.ServiceInvocationHandler

/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License").  You
* may not use this file except in compliance with the License. You can obtain
* a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
* or glassfish/bootstrap/legal/LICENSE.txt.  See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
* Sun designates this particular file as subject to the "Classpath" exception
* as provided by Sun in the GPL Version 2 section of the License file that
* accompanied this code.  If applicable, add the following below the License
* Header, with the fields enclosed by brackets [] replaced by your own
* identifying information: "Portions Copyrighted [year]
* [name of copyright owner]"
*
* Contributor(s):
*
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license."  If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above.  However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
package com.sun.enterprise.webservice;

import java.lang.UnsupportedOperationException;

import java.net.URL;

import java.util.HashSet;
import java.util.Set;
import java.util.Map;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;

import javax.xml.namespace.QName;
import javax.xml.rpc.Service;
import javax.xml.rpc.handler.HandlerInfo;
import javax.xml.rpc.handler.HandlerRegistry;
import javax.xml.rpc.Stub;
import javax.xml.rpc.Call;

import com.sun.enterprise.deployment.ServiceReferenceDescriptor;
import com.sun.enterprise.deployment.ServiceRefPortInfo;
import com.sun.enterprise.deployment.NameValuePairDescriptor;
import com.sun.enterprise.deployment.runtime.common.MessageSecurityBindingDescriptor;

import com.sun.enterprise.security.jauth.ClientAuthConfig;
import com.sun.enterprise.webservice.MessageLayerClientHandler;

/**
* InvocationHandler used to intercept calls to concrete JAXRPC
* Service implementation. 
*
* NOTE : This class makes no distinction between "partial" WSDL and
* "full" WSDL.  If a service-ref's packaged WSDL is "partial", the
* deployer is required to specify a wsdl-override in the runtime info
* that points to a final WSDL.  In such a case, the behavior for each
* method listed in the table in section 4.2.2.7 of the spec is the
* same as Full WSDL.
*
* @author Kenneth Saks
*/
public class ServiceInvocationHandler implements InvocationHandler {

    private ServiceReferenceDescriptor serviceRef;

    // real service instance
    private Service serviceDelegate;

    // used in full wsdl case for DII methods. Lazily instantiated.
    private Service configuredServiceDelegate;

    private ClassLoader classLoader;

    private Method getClientManagedPortMethod;

    // location of full wsdl associated with service-ref
    private URL wsdlLocation;

    private boolean fullWsdl = false;
    private boolean noWsdl = false;

    private WsUtil wsUtil = new WsUtil();

    // Service method types
    private static final int CREATE_CALL_NO_ARGS = 1;
    private static final int CREATE_CALL_PORT = 2;
    private static final int CREATE_CALL_OPERATION_QNAME = 3;
    private static final int CREATE_CALL_OPERATION_STRING = 4;
    private static final int GET_CALLS = 5;
    private static final int GET_HANDLER_REGISTRY = 6;
    private static final int GET_PORT_CONTAINER_MANAGED = 7;
    private static final int GET_PORT_CLIENT_MANAGED = 8;
    private static final int GET_PORTS = 9;
    private static final int GET_SERVICE_NAME = 10;
    private static final int GET_TYPE_MAPPING_REGISTRY = 11;
    private static final int GET_WSDL_LOCATION = 12;
    private static final int GENERATED_SERVICE_METHOD = 13;

    private static Map serviceMethodTypes;
    private static Set fullWsdlIllegalMethods;
    private static Set noWsdlIllegalMethods;

    static {
        Init();
    }

    public ServiceInvocationHandler(ServiceReferenceDescriptor descriptor,
                                    Service delegate, ClassLoader loader)
        throws Exception {

        serviceRef = descriptor;
        serviceDelegate = delegate;
        classLoader = loader;

        if( serviceRef.hasWsdlFile() ) {
            wsdlLocation = wsUtil.privilegedGetServiceRefWsdl(serviceRef);
            fullWsdl = true;
        } else {
            noWsdl = true;
        }

        getClientManagedPortMethod = javax.xml.rpc.Service.class.getMethod
            ("getPort", new Class[] { QName.class, Class.class } );

  addMessageSecurityHandler(delegate);
    }
   
    public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable {

        // NOTE : be careful with "args" parameter.  It is null
        //        if method signature has 0 arguments.

        if( method.getDeclaringClass() == java.lang.Object.class )  {
            return invokeJavaObjectMethod(this, method, args);
        }

        int methodType = getMethodType(method);

        checkUnsupportedMethods(methodType);

        Object returnValue = null;

        try {

            // Initialize method info for invocation based on arguments.
            // Some/All of this might be overridden below.
            Object serviceToInvoke = serviceDelegate;
            Method methodToInvoke  = method;
            int methodTypeToInvoke = methodType;
            Object[] argsForInvoke = args;

            switch(methodType) {

            case GET_PORT_CONTAINER_MANAGED :
                Class serviceEndpointInterfaceClass = (Class) args[0];
                String serviceEndpointInterface =
                    serviceEndpointInterfaceClass.getName();
                ServiceRefPortInfo portInfo =
                    serviceRef.getPortInfo(serviceEndpointInterface);
               
                // If we have a port, use it to call getPort(QName, SEI) instead
                if( (portInfo != null) && portInfo.hasWsdlPort() ) {
                    methodToInvoke = getClientManagedPortMethod;
                    methodTypeToInvoke = GET_PORT_CLIENT_MANAGED;
                    argsForInvoke  = new Object[] { portInfo.getWsdlPort(),
                                                    args[0] };
                } else {
                    // This means the deployer did not resolve the port to
                    // which this SEI is mapped.  Just call getPort(SEI)
                    // method on delegate. This is not guaranteed to work.
                }
                break;

            case GET_WSDL_LOCATION :
                return wsdlLocation;

            case CREATE_CALL_PORT :
            case CREATE_CALL_OPERATION_QNAME :
            case CREATE_CALL_OPERATION_STRING :
            case GET_CALLS :
            case GET_PORTS :

                serviceToInvoke = getConfiguredServiceDelegate();
                break;

            } // End switch (methodType)

            returnValue = methodToInvoke.invoke(serviceToInvoke, argsForInvoke);
           
            if( returnValue instanceof Stub ) {
                Stub stub = (Stub) returnValue;
                setStubProperties(stub, methodTypeToInvoke, methodToInvoke,
                                  argsForInvoke);
            } else if( returnValue instanceof Call ) {
                Call[] calls = new Call[1];
                calls[0] = (Call) returnValue;
                setCallProperties(calls, methodTypeToInvoke, argsForInvoke);
            } else if( methodType == GET_CALLS ) {
                Call[] calls = (Call[]) returnValue;
                setCallProperties(calls, methodTypeToInvoke, argsForInvoke);
            }
           
        } catch(InvocationTargetException ite) {
            throw ite.getCause();
        }

  return returnValue;
    }

    public HandlerInfo getMessageSecurityHandlerInfo(QName port) throws Exception
    {
  HandlerInfo rvalue = null;

  MessageSecurityBindingDescriptor binding = null;
  ServiceRefPortInfo portInfo = serviceRef.getPortInfoByPort(port);
  if (portInfo != null) {
      binding = portInfo.getMessageSecurityBinding();
  }

  ClientAuthConfig config = ClientAuthConfig.getConfig
      (com.sun.enterprise.security.jauth.AuthConfig.SOAP,
       binding, null);

  if (config != null) {

      // get understood headers from auth module.
      QName[] headers = config.getMechanisms();
     
      Map properties = new HashMap();
      properties.put(MessageLayerClientHandler.CLIENT_AUTH_CONFIG, config);
            properties.put(javax.xml.ws.handler.MessageContext.WSDL_SERVICE,
                serviceRef.getServiceName());

      rvalue = new HandlerInfo(MessageLayerClientHandler.class,
             properties, headers);
  }

  return rvalue;
    }

    private boolean addMessageSecurityHandler(Service service) throws Exception
    {
  HandlerRegistry registry = service.getHandlerRegistry();
  Iterator ports = null;
  try {
      ports = service.getPorts();
  } catch (Exception e) {
      // FIXME: should make sure that the exception was thrown because
      // the service is not fully defined; but for now just return.
      ports = null;
  }

        while(ports != null && ports.hasNext()) {

            QName nextPort = (QName) ports.next();

            List handlerChain = registry.getHandlerChain(nextPort);

      // append security handler to the end of every handler chain
      // ASSUMPTION 1: that registry.getHandlerChain() never returns null.
      // ASSUMPTION 2: that handlers from ServiceRef have already been added

      HandlerInfo handlerInfo = getMessageSecurityHandlerInfo(nextPort);

      if (handlerInfo != null) {
    handlerChain.add(handlerInfo);
      }
        }

  return ports == null ? false : true;
    }
 
    private Service getConfiguredServiceDelegate() throws Exception {
        synchronized(this) {
            if( configuredServiceDelegate == null ) {
                // We need a ConfiguredService to handle these
                // invocations, since the JAXRPC RI Generated Service impl
                // does not.  Configured service is potentially
                // a heavy-weight object so we lazily instantiate it to
                // take advantage of the likelihood that
                // GeneratedService service-refs won't be used for DII.
                Service configuredService =
                    wsUtil.createConfiguredService(serviceRef);
                wsUtil.configureHandlerChain(serviceRef, configuredService,
               configuredService.getPorts(), classLoader);
                configuredServiceDelegate = configuredService;
   
    addMessageSecurityHandler(configuredService);
            }
        }
        return configuredServiceDelegate;
    }

    private int getMethodType(Method method) {
        Integer methodType = (Integer) serviceMethodTypes.get(method);
        return (methodType != null) ?
            methodType.intValue() : GENERATED_SERVICE_METHOD;
    }

    /**
     * Convert invocation method to a constant for easier processing.
     */
    private static void Init() {

        serviceMethodTypes     = new HashMap();
        fullWsdlIllegalMethods = new HashSet();
        noWsdlIllegalMethods   = new HashSet();

        try {

            Class noParams[]   = new Class[0];
            String createCall  = "createCall";
            Class serviceClass = javax.xml.rpc.Service.class;

            //
            // Map Service method to method type.
            //

            Method createCallNoArgs =
                serviceClass.getDeclaredMethod(createCall, noParams);
            serviceMethodTypes.put(createCallNoArgs,
                                   new Integer(CREATE_CALL_NO_ARGS));

            Method createCallPort =
                serviceClass.getDeclaredMethod(createCall,
                                               new Class[] { QName.class });
            serviceMethodTypes.put(createCallPort,
                                   new Integer(CREATE_CALL_PORT));

            Method createCallOperationQName =
                serviceClass.getDeclaredMethod
                (createCall, new Class[] { QName.class, QName.class });
            serviceMethodTypes.put(createCallOperationQName,
                                   new Integer(CREATE_CALL_OPERATION_QNAME));

            Method createCallOperationString =
                serviceClass.getDeclaredMethod
                (createCall, new Class[] { QName.class, String.class });
            serviceMethodTypes.put(createCallOperationString,
                                   new Integer(CREATE_CALL_OPERATION_STRING));
           
            Method getCalls = serviceClass.getDeclaredMethod
                ("getCalls", new Class[] { QName.class });
            serviceMethodTypes.put(getCalls, new Integer(GET_CALLS));

            Method getHandlerRegistry = serviceClass.getDeclaredMethod
                ("getHandlerRegistry", noParams);
            serviceMethodTypes.put(getHandlerRegistry,
                                   new Integer(GET_HANDLER_REGISTRY));

            Method getPortContainerManaged = serviceClass.getDeclaredMethod
                ("getPort", new Class[] { Class.class });
            serviceMethodTypes.put(getPortContainerManaged,
                                   new Integer(GET_PORT_CONTAINER_MANAGED));

            Method getPortClientManaged = serviceClass.getDeclaredMethod
                ("getPort", new Class[] { QName.class, Class.class });
            serviceMethodTypes.put(getPortClientManaged,
                                   new Integer(GET_PORT_CLIENT_MANAGED));
           
            Method getPorts = serviceClass.getDeclaredMethod
                ("getPorts", noParams);
            serviceMethodTypes.put(getPorts, new Integer(GET_PORTS));

            Method getServiceName = serviceClass.getDeclaredMethod
                ("getServiceName", noParams);
            serviceMethodTypes.put(getServiceName,
                                   new Integer(GET_SERVICE_NAME));

            Method getTypeMappingRegistry = serviceClass.getDeclaredMethod
                ("getTypeMappingRegistry", noParams);
            serviceMethodTypes.put(getTypeMappingRegistry,
                                   new Integer(GET_TYPE_MAPPING_REGISTRY));

            Method getWsdlLocation = serviceClass.getDeclaredMethod
                ("getWSDLDocumentLocation", noParams);
            serviceMethodTypes.put(getWsdlLocation,
                                   new Integer(GET_WSDL_LOCATION));
        } catch(NoSuchMethodException nsme) {}

        // Implementation of table 4.2.2.7.  All "No WSDL" column cells
        // with value Unspecified throw UnsupportedOperationException

        fullWsdlIllegalMethods.add(new Integer(GET_HANDLER_REGISTRY));
        fullWsdlIllegalMethods.add(new Integer(GET_TYPE_MAPPING_REGISTRY));

        noWsdlIllegalMethods.add(new Integer(CREATE_CALL_PORT));
        noWsdlIllegalMethods.add(new Integer(CREATE_CALL_OPERATION_QNAME));
        noWsdlIllegalMethods.add(new Integer(CREATE_CALL_OPERATION_STRING));
        noWsdlIllegalMethods.add(new Integer(GET_CALLS));
        noWsdlIllegalMethods.add(new Integer(GET_HANDLER_REGISTRY));
        noWsdlIllegalMethods.add(new Integer(GET_PORT_CONTAINER_MANAGED));
        noWsdlIllegalMethods.add(new Integer(GET_PORT_CLIENT_MANAGED));
        noWsdlIllegalMethods.add(new Integer(GET_PORTS));
        noWsdlIllegalMethods.add(new Integer(GET_SERVICE_NAME));
        noWsdlIllegalMethods.add(new Integer(GET_TYPE_MAPPING_REGISTRY));
        noWsdlIllegalMethods.add(new Integer(GET_WSDL_LOCATION));

        // This case shouldn't happen since if service-ref has generated
        // service and no WSDL it won't get past deployment, but it's here
        // for completeness.
        noWsdlIllegalMethods.add(new Integer(GENERATED_SERVICE_METHOD));
    }

    private void checkUnsupportedMethods(int methodType)
        throws UnsupportedOperationException {

        Set illegalMethods = fullWsdl ?
            fullWsdlIllegalMethods : noWsdlIllegalMethods;

        if( illegalMethods.contains(new Integer(methodType)) ) {
            throw new UnsupportedOperationException();
        }

        return;
    }

    private void setStubProperties(Stub stub, int methodType, Method method,
                                   Object[] args) {

        // Port info lookup will be based on SEI or port.
        QName port = null;
        String serviceEndpointInterface = null;

        switch(methodType) {
        case GET_PORT_CONTAINER_MANAGED :

            serviceEndpointInterface = ((Class) args[0]).getName();
            break;

        case GET_PORT_CLIENT_MANAGED :

            port = (QName) args[0];
            serviceEndpointInterface = ((Class) args[1]).getName();
            break;

        case GENERATED_SERVICE_METHOD :

            // java.rmi.Remote get<Name_of_wsdl:port>()
            String portLocalPart = method.getName().startsWith("get") ?
                method.getName().substring(3) : null;
            if( portLocalPart != null ) {
                QName serviceName = serviceRef.getServiceName();
                port = new QName(serviceName.getNamespaceURI(), portLocalPart);
            }
            serviceEndpointInterface = method.getReturnType().getName();

            break;

        default :
            return;
        }

        ServiceRefPortInfo portInfo = null;

        // If port is known, it takes precedence in lookup.
        if( port != null ) {
            portInfo = serviceRef.getPortInfoByPort(port);
        }
        if( portInfo == null ) {
            portInfo = serviceRef.getPortInfoBySEI(serviceEndpointInterface);
        }
           
        if( portInfo != null ) {
            Set properties = portInfo.getStubProperties();           

            for(Iterator iter = properties.iterator(); iter.hasNext();) {
                NameValuePairDescriptor next = (NameValuePairDescriptor)
                    iter.next();
                if( next.getName().equals
                    (WsUtil.CLIENT_TRANSPORT_LOG_PROPERTY) ) {
                    // value is a URL
                    wsUtil.setClientTransportLog(serviceRef, stub,
                                                 next.getValue());
                } else if(next.getName().equals(ServiceEngineUtil.JBI_ENABLED)){
                    setJBIProperties(stub, portInfo);
                } else {
                    stub._setProperty(next.getName(), next.getValue());
                }
            }

            // If this port has a resolved target endpoint address due to a
            // port-component-link, set it on stub.  However, if the runtime
            // info has an entry for target endpoint address, that takes
            // precedence.
            if( portInfo.hasTargetEndpointAddress() ) {
                if(!portInfo.hasStubProperty(Stub.ENDPOINT_ADDRESS_PROPERTY)) {
                    stub._setProperty(Stub.ENDPOINT_ADDRESS_PROPERTY,
                                      portInfo.getTargetEndpointAddress());
                }
            }
        }
    }

    private void setCallProperties(Call[] calls, int methodType, Object[] args){

        Set callProperties = getPropertiesForCall(methodType, args);

        if( callProperties != null ) {
            for(int callIndex = 0; callIndex < calls.length; callIndex++) {
                setCallProperties(calls[callIndex], callProperties);
            }
        }
    }
       
    private Set getPropertiesForCall(int methodType, Object args[]) {

        Set callProperties = null;
        switch(methodType) {

        case CREATE_CALL_PORT :
        case CREATE_CALL_OPERATION_QNAME :
        case CREATE_CALL_OPERATION_STRING :
        case GET_CALLS :

                // Each of these methods has port as first argument.
                QName port = (QName) args[0];
               
                // Check if call properties are set at the port level.
                ServiceRefPortInfo portInfo =
                    serviceRef.getPortInfoByPort(port);
                if( portInfo != null ) {
                    callProperties = portInfo.getCallProperties();
                }

                break;

        case CREATE_CALL_NO_ARGS :

            callProperties = serviceRef.getCallProperties();
            break;

        }
       
        return callProperties;
    }

    private void setCallProperties(Call call, Set callProperties) {
        for(Iterator iter = callProperties.iterator(); iter.hasNext();) {
            NameValuePairDescriptor next = (NameValuePairDescriptor)
                iter.next();
            call.setProperty(next.getName(), next.getValue());
        }
    }

    private Object invokeJavaObjectMethod(InvocationHandler handler,
                                          Method method, Object[] args)
        throws Throwable {

        Object returnValue = null;

        // Can only be one of :
        //     boolean java.lang.Object.equals(Object)
        //     int     java.lang.Object.hashCode()
        //     String  java.lang.Object.toString()
        //
        // Optimize by comparing as few characters as possible.

        switch( method.getName().charAt(0) ) {
            case 'e' :
                Object other = Proxy.isProxyClass(args[0].getClass()) ?
                    Proxy.getInvocationHandler(args[0]) : args[0];
                returnValue = new Boolean(handler.equals(other));
                break;
            case 'h' :
                returnValue = new Integer(handler.hashCode());
                break;
            case 't' :
                returnValue = handler.toString();
                break;
            default :
                throw new Throwable("Object method " + method.getName() +
                                    "not found");
        }

        return returnValue;
    }

    private void setJBIProperties(Object stubOrCall, ServiceRefPortInfo portInfo) {
        // Check if the target service is a JBI service, and get its QName
        QName svcQName = serviceRef.getServiceName();
        if ( svcQName == null )
            return;
                                                                               
        if ( stubOrCall instanceof Stub ) {
            com.sun.xml.rpc.spi.runtime.StubBase stub =
                    (com.sun.xml.rpc.spi.runtime.StubBase)stubOrCall;
                                                                               
            try {
                // This statement is getting executed only
                //because jbi-enabled property on the stub is set to true
                ServiceEngineUtil.setJBITransportFactory(portInfo, stub, true);
            } catch(Throwable e) {
                // Do nothing
                //logger.severe("Exception raised while setting transport " +
                //      "factory to NMR : " + e.getMessage());
            }
            return;
        }
    }
}
TOP

Related Classes of com.sun.enterprise.webservice.ServiceInvocationHandler

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.