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 }