W3CAddressingWSDLParserExtension.java revision 524:dcaa586ab756
1227614Sluigi/*
2227614Sluigi * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
3227614Sluigi * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4227614Sluigi *
5227614Sluigi * This code is free software; you can redistribute it and/or modify it
6227614Sluigi * under the terms of the GNU General Public License version 2 only, as
7227614Sluigi * published by the Free Software Foundation.  Oracle designates this
8227614Sluigi * particular file as subject to the "Classpath" exception as provided
9227614Sluigi * by Oracle in the LICENSE file that accompanied this code.
10227614Sluigi *
11227614Sluigi * This code is distributed in the hope that it will be useful, but WITHOUT
12227614Sluigi * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13227614Sluigi * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14227614Sluigi * version 2 for more details (a copy is included in the LICENSE file that
15227614Sluigi * accompanied this code).
16227614Sluigi *
17227614Sluigi * You should have received a copy of the GNU General Public License version
18227614Sluigi * 2 along with this work; if not, write to the Free Software Foundation,
19227614Sluigi * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20227614Sluigi *
21227614Sluigi * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22227614Sluigi * or visit www.oracle.com if you need additional information or have any
23227614Sluigi * questions.
24227614Sluigi */
25227614Sluigi
26232238Sluigipackage com.sun.xml.internal.ws.wsdl.parser;
27227614Sluigi
28227614Sluigiimport com.sun.xml.internal.ws.api.addressing.AddressingVersion;
29232238Sluigiimport com.sun.xml.internal.ws.api.model.wsdl.WSDLFeaturedObject;
30227614Sluigiimport static com.sun.xml.internal.ws.api.model.wsdl.WSDLBoundOperation.ANONYMOUS;
31232238Sluigiimport com.sun.xml.internal.ws.api.model.wsdl.editable.*;
32228276Sluigiimport com.sun.xml.internal.ws.api.wsdl.parser.WSDLParserExtension;
33232238Sluigiimport com.sun.xml.internal.ws.api.wsdl.parser.WSDLParserExtensionContext;
34227614Sluigiimport com.sun.xml.internal.ws.streaming.XMLStreamReaderUtil;
35227614Sluigi
36227614Sluigiimport javax.xml.namespace.QName;
37227614Sluigiimport javax.xml.stream.XMLStreamException;
38227614Sluigiimport javax.xml.stream.XMLStreamReader;
39227614Sluigiimport javax.xml.ws.WebServiceException;
40227614Sluigiimport javax.xml.ws.soap.AddressingFeature;
41227614Sluigi
42227614Sluigi/**
43227614Sluigi * W3C WS-Addressing Runtime WSDL parser extension
44231594Sluigi *
45227614Sluigi * @author Arun Gupta
46231594Sluigi */
47227614Sluigipublic class W3CAddressingWSDLParserExtension extends WSDLParserExtension {
48227614Sluigi    @Override
49227614Sluigi    public boolean bindingElements(EditableWSDLBoundPortType binding, XMLStreamReader reader) {
50227614Sluigi        return addressibleElement(reader, binding);
51227614Sluigi    }
52227614Sluigi
53227614Sluigi    @Override
54227614Sluigi    public boolean portElements(EditableWSDLPort port, XMLStreamReader reader) {
55227614Sluigi        return addressibleElement(reader, port);
56227614Sluigi    }
57227614Sluigi
58227614Sluigi    private boolean addressibleElement(XMLStreamReader reader, WSDLFeaturedObject binding) {
59227614Sluigi        QName ua = reader.getName();
60227614Sluigi        if (ua.equals(AddressingVersion.W3C.wsdlExtensionTag)) {
61227614Sluigi            String required = reader.getAttributeValue(WSDLConstants.NS_WSDL, "required");
62227614Sluigi            binding.addFeature(new AddressingFeature(true, Boolean.parseBoolean(required)));
63227614Sluigi            XMLStreamReaderUtil.skipElement(reader);
64227614Sluigi            return true;        // UsingAddressing is consumed
65227614Sluigi        }
66227614Sluigi
67227614Sluigi        return false;
68227614Sluigi    }
69227614Sluigi
70227614Sluigi    @Override
71227614Sluigi    public boolean bindingOperationElements(EditableWSDLBoundOperation operation, XMLStreamReader reader) {
72227614Sluigi        EditableWSDLBoundOperation edit = (EditableWSDLBoundOperation) operation;
73232238Sluigi
74227614Sluigi        QName anon = reader.getName();
75227614Sluigi        if (anon.equals(AddressingVersion.W3C.wsdlAnonymousTag)) {
76228276Sluigi            try {
77228276Sluigi                String value = reader.getElementText();
78228276Sluigi                if (value == null || value.trim().equals("")) {
79228276Sluigi                    throw new WebServiceException("Null values not permitted in wsaw:Anonymous.");
80228276Sluigi                    // TODO: throw exception only if wsdl:required=true
81228276Sluigi                    // TODO: is this the right exception ?
82228276Sluigi                } else if (value.equals("optional")) {
83232238Sluigi                    edit.setAnonymous(ANONYMOUS.optional);
84228276Sluigi                } else if (value.equals("required")) {
85228276Sluigi                    edit.setAnonymous(ANONYMOUS.required);
86228276Sluigi                } else if (value.equals("prohibited")) {
87228276Sluigi                    edit.setAnonymous(ANONYMOUS.prohibited);
88228276Sluigi                } else {
89228276Sluigi                    throw new WebServiceException("wsaw:Anonymous value \"" + value + "\" not understood.");
90228276Sluigi                    // TODO: throw exception only if wsdl:required=true
91228276Sluigi                    // TODO: is this the right exception ?
92228276Sluigi                }
93228276Sluigi            } catch (XMLStreamException e) {
94228276Sluigi                throw new WebServiceException(e);       // TODO: is this the correct behavior ?
95228276Sluigi            }
96228276Sluigi
97228276Sluigi            return true;        // consumed the element
98228276Sluigi        }
99228276Sluigi
100228276Sluigi        return false;
101228276Sluigi    }
102228276Sluigi
103228276Sluigi    public void portTypeOperationInputAttributes(EditableWSDLInput input, XMLStreamReader reader) {
104228276Sluigi       String action = ParserUtil.getAttribute(reader, getWsdlActionTag());
105228276Sluigi       if (action != null) {
106228276Sluigi            input.setAction(action);
107228276Sluigi            input.setDefaultAction(false);
108231778Sluigi        }
109228276Sluigi    }
110228276Sluigi
111231778Sluigi
112228276Sluigi    public void portTypeOperationOutputAttributes(EditableWSDLOutput output, XMLStreamReader reader) {
113228276Sluigi       String action = ParserUtil.getAttribute(reader, getWsdlActionTag());
114228276Sluigi       if (action != null) {
115228276Sluigi            output.setAction(action);
116228276Sluigi            output.setDefaultAction(false);
117228276Sluigi        }
118228276Sluigi    }
119228276Sluigi
120228276Sluigi
121228276Sluigi    public void portTypeOperationFaultAttributes(EditableWSDLFault fault, XMLStreamReader reader) {
122228276Sluigi        String action = ParserUtil.getAttribute(reader, getWsdlActionTag());
123232238Sluigi        if (action != null) {
124228276Sluigi            fault.setAction(action);
125228276Sluigi            fault.setDefaultAction(false);
126231594Sluigi        }
127227614Sluigi    }
128231594Sluigi
129232238Sluigi    /**
130231796Sluigi     * Process wsdl:portType operation after the entire WSDL model has been populated.
131227614Sluigi     * The task list includes: <p>
132232238Sluigi     * <ul>
133227614Sluigi     * <li>Patch the value of UsingAddressing in wsdl:port and wsdl:binding</li>
134227614Sluigi     * <li>Populate actions for the messages that do not have an explicit wsaw:Action</li>
135227614Sluigi     * <li>Patch the default value of wsaw:Anonymous=optional if none is specified</li>
136227614Sluigi     * </ul>
137232238Sluigi     * @param context
138227614Sluigi     */
139228276Sluigi    @Override
140227614Sluigi    public void finished(WSDLParserExtensionContext context) {
141227614Sluigi        EditableWSDLModel model = context.getWSDLModel();
142227614Sluigi        for (EditableWSDLService service : model.getServices().values()) {
143227614Sluigi            for (EditableWSDLPort port : service.getPorts()) {
144227614Sluigi                EditableWSDLBoundPortType binding = port.getBinding();
145227614Sluigi
146232238Sluigi                // populate actions for the messages that do not have an explicit wsaw:Action
147232238Sluigi                populateActions(binding);
148232238Sluigi
149231778Sluigi                // patch the default value of wsaw:Anonymous=optional if none is specified
150231778Sluigi                patchAnonymousDefault(binding);
151232238Sluigi            }
152232238Sluigi        }
153231881Sluigi    }
154232238Sluigi
155227614Sluigi    protected String getNamespaceURI() {
156232238Sluigi        return AddressingVersion.W3C.wsdlNsUri;
157228276Sluigi    }
158228276Sluigi
159227614Sluigi    protected QName getWsdlActionTag() {
160227614Sluigi       return AddressingVersion.W3C.wsdlActionTag;
161227614Sluigi    }
162231778Sluigi    /**
163231778Sluigi     * Populate all the Actions
164232238Sluigi     *
165227614Sluigi     * @param binding soapbinding:operation
166227614Sluigi     */
167227614Sluigi    private void populateActions(EditableWSDLBoundPortType binding) {
168227614Sluigi        EditableWSDLPortType porttype = binding.getPortType();
169227614Sluigi        for (EditableWSDLOperation o : porttype.getOperations()) {
170227614Sluigi            // TODO: this may be performance intensive. Alternatively default action
171227614Sluigi            // TODO: can be calculated when the operation is actually invoked.
172228276Sluigi                EditableWSDLBoundOperation wboi = binding.get(o.getName());
173227614Sluigi
174228276Sluigi            if (wboi == null) {
175229939Sluigi                //If this operation is unbound set the action to default
176232238Sluigi                o.getInput().setAction(defaultInputAction(o));
177227614Sluigi                continue;
178227614Sluigi            }
179232238Sluigi                String soapAction = wboi.getSOAPAction();
180232238Sluigi            if (o.getInput().getAction() == null || o.getInput().getAction().equals("")) {
181232238Sluigi                // explicit wsaw:Action is not specified
182232238Sluigi
183227614Sluigi                if (soapAction != null && !soapAction.equals("")) {
184227614Sluigi                    // if soapAction is non-empty, use that
185228276Sluigi                    o.getInput().setAction(soapAction);
186227614Sluigi                } else {
187228276Sluigi                    // otherwise generate default Action
188227614Sluigi                    o.getInput().setAction(defaultInputAction(o));
189232238Sluigi                }
190228276Sluigi            }
191227614Sluigi
192227614Sluigi            // skip output and fault processing for one-way methods
193228276Sluigi            if (o.getOutput() == null)
194227614Sluigi                continue;
195228276Sluigi
196227614Sluigi            if (o.getOutput().getAction() == null || o.getOutput().getAction().equals("")) {
197228276Sluigi                o.getOutput().setAction(defaultOutputAction(o));
198228276Sluigi            }
199228276Sluigi
200228276Sluigi            if (o.getFaults() == null || !o.getFaults().iterator().hasNext())
201228276Sluigi                continue;
202228276Sluigi
203231778Sluigi            for (EditableWSDLFault f : o.getFaults()) {
204228276Sluigi                if (f.getAction() == null || f.getAction().equals("")) {
205228276Sluigi                    f.setAction(defaultFaultAction(f.getName(), o));
206228276Sluigi                }
207228276Sluigi
208228276Sluigi            }
209232238Sluigi        }
210228276Sluigi    }
211228276Sluigi
212228276Sluigi    /**
213228276Sluigi     * Patch the default value of wsaw:Anonymous=optional if none is specified
214228276Sluigi     *
215228276Sluigi     * @param binding WSDLBoundPortTypeImpl
216232238Sluigi     */
217231778Sluigi    protected void patchAnonymousDefault(EditableWSDLBoundPortType binding) {
218231198Sluigi        for (EditableWSDLBoundOperation wbo : binding.getBindingOperations()) {
219227614Sluigi            if (wbo.getAnonymous() == null)
220227614Sluigi                wbo.setAnonymous(ANONYMOUS.optional);
221227614Sluigi        }
222227614Sluigi    }
223227614Sluigi
224227614Sluigi    private String defaultInputAction(EditableWSDLOperation o) {
225227614Sluigi        return buildAction(o.getInput().getName(), o, false);
226228276Sluigi    }
227227614Sluigi
228227614Sluigi    private String defaultOutputAction(EditableWSDLOperation o) {
229231594Sluigi        return buildAction(o.getOutput().getName(), o, false);
230227614Sluigi    }
231231594Sluigi
232232238Sluigi    private String defaultFaultAction(String name, EditableWSDLOperation o) {
233231796Sluigi        return buildAction(name, o, true);
234227614Sluigi    }
235232238Sluigi
236232238Sluigi    protected static final String buildAction(String name, EditableWSDLOperation o, boolean isFault) {
237232238Sluigi        String tns = o.getName().getNamespaceURI();
238227614Sluigi
239228276Sluigi        String delim = SLASH_DELIMITER;
240227614Sluigi
241227614Sluigi        // TODO: is this the correct way to find the separator ?
242227614Sluigi        if (!tns.startsWith("http"))
243227614Sluigi            delim = COLON_DELIMITER;
244231778Sluigi
245227614Sluigi        if (tns.endsWith(delim))
246227614Sluigi            tns = tns.substring(0, tns.length()-1);
247227614Sluigi
248227614Sluigi        if (o.getPortTypeName() == null)
249232238Sluigi            throw new WebServiceException("\"" + o.getName() + "\" operation's owning portType name is null.");
250232238Sluigi
251232238Sluigi        return tns +
252231778Sluigi            delim +
253231778Sluigi            o.getPortTypeName().getLocalPart() +
254232238Sluigi            delim +
255232238Sluigi            (isFault ? o.getName().getLocalPart() + delim + "Fault" + delim : "") +
256232238Sluigi            name;
257232238Sluigi    }
258232238Sluigi
259232238Sluigi    protected static final String COLON_DELIMITER = ":";
260227614Sluigi    protected static final String SLASH_DELIMITER = "/";
261232238Sluigi}
262232238Sluigi