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
26package com.sun.xml.internal.ws.model.wsdl;
27
28import com.sun.istack.internal.Nullable;
29import com.sun.istack.internal.NotNull;
30import com.sun.xml.internal.ws.api.model.ParameterBinding;
31import com.sun.xml.internal.ws.api.model.wsdl.*;
32import com.sun.xml.internal.ws.api.model.wsdl.editable.EditableWSDLBoundFault;
33import com.sun.xml.internal.ws.api.model.wsdl.editable.EditableWSDLBoundOperation;
34import com.sun.xml.internal.ws.api.model.wsdl.editable.EditableWSDLBoundPortType;
35import com.sun.xml.internal.ws.api.model.wsdl.editable.EditableWSDLMessage;
36import com.sun.xml.internal.ws.api.model.wsdl.editable.EditableWSDLModel;
37import com.sun.xml.internal.ws.api.model.wsdl.editable.EditableWSDLOperation;
38import com.sun.xml.internal.ws.api.model.wsdl.editable.EditableWSDLPart;
39import com.sun.xml.internal.ws.model.RuntimeModeler;
40
41import javax.jws.WebParam.Mode;
42import javax.jws.soap.SOAPBinding.Style;
43import javax.xml.namespace.QName;
44import javax.xml.stream.XMLStreamReader;
45
46import java.util.*;
47
48/**
49 * Implementation of {@link WSDLBoundOperation}
50 *
51 * @author Vivek Pandey
52 */
53public final class WSDLBoundOperationImpl extends AbstractExtensibleImpl implements EditableWSDLBoundOperation {
54    private final QName name;
55
56    // map of wsdl:part to the binding
57    private final Map<String, ParameterBinding> inputParts;
58    private final Map<String, ParameterBinding> outputParts;
59    private final Map<String, ParameterBinding> faultParts;
60    private final Map<String, String> inputMimeTypes;
61    private final Map<String, String> outputMimeTypes;
62    private final Map<String, String> faultMimeTypes;
63
64    private boolean explicitInputSOAPBodyParts = false;
65    private boolean explicitOutputSOAPBodyParts = false;
66    private boolean explicitFaultSOAPBodyParts = false;
67
68    private Boolean emptyInputBody;
69    private Boolean emptyOutputBody;
70    private Boolean emptyFaultBody;
71
72    private final Map<String, EditableWSDLPart> inParts;
73    private final Map<String, EditableWSDLPart> outParts;
74    private final List<EditableWSDLBoundFault> wsdlBoundFaults;
75    private EditableWSDLOperation operation;
76    private String soapAction;
77    private ANONYMOUS anonymous;
78
79    private final EditableWSDLBoundPortType owner;
80
81    /**
82     *
83     * @param name wsdl:operation name qualified value
84     */
85    public WSDLBoundOperationImpl(XMLStreamReader xsr, EditableWSDLBoundPortType owner, QName name) {
86        super(xsr);
87        this.name = name;
88        inputParts = new HashMap<String, ParameterBinding>();
89        outputParts = new HashMap<String, ParameterBinding>();
90        faultParts = new HashMap<String, ParameterBinding>();
91        inputMimeTypes = new HashMap<String, String>();
92        outputMimeTypes = new HashMap<String, String>();
93        faultMimeTypes = new HashMap<String, String>();
94        inParts = new HashMap<String, EditableWSDLPart>();
95        outParts = new HashMap<String, EditableWSDLPart>();
96        wsdlBoundFaults = new ArrayList<EditableWSDLBoundFault>();
97        this.owner = owner;
98    }
99
100    @Override
101    public QName getName(){
102        return name;
103    }
104
105    @Override
106    public String getSOAPAction() {
107        return soapAction;
108    }
109
110    public void setSoapAction(String soapAction) {
111        this.soapAction = soapAction!=null?soapAction:"";
112    }
113
114    @Override
115    public EditableWSDLPart getPart(String partName, Mode mode) {
116        if(mode==Mode.IN){
117            return inParts.get(partName);
118        }else if(mode==Mode.OUT){
119            return outParts.get(partName);
120        }
121        return null;
122    }
123
124    public void addPart(EditableWSDLPart part, Mode mode){
125        if(mode==Mode.IN)
126            inParts.put(part.getName(), part);
127        else if(mode==Mode.OUT)
128            outParts.put(part.getName(), part);
129    }
130
131    /**
132     * Map of wsdl:input part name and the binding as {@link ParameterBinding}
133     *
134     * @return empty Map if there is no parts
135     */
136    public Map<String, ParameterBinding> getInputParts() {
137        return inputParts;
138    }
139
140    /**
141     * Map of wsdl:output part name and the binding as {@link ParameterBinding}
142     *
143     * @return empty Map if there is no parts
144     */
145    public Map<String, ParameterBinding> getOutputParts() {
146        return outputParts;
147    }
148
149    /**
150     * Map of wsdl:fault part name and the binding as {@link ParameterBinding}
151     *
152     * @return empty Map if there is no parts
153     */
154    public Map<String, ParameterBinding> getFaultParts() {
155        return faultParts;
156    }
157
158    // TODO: what's the difference between this and inputParts/outputParts?
159    @Override
160    public Map<String, ? extends EditableWSDLPart> getInParts() {
161        return Collections.<String, EditableWSDLPart>unmodifiableMap(inParts);
162    }
163
164    @Override
165    public Map<String, ? extends EditableWSDLPart> getOutParts() {
166        return Collections.<String, EditableWSDLPart>unmodifiableMap(outParts);
167    }
168
169    @NotNull
170    @Override
171    public List<? extends EditableWSDLBoundFault> getFaults() {
172        return wsdlBoundFaults;
173    }
174
175    public void addFault(@NotNull EditableWSDLBoundFault fault){
176        wsdlBoundFaults.add(fault);
177    }
178
179
180    /**
181     * Gets {@link ParameterBinding} for a given wsdl part in wsdl:input
182     *
183     * @param part Name of wsdl:part, must be non-null
184     * @return null if the part is not found.
185     */
186    public ParameterBinding getInputBinding(String part){
187        if(emptyInputBody == null){
188            if(inputParts.get(" ") != null)
189                emptyInputBody = true;
190            else
191                emptyInputBody = false;
192        }
193        ParameterBinding block = inputParts.get(part);
194        if(block == null){
195            if(explicitInputSOAPBodyParts || emptyInputBody)
196                return ParameterBinding.UNBOUND;
197            return ParameterBinding.BODY;
198        }
199
200        return block;
201    }
202
203    /**
204     * Gets {@link ParameterBinding} for a given wsdl part in wsdl:output
205     *
206     * @param part Name of wsdl:part, must be non-null
207     * @return null if the part is not found.
208     */
209    public ParameterBinding getOutputBinding(String part){
210        if(emptyOutputBody == null){
211            if(outputParts.get(" ") != null)
212                emptyOutputBody = true;
213            else
214                emptyOutputBody = false;
215        }
216        ParameterBinding block = outputParts.get(part);
217        if(block == null){
218            if(explicitOutputSOAPBodyParts || emptyOutputBody)
219                return ParameterBinding.UNBOUND;
220            return ParameterBinding.BODY;
221        }
222
223        return block;
224    }
225
226    /**
227     * Gets {@link ParameterBinding} for a given wsdl part in wsdl:fault
228     *
229     * @param part Name of wsdl:part, must be non-null
230     * @return null if the part is not found.
231     */
232    public ParameterBinding getFaultBinding(String part){
233        if(emptyFaultBody == null){
234            if(faultParts.get(" ") != null)
235                emptyFaultBody = true;
236            else
237                emptyFaultBody = false;
238        }
239        ParameterBinding block = faultParts.get(part);
240        if(block == null){
241            if(explicitFaultSOAPBodyParts || emptyFaultBody)
242                return ParameterBinding.UNBOUND;
243            return ParameterBinding.BODY;
244        }
245
246        return block;
247    }
248
249    /**
250     * Gets the MIME type for a given wsdl part in wsdl:input
251     *
252     * @param part Name of wsdl:part, must be non-null
253     * @return null if the part is not found.
254     */
255    public String getMimeTypeForInputPart(String part){
256        return inputMimeTypes.get(part);
257    }
258
259    /**
260     * Gets the MIME type for a given wsdl part in wsdl:output
261     *
262     * @param part Name of wsdl:part, must be non-null
263     * @return null if the part is not found.
264     */
265    public String getMimeTypeForOutputPart(String part){
266        return outputMimeTypes.get(part);
267    }
268
269    /**
270     * Gets the MIME type for a given wsdl part in wsdl:fault
271     *
272     * @param part Name of wsdl:part, must be non-null
273     * @return null if the part is not found.
274     */
275    public String getMimeTypeForFaultPart(String part){
276        return faultMimeTypes.get(part);
277    }
278
279    @Override
280    public EditableWSDLOperation getOperation() {
281        return operation;
282    }
283
284
285    @Override
286    public EditableWSDLBoundPortType getBoundPortType() {
287        return owner;
288    }
289
290    public void setInputExplicitBodyParts(boolean b) {
291        explicitInputSOAPBodyParts = b;
292    }
293
294    public void setOutputExplicitBodyParts(boolean b) {
295        explicitOutputSOAPBodyParts = b;
296    }
297
298    public void setFaultExplicitBodyParts(boolean b) {
299        explicitFaultSOAPBodyParts = b;
300    }
301
302    private Style style = Style.DOCUMENT;
303    public void setStyle(Style style){
304        this.style = style;
305    }
306
307    @Override
308    public @Nullable QName getRequestPayloadName() {
309        if (emptyRequestPayload)
310            return null;
311
312        if (requestPayloadName != null)
313            return requestPayloadName;
314
315        if(style.equals(Style.RPC)){
316            String ns = getRequestNamespace() != null ? getRequestNamespace() : name.getNamespaceURI();
317            requestPayloadName = new QName(ns, name.getLocalPart());
318            return requestPayloadName;
319        }else{
320            QName inMsgName = operation.getInput().getMessage().getName();
321            EditableWSDLMessage message = messages.get(inMsgName);
322            for(EditableWSDLPart part:message.parts()){
323                ParameterBinding binding = getInputBinding(part.getName());
324                if(binding.isBody()){
325                    requestPayloadName = part.getDescriptor().name();
326                    return requestPayloadName;
327                }
328            }
329
330            //Its empty payload
331            emptyRequestPayload = true;
332        }
333        //empty body
334        return null;
335    }
336
337    @Override
338    public @Nullable QName getResponsePayloadName() {
339        if (emptyResponsePayload)
340            return null;
341
342        if (responsePayloadName != null)
343            return responsePayloadName;
344
345        if(style.equals(Style.RPC)){
346            String ns = getResponseNamespace() != null ? getResponseNamespace() : name.getNamespaceURI();
347            responsePayloadName = new QName(ns, name.getLocalPart()+"Response");
348            return responsePayloadName;
349        }else{
350            QName outMsgName = operation.getOutput().getMessage().getName();
351            EditableWSDLMessage message = messages.get(outMsgName);
352            for(EditableWSDLPart part:message.parts()){
353                ParameterBinding binding = getOutputBinding(part.getName());
354                if(binding.isBody()){
355                    responsePayloadName = part.getDescriptor().name();
356                    return responsePayloadName;
357                }
358            }
359
360            //Its empty payload
361            emptyResponsePayload = true;
362        }
363        //empty body
364        return null;
365    }
366
367
368    private String reqNamespace;
369    private String respNamespace;
370
371    /**
372     * For rpclit gives namespace value on soapbinding:body@namespace
373     *
374     * @return   non-null for rpclit and null for doclit
375     * @see RuntimeModeler#processRpcMethod(JavaMethodImpl, String, String, Method)
376     */
377    @Override
378    public String getRequestNamespace(){
379        return (reqNamespace != null)?reqNamespace:name.getNamespaceURI();
380    }
381
382    public void setRequestNamespace(String ns){
383        reqNamespace = ns;
384    }
385
386    /**
387     * For rpclit gives namespace value on soapbinding:body@namespace
388     *
389     * @return   non-null for rpclit and null for doclit
390     * @see RuntimeModeler#processRpcMethod(JavaMethodImpl, String, String, Method)
391     */
392    @Override
393    public String getResponseNamespace(){
394        return (respNamespace!=null)?respNamespace:name.getNamespaceURI();
395    }
396
397    public void setResponseNamespace(String ns){
398        respNamespace = ns;
399    }
400
401    EditableWSDLBoundPortType getOwner(){
402        return owner;
403    }
404
405    private QName requestPayloadName;
406    private QName responsePayloadName;
407    private boolean emptyRequestPayload;
408    private boolean emptyResponsePayload;
409    private Map<QName, ? extends EditableWSDLMessage> messages;
410
411    public void freeze(EditableWSDLModel parent) {
412        messages = parent.getMessages();
413        operation = owner.getPortType().get(name.getLocalPart());
414        for(EditableWSDLBoundFault bf : wsdlBoundFaults){
415            bf.freeze(this);
416        }
417    }
418
419    public void setAnonymous(ANONYMOUS anonymous) {
420        this.anonymous = anonymous;
421    }
422
423    /**
424     * @inheritDoc
425     */
426    @Override
427    public ANONYMOUS getAnonymous() {
428        return anonymous;
429    }
430}
431