/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.ode.utils.wsdl; import org.apache.ode.utils.Namespaces; import org.apache.ode.utils.stl.CollectionsX; import org.w3c.dom.Element; import javax.wsdl.Binding; import javax.wsdl.BindingFault; import javax.wsdl.BindingInput; import javax.wsdl.BindingOperation; import javax.wsdl.Definition; import javax.wsdl.Fault; import javax.wsdl.Operation; import javax.wsdl.Part; import javax.wsdl.Port; import javax.wsdl.Service; import javax.wsdl.extensions.ExtensibilityElement; import javax.wsdl.extensions.UnknownExtensibilityElement; import javax.wsdl.extensions.http.HTTPAddress; import javax.wsdl.extensions.http.HTTPBinding; import javax.wsdl.extensions.http.HTTPOperation; import javax.wsdl.extensions.http.HTTPUrlEncoded; import javax.wsdl.extensions.http.HTTPUrlReplacement; import javax.wsdl.extensions.mime.MIMEContent; import javax.wsdl.extensions.mime.MIMEMultipartRelated; import javax.wsdl.extensions.soap.SOAPAddress; import javax.wsdl.extensions.soap.SOAPBinding; import javax.wsdl.extensions.soap.SOAPOperation; import javax.xml.namespace.QName; import java.util.ArrayList; import java.util.Collection; import java.util.List; /** * @author <a href="mailto:midon@intalio.com">Alexis Midon</a> */ public class WsdlUtils { private static final Messages msgs = Messages.getMessages(Messages.class); /** * Test if the given binding uses a Soap binding. * * @param binding * @return true if {@link SOAPBinding} is assignable from the binding * @see #getBindingExtension(javax.wsdl.Binding) */ public static boolean useSOAPBinding(Binding binding) { ExtensibilityElement element = getBindingExtension(binding); return SOAPBinding.class.isAssignableFrom(element.getClass()); } /** * Test if the given binding uses HTTP binding. * * @param binding * @return true if {@link HTTPBinding} is assignable from the binding * @see #getBindingExtension(javax.wsdl.Binding) */ public static boolean useHTTPBinding(Binding binding) { ExtensibilityElement element = getBindingExtension(binding); // with a fully wsdl-compliant document, this element cannot be null. // but ODE extends the HTTP binding and supports the HTTP verb at the operation level. // A port using this extension may have no HTTPBinding at the port level. if (element == null) { // in this case, we check the binding information of one operation final BindingOperation anOperation = (BindingOperation) binding.getBindingOperations().get(0); final ExtensibilityElement opExt = getOperationExtension(anOperation); return HTTPOperation.class.isAssignableFrom(opExt.getClass()); } else { return HTTPBinding.class.isAssignableFrom(element.getClass()); } } /** * @see #useSOAPBinding(javax.wsdl.Binding) */ public static boolean useSOAPBinding(Port port) { return useSOAPBinding(port.getBinding()); } /** * @see #useHTTPBinding(javax.wsdl.Binding) */ public static boolean useHTTPBinding(Port port) { return useHTTPBinding(port.getBinding()); } /** * @see #useSOAPBinding(javax.wsdl.Binding) */ public static boolean useSOAPBinding(Definition def, QName serviceName, String portName) { Service serviceDef = def.getService(serviceName); if (serviceDef == null) throw new IllegalArgumentException(msgs.msgServiceDefinitionNotFound(serviceName)); Port port = serviceDef.getPort(portName); if (port == null) throw new IllegalArgumentException(msgs.msgPortDefinitionNotFound(serviceName, portName)); return useSOAPBinding(port); } /** * @see #useHTTPBinding(javax.wsdl.Binding) */ public static boolean useHTTPBinding(Definition def, QName serviceName, String portName) { Service serviceDef = def.getService(serviceName); if (serviceDef == null) throw new IllegalArgumentException(msgs.msgServiceDefinitionNotFound(serviceName)); Port port = serviceDef.getPort(portName); if (port == null) throw new IllegalArgumentException(msgs.msgPortDefinitionNotFound(serviceName, portName)); return useHTTPBinding(port); } /** * Look up the ExtensibilityElement defining the binding for the given Port or * throw an {@link IllegalArgumentException} if multiple bindings found. * * @param binding * @return an instance of {@link SOAPBinding} or {@link HTTPBinding} or null * @throws IllegalArgumentException if multiple bindings found. */ public static ExtensibilityElement getBindingExtension(Binding binding) { Collection bindings = new ArrayList(); CollectionsX.filter(bindings, binding.getExtensibilityElements(), HTTPBinding.class); CollectionsX.filter(bindings, binding.getExtensibilityElements(), SOAPBinding.class); if (bindings.size() == 0) { return null; } else if (bindings.size() > 1) { // exception if multiple bindings found throw new IllegalArgumentException(msgs.msgMultipleBindings(binding.getQName())); } else { // retrieve the single element ExtensibilityElement result = (ExtensibilityElement) bindings.iterator().next(); return result; } } /** * @see #getBindingExtension(javax.wsdl.Binding) */ public static ExtensibilityElement getBindingExtension(Port port) { Binding binding = port.getBinding(); if (binding == null) { throw new IllegalArgumentException(msgs.msgBindingNotFound(port.getName())); } return getBindingExtension(binding); } /** * Extract the instance of {@link javax.wsdl.extensions.http.HTTPOperation] or {@link javax.wsdl.extensions.soap.SOAPOperation} * from the list of extensibility elements of the given {@link javax.wsdl.BindingOperation}. * * @param bindingOperation * @return an instance of {@link javax.wsdl.extensions.http.HTTPOperation} or {@link javax.wsdl.extensions.soap.SOAPOperation} * @throws IllegalArgumentException if not exactly 1 element is found. */ public static ExtensibilityElement getOperationExtension(BindingOperation bindingOperation) { Collection operations = new ArrayList(); CollectionsX.filter(operations, bindingOperation.getExtensibilityElements(), HTTPOperation.class); CollectionsX.filter(operations, bindingOperation.getExtensibilityElements(), SOAPOperation.class); if (operations.size() == 0) { // exception if no bindings found throw new IllegalArgumentException(msgs.msgNoBindingForOperation(bindingOperation.getName())); } else if (operations.size() > 1) { // exception if multiple bindings found throw new IllegalArgumentException(msgs.msgMultipleBindingsForOperation(bindingOperation.getName())); } else { // retrieve the single element ExtensibilityElement result = (ExtensibilityElement) operations.iterator().next(); return result; } } /** * @return true if the extensibility elements of the given {@link javax.wsdl.BindingInput} contains an instance of {@link javax.wsdl.extensions.http.HTTPUrlEncoded} */ public static boolean useUrlEncoded(BindingInput bindingInput) { Collection<HTTPUrlEncoded> coll = CollectionsX.filter(bindingInput.getExtensibilityElements(), HTTPUrlEncoded.class); return !coll.isEmpty(); } /** * @return true if the extensibility elements of the given {@link javax.wsdl.BindingInput} contains an instance of {@link javax.wsdl.extensions.http.HTTPUrlReplacement} */ public static boolean useUrlReplacement(BindingInput bindingInput) { Collection<HTTPUrlReplacement> coll = CollectionsX.filter(bindingInput.getExtensibilityElements(), HTTPUrlReplacement.class); return !coll.isEmpty(); } /** * @return true if the extensibility elements of the given {@link javax.wsdl.BindingInput} contains an instance of {@link javax.wsdl.extensions.mime.MIMEMultipartRelated} */ public static boolean useMimeMultipartRelated(BindingInput bindingInput) { Collection<MIMEMultipartRelated> coll = CollectionsX.filter(bindingInput.getExtensibilityElements(), MIMEMultipartRelated.class); return !coll.isEmpty(); } /** * @return the {@linkplain javax.wsdl.extensions.mime.MIMEContent#getType() type} of the instance of {@link javax.wsdl.extensions.mime.MIMEContent} * contained in the extensibility element list. Or null if none. * @throws IllegalArgumentException if more than 1 MIMEContent is found. */ public static MIMEContent getMimeContent(List extensibilityElements) { Collection<MIMEContent> coll = CollectionsX.filter(extensibilityElements, MIMEContent.class); if (coll.size() == 0) { return null; } else if (coll.size() > 1) { // exception if multiple contents found throw new IllegalArgumentException(msgs.msgMultipleMimeContent()); } else { // retrieve the single element return coll.iterator().next(); } } /** * Extract the instance of {@link javax.wsdl.extensions.http.HTTPAddress] or {@link javax.wsdl.extensions.soap.SOAPAddress} * from the list of extensibility elements of the given {@link javax.wsdl.Port}. * * @param port * @return an instance of {@link javax.wsdl.extensions.http.HTTPAddress} or {@link javax.wsdl.extensions.soap.SOAPAddress} * @throws IllegalArgumentException if not exactly 1 element is found. */ public static ExtensibilityElement getAddressExtension(Port port) { Collection operations = new ArrayList(); CollectionsX.filter(operations, port.getExtensibilityElements(), HTTPAddress.class); CollectionsX.filter(operations, port.getExtensibilityElements(), SOAPAddress.class); if (operations.size() == 0) { // exception if no bindings found throw new IllegalArgumentException(msgs.msgNoAddressForPort(port.getName())); } else if (operations.size() > 1) { // exception if multiple bindings found throw new IllegalArgumentException(msgs.msgMultipleAddressesForPort(port.getName())); } else { // retrieve the single element ExtensibilityElement result = (ExtensibilityElement) operations.iterator().next(); return result; } } /** * ODE extends the wsdl spec by allowing definition of the HTTP verb at the operation level. * <br/> If you do so, an {@link UnknownExtensibilityElement} will be added to the list of extensibility elements of the {@link javax.wsdl.BindingOperation}. * <br/> This method looks up for such an element and return the value of the verb attribute if the underlying {@link org.w3c.dom.Element} is {@literal <binding xmlns="http://schemas.xmlsoap.org/wsdl/http/"/>} * or null. * * @param bindingOperation */ public static String getOperationVerb(BindingOperation bindingOperation) { final Collection<UnknownExtensibilityElement> unknownExtElements = CollectionsX.filter(bindingOperation.getExtensibilityElements(), UnknownExtensibilityElement.class); for (UnknownExtensibilityElement extensibilityElement : unknownExtElements) { final Element e = extensibilityElement.getElement(); if (Namespaces.ODE_HTTP_EXTENSION_NS.equalsIgnoreCase(e.getNamespaceURI()) && "binding".equals(extensibilityElement.getElement().getLocalName()) && e.hasAttribute("verb")) { return e.getAttribute("verb"); } } return null; } /** * @param fault * @return true if the given fault is bound with the {@link org.apache.ode.utils.Namespaces.ODE_HTTP_EXTENSION_NS}:fault element. */ public static boolean isOdeFault(BindingFault fault) { final Collection<UnknownExtensibilityElement> unknownExtElements = CollectionsX.filter(fault.getExtensibilityElements(), UnknownExtensibilityElement.class); for (UnknownExtensibilityElement extensibilityElement : unknownExtElements) { final Element e = extensibilityElement.getElement(); if (Namespaces.ODE_HTTP_EXTENSION_NS.equalsIgnoreCase(e.getNamespaceURI()) && "fault".equals(extensibilityElement.getElement().getLocalName())) { // name attribute is optional, but if any it must match the fault name if (e.hasAttribute("name")) { return fault.getName().equals(e.getAttribute("name")); } else { return true; } } } return false; } public static Collection<UnknownExtensibilityElement> getHttpHeaders(List extensibilityElements) { final Collection<UnknownExtensibilityElement> unknownExtElements = CollectionsX.filter(extensibilityElements, UnknownExtensibilityElement.class); for (UnknownExtensibilityElement extensibilityElement : unknownExtElements) { final Element e = extensibilityElement.getElement(); // keep only the header elements if (!Namespaces.ODE_HTTP_EXTENSION_NS.equalsIgnoreCase(e.getNamespaceURI()) || !"header".equals(extensibilityElement.getElement().getLocalName())) { unknownExtElements.remove(extensibilityElement); } } return unknownExtElements; } /** * Return the {@link javax.wsdl.Fault} that has the given element as message part. * * @param operation the operation * @param elName the qname to look for * @return the first fault for which the element of message part matches the given qname */ @SuppressWarnings("unchecked") public static Fault inferFault(Operation operation, QName elName) { for (Fault f : (Collection<Fault>) operation.getFaults().values()) { if (f.getMessage() == null) continue; Collection<Part> parts = f.getMessage().getParts().values(); if (parts.isEmpty()) continue; Part p = parts.iterator().next(); if (p.getElementName() == null) continue; if (p.getElementName().equals(elName)) return f; } return null; } /** * ODE extends the wsdl spec by allowing definition of the HTTP verb at the operation level. * <br/>The current implementation implementations allows you to have a {@literal <binding xmlns="http://schemas.xmlsoap.org/wsdl/http/"/>} element * at the port level <strong>and</strong> at the operation level. In such a case the operation's verb overrides the port's verb. * <br/> This method applies the later rule. * <br/> If defined the operation's verb is returned, else the port's verb. * * @param binding * @param bindingOperation * @return If defined the operation's verb is returned, else the port's verb. * @see #getOperationVerb(javax.wsdl.BindingOperation) */ public static String resolveVerb(Binding binding, BindingOperation bindingOperation) { final HTTPBinding httpBinding = (HTTPBinding) WsdlUtils.getBindingExtension(binding); String portVerb = httpBinding != null ? httpBinding.getVerb() : null; String operationVerb = WsdlUtils.getOperationVerb(bindingOperation); return operationVerb != null ? operationVerb : portVerb; } }