View Javadoc
1   /*
2    * Copyright (c) 1997, 2013, 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.addressing.WSEndpointReference;
32  import com.sun.xml.internal.ws.api.client.WSPortInfo;
33  import com.sun.xml.internal.ws.api.databinding.Databinding;
34  import com.sun.xml.internal.ws.api.addressing.WSEndpointReference;
35  import com.sun.xml.internal.ws.api.message.Header;
36  import com.sun.xml.internal.ws.api.message.Headers;
37  import com.sun.xml.internal.ws.api.message.Packet;
38  import com.sun.xml.internal.ws.api.model.MEP;
39  import com.sun.xml.internal.ws.api.model.wsdl.WSDLBoundOperation;
40  import com.sun.xml.internal.ws.api.pipe.Fiber;
41  import com.sun.xml.internal.ws.api.pipe.Tube;
42  import com.sun.xml.internal.ws.api.server.Container;
43  import com.sun.xml.internal.ws.api.server.ContainerResolver;
44  import com.sun.xml.internal.ws.binding.BindingImpl;
45  import com.sun.xml.internal.ws.client.AsyncResponseImpl;
46  import com.sun.xml.internal.ws.client.RequestContext;
47  import com.sun.xml.internal.ws.client.ResponseContextReceiver;
48  import com.sun.xml.internal.ws.client.Stub;
49  import com.sun.xml.internal.ws.client.WSServiceDelegate;
50  import com.sun.xml.internal.ws.model.JavaMethodImpl;
51  import com.sun.xml.internal.ws.model.SOAPSEIModel;
52  import com.sun.xml.internal.ws.wsdl.OperationDispatcher;
53  
54  import javax.xml.namespace.QName;
55  import java.lang.reflect.InvocationHandler;
56  import java.lang.reflect.InvocationTargetException;
57  import java.lang.reflect.Method;
58  import java.lang.reflect.Modifier;
59  import java.lang.reflect.Proxy;
60  import java.util.HashMap;
61  import java.util.Map;
62  
63  /**
64   * {@link Stub} that handles method invocations
65   * through a strongly-typed endpoint interface.
66   *
67   * @author Kohsuke Kawaguchi
68   */
69  public final class SEIStub extends Stub implements InvocationHandler {
70  
71          Databinding databinding;
72  
73      @Deprecated
74      public SEIStub(WSServiceDelegate owner, BindingImpl binding, SOAPSEIModel seiModel, Tube master, WSEndpointReference epr) {
75          super(owner, master, binding, seiModel.getPort(), seiModel.getPort().getAddress(), epr);
76          this.seiModel = seiModel;
77          this.soapVersion = binding.getSOAPVersion();
78          databinding = seiModel.getDatabinding();
79          initMethodHandlers();
80      }
81  
82      // added portInterface to the constructor, otherwise AsyncHandler won't work
83      public SEIStub(WSPortInfo portInfo, BindingImpl binding, SOAPSEIModel seiModel, WSEndpointReference epr) {
84          super(portInfo, binding, seiModel.getPort().getAddress(),epr);
85          this.seiModel = seiModel;
86          this.soapVersion = binding.getSOAPVersion();
87          databinding = seiModel.getDatabinding();
88          initMethodHandlers();
89      }
90  
91      private void initMethodHandlers() {
92          Map<WSDLBoundOperation, JavaMethodImpl> syncs = new HashMap<WSDLBoundOperation, JavaMethodImpl>();
93  
94          // fill in methodHandlers.
95          // first fill in sychronized versions
96          for (JavaMethodImpl m : seiModel.getJavaMethods()) {
97              if (!m.getMEP().isAsync) {
98                  SyncMethodHandler handler = new SyncMethodHandler(this, m);
99                  syncs.put(m.getOperation(), m);
100                 methodHandlers.put(m.getMethod(), handler);
101             }
102         }
103 
104         for (JavaMethodImpl jm : seiModel.getJavaMethods()) {
105             JavaMethodImpl sync = syncs.get(jm.getOperation());
106             if (jm.getMEP() == MEP.ASYNC_CALLBACK) {
107                 Method m = jm.getMethod();
108                 CallbackMethodHandler handler = new CallbackMethodHandler(
109                         this, m, m.getParameterTypes().length - 1);
110                 methodHandlers.put(m, handler);
111             }
112             if (jm.getMEP() == MEP.ASYNC_POLL) {
113                 Method m = jm.getMethod();
114                 PollingMethodHandler handler = new PollingMethodHandler(this, m);
115                 methodHandlers.put(m, handler);
116             }
117         }
118     }
119 
120     public final SOAPSEIModel seiModel;
121 
122     public final SOAPVersion soapVersion;
123 
124     /**
125      * Nullable when there is no associated WSDL Model
126      * @return
127      */
128     public @Nullable
129     OperationDispatcher getOperationDispatcher() {
130         if(operationDispatcher == null && wsdlPort != null)
131             operationDispatcher = new OperationDispatcher(wsdlPort,binding,seiModel);
132         return operationDispatcher;
133     }
134 
135     /**
136      * For each method on the port interface we have
137      * a {@link MethodHandler} that processes it.
138      */
139     private final Map<Method, MethodHandler> methodHandlers = new HashMap<Method, MethodHandler>();
140 
141     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
142         validateInputs(proxy, method);
143         Container old = ContainerResolver.getDefault().enterContainer(owner.getContainer());
144         try {
145             MethodHandler handler = methodHandlers.get(method);
146             if (handler != null) {
147                 return handler.invoke(proxy, args);
148             } else {
149                 // we handle the other method invocations by ourselves
150                 try {
151                     return method.invoke(this, args);
152                 } catch (IllegalAccessException e) {
153                     // impossible
154                     throw new AssertionError(e);
155                 } catch (IllegalArgumentException e) {
156                     throw new AssertionError(e);
157                 } catch (InvocationTargetException e) {
158                     throw e.getCause();
159                 }
160             }
161         } finally {
162             ContainerResolver.getDefault().exitContainer(old);
163         }
164     }
165 
166     private void validateInputs(Object proxy, Method method) {
167         if (proxy == null || !Proxy.isProxyClass(proxy.getClass())) {
168             throw new IllegalStateException("Passed object is not proxy!");
169         }
170         Class<?> declaringClass = method.getDeclaringClass();
171         if (method == null || declaringClass == null
172                 || Modifier.isStatic(method.getModifiers())) {
173             throw new IllegalStateException("Invoking static method is not allowed!");
174         }
175     }
176 
177     public final Packet doProcess(Packet request, RequestContext rc, ResponseContextReceiver receiver) {
178         return super.process(request, rc, receiver);
179     }
180 
181     public final void doProcessAsync(AsyncResponseImpl<?> receiver, Packet request, RequestContext rc, Fiber.CompletionCallback callback) {
182         super.processAsync(receiver, request, rc, callback);
183     }
184 
185     protected final @NotNull QName getPortName() {
186         return wsdlPort.getName();
187     }
188 
189 
190     public void setOutboundHeaders(Object... headers) {
191         if(headers==null)
192             throw new IllegalArgumentException();
193         Header[] hl = new Header[headers.length];
194         for( int i=0; i<hl.length; i++ ) {
195             if(headers[i]==null)
196                 throw new IllegalArgumentException();
197             hl[i] = Headers.create(seiModel.getBindingContext(),headers[i]);
198         }
199         super.setOutboundHeaders(hl);
200     }
201 }