View Javadoc

1   package org.codehaus.xfire.wsdl11.builder;
2   
3   import java.io.IOException;
4   import java.io.OutputStream;
5   import java.util.HashMap;
6   import java.util.HashSet;
7   import java.util.Iterator;
8   import java.util.Map;
9   import java.util.Set;
10  
11  import javax.wsdl.Definition;
12  import javax.wsdl.WSDLException;
13  import javax.wsdl.factory.WSDLFactory;
14  
15  import org.codehaus.xfire.XFireRuntimeException;
16  import org.codehaus.xfire.service.Service;
17  import org.codehaus.xfire.soap.SoapConstants;
18  import org.codehaus.xfire.util.NamespaceHelper;
19  import org.codehaus.xfire.wsdl.SchemaType;
20  import org.codehaus.xfire.wsdl.WSDLWriter;
21  import org.codehaus.yom.Attribute;
22  import org.codehaus.yom.Document;
23  import org.codehaus.yom.Element;
24  import org.codehaus.yom.Elements;
25  import org.codehaus.yom.Serializer;
26  import org.codehaus.yom.converters.DOMConverter;
27  
28  /***
29   * AbstractWSDL
30   * 
31   * @author <a href="mailto:dan@envoisolutions.com">Dan Diephouse</a>
32   */
33  public abstract class AbstractWSDL
34      implements WSDLWriter
35  {
36      private Definition def;
37  
38      private String targetNamespace;
39  
40      private Service service;
41  
42      private Document wsdlDocument;
43  
44      private Map dependencies = new HashMap();
45      
46      private Map namespaceImports = new HashMap();
47      
48      private Element schemaTypes;
49  
50      private Map typeMap;
51      
52      private WSDLBuilderInfo info;
53  
54      /*-------------------------------------------------
55       * Namespace and QName definitions for easy access.
56       *-------------------------------------------------*/
57  
58      public final static String schemaQ = SoapConstants.XSD_PREFIX + ":" + "schema";
59  
60      public final static String elementQ = SoapConstants.XSD_PREFIX + ":" + "element";
61  
62      public final static String complexQ = SoapConstants.XSD_PREFIX + ":" + "complexType";
63  
64      public final static String sequenceQ = SoapConstants.XSD_PREFIX + ":" + "sequence";
65  
66      public AbstractWSDL(Service service) throws WSDLException
67      {
68          this.service = service;
69          this.info = (WSDLBuilderInfo) service.getProperty(WSDLBuilderInfo.KEY);
70  
71          if (info == null)
72              info = new WSDLBuilderInfo(service);
73  
74          setDefinition(WSDLFactory.newInstance().newDefinition());
75          getDefinition().setTargetNamespace(info.getTargetNamespace());
76  
77          Element root = new Element("wsdl:types", WSDL11_NS);
78          setSchemaTypes(root);
79          root.addNamespaceDeclaration(SoapConstants.XSD_PREFIX, SoapConstants.XSD);
80  
81          addNamespace("soap", service.getSoapVersion().getNamespace());
82          addNamespace("soapenc", service.getSoapVersion().getSoapEncodingStyle());
83          addNamespace("xsd", SoapConstants.XSD);
84          addNamespace("wsdl", WSDL11_NS);
85          addNamespace("wsdlsoap", WSDL11_SOAP_NS);
86          addNamespace("tns", info.getTargetNamespace());
87  
88          typeMap = new HashMap();
89      }
90  
91      protected void writeDocument()
92          throws WSDLException
93      {
94          writeImports();
95          
96          org.w3c.dom.Document doc = WSDLFactory.newInstance().newWSDLWriter().getDocument(def);
97  
98          wsdlDocument = DOMConverter.convert(doc);
99  
100         writeComplexTypes();
101     }
102 
103     /***
104      * Write xs:import elements for each schema.
105      */
106     protected void writeImports()
107     {
108         for (Iterator itr = namespaceImports.entrySet().iterator(); itr.hasNext();)
109         {
110             Map.Entry entry = (Map.Entry) itr.next();
111             
112             String uri = (String) entry.getKey();
113             Set imports = (Set) entry.getValue();
114             
115             Element schema = createSchemaType(uri);
116             
117             for (Iterator importItr = imports.iterator(); importItr.hasNext();)
118             {
119                 String ns = (String) importItr.next();
120                 if (!ns.equals(SoapConstants.XSD) && !hasImport(schema, ns))
121                 {
122                     Element importEl = new Element("xsd:import", SoapConstants.XSD);
123                     importEl.addAttribute(new Attribute("namespace", ns));
124                     
125                     schema.insertChild(importEl, 0);
126                 }
127             }
128         }
129     }
130 
131     public boolean hasImport(Element schema, String ns)
132     {
133         Elements children = schema.getChildElements("import", SoapConstants.XSD);
134         
135         for (int i = 0; i < children.size(); i++)
136         {
137             Element importEl = children.get(i);
138             String value = importEl.getAttributeValue("namespace");
139             
140             if (value != null && value.equals(ns)) return true;
141         }
142         
143         return false;
144     }
145 
146     protected void writeComplexTypes()
147         throws WSDLException
148     {
149         Element rootEl = getDocument().getRootElement();
150 
151         if (schemaTypes.getChildCount() > 0)
152         {
153             schemaTypes.detach();
154             rootEl.insertChild(schemaTypes, 0);
155         }
156 
157     }
158 
159     public void addDependency(SchemaType type)
160     {
161         if (!type.isComplex())
162         {
163             return;
164         }
165         
166         if (!hasDependency(type))
167         {
168             dependencies.put(type.getSchemaType(), type);
169 
170             Element e = createSchemaType(type.getSchemaType().getNamespaceURI());
171             type.writeSchema(e);
172             
173             Set deps = type.getDependencies();
174 
175             if (deps != null)
176             {
177                 for (Iterator itr = deps.iterator(); itr.hasNext();)
178                 {
179                     SchemaType child = (SchemaType) itr.next();
180                     addDependency(child);
181                     addNamespaceImport(type.getSchemaType().getNamespaceURI(), 
182                                        child.getSchemaType().getNamespaceURI());
183                 }
184             }
185         }
186     }
187 
188     protected boolean hasDependency(SchemaType type)
189     {
190         return dependencies.containsKey(type.getSchemaType());
191     }
192 
193     /***
194      * Adds an import to another namespace. 
195      * @param uri The namespace to import into.
196      * @param imported The namespace to import.
197      */
198     public void addNamespaceImport(String uri, String imported)
199     {
200         if (uri.equals(imported)) return;
201         
202         Set imports = (Set) namespaceImports.get(uri);
203         
204         if (imports == null)
205         {
206             imports = new HashSet();
207             namespaceImports.put(uri, imports);
208         }
209         
210         imports.add(imported);
211     }
212     
213     /***
214      * @see org.codehaus.xfire.wsdl.WSDLWriter#write(java.io.OutputStream)
215      */
216     public void write(OutputStream out)
217         throws IOException
218     {
219         Serializer writer = new Serializer(out);
220         writer.write(getDocument());
221         writer.flush();
222     }
223 
224     public void addNamespace(String prefix, String uri)
225     {
226         def.addNamespace(prefix, uri);
227 
228         String declaredUri = schemaTypes.getNamespaceURI(prefix);
229         if (declaredUri == null)
230         {
231             schemaTypes.addNamespaceDeclaration(prefix, uri);
232         }
233         else if (!declaredUri.equals(uri))
234         {
235             throw new XFireRuntimeException("Namespace conflict: " + declaredUri
236                     + " was declared but " + uri + " was attempted.");
237         }
238     }
239 
240     public String getNamespacePrefix(String uri)
241     {
242         return NamespaceHelper.getUniquePrefix(schemaTypes, uri);
243     }
244 
245     public WSDLBuilderInfo getInfo()
246     {
247         return info;
248     }
249 
250     /***
251      * @see org.codehaus.xfire.wsdl.WSDLWriter#getDocument()
252      */
253     public Document getDocument()
254     {
255         return wsdlDocument;
256     }
257 
258     public Definition getDefinition()
259     {
260         return def;
261     }
262 
263     public void setDefinition(Definition definition)
264     {
265         this.def = definition;
266     }
267 
268     public Service getService()
269     {
270         return service;
271     }
272 
273     public void setService(Service service)
274     {
275         this.service = service;
276     }
277 
278     /***
279      * Create a shcema type element and store it to be written later on.
280      * 
281      * @param namespace
282      *            The namespace to create the type in.
283      * @return
284      */
285     public Element createSchemaType(String namespace)
286     {
287         Element e = (Element) typeMap.get(namespace);
288 
289         if (e == null)
290         {
291             e = new Element(schemaQ, SoapConstants.XSD);
292 
293             e.addAttribute(new Attribute("targetNamespace", namespace));
294             e.addAttribute(new Attribute("elementFormDefault", "qualified"));
295             e.addAttribute(new Attribute("attributeFormDefault", "qualified"));
296 
297             setSchema(namespace, e);
298         }
299 
300         return e;
301     }
302 
303     protected boolean hasSchema(String namespace)
304     {
305         return typeMap.containsKey(namespace);
306     }
307     
308     protected void setSchema(String namespace, Element schema)
309     {
310         typeMap.put(namespace, schema);
311         getSchemaTypes().appendChild(schema);
312     }
313 
314     protected Element getSchemaTypes()
315     {
316         return schemaTypes;
317     }
318 
319     protected void setSchemaTypes(Element schemaTypes)
320     {
321         this.schemaTypes = schemaTypes;
322     }
323 }