Package org.glassfish.webservices

Source Code of org.glassfish.webservices.ServiceInvocationHandler

/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 1997-2010 Oracle and/or its affiliates. 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_1_1.html
* or packager/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 packager/legal/LICENSE.txt.
*
* GPL Classpath Exception:
* Oracle designates this particular file as subject to the "Classpath"
* exception as provided by Oracle in the GPL Version 2 section of the License
* file that accompanied this code.
*
* Modifications:
* If applicable, add the following below the License Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyright [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 org.glassfish.webservices;


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 org.glassfish.internal.api.Globals;



/**
* 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();
    private org.glassfish.webservices.SecurityService  secServ;

    // 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 } );

        if (Globals.getDefaultHabitat() != null) {
            secServ = Globals.get(org.glassfish.webservices.SecurityService.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();
        }
        if (secServ != null) {
           rvalue = secServ.getMessageSecurityHandler(binding, serviceRef.getServiceName());
        }
        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
                /**TODO BM fix this later
                 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 org.glassfish.webservices.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.