/* * Copyright 2005-2014 the original author or authors. * * Licensed 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.springframework.ws.wsdl.wsdl11.provider; import java.util.Iterator; import javax.wsdl.Binding; import javax.wsdl.BindingFault; import javax.wsdl.BindingInput; import javax.wsdl.BindingOperation; import javax.wsdl.BindingOutput; import javax.wsdl.Definition; import javax.wsdl.Fault; import javax.wsdl.Input; import javax.wsdl.Operation; import javax.wsdl.OperationType; import javax.wsdl.Output; import javax.wsdl.Port; import javax.wsdl.PortType; import javax.wsdl.Service; import javax.wsdl.WSDLException; import javax.xml.namespace.QName; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.util.Assert; import org.springframework.util.StringUtils; /** * Default implementation of the {@link BindingsProvider} and {@link ServicesProvider} interfaces. * * <p>Creates a {@code binding} that matches any present {@code portType}, and a service containing * {@code port}s that match the {@code binding}s. Lets subclasses populate these through template methods. * * * @author Arjen Poutsma * @since 1.5.0 */ public class DefaultConcretePartProvider implements BindingsProvider, ServicesProvider { /** Logger available to subclasses. */ protected final Log logger = LogFactory.getLog(getClass()); private String bindingSuffix; private String serviceName; /** Returns the service name. */ public String getServiceName() { return serviceName; } /** Sets the service name. */ public void setServiceName(String serviceName) { Assert.hasText(serviceName, "'serviceName' must not be null"); this.serviceName = serviceName; } /** Returns the suffix to append to the port type name to obtain the binding name. */ public String getBindingSuffix() { return bindingSuffix; } /** Sets the suffix to append to the port type name to obtain the binding name. */ public void setBindingSuffix(String bindingSuffix) { Assert.notNull(bindingSuffix, "'bindingSuffix' must not be null"); this.bindingSuffix = bindingSuffix; } /** * Creates a {@link Binding} for each {@link PortType} in the definition, and calls {@link * #populateBinding(Definition,javax.wsdl.Binding)} with it. Creates a {@link BindingOperation} for each {@link * Operation} in the port type, a {@link BindingInput} for each {@link Input} in the operation, etc. * * <p>Calls the various {@code populate} methods with the created WSDL4J objects. * * @param definition the WSDL4J {@code Definition} * @throws WSDLException in case of errors * @see #populateBinding(Definition,javax.wsdl.Binding) * @see #populateBindingOperation(Definition,javax.wsdl.BindingOperation) * @see #populateBindingInput(Definition,javax.wsdl.BindingInput,javax.wsdl.Input) * @see #populateBindingOutput(Definition,javax.wsdl.BindingOutput,javax.wsdl.Output) * @see #populateBindingFault(Definition,javax.wsdl.BindingFault,javax.wsdl.Fault) */ @Override public void addBindings(Definition definition) throws WSDLException { for (Iterator<?> iterator = definition.getPortTypes().values().iterator(); iterator.hasNext();) { PortType portType = (PortType) iterator.next(); Binding binding = definition.createBinding(); binding.setPortType(portType); populateBinding(definition, binding); createBindingOperations(definition, binding); binding.setUndefined(false); if (binding.getQName() != null) { definition.addBinding(binding); } } if (definition.getBindings().isEmpty() && logger.isWarnEnabled()) { logger.warn("No bindings were created, make sure the WSDL contains port types"); } } /** * Called after the {@link Binding} has been created, but before any sub-elements are added. Subclasses can override * this method to define the binding name, or add extensions to it. * * <p>Default implementation sets the binding name to the port type name with the {@link #getBindingSuffix() suffix} * appended to it. * * @param definition the WSDL4J {@code Definition} * @param binding the WSDL4J {@code Binding} */ protected void populateBinding(Definition definition, Binding binding) throws WSDLException { QName portTypeName = binding.getPortType().getQName(); if (portTypeName != null) { QName bindingName = new QName(portTypeName.getNamespaceURI(), portTypeName.getLocalPart() + getBindingSuffix()); if (logger.isDebugEnabled()) { logger.debug("Creating binding [" + bindingName + "]"); } binding.setQName(bindingName); } } private void createBindingOperations(Definition definition, Binding binding) throws WSDLException { PortType portType = binding.getPortType(); for (Iterator<?> operationIterator = portType.getOperations().iterator(); operationIterator.hasNext();) { Operation operation = (Operation) operationIterator.next(); BindingOperation bindingOperation = definition.createBindingOperation(); bindingOperation.setOperation(operation); populateBindingOperation(definition, bindingOperation); if (OperationType.REQUEST_RESPONSE.equals(operation.getStyle())) { createBindingInput(definition, operation, bindingOperation); createBindingOutput(definition, operation, bindingOperation); } else if (OperationType.ONE_WAY.equals(operation.getStyle())) { createBindingInput(definition, operation, bindingOperation); } else if (OperationType.NOTIFICATION.equals(operation.getStyle())) { createBindingOutput(definition, operation, bindingOperation); } else if (OperationType.SOLICIT_RESPONSE.equals(operation.getStyle())) { createBindingOutput(definition, operation, bindingOperation); createBindingInput(definition, operation, bindingOperation); } for (Iterator<?> faultIterator = operation.getFaults().values().iterator(); faultIterator.hasNext();) { Fault fault = (Fault) faultIterator.next(); BindingFault bindingFault = definition.createBindingFault(); populateBindingFault(definition, bindingFault, fault); if (StringUtils.hasText(bindingFault.getName())) { bindingOperation.addBindingFault(bindingFault); } } binding.addBindingOperation(bindingOperation); } } /** * Called after the {@link BindingOperation} has been created, but before any sub-elements are added. Subclasses can * override this method to define the binding name, or add extensions to it. * * <p>Default implementation sets the name of the binding operation to the name of the operation. * * @param definition the WSDL4J {@code Definition} * @param bindingOperation the WSDL4J {@code BindingOperation} * @throws WSDLException in case of errors */ protected void populateBindingOperation(Definition definition, BindingOperation bindingOperation) throws WSDLException { bindingOperation.setName(bindingOperation.getOperation().getName()); } private void createBindingInput(Definition definition, Operation operation, BindingOperation bindingOperation) throws WSDLException { BindingInput bindingInput = definition.createBindingInput(); populateBindingInput(definition, bindingInput, operation.getInput()); bindingOperation.setBindingInput(bindingInput); } private void createBindingOutput(Definition definition, Operation operation, BindingOperation bindingOperation) throws WSDLException { BindingOutput bindingOutput = definition.createBindingOutput(); populateBindingOutput(definition, bindingOutput, operation.getOutput()); bindingOperation.setBindingOutput(bindingOutput); } /** * Called after the {@link BindingInput} has been created. Subclasses can override this method to define the name, * or add extensions to it. * * <p>Default implementation set the name of the binding input to the name of the input. * * @param definition the WSDL4J {@code Definition} * @param bindingInput the WSDL4J {@code BindingInput} * @param input the corresponding WSDL4J {@code Input} @throws WSDLException in case of errors */ protected void populateBindingInput(Definition definition, BindingInput bindingInput, Input input) throws WSDLException { bindingInput.setName(input.getName()); } /** * Called after the {@link BindingOutput} has been created. Subclasses can override this method to define the name, * or add extensions to it. * * <p>Default implementation sets the name of the binding output to the name of the output. * * @param definition the WSDL4J {@code Definition} * @param bindingOutput the WSDL4J {@code BindingOutput} * @param output the corresponding WSDL4J {@code Output} @throws WSDLException in case of errors */ protected void populateBindingOutput(Definition definition, BindingOutput bindingOutput, Output output) throws WSDLException { bindingOutput.setName(output.getName()); } /** * Called after the {@link BindingFault} has been created. Subclasses can implement this method to define the name, * or add extensions to it. * * <p>Default implementation set the name of the binding fault to the name of the fault. * * @param bindingFault the WSDL4J {@code BindingFault} * @param fault the corresponding WSDL4J {@code Fault} @throws WSDLException in case of errors */ protected void populateBindingFault(Definition definition, BindingFault bindingFault, Fault fault) throws WSDLException { bindingFault.setName(fault.getName()); } /** * Creates a single {@link Service} if not present, and calls {@link #populateService(Definition, Service)} with it. * Creates a corresponding {@link Port} for each {@link Binding}, which is passed to {@link * #populatePort(javax.wsdl.Definition,javax.wsdl.Port)}. * * @param definition the WSDL4J {@code Definition} * @throws WSDLException in case of errors */ @Override public void addServices(Definition definition) throws WSDLException { Assert.notNull(getServiceName(), "'serviceName' is required"); Service service; if (definition.getServices().isEmpty()) { service = definition.createService(); } else { service = (Service) definition.getServices().values().iterator().next(); } populateService(definition, service); createPorts(definition, service); if (service.getQName() != null) { definition.addService(service); } } /** * Called after the {@link Service} has been created, but before any sub-elements are added. Subclasses can * implement this method to define the service name, or add extensions to it. * * <p>Default implementation sets the name to the {@link #setServiceName(String) serviceName} property. * * @param service the WSDL4J {@code Service} * @throws WSDLException in case of errors */ protected void populateService(Definition definition, Service service) throws WSDLException { if (StringUtils.hasText(definition.getTargetNamespace()) && StringUtils.hasText(getServiceName())) { QName serviceName = new QName(definition.getTargetNamespace(), getServiceName()); if (logger.isDebugEnabled()) { logger.debug("Creating service [" + serviceName + "]"); } service.setQName(serviceName); } } private void createPorts(Definition definition, Service service) throws WSDLException { for (Iterator<?> iterator = definition.getBindings().values().iterator(); iterator.hasNext();) { Binding binding = (Binding) iterator.next(); Port port = null; for (Iterator<?> iterator1 = service.getPorts().values().iterator(); iterator1.hasNext();) { Port existingPort = (Port) iterator1.next(); if (binding.equals(existingPort.getBinding())) { port = existingPort; } } if (port == null) { port = definition.createPort(); port.setBinding(binding); } populatePort(definition, port); if (StringUtils.hasText(port.getName())) { if (logger.isDebugEnabled()) { logger.debug("Adding port [" + port.getName() + "] to service [" + service.getQName() + "]"); } service.addPort(port); } } if (service.getPorts().isEmpty() && logger.isWarnEnabled()) { logger.warn("No ports were created, make sure the WSDL contains bindings"); } } /** * Called after the {@link Port} has been created, but before any sub-elements are added. Subclasses can implement * this method to define the port name, or add extensions to it. * * <p>Default implementation sets the port name to the binding name. * * @param definition the WSDL4J {@code Definition} * @param port the WSDL4J {@code Port} * @throws WSDLException in case of errors */ protected void populatePort(Definition definition, Port port) throws WSDLException { String portName = port.getBinding().getQName().getLocalPart(); port.setName(portName); } }