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