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