View Javadoc

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              // this is a hack so our namespaces in types still work.
87              // Is there a better way?
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         // Create Abstract operations
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         // Create a concrete instance for each transport.
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                 // todo: move out of the first loop, we'll be creating req/res multiple times otherwise
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         // response message
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                 // Get the namespace from the schema types document.
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         // response message part
326         Part part = getDefinition().createPart();
327 
328         // Document style service
329         QName typeQName = createResponseSchemaType(op, part);
330         part.setElementName( typeQName );
331         part.setName( "parameters" );
332         
333         req.addPart( part );
334     }
335 
336 }