org.glassfish.webservices.ServiceInvocationHandler Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of payara-embedded-web Show documentation
Show all versions of payara-embedded-web Show documentation
Embedded-Web Distribution of the Payara Project for IBM JDK
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 1997-2012 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 volatile Service configuredServiceDelegate;
private ClassLoader classLoader;
private Method getClientManagedPortMethod;
// location of full wsdl associated with service-ref
private URL wsdlLocation;
private boolean fullWsdl = 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;
}
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;
default:
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 {
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,
Integer.valueOf(CREATE_CALL_NO_ARGS));
Method createCallPort =
serviceClass.getDeclaredMethod(createCall,
new Class[] { QName.class });
serviceMethodTypes.put(createCallPort,
Integer.valueOf(CREATE_CALL_PORT));
Method createCallOperationQName =
serviceClass.getDeclaredMethod
(createCall, new Class[] { QName.class, QName.class });
serviceMethodTypes.put(createCallOperationQName,
Integer.valueOf(CREATE_CALL_OPERATION_QNAME));
Method createCallOperationString =
serviceClass.getDeclaredMethod
(createCall, new Class[] { QName.class, String.class });
serviceMethodTypes.put(createCallOperationString,
Integer.valueOf(CREATE_CALL_OPERATION_STRING));
Method getCalls = serviceClass.getDeclaredMethod
("getCalls", new Class[] { QName.class });
serviceMethodTypes.put(getCalls, Integer.valueOf(GET_CALLS));
Method getHandlerRegistry = serviceClass.getDeclaredMethod
("getHandlerRegistry", noParams);
serviceMethodTypes.put(getHandlerRegistry,
Integer.valueOf(GET_HANDLER_REGISTRY));
Method getPortContainerManaged = serviceClass.getDeclaredMethod
("getPort", new Class[] { Class.class });
serviceMethodTypes.put(getPortContainerManaged,
Integer.valueOf(GET_PORT_CONTAINER_MANAGED));
Method getPortClientManaged = serviceClass.getDeclaredMethod
("getPort", new Class[] { QName.class, Class.class });
serviceMethodTypes.put(getPortClientManaged,
Integer.valueOf(GET_PORT_CLIENT_MANAGED));
Method getPorts = serviceClass.getDeclaredMethod
("getPorts", noParams);
serviceMethodTypes.put(getPorts, Integer.valueOf(GET_PORTS));
Method getServiceName = serviceClass.getDeclaredMethod
("getServiceName", noParams);
serviceMethodTypes.put(getServiceName,
Integer.valueOf(GET_SERVICE_NAME));
Method getTypeMappingRegistry = serviceClass.getDeclaredMethod
("getTypeMappingRegistry", noParams);
serviceMethodTypes.put(getTypeMappingRegistry,
Integer.valueOf(GET_TYPE_MAPPING_REGISTRY));
Method getWsdlLocation = serviceClass.getDeclaredMethod
("getWSDLDocumentLocation", noParams);
serviceMethodTypes.put(getWsdlLocation,
Integer.valueOf(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( GET_HANDLER_REGISTRY);
fullWsdlIllegalMethods.add(GET_TYPE_MAPPING_REGISTRY);
noWsdlIllegalMethods.add( CREATE_CALL_PORT);
noWsdlIllegalMethods.add( CREATE_CALL_OPERATION_QNAME);
noWsdlIllegalMethods.add(CREATE_CALL_OPERATION_STRING);
noWsdlIllegalMethods.add(GET_CALLS);
noWsdlIllegalMethods.add(GET_HANDLER_REGISTRY);
noWsdlIllegalMethods.add(GET_PORT_CONTAINER_MANAGED);
noWsdlIllegalMethods.add(GET_PORT_CLIENT_MANAGED);
noWsdlIllegalMethods.add(GET_PORTS);
noWsdlIllegalMethods.add(GET_SERVICE_NAME);
noWsdlIllegalMethods.add(GET_TYPE_MAPPING_REGISTRY);
noWsdlIllegalMethods.add(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(Integer.valueOf(GENERATED_SERVICE_METHOD));
}
private void checkUnsupportedMethods(int methodType)
throws UnsupportedOperationException {
Set illegalMethods = fullWsdl ?
fullWsdlIllegalMethods : noWsdlIllegalMethods;
if( illegalMethods.contains( Integer.valueOf(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()
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();
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;
default:
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 = Boolean.valueOf(handler.equals(other));
break;
case 'h' :
returnValue = Integer.valueOf(handler.hashCode());
break;
case 't' :
returnValue = handler.toString();
break;
default :
throw new Throwable("Object method " + method.getName() +
"not found");
}
return returnValue;
}
/* TODO remove me if none of the cts use this
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;
}
}*/
}