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