FileDocCategorySizeDatePackage
ServiceInvocationHandler.javaAPI DocGlassfish v2 API24057Fri May 04 22:36:12 BST 2007com.sun.enterprise.webservice

ServiceInvocationHandler

public class ServiceInvocationHandler extends Object implements InvocationHandler
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

Fields Summary
private com.sun.enterprise.deployment.ServiceReferenceDescriptor
serviceRef
private javax.xml.rpc.Service
serviceDelegate
private javax.xml.rpc.Service
configuredServiceDelegate
private ClassLoader
classLoader
private Method
getClientManagedPortMethod
private URL
wsdlLocation
private boolean
fullWsdl
private boolean
noWsdl
private WsUtil
wsUtil
private static final int
CREATE_CALL_NO_ARGS
private static final int
CREATE_CALL_PORT
private static final int
CREATE_CALL_OPERATION_QNAME
private static final int
CREATE_CALL_OPERATION_STRING
private static final int
GET_CALLS
private static final int
GET_HANDLER_REGISTRY
private static final int
GET_PORT_CONTAINER_MANAGED
private static final int
GET_PORT_CLIENT_MANAGED
private static final int
GET_PORTS
private static final int
GET_SERVICE_NAME
private static final int
GET_TYPE_MAPPING_REGISTRY
private static final int
GET_WSDL_LOCATION
private static final int
GENERATED_SERVICE_METHOD
private static Map
serviceMethodTypes
private static Set
fullWsdlIllegalMethods
private static Set
noWsdlIllegalMethods
Constructors Summary
public ServiceInvocationHandler(com.sun.enterprise.deployment.ServiceReferenceDescriptor descriptor, javax.xml.rpc.Service delegate, ClassLoader loader)


     
        Init();
    

        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);
    
Methods Summary
private static voidInit()
Convert invocation method to a constant for easier processing.


        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 booleanaddMessageSecurityHandler(javax.xml.rpc.Service service)

	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 voidcheckUnsupportedMethods(int methodType)


        Set illegalMethods = fullWsdl ?
            fullWsdlIllegalMethods : noWsdlIllegalMethods;

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

        return;
    
private javax.xml.rpc.ServicegetConfiguredServiceDelegate()

        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;
    
public javax.xml.rpc.handler.HandlerInfogetMessageSecurityHandlerInfo(javax.xml.namespace.QName port)

	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 intgetMethodType(java.lang.reflect.Method method)

        Integer methodType = (Integer) serviceMethodTypes.get(method);
        return (methodType != null) ? 
            methodType.intValue() : GENERATED_SERVICE_METHOD;
    
private java.util.SetgetPropertiesForCall(int methodType, java.lang.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;
    
public java.lang.Objectinvoke(java.lang.Object proxy, java.lang.reflect.Method method, java.lang.Object[] args)


        // 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;
    
private java.lang.ObjectinvokeJavaObjectMethod(java.lang.reflect.InvocationHandler handler, java.lang.reflect.Method method, java.lang.Object[] args)


        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 voidsetCallProperties(javax.xml.rpc.Call[] calls, int methodType, java.lang.Object[] args)


        Set callProperties = getPropertiesForCall(methodType, args);

        if( callProperties != null ) {
            for(int callIndex = 0; callIndex < calls.length; callIndex++) {
                setCallProperties(calls[callIndex], callProperties);
            }
        }
    
private voidsetCallProperties(javax.xml.rpc.Call call, java.util.Set callProperties)

        for(Iterator iter = callProperties.iterator(); iter.hasNext();) {
            NameValuePairDescriptor next = (NameValuePairDescriptor) 
                iter.next();
            call.setProperty(next.getName(), next.getValue());
        }
    
private voidsetJBIProperties(java.lang.Object stubOrCall, com.sun.enterprise.deployment.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;
        }
    
private voidsetStubProperties(javax.xml.rpc.Stub stub, int methodType, java.lang.reflect.Method method, java.lang.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());
                }
            }
        }