KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > openlaszlo > remote > soap > SchemaParser


1 /* *****************************************************************************
2  * SchemaParser.java
3  * ****************************************************************************/

4
5 /* J_LZ_COPYRIGHT_BEGIN *******************************************************
6 * Copyright 2001-2004 Laszlo Systems, Inc. All Rights Reserved. *
7 * Use is subject to license terms. *
8 * J_LZ_COPYRIGHT_END *********************************************************/

9
10 package org.openlaszlo.remote.soap;
11
12 import java.util.*;
13 import java.io.*;
14 import javax.xml.rpc.*;
15 import javax.xml.parsers.*;
16 import javax.xml.namespace.*;
17 import org.w3c.dom.*;
18 import org.xml.sax.*;
19 import org.apache.axis.Constants;
20
21 import org.apache.log4j.Logger;
22
23 import org.apache.axis.utils.*;
24
25
26 public class SchemaParser
27 {
28     public static Logger mLogger = Logger.getLogger(SchemaParser.class);
29
30     static final int ARRAY = 0;
31     static final int REGULAR_OBJECT = 1;
32     static final int SEQUENCED_OBJECT = 2;
33
34     /** don't support for now
35     static final int EXTENDED_OBJECT = 3; // object with <xsd:extention>
36     **/

37
38     // Contains a list of complex types that extend from types not yet defined
39
// in the schema. Once base complex type is found, subclasses are assigned
40
// the complex type objects.
41
Map mBaseForwardTypeMap;
42     Map mArrayForwardTypeMap;
43
44     Map mComplexTypeMap;
45
46     // Values which are set when WSDLParser is passed in.
47
String JavaDoc mNamespaceURI_SOAP_ENC;
48     String JavaDoc mNamespaceURI_SCHEMA_XSD;
49     String JavaDoc mNamespaceURI_WSDL;
50     String JavaDoc mTargetNamespaceURI;
51
52     QName mSOAPEncodingArray;
53     QName mSOAPEncodingArrayType;
54
55     Element mSchema;
56
57     /**
58      * @param wp parsed WSDLParser
59      * @param schema element representing schema element
60      */

61     public SchemaParser(WSDLParser wp, Element schema) {
62
63         mNamespaceURI_SCHEMA_XSD = wp.mNamespaceURI_SCHEMA_XSD;
64         mNamespaceURI_SOAP_ENC = wp.mNamespaceURI_SOAP_ENC;
65         mNamespaceURI_WSDL = wp.mNamespaceURI_WSDL;
66
67         mSOAPEncodingArray = new QName(mNamespaceURI_SOAP_ENC, "Array");
68         mSOAPEncodingArrayType = new QName(mNamespaceURI_SOAP_ENC, "arrayType");
69
70         // set the target element here.
71
mTargetNamespaceURI = schema.getAttribute("targetNamespace");
72
73         mBaseForwardTypeMap = new HashMap();
74         mArrayForwardTypeMap = new HashMap();
75
76         mSchema = schema;
77
78         if (mLogger.isDebugEnabled()) {
79             mLogger.debug("mNamespaceURI_SCHEMA_XSD: " + mNamespaceURI_SCHEMA_XSD);
80             mLogger.debug("mNamespaceURI_SOAP_ENC: " + mNamespaceURI_SOAP_ENC);
81             mLogger.debug("mNamespaceURI_WSDL_SOAP: " + mNamespaceURI_WSDL);
82             mLogger.debug("mSOAPEncodingArray: " + mSOAPEncodingArray);
83             mLogger.debug("mSOAPEncodingArrayType: " + mSOAPEncodingArrayType);
84             mLogger.debug("mTargetNamespaceURI: " + mTargetNamespaceURI);
85         }
86     }
87
88     /**
89      * @param complexTypeMap map where ComplexType objects will be stored.
90      */

91     public void parse(Map complexTypeMap) {
92
93         // save it so we can use it for checkExtension
94
mComplexTypeMap = complexTypeMap;
95
96         // just get the complex types
97
NodeList list = mSchema.getElementsByTagNameNS(mNamespaceURI_SCHEMA_XSD, "complexType");
98
99         for (int i=0; i < list.getLength(); i++) {
100             try {
101                 ComplexType so = getComplexType((Element)list.item(i));
102                 if (so != null) {
103                     fixBaseForwardRefs(so);
104                     fixArrayForwardRefs(so);
105                     complexTypeMap.put(so.getName(), so);
106                 } else {
107                     mLogger.warn("skipping: " + list.item(i));
108                 }
109             } catch (Exception JavaDoc e) {
110                 mLogger.error("skipping complexType: " + e.getMessage(), e);
111             }
112         }
113
114         if (mBaseForwardTypeMap.size() != 0) {
115             mLogger.warn("The following base classes were not defined:");
116             Iterator iter = mBaseForwardTypeMap.keySet().iterator();
117             while (iter.hasNext()) {
118                 QName baseQName = (QName)iter.next();
119                 mLogger.warn(" " + baseQName);
120             }
121         }
122     }
123
124     /**
125      * Checks to see if object was referred by other types earlier in the
126      * schema. If so, set their base class to baseType.
127      */

128     void fixBaseForwardRefs(ComplexType baseType) {
129         QName baseQName = baseType.getName();
130         Vector list = (Vector)mBaseForwardTypeMap.get(baseQName);
131         if (list == null) return;
132         for (int i=0; i < list.size(); i++) {
133             ComplexType ct = (ComplexType)list.get(i);
134             ct.setBase(baseType);
135         }
136         mBaseForwardTypeMap.remove(baseQName);
137     }
138
139     /**
140      * Checks to see if object was referred by other types earlier in the
141      * schema. If so, set their base class to baseType.
142      */

143     void fixArrayForwardRefs(ComplexType arrayItemType) {
144         QName arrayQName = arrayItemType.getName();
145         Vector list = (Vector)mArrayForwardTypeMap.get(arrayQName);
146         if (list == null) return;
147         for (int i=0; i < list.size(); i++) {
148             ComplexType ct = (ComplexType)list.get(i);
149             ct.setArrayItemType(arrayItemType);
150         }
151         mArrayForwardTypeMap.remove(arrayQName);
152     }
153
154     /**
155      * Set the base type object for complex type, if it exists. Otherwise, mark
156      * base type forward ref.
157      * @param baseQName the qname for the base type.
158      * @param ct the complex type object that extends from baseQName.
159      */

160     void setBaseType(QName baseQName, ComplexType ct) {
161         ComplexType baseType = (ComplexType)mComplexTypeMap.get(baseQName);
162         if (baseType == null) {
163             // place soap enc type in map. Set actual soap enc for arrays.
164
if (Constants.isSOAP_ENC(baseQName.getNamespaceURI()) ) {
165                 baseType = new ComplexType(baseQName);
166                 mComplexTypeMap.put(baseQName, baseType);
167                 ct.setBase(baseType);
168             } else {
169                 Vector list = (Vector)mBaseForwardTypeMap.get(baseQName);
170                 if (list == null) {
171                     list = new Vector();
172                     mBaseForwardTypeMap.put(baseQName, list);
173                 }
174                 list.add(ct);
175             }
176         } else {
177             ct.setBase(baseType);
178         }
179     }
180
181     /**
182      * Set the aray type object for array type, if it exists. Otherwise, mark
183      * array type forward ref.
184      * @param arrayQName the qname for the array type.
185      * @param ct the complex type object that is an array.
186      */

187     void setArrayItemType(QName arrayQName, ComplexType ct) {
188         ComplexType arrayItemType = (ComplexType)mComplexTypeMap.get(arrayQName);
189         if (arrayItemType == null) {
190             // place simple type in map
191
if (Constants.isSchemaXSD(arrayQName.getNamespaceURI()) ) {
192                 arrayItemType = new ComplexType(arrayQName);
193                 mComplexTypeMap.put(arrayQName, arrayItemType);
194                 ct.setArrayItemType(arrayItemType);
195             } else {
196                 // set forward ref
197
Vector list = (Vector)mArrayForwardTypeMap.get(arrayQName);
198                 if (list == null) {
199                     list = new Vector();
200                     mArrayForwardTypeMap.put(arrayQName, list);
201                 }
202                 list.add(ct);
203             }
204
205         } else {
206             ct.setArrayItemType(arrayItemType);
207         }
208     }
209
210     ComplexType getComplexType(Element ct) throws Exception JavaDoc {
211         String JavaDoc name = ct.getAttribute("name");
212
213         NodeList list;
214         list = ct.getElementsByTagNameNS(mNamespaceURI_SCHEMA_XSD, "complexContent");
215         if (foundOne(list)) {
216             // check for array in elements inside of <complexContent>
217
return checkComplexContent(name, (Element)list.item(0));
218         }
219
220         list = ct.getElementsByTagNameNS(mNamespaceURI_SCHEMA_XSD, "all");
221         if (foundOne(list)) {
222             // get values inside <all> element
223
return checkAllOrSequence(name, (Element)list.item(0));
224         }
225
226         list = ct.getElementsByTagNameNS(mNamespaceURI_SCHEMA_XSD, "sequence");
227         if (foundOne(list)) {
228             // get values inside <sequence> element
229
return checkAllOrSequence(name, (Element)list.item(0));
230         }
231
232         mLogger.warn("no <complexContent>, <all>, or <sequence> nodes found under <complexType>");
233         return null;
234     }
235
236
237     /**
238      * Currently, just checks to see if complex content is an array. Anything
239      * else will throw an exception.
240      */

241     ComplexType checkComplexContent(String JavaDoc name, Element cc) throws Exception JavaDoc {
242         if (mLogger.isDebugEnabled()) {
243             mLogger.debug("checkComplexContent: " + name + ", " + cc);
244         }
245
246         NodeList list;
247         list = cc.getElementsByTagNameNS(mNamespaceURI_SCHEMA_XSD, "restriction");
248         if (foundOne(list)) {
249             return checkRestriction(name, (Element)list.item(0));
250         }
251
252         list = cc.getElementsByTagNameNS(mNamespaceURI_SCHEMA_XSD, "extension");
253         if (foundOne(list)) {
254             return checkExtension(name, (Element)list.item(0));
255         }
256
257         // <restriction> and <extension> ony supported in <complexContent>
258
mLogger.warn("No <restriction> or <extension> tags were found inside of <complexContent>");
259         return null;
260     }
261
262     /**
263      *
264      */

265     ComplexType checkExtension(String JavaDoc name, Element extension) throws Exception JavaDoc {
266         NodeList list;
267         ComplexType ct = null;
268         list = extension.getElementsByTagNameNS(mNamespaceURI_SCHEMA_XSD, "all");
269         if (foundOne(list)) {
270             // get values inside <all> element
271
ct = checkAllOrSequence(name, (Element)list.item(0));
272         }
273
274         list = extension.getElementsByTagNameNS(mNamespaceURI_SCHEMA_XSD, "sequence");
275         if (foundOne(list)) {
276             // get values inside <sequence> element
277
ct = checkAllOrSequence(name, (Element)list.item(0));
278         }
279
280         if (ct == null) {
281             mLogger.warn("no <all> or <sequence> nodes found under <extension>");
282             return null;
283         }
284
285         String JavaDoc base = extension.getAttribute("base");
286         if (base == null || base.equals("")) {
287             throw new Exception JavaDoc("no base attribute found in <extension>");
288         }
289
290         QName baseQName = XMLUtils.getQNameFromString(base, extension);
291         setBaseType(baseQName, ct);
292         return ct;
293     }
294
295     /**
296      * Assume <restriction> in <complexContent> means array (for now).
297      */

298     ComplexType checkRestriction(String JavaDoc name, Element restriction) throws Exception JavaDoc {
299         String JavaDoc base = restriction.getAttribute("base");
300         if (base == null || base.equals("")) {
301             throw new Exception JavaDoc("no base attribute found in <restriction>");
302         }
303
304         QName baseQName = XMLUtils.getQNameFromString(base, restriction);
305         if (! mSOAPEncodingArray.equals(baseQName)) {
306             throw new Exception JavaDoc("only arrays are supported in <restriction>, instead found "
307                                 + baseQName);
308         }
309
310         // now try to get type of array from <attribute> element in
311
// <restriction>
312
NodeList list = restriction.getElementsByTagNameNS(mNamespaceURI_SCHEMA_XSD, "attribute");
313         if (! foundOne(list)) {
314             // FIXME
315
// XXX this is not necessarily true...I think we can assume anyType
316
// array if attribute is missing. Fix this later.
317
throw new Exception JavaDoc("expecting only one attribute inside <restriction base=\"soapenc:Array\">");
318         }
319
320         Element attributeElement = (Element)list.item(0);
321         String JavaDoc ref = attributeElement.getAttribute("ref");
322
323         String JavaDoc arrayItemType = attributeElement.getAttributeNS(mNamespaceURI_WSDL, "arrayType");
324
325         if (ref.equals("")) {
326             throw new Exception JavaDoc("empty ref attribute in <attribute> inside of <restriction> for <complexType> named " + name);
327         }
328
329         if (arrayItemType.equals("")) {
330             throw new Exception JavaDoc("empty ref attribute in <attribute> inside of <restriction> for <complexType> named " + name);
331         }
332
333         QName refQName = XMLUtils.getQNameFromString(ref, attributeElement);
334         if (! mSOAPEncodingArrayType.equals(refQName)) {
335             throw new Exception JavaDoc("ref attribute in <attribute> inside of <restriction> does not refer to SOAP-ENC array");
336         }
337
338         String JavaDoc type = removeBrackets(arrayItemType);
339         QName typeQName = XMLUtils.getQNameFromString(type, attributeElement);
340         
341         // array complex type
342
ComplexType ct = new ComplexType(new QName(mTargetNamespaceURI, name), true);
343         setArrayItemType(typeQName, ct);
344         setBaseType(baseQName, ct);
345         return ct;
346     }
347
348
349     /**
350      * Get arrayItemType without brackets to just get type.
351      */

352     String JavaDoc removeBrackets(String JavaDoc arrayItemType) {
353         int index = arrayItemType.indexOf('[');
354         if (index == -1) {
355             return arrayItemType;
356         }
357         return arrayItemType.substring(0, index);
358     }
359
360
361     /**
362      * Check for elements inside <all> or sequence. All elements must have a type
363      * attribute. We don't support anonymous types.
364      */

365     ComplexType checkAllOrSequence(String JavaDoc name, Element node) throws Exception JavaDoc {
366         if (mLogger.isDebugEnabled()) {
367             mLogger.debug("checkAllOrSequence: " + name + ", " + node);
368         }
369
370         String JavaDoc tag = node.getTagName();
371         Map members = new HashMap();
372         NodeList list = node.getElementsByTagNameNS(mNamespaceURI_SCHEMA_XSD, "element");
373         for (int i=0; i < list.getLength(); i++) {
374             Element element = (Element)list.item(i);
375             String JavaDoc elRef = element.getAttribute("ref");
376             String JavaDoc elName = element.getAttribute("name");
377             String JavaDoc elType = element.getAttribute("type");
378             if (! elRef.equals("")) {
379                 mLogger.warn("!!! skipping element #" + (i+1) + " !!! " +
380                              "references ignored");
381                 continue;
382             } else {
383                 if (elName.equals("")) {
384                     mLogger.warn("!!! skipping element #" + (i+1) + " !!! " +
385                                  "name attribute missing in inside <" + tag +
386                                  ">: " + node);
387                     continue;
388                 }
389                 if (elType.equals("")) {
390                     mLogger.warn("!!! skipping element #" + (i+1) + " !!! " +
391                                  "type attribute missing inside <" + tag +
392                                  ">: " + node + "(anonymous types not supported)");
393                     continue;
394                 }
395             }
396             QName elTypeQName = XMLUtils.getQNameFromString(elType, element);
397             members.put(elName, elTypeQName);
398         }
399
400         // struct complex type
401
return new ComplexType(new QName(mTargetNamespaceURI, name), members);
402     }
403
404
405     /**
406      * See if complexType element was found.
407      */

408     boolean foundOne(NodeList list) {
409         return list.getLength() == 1;
410     }
411 }
412
Popular Tags