View Javadoc

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              // this is a hack so our namespaces in types still work.
86              // Is there a better way?
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         // Create Abstract operations
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         // Create a concrete instance for each transport.
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                 // todo: move out of the first loop, we'll be creating req/res multiple times otherwise
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         // response message
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                 // Get the namespace from the schema types document.
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                 // Get the namespace from the schema types document.
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         // response message part
344         Part part = getDefinition().createPart();
345 
346         // Document style service
347         QName typeQName = createResponseSchemaType(op, part);
348         part.setElementName( typeQName );
349         part.setName( "parameters" );
350         
351         req.addPart( part );
352     }
353 
354 }