1 package org.codehaus.xfire.aegis.wsdl;
2
3 import java.util.HashMap;
4 import java.util.Iterator;
5 import java.util.Map;
6 import java.util.Set;
7
8 import javax.wsdl.Binding;
9 import javax.wsdl.BindingOperation;
10 import javax.wsdl.Definition;
11 import javax.wsdl.Input;
12 import javax.wsdl.Message;
13 import javax.wsdl.Operation;
14 import javax.wsdl.Output;
15 import javax.wsdl.Part;
16 import javax.wsdl.Port;
17 import javax.wsdl.PortType;
18 import javax.wsdl.WSDLException;
19 import javax.xml.namespace.QName;
20
21 import org.codehaus.xfire.aegis.AegisService;
22 import org.codehaus.xfire.aegis.operation.WrappedOperation;
23 import org.codehaus.xfire.aegis.type.Type;
24 import org.codehaus.xfire.transport.Transport;
25 import org.codehaus.xfire.wsdl.AbstractWSDL;
26 import org.codehaus.xfire.wsdl.WSDL;
27 import org.dom4j.Document;
28 import org.dom4j.Element;
29 import org.dom4j.Namespace;
30 import org.dom4j.Node;
31
32 /***
33 * AegisWSDL
34 *
35 * @author <a href="mailto:dan@envoisolutions.com">Dan Diephouse</a>
36 */
37 public class AegisWSDL
38 extends AbstractWSDL
39 implements WSDL
40 {
41 private Set transports;
42
43 private Map wsdlOps;
44
45 public AegisWSDL(AegisService service, Set transports)
46 throws WSDLException
47 {
48 super( service );
49 this.transports = transports;
50 wsdlOps = new HashMap();
51
52 Document descriptor = service.getServiceDescriptor();
53
54 Element userTypes = descriptor.getRootElement().element("types");
55 if ( userTypes != null )
56 {
57 addUserTypes(userTypes);
58 }
59
60 PortType portType = createAbstractInterface();
61
62 createConcreteInterface(portType);
63
64 writeDocument();
65 }
66
67
68 /***
69 * @param element
70 */
71 private void addUserTypes(Element element)
72 {
73 for (Iterator itr = element.elementIterator(); itr.hasNext();)
74 {
75 Element typeEl = (Element) itr.next();
76 String name = typeEl.attributeValue("name");
77
78 int index = name.indexOf(":");
79 String prefix = name.substring(0, index);
80 String typeName = name.substring(index+1);
81
82 Namespace ns = element.getNamespaceForPrefix(prefix);
83 Element newType = createSchemaType(ns.getURI());
84
85
86
87 newType.add(ns);
88
89 int size = typeEl.elements().size();
90 for (int i = 0; i < size; i++ )
91 {
92 Element te = (Element) typeEl.elements().get(0);
93 Node n = te.detach();
94 newType.add(n);
95 }
96 }
97 }
98
99
100 /***
101 * Create the PortType for this service.
102 * @param service
103 * @return
104 */
105 protected PortType createAbstractInterface()
106 {
107 AegisService service = (AegisService) getService();
108 QName portName = new QName( service.getDefaultNamespace(),
109 service.getName() + "PortType" );
110
111 Definition def = getDefinition();
112
113 PortType portType = def.createPortType();
114 portType.setQName( portName );
115 portType.setUndefined(false);
116 def.addPortType( portType );
117
118
119
120 for ( Iterator itr = service.getOperations().iterator(); itr.hasNext(); )
121 {
122 WrappedOperation op = (WrappedOperation) itr.next();
123 Message req = getInputMessage(op);
124 def.addMessage( req );
125
126 Message res = getOutputMessage(op);
127 def.addMessage( res );
128
129 String opName = op.getQName().getName();
130 javax.wsdl.Operation wsdlOp = createOperation( opName, req, res );
131 wsdlOp.setUndefined(false);
132 portType.addOperation( wsdlOp );
133
134 wsdlOps.put( opName, wsdlOp );
135 }
136
137 return portType;
138 }
139
140 protected void createConcreteInterface(PortType portType)
141 {
142 AegisService service = (AegisService) getService();
143 QName name = new QName( service.getDefaultNamespace(),
144 service.getName() );
145
146
147 javax.wsdl.Service wsdlService = getDefinition().createService();
148 wsdlService.setQName( name );
149
150 for ( Iterator itr = transports.iterator(); itr.hasNext(); )
151 {
152 Transport transport = (Transport) itr.next();
153
154 Binding transportBinding = transport.createBinding( portType, service );
155
156 for ( Iterator oitr = service.getOperations().iterator(); oitr.hasNext(); )
157 {
158
159 WrappedOperation op = (WrappedOperation) oitr.next();
160
161 javax.wsdl.Operation wsdlOp = (javax.wsdl.Operation) wsdlOps.get( op.getQName().getName() );
162
163 BindingOperation bop = transport.createBindingOperation( portType, wsdlOp, service );
164 transportBinding.addBindingOperation( bop );
165 }
166
167 Port transportPort = transport.createPort(transportBinding, service);
168
169 getDefinition().addBinding( transportBinding );
170 wsdlService.addPort( transportPort );
171 }
172
173 getDefinition().addService( wsdlService );
174 }
175
176 /***
177 * Create the input and response parts for thes messages.
178 * @return
179 */
180 protected Operation createOperation(String opName, Message req, Message res)
181 {
182 Definition def = getDefinition();
183
184 Input input = def.createInput();
185 input.setMessage( req );
186 input.setName( req.getQName().getLocalPart() );
187
188 Output output = def.createOutput();
189 output.setMessage( res );
190 output.setName( res.getQName().getLocalPart() );
191
192 javax.wsdl.Operation wsdlOp = def.createOperation();
193 wsdlOp.setName( opName );
194 wsdlOp.setInput( input );
195 wsdlOp.setOutput( output );
196
197 return wsdlOp;
198 }
199
200 private Message getOutputMessage(WrappedOperation op)
201 {
202
203 Message res = getDefinition().createMessage();
204 res.setQName( new QName( getService().getDefaultNamespace(),
205 op.getQName().getName() + "Response") );
206
207 res.setUndefined(false);
208
209 createOutputParts( res, op );
210
211 return res;
212 }
213
214 private Message getInputMessage(WrappedOperation op)
215 {
216 Message req = getDefinition().createMessage();
217 req.setQName( new QName( getService().getDefaultNamespace(), op.getQName().getName() + "Request") );
218 req.setUndefined(false);
219
220 createInputParts( req, op );
221
222 return req;
223 }
224
225 private QName createResponseSchemaType(WrappedOperation op, Part part)
226 {
227 String opName = op.getQName().getName() + "Response";
228 QName qName = new QName( getService().getDefaultNamespace(), opName );
229
230 Element root = createSchemaType( qName.getNamespaceURI() );
231 Element element = root.addElement( elementQ );
232 element.addAttribute( "name", opName );
233
234 org.dom4j.QName complexQ = new org.dom4j.QName("complexType", xsdNs);
235 Element complex = element.addElement( complexQ );
236
237 if ( op.getResponse().size() > 0 )
238 {
239 Element sequence = createSequence( complex );
240
241 for ( Iterator itr = op.getResponse().iterator(); itr.hasNext(); )
242 {
243 Type type = (Type) itr.next();
244
245
246 Namespace typeNS = getNamespace( type.getSchemaType().getNamespaceURI() );
247
248 org.dom4j.QName outElementQ = new org.dom4j.QName("element", xsdNs);
249 Element outElement = sequence.addElement( outElementQ );
250 if ( type.isComplex() )
251 {
252 outElement.addAttribute( "ref", typeNS.getPrefix() + ":" + type.getSchemaType().getName() );
253 }
254 else
255 {
256 outElement.addAttribute("name", type.getName() );
257 outElement.addAttribute("type", typeNS.getPrefix() + ":" + type.getSchemaType().getName() );
258 }
259 outElement.addAttribute("minOccurs", type.getMinOccurs());
260 outElement.addAttribute("maxOccurs", type.getMaxOccurs());
261
262 addDependency( type );
263 }
264 }
265
266 return qName;
267 }
268
269
270 private QName createRequestSchemaType(WrappedOperation op, Part part)
271 {
272 String opName = op.getQName().getName();
273 QName qName = new QName( getService().getDefaultNamespace(), opName );
274
275 Element root = createSchemaType( qName.getNamespaceURI() );
276 Element element = root.addElement( elementQ );
277 element.addAttribute( "name", opName );
278
279 org.dom4j.QName complexQ = new org.dom4j.QName("complexType", xsdNs);
280 Element complex = element.addElement( complexQ );
281
282 if ( op.getRequest().size() > 0 )
283 {
284 Element sequence = createSequence( complex );
285
286 for ( Iterator itr = op.getRequest().iterator(); itr.hasNext(); )
287 {
288 Type type = (Type) itr.next();
289
290
291 Namespace typeNS = getNamespace( type.getSchemaType().getNamespaceURI() );
292
293 org.dom4j.QName outElementQ = new org.dom4j.QName("element", xsdNs);
294 Element outElement = sequence.addElement( outElementQ );
295 if ( type.isComplex() )
296 {
297 outElement.addAttribute( "ref", typeNS.getPrefix() + ":" + type.getSchemaType().getName() );
298 }
299 else
300 {
301 outElement.addAttribute("name", type.getName() );
302 outElement.addAttribute("type", typeNS.getPrefix() + ":" + type.getSchemaType().getName() );
303 }
304 outElement.addAttribute("minOccurs", type.getMinOccurs());
305 outElement.addAttribute("maxOccurs", type.getMaxOccurs());
306 }
307 }
308
309 return qName;
310 }
311
312 private Element createSequence( Element complex )
313 {
314 org.dom4j.QName sequenceQ = new org.dom4j.QName("sequence", xsdNs);
315 return complex.addElement( sequenceQ );
316 }
317
318 /***
319 * @see org.codehaus.xfire.java.wsdl.AbstractWSDL#createInputParts(javax.wsdl.Message, org.codehaus.xfire.java.Operation)
320 */
321 protected void createInputParts( Message req, WrappedOperation op )
322 {
323 Part part = getDefinition().createPart();
324
325 QName typeQName = createRequestSchemaType(op, part);
326
327 part.setName( "parameters" );
328 part.setElementName( typeQName );
329
330 req.addPart( part );
331 }
332
333 /***
334 * Create the output parts for this message/operation. This involves
335 * creating an part with the name "parameters" which refers to
336 * a type that we create for the request/response.
337 *
338 * @param req
339 * @param op
340 */
341 protected void createOutputParts( Message req, WrappedOperation op )
342 {
343
344 Part part = getDefinition().createPart();
345
346
347 QName typeQName = createResponseSchemaType(op, part);
348 part.setElementName( typeQName );
349 part.setName( "parameters" );
350
351 req.addPart( part );
352 }
353
354 }