View Javadoc

1   /*
2    * Copyright 2008 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.springframework.ws.wsdl.wsdl11.provider;
18  
19  import java.util.Iterator;
20  import javax.wsdl.Binding;
21  import javax.wsdl.BindingFault;
22  import javax.wsdl.BindingInput;
23  import javax.wsdl.BindingOperation;
24  import javax.wsdl.BindingOutput;
25  import javax.wsdl.Definition;
26  import javax.wsdl.Fault;
27  import javax.wsdl.Input;
28  import javax.wsdl.Operation;
29  import javax.wsdl.OperationType;
30  import javax.wsdl.Output;
31  import javax.wsdl.Port;
32  import javax.wsdl.PortType;
33  import javax.wsdl.Service;
34  import javax.wsdl.WSDLException;
35  import javax.xml.namespace.QName;
36  
37  import org.apache.commons.logging.Log;
38  import org.apache.commons.logging.LogFactory;
39  
40  import org.springframework.util.Assert;
41  import org.springframework.util.StringUtils;
42  
43  /**
44   * Default implementation of the {@link BindingsProvider} and {@link ServicesProvider} interfaces.
45   * <p/>
46   * Creates a <code>binding</code> that matches any present <code>portType</code>, and a service containing
47   * <code>port</code>s that match the <code>binding</code>s. Lets subclasses populate these through template methods. *
48   *
49   * @author Arjen Poutsma
50   * @since 1.5.0
51   */
52  public class DefaultConcretePartProvider implements BindingsProvider, ServicesProvider {
53  
54      /** Logger available to subclasses. */
55      protected final Log logger = LogFactory.getLog(getClass());
56  
57      private String bindingSuffix;
58  
59      private String serviceName;
60  
61      /** Returns the service name. */
62      public String getServiceName() {
63          return serviceName;
64      }
65  
66      /** Sets the service name. */
67      public void setServiceName(String serviceName) {
68          Assert.hasText(serviceName, "'serviceName' must not be null");
69          this.serviceName = serviceName;
70      }
71  
72      /** Returns the suffix to append to the port type name to obtain the binding name. */
73      public String getBindingSuffix() {
74          return bindingSuffix;
75      }
76  
77      /** Sets the suffix to append to the port type name to obtain the binding name. */
78      public void setBindingSuffix(String bindingSuffix) {
79          Assert.hasText(bindingSuffix, "'bindingSuffix' must not be null");
80          this.bindingSuffix = bindingSuffix;
81      }
82  
83      /**
84       * Creates a {@link Binding} for each {@link PortType} in the definition, and calls {@link
85       * #populateBinding(Definition,javax.wsdl.Binding)} with it. Creates a {@link BindingOperation} for each {@link
86       * Operation} in the port type, a {@link BindingInput} for each {@link Input} in the operation, etc.
87       * <p/>
88       * Calls the various <code>populate</code> methods with the created WSDL4J objects.
89       *
90       * @param definition the WSDL4J <code>Definition</code>
91       * @throws WSDLException in case of errors
92       * @see #populateBinding(Definition,javax.wsdl.Binding)
93       * @see #populateBindingOperation(Definition,javax.wsdl.BindingOperation)
94       * @see #populateBindingInput(Definition,javax.wsdl.BindingInput,javax.wsdl.Input)
95       * @see #populateBindingOutput(Definition,javax.wsdl.BindingOutput,javax.wsdl.Output)
96       * @see #populateBindingFault(Definition,javax.wsdl.BindingFault,javax.wsdl.Fault)
97       */
98      public void addBindings(Definition definition) throws WSDLException {
99          for (Iterator iterator = definition.getPortTypes().values().iterator(); iterator.hasNext();) {
100             PortType portType = (PortType) iterator.next();
101             Binding binding = definition.createBinding();
102             binding.setPortType(portType);
103             populateBinding(definition, binding);
104             createBindingOperations(definition, binding);
105             binding.setUndefined(false);
106             if (binding.getQName() != null) {
107                 definition.addBinding(binding);
108             }
109         }
110         if (definition.getBindings().isEmpty() && logger.isWarnEnabled()) {
111             logger.warn("No bindings were created, make sure the WSDL contains port types");
112         }
113     }
114 
115     /**
116      * Called after the {@link Binding} has been created, but before any sub-elements are added. Subclasses can override
117      * this method to define the binding name, or add extensions to it.
118      * <p/>
119      * Default implementation sets the binding name to the port type name with the {@link #getBindingSuffix() suffix}
120      * appended to it.
121      *
122      * @param definition the WSDL4J <code>Definition</code>
123      * @param binding    the WSDL4J <code>Binding</code>
124      */
125     protected void populateBinding(Definition definition, Binding binding) throws WSDLException {
126         QName portTypeName = binding.getPortType().getQName();
127         if (portTypeName != null) {
128             QName bindingName =
129                     new QName(portTypeName.getNamespaceURI(), portTypeName.getLocalPart() + getBindingSuffix());
130             if (logger.isDebugEnabled()) {
131                 logger.debug("Creating binding [" + bindingName + "]");
132             }
133             binding.setQName(bindingName);
134         }
135     }
136 
137     private void createBindingOperations(Definition definition, Binding binding) throws WSDLException {
138         PortType portType = binding.getPortType();
139         for (Iterator operationIterator = portType.getOperations().iterator(); operationIterator.hasNext();) {
140             Operation operation = (Operation) operationIterator.next();
141             BindingOperation bindingOperation = definition.createBindingOperation();
142             bindingOperation.setOperation(operation);
143             populateBindingOperation(definition, bindingOperation);
144             if (OperationType.REQUEST_RESPONSE.equals(operation.getStyle())) {
145                 createBindingInput(definition, operation, bindingOperation);
146                 createBindingOutput(definition, operation, bindingOperation);
147             }
148             else if (OperationType.ONE_WAY.equals(operation.getStyle())) {
149                 createBindingInput(definition, operation, bindingOperation);
150             }
151             else if (OperationType.NOTIFICATION.equals(operation.getStyle())) {
152                 createBindingOutput(definition, operation, bindingOperation);
153             }
154             else if (OperationType.SOLICIT_RESPONSE.equals(operation.getStyle())) {
155                 createBindingOutput(definition, operation, bindingOperation);
156                 createBindingInput(definition, operation, bindingOperation);
157             }
158             for (Iterator faultIterator = operation.getFaults().values().iterator(); faultIterator.hasNext();) {
159                 Fault fault = (Fault) faultIterator.next();
160                 BindingFault bindingFault = definition.createBindingFault();
161                 populateBindingFault(definition, bindingFault, fault);
162                 if (StringUtils.hasText(bindingFault.getName())) {
163                     bindingOperation.addBindingFault(bindingFault);
164                 }
165             }
166             binding.addBindingOperation(bindingOperation);
167         }
168     }
169 
170     /**
171      * Called after the {@link BindingOperation} has been created, but before any sub-elements are added. Subclasses can
172      * override this method to define the binding name, or add extensions to it.
173      * <p/>
174      * Default implementation sets the name of the binding operation to the name of the operation.
175      *
176      * @param definition       the WSDL4J <code>Definition</code>
177      * @param bindingOperation the WSDL4J <code>BindingOperation</code>
178      * @throws WSDLException in case of errors
179      */
180     protected void populateBindingOperation(Definition definition, BindingOperation bindingOperation)
181             throws WSDLException {
182         bindingOperation.setName(bindingOperation.getOperation().getName());
183     }
184 
185     private void createBindingInput(Definition definition, Operation operation, BindingOperation bindingOperation)
186             throws WSDLException {
187         BindingInput bindingInput = definition.createBindingInput();
188         populateBindingInput(definition, bindingInput, operation.getInput());
189         bindingOperation.setBindingInput(bindingInput);
190     }
191 
192     private void createBindingOutput(Definition definition, Operation operation, BindingOperation bindingOperation)
193             throws WSDLException {
194         BindingOutput bindingOutput = definition.createBindingOutput();
195         populateBindingOutput(definition, bindingOutput, operation.getOutput());
196         bindingOperation.setBindingOutput(bindingOutput);
197     }
198 
199     /**
200      * Called after the {@link BindingInput} has been created. Subclasses can override this method to define the name,
201      * or add extensions to it.
202      * <p/>
203      * Default implementation set the name of the binding input to the name of the input.
204      *
205      * @param definition   the WSDL4J <code>Definition</code>
206      * @param bindingInput the WSDL4J <code>BindingInput</code>
207      * @param input        the corresponding WSDL4J <code>Input</code> @throws WSDLException in case of errors
208      */
209     protected void populateBindingInput(Definition definition, BindingInput bindingInput, Input input)
210             throws WSDLException {
211         bindingInput.setName(input.getName());
212     }
213 
214     /**
215      * Called after the {@link BindingOutput} has been created. Subclasses can override this method to define the name,
216      * or add extensions to it.
217      * <p/>
218      * Default implementation sets the name of the binding output to the name of the output.
219      *
220      * @param definition    the WSDL4J <code>Definition</code>
221      * @param bindingOutput the WSDL4J <code>BindingOutput</code>
222      * @param output        the corresponding WSDL4J <code>Output</code> @throws WSDLException in case of errors
223      */
224     protected void populateBindingOutput(Definition definition, BindingOutput bindingOutput, Output output)
225             throws WSDLException {
226         bindingOutput.setName(output.getName());
227     }
228 
229     /**
230      * Called after the {@link BindingFault} has been created. Subclasses can implement this method to define the name,
231      * or add extensions to it.
232      * <p/>
233      * Default implementation set the name of the binding fault to the name of the fault.
234      *
235      * @param bindingFault the WSDL4J <code>BindingFault</code>
236      * @param fault        the corresponding WSDL4J <code>Fault</code> @throws WSDLException in case of errors
237      */
238     protected void populateBindingFault(Definition definition, BindingFault bindingFault, Fault fault)
239             throws WSDLException {
240         bindingFault.setName(fault.getName());
241     }
242 
243     /**
244      * Creates a single {@link Service} if not present, and calls {@link #populateService(Definition, Service)} with it.
245      * Creates a corresponding {@link Port} for each {@link Binding}, which is passed to {@link
246      * #populatePort(javax.wsdl.Definition,javax.wsdl.Port)}.
247      *
248      * @param definition the WSDL4J <code>Definition</code>
249      * @throws WSDLException in case of errors
250      */
251     public void addServices(Definition definition) throws WSDLException {
252         Assert.notNull(getServiceName(), "'serviceName' is required");
253         Service service;
254         if (definition.getServices().isEmpty()) {
255             service = definition.createService();
256         }
257         else {
258             service = (Service) definition.getServices().values().iterator().next();
259         }
260         populateService(definition, service);
261         createPorts(definition, service);
262         if (service.getQName() != null) {
263             definition.addService(service);
264         }
265     }
266 
267     /**
268      * Called after the {@link Service} has been created, but before any sub-elements are added. Subclasses can
269      * implement this method to define the service name, or add extensions to it.
270      * <p/>
271      * Default implementation sets the name to the {@link #setServiceName(String) serviceName} property.
272      *
273      * @param service the WSDL4J <code>Service</code>
274      * @throws WSDLException in case of errors
275      */
276     protected void populateService(Definition definition, Service service) throws WSDLException {
277         if (StringUtils.hasText(definition.getTargetNamespace()) && StringUtils.hasText(getServiceName())) {
278             QName serviceName = new QName(definition.getTargetNamespace(), getServiceName());
279             if (logger.isDebugEnabled()) {
280                 logger.debug("Creating service [" + serviceName + "]");
281             }
282             service.setQName(serviceName);
283         }
284     }
285 
286     private void createPorts(Definition definition, Service service) throws WSDLException {
287         for (Iterator iterator = definition.getBindings().values().iterator(); iterator.hasNext();) {
288             Binding binding = (Binding) iterator.next();
289             Port port = null;
290             for (Iterator iterator1 = service.getPorts().values().iterator(); iterator1.hasNext();) {
291                 Port existingPort = (Port) iterator1.next();
292                 if (binding.equals(existingPort.getBinding())) {
293                     port = existingPort;
294                 }
295             }
296             if (port == null) {
297                 port = definition.createPort();
298                 port.setBinding(binding);
299             }
300             populatePort(definition, port);
301             if (StringUtils.hasText(port.getName())) {
302                 if (logger.isDebugEnabled()) {
303                     logger.debug("Adding port [" + port.getName() + "] to service [" + service.getQName() + "]");
304                 }
305                 service.addPort(port);
306             }
307         }
308         if (service.getPorts().isEmpty() && logger.isWarnEnabled()) {
309             logger.warn("No ports were created, make sure the WSDL contains bindings");
310         }
311     }
312 
313     /**
314      * Called after the {@link Port} has been created, but before any sub-elements are added. Subclasses can implement
315      * this method to define the port name, or add extensions to it.
316      * <p/>
317      * Default implementation sets the port name to the binding name.
318      *
319      * @param definition the WSDL4J <code>Definition</code>
320      * @param port       the WSDL4J <code>Port</code>
321      * @throws WSDLException in case of errors
322      */
323     protected void populatePort(Definition definition, Port port) throws WSDLException {
324         String portName = port.getBinding().getQName().getLocalPart();
325         port.setName(portName);
326     }
327 
328 }