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
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 }