View Javadoc

1   /*
2    * Copyright 2005-2010 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 java.util.List;
21  import javax.wsdl.Definition;
22  import javax.wsdl.Fault;
23  import javax.wsdl.Input;
24  import javax.wsdl.Message;
25  import javax.wsdl.Operation;
26  import javax.wsdl.OperationType;
27  import javax.wsdl.Output;
28  import javax.wsdl.PortType;
29  import javax.wsdl.WSDLException;
30  import javax.xml.namespace.QName;
31  
32  import org.springframework.util.Assert;
33  import org.springframework.util.LinkedMultiValueMap;
34  import org.springframework.util.MultiValueMap;
35  import org.springframework.util.StringUtils;
36  
37  import org.apache.commons.logging.Log;
38  import org.apache.commons.logging.LogFactory;
39  
40  /**
41   * Abstract base class for {@link PortTypesProvider} implementations.
42   *
43   * @author Arjen Poutsma
44   * @since 1.5.0
45   */
46  public abstract class AbstractPortTypesProvider implements PortTypesProvider {
47  
48      /** Logger available to subclasses. */
49      protected final Log logger = LogFactory.getLog(getClass());
50  
51      private String portTypeName;
52  
53      /** Returns the port type name used for this definition. */
54      public String getPortTypeName() {
55          return portTypeName;
56      }
57  
58      /** Sets the port type name used for this definition. Required. */
59      public void setPortTypeName(String portTypeName) {
60          this.portTypeName = portTypeName;
61      }
62  
63      /**
64       * Creates a single {@link PortType}, and calls {@link #populatePortType(Definition, PortType)} with it.
65       *
66       * @param definition the WSDL4J <code>Definition</code>
67       * @throws WSDLException in case of errors
68       */
69      public void addPortTypes(Definition definition) throws WSDLException {
70          Assert.notNull(getPortTypeName(), "'portTypeName' is required");
71          PortType portType = definition.createPortType();
72          populatePortType(definition, portType);
73          createOperations(definition, portType);
74          portType.setUndefined(false);
75          definition.addPortType(portType);
76      }
77  
78      /**
79       * Called after the {@link PortType} has been created.
80       * <p/>
81       * Default implementation sets the name of the port type to the defined value.
82       *
83       * @param portType the WSDL4J <code>PortType</code>
84       * @throws WSDLException in case of errors
85       * @see #setPortTypeName(String)
86       */
87      protected void populatePortType(Definition definition, PortType portType) throws WSDLException {
88          QName portTypeName = new QName(definition.getTargetNamespace(), getPortTypeName());
89          if (logger.isDebugEnabled()) {
90              logger.debug("Creating port type [" + portTypeName + "]");
91          }
92          portType.setQName(portTypeName);
93      }
94  
95      private void createOperations(Definition definition, PortType portType) throws WSDLException {
96          MultiValueMap<String, Message> operations = new LinkedMultiValueMap<String, Message>();
97          for (Iterator<?> iterator = definition.getMessages().values().iterator(); iterator.hasNext();) {
98              Message message = (Message) iterator.next();
99              String operationName = getOperationName(message);
100             if (StringUtils.hasText(operationName)) {
101                 operations.add(operationName,message);
102             }
103         }
104         if (operations.isEmpty() && logger.isWarnEnabled()) {
105             logger.warn("No operations were created, make sure the WSDL contains messages");
106         }
107         for (String operationName : operations.keySet()) {
108             Operation operation = definition.createOperation();
109             operation.setName(operationName);
110             List<Message> messages = operations.get(operationName);
111             for (Message message : messages) {
112                 if (isInputMessage(message)) {
113                     Input input = definition.createInput();
114                     input.setMessage(message);
115                     populateInput(definition, input);
116                     operation.setInput(input);
117                 }
118                 else if (isOutputMessage(message)) {
119                     Output output = definition.createOutput();
120                     output.setMessage(message);
121                     populateOutput(definition, output);
122                     operation.setOutput(output);
123                 }
124                 else if (isFaultMessage(message)) {
125                     Fault fault = definition.createFault();
126                     fault.setMessage(message);
127                     populateFault(definition, fault);
128                     operation.addFault(fault);
129                 }
130             }
131             operation.setStyle(getOperationType(operation));
132             operation.setUndefined(false);
133             if (logger.isDebugEnabled()) {
134                 logger.debug(
135                         "Adding operation [" + operation.getName() + "] to port type [" + portType.getQName() + "]");
136             }
137             portType.addOperation(operation);
138         }
139     }
140 
141     /**
142      * Template method that returns the name of the operation coupled to the given {@link Message}. Subclasses can
143      * return <code>null</code> to indicate that a message should not be coupled to an operation.
144      *
145      * @param message the WSDL4J <code>Message</code>
146      * @return the operation name; or <code>null</code>
147      */
148     protected abstract String getOperationName(Message message);
149 
150     /**
151      * Indicates whether the given name name should be included as {@link Input} message in the definition.
152      *
153      * @param message the message
154      * @return <code>true</code> if to be included as input; <code>false</code> otherwise
155      */
156     protected abstract boolean isInputMessage(Message message);
157 
158     /**
159      * Called after the {@link javax.wsdl.Input} has been created, but it's added to the operation. Subclasses can
160      * override this method to define the input name.
161      * <p/>
162      * Default implementation sets the input name to the message name.
163      *
164      * @param definition the WSDL4J <code>Definition</code>
165      * @param input      the WSDL4J <code>Input</code>
166      */
167     protected void populateInput(Definition definition, Input input) {
168         input.setName(input.getMessage().getQName().getLocalPart());
169     }
170 
171     /**
172      * Indicates whether the given name name should be included as {@link Output} message in the definition.
173      *
174      * @param message the message
175      * @return <code>true</code> if to be included as output; <code>false</code> otherwise
176      */
177     protected abstract boolean isOutputMessage(Message message);
178 
179     /**
180      * Called after the {@link javax.wsdl.Output} has been created, but it's added to the operation. Subclasses can
181      * override this method to define the output name.
182      * <p/>
183      * Default implementation sets the output name to the message name.
184      *
185      * @param definition the WSDL4J <code>Definition</code>
186      * @param output     the WSDL4J <code>Output</code>
187      */
188     protected void populateOutput(Definition definition, Output output) {
189         output.setName(output.getMessage().getQName().getLocalPart());
190     }
191 
192     /**
193      * Indicates whether the given name name should be included as {@link Fault} message in the definition.
194      *
195      * @param message the message
196      * @return <code>true</code> if to be included as fault; <code>false</code> otherwise
197      */
198     protected abstract boolean isFaultMessage(Message message);
199 
200     /**
201      * Called after the {@link javax.wsdl.Fault} has been created, but it's added to the operation. Subclasses can
202      * override this method to define the fault name.
203      * <p/>
204      * Default implementation sets the fault name to the message name.
205      *
206      * @param definition the WSDL4J <code>Definition</code>
207      * @param fault      the WSDL4J <code>Fault</code>
208      */
209     protected void populateFault(Definition definition, Fault fault) {
210         fault.setName(fault.getMessage().getQName().getLocalPart());
211     }
212 
213     /**
214      * Returns the {@link OperationType} for the given operation.
215      * <p/>
216      * Default implementation returns {@link OperationType#REQUEST_RESPONSE} if both input and output are set; {@link
217      * OperationType#ONE_WAY} if only input is set, or {@link OperationType#NOTIFICATION} if only output is set.
218      *
219      * @param operation the WSDL4J <code>Operation</code>
220      * @return the operation type for the operation
221      */
222     protected OperationType getOperationType(Operation operation) {
223         if (operation.getInput() != null && operation.getOutput() != null) {
224             return OperationType.REQUEST_RESPONSE;
225         }
226         else if (operation.getInput() != null && operation.getOutput() == null) {
227             return OperationType.ONE_WAY;
228         }
229         else if (operation.getInput() == null && operation.getOutput() != null) {
230             return OperationType.NOTIFICATION;
231         }
232         else {
233             return null;
234         }
235     }
236 
237 
238 }
239 
240 
241