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
26package com.sun.xml.internal.ws.client.sei;
27
28import com.sun.istack.internal.NotNull;
29import com.sun.istack.internal.Nullable;
30import com.sun.xml.internal.ws.api.SOAPVersion;
31import com.sun.xml.internal.ws.api.client.WSPortInfo;
32import com.sun.xml.internal.ws.api.databinding.Databinding;
33import com.sun.xml.internal.ws.api.addressing.WSEndpointReference;
34import com.sun.xml.internal.ws.api.message.Header;
35import com.sun.xml.internal.ws.api.message.Headers;
36import com.sun.xml.internal.ws.api.message.Packet;
37import com.sun.xml.internal.ws.api.model.MEP;
38import com.sun.xml.internal.ws.api.model.wsdl.WSDLBoundOperation;
39import com.sun.xml.internal.ws.api.pipe.Fiber;
40import com.sun.xml.internal.ws.api.pipe.Tube;
41import com.sun.xml.internal.ws.api.server.Container;
42import com.sun.xml.internal.ws.api.server.ContainerResolver;
43import com.sun.xml.internal.ws.binding.BindingImpl;
44import com.sun.xml.internal.ws.client.AsyncResponseImpl;
45import com.sun.xml.internal.ws.client.RequestContext;
46import com.sun.xml.internal.ws.client.ResponseContextReceiver;
47import com.sun.xml.internal.ws.client.Stub;
48import com.sun.xml.internal.ws.client.WSServiceDelegate;
49import com.sun.xml.internal.ws.model.JavaMethodImpl;
50import com.sun.xml.internal.ws.model.SOAPSEIModel;
51import com.sun.xml.internal.ws.wsdl.OperationDispatcher;
52
53import javax.xml.namespace.QName;
54import java.lang.reflect.InvocationHandler;
55import java.lang.reflect.InvocationTargetException;
56import java.lang.reflect.Method;
57import java.lang.reflect.Modifier;
58import java.lang.reflect.Proxy;
59import java.util.HashMap;
60import 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 */
68public 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}
200