1 /* 2 * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.xml.internal.ws.client.sei; 27 28 import com.sun.istack.internal.NotNull; 29 import com.sun.istack.internal.Nullable; 30 import com.sun.xml.internal.ws.api.SOAPVersion; 31 import com.sun.xml.internal.ws.api.client.WSPortInfo; 32 import com.sun.xml.internal.ws.api.databinding.Databinding; 33 import com.sun.xml.internal.ws.api.addressing.WSEndpointReference; 34 import com.sun.xml.internal.ws.api.message.Header; 35 import com.sun.xml.internal.ws.api.message.Headers; 36 import com.sun.xml.internal.ws.api.message.Packet; 37 import com.sun.xml.internal.ws.api.model.MEP; 38 import com.sun.xml.internal.ws.api.model.wsdl.WSDLBoundOperation; 39 import com.sun.xml.internal.ws.api.pipe.Fiber; 40 import com.sun.xml.internal.ws.api.pipe.Tube; 41 import com.sun.xml.internal.ws.api.server.Container; 42 import com.sun.xml.internal.ws.api.server.ContainerResolver; 43 import com.sun.xml.internal.ws.binding.BindingImpl; 44 import com.sun.xml.internal.ws.client.AsyncResponseImpl; 45 import com.sun.xml.internal.ws.client.RequestContext; 46 import com.sun.xml.internal.ws.client.ResponseContextReceiver; 47 import com.sun.xml.internal.ws.client.Stub; 48 import com.sun.xml.internal.ws.client.WSServiceDelegate; 49 import com.sun.xml.internal.ws.model.JavaMethodImpl; 50 import com.sun.xml.internal.ws.model.SOAPSEIModel; 51 import com.sun.xml.internal.ws.wsdl.OperationDispatcher; 52 53 import javax.xml.namespace.QName; 54 import java.lang.reflect.InvocationHandler; 55 import java.lang.reflect.InvocationTargetException; 56 import java.lang.reflect.Method; 57 import java.lang.reflect.Modifier; 58 import java.lang.reflect.Proxy; 59 import java.util.HashMap; 60 import java.util.Map; 61 62 /** 63 * {@link Stub} that handles method invocations 64 * through a strongly-typed endpoint interface. 65 * 66 * @author Kohsuke Kawaguchi 67 */ 68 public final class SEIStub extends Stub implements InvocationHandler { 69 70 Databinding databinding; 71 72 @Deprecated 73 public SEIStub(WSServiceDelegate owner, BindingImpl binding, SOAPSEIModel seiModel, Tube master, WSEndpointReference epr) { 74 super(owner, master, binding, seiModel.getPort(), seiModel.getPort().getAddress(), epr); 75 this.seiModel = seiModel; 76 this.soapVersion = binding.getSOAPVersion(); 77 databinding = seiModel.getDatabinding(); 78 initMethodHandlers(); 79 } 80 81 // added portInterface to the constructor, otherwise AsyncHandler won't work 82 public SEIStub(WSPortInfo portInfo, BindingImpl binding, SOAPSEIModel seiModel, WSEndpointReference epr) { 83 super(portInfo, binding, seiModel.getPort().getAddress(),epr); 84 this.seiModel = seiModel; 85 this.soapVersion = binding.getSOAPVersion(); 86 databinding = seiModel.getDatabinding(); 87 initMethodHandlers(); 88 } 89 90 private void initMethodHandlers() { 91 Map<WSDLBoundOperation, JavaMethodImpl> syncs = new HashMap<WSDLBoundOperation, JavaMethodImpl>(); 92 93 // fill in methodHandlers. 94 // first fill in sychronized versions 95 for (JavaMethodImpl m : seiModel.getJavaMethods()) { 96 if (!m.getMEP().isAsync) { 97 SyncMethodHandler handler = new SyncMethodHandler(this, m); 98 syncs.put(m.getOperation(), m); 99 methodHandlers.put(m.getMethod(), handler); 100 } 101 } 102 103 for (JavaMethodImpl jm : seiModel.getJavaMethods()) { 104 JavaMethodImpl sync = syncs.get(jm.getOperation()); 105 if (jm.getMEP() == MEP.ASYNC_CALLBACK) { 106 Method m = jm.getMethod(); 107 CallbackMethodHandler handler = new CallbackMethodHandler( 108 this, m, m.getParameterTypes().length - 1); 109 methodHandlers.put(m, handler); 110 } 111 if (jm.getMEP() == MEP.ASYNC_POLL) { 112 Method m = jm.getMethod(); 113 PollingMethodHandler handler = new PollingMethodHandler(this, m); 114 methodHandlers.put(m, handler); 115 } 116 } 117 } 118 119 public final SOAPSEIModel seiModel; 120 121 public final SOAPVersion soapVersion; 122 123 /** 124 * Nullable when there is no associated WSDL Model 125 * @return 126 */ 127 public @Nullable 128 OperationDispatcher getOperationDispatcher() { 129 if(operationDispatcher == null && wsdlPort != null) 130 operationDispatcher = new OperationDispatcher(wsdlPort,binding,seiModel); 131 return operationDispatcher; 132 } 133 134 /** 135 * For each method on the port interface we have 136 * a {@link MethodHandler} that processes it. 137 */ 138 private final Map<Method, MethodHandler> methodHandlers = new HashMap<Method, MethodHandler>(); 139 140 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 141 validateInputs(proxy, method); 142 Container old = ContainerResolver.getDefault().enterContainer(owner.getContainer()); 143 try { 144 MethodHandler handler = methodHandlers.get(method); 145 if (handler != null) { 146 return handler.invoke(proxy, args); 147 } else { 148 // we handle the other method invocations by ourselves 149 try { 150 return method.invoke(this, args); 151 } catch (IllegalAccessException e) { 152 // impossible 153 throw new AssertionError(e); 154 } catch (IllegalArgumentException e) { 155 throw new AssertionError(e); 156 } catch (InvocationTargetException e) { 157 throw e.getCause(); 158 } 159 } 160 } finally { 161 ContainerResolver.getDefault().exitContainer(old); 162 } 163 } 164 165 private void validateInputs(Object proxy, Method method) { 166 if (proxy == null || !Proxy.isProxyClass(proxy.getClass())) { 167 throw new IllegalStateException("Passed object is not proxy!"); 168 } 169 if (method == null || method.getDeclaringClass() == null 170 || Modifier.isStatic(method.getModifiers())) { 171 throw new IllegalStateException("Invoking static method is not allowed!"); 172 } 173 } 174 175 public final Packet doProcess(Packet request, RequestContext rc, ResponseContextReceiver receiver) { 176 return super.process(request, rc, receiver); 177 } 178 179 public final void doProcessAsync(AsyncResponseImpl<?> receiver, Packet request, RequestContext rc, Fiber.CompletionCallback callback) { 180 super.processAsync(receiver, request, rc, callback); 181 } 182 183 protected final @NotNull QName getPortName() { 184 return wsdlPort.getName(); 185 } 186 187 188 public void setOutboundHeaders(Object... headers) { 189 if(headers==null) 190 throw new IllegalArgumentException(); 191 Header[] hl = new Header[headers.length]; 192 for( int i=0; i<hl.length; i++ ) { 193 if(headers[i]==null) 194 throw new IllegalArgumentException(); 195 hl[i] = Headers.create(seiModel.getBindingContext(),headers[i]); 196 } 197 super.setOutboundHeaders(hl); 198 } 199 }