1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.student.contract.model.impl;
17
18 import com.sun.xml.xsom.XSAnnotation;
19 import com.sun.xml.xsom.XSComplexType;
20 import com.sun.xml.xsom.XSContentType;
21 import com.sun.xml.xsom.XSElementDecl;
22 import com.sun.xml.xsom.XSFacet;
23 import com.sun.xml.xsom.XSModelGroup;
24 import com.sun.xml.xsom.XSParticle;
25 import com.sun.xml.xsom.XSSchema;
26 import com.sun.xml.xsom.XSSchemaSet;
27 import com.sun.xml.xsom.XSSimpleType;
28 import com.sun.xml.xsom.XSTerm;
29 import com.sun.xml.xsom.XSType;
30 import com.sun.xml.xsom.parser.AnnotationContext;
31 import com.sun.xml.xsom.parser.AnnotationParser;
32 import com.sun.xml.xsom.parser.AnnotationParserFactory;
33 import com.sun.xml.xsom.parser.SchemaDocument;
34 import com.sun.xml.xsom.parser.XSOMParser;
35 import com.sun.xml.xsom.util.DomAnnotationParserFactory;
36 import java.io.File;
37 import java.io.IOException;
38 import java.util.ArrayList;
39 import java.util.LinkedHashMap;
40 import java.util.List;
41 import java.util.Map;
42 import java.util.Set;
43 import org.kuali.student.contract.model.MessageStructure;
44 import org.kuali.student.contract.model.Service;
45 import org.kuali.student.contract.model.ServiceContractModel;
46 import org.kuali.student.contract.model.ServiceMethod;
47 import org.kuali.student.contract.model.ServiceMethodReturnValue;
48 import org.kuali.student.contract.model.XmlType;
49 import org.xml.sax.Attributes;
50 import org.xml.sax.ContentHandler;
51 import org.xml.sax.EntityResolver;
52 import org.xml.sax.ErrorHandler;
53 import org.xml.sax.Locator;
54 import org.xml.sax.SAXException;
55
56
57
58
59
60 public class ServiceContractModelPescXsdLoader implements
61 ServiceContractModel {
62
63 private List<String> xsdFileNames;
64 private List<Service> services = null;
65 private List<ServiceMethod> serviceMethods = null;
66 private Map<String, XmlType> xmlTypeMap = null;
67 private List<MessageStructure> messageStructures;
68
69 public ServiceContractModelPescXsdLoader(List<String> xsdFileNames) {
70 this.xsdFileNames = xsdFileNames;
71 }
72
73 @Override
74 public List<ServiceMethod> getServiceMethods() {
75 if (this.serviceMethods == null) {
76 this.parse();
77 }
78 return this.serviceMethods;
79 }
80
81 @Override
82 public List<String> getSourceNames() {
83 List<String> list = new ArrayList();
84 list.addAll(this.xsdFileNames);
85 return list;
86 }
87
88 @Override
89 public List<Service> getServices() {
90 if (services == null) {
91 this.parse();
92 }
93 return services;
94 }
95
96 @Override
97 public List<XmlType> getXmlTypes() {
98 if (xmlTypeMap == null) {
99 this.parse();
100 }
101 return new ArrayList(xmlTypeMap.values());
102 }
103
104 @Override
105 public List<MessageStructure> getMessageStructures() {
106 if (messageStructures == null) {
107 this.parse();
108 }
109 return this.messageStructures;
110 }
111
112 private void parse() {
113 System.out.println("ServiceContractModelQDoxLoader: Starting parse");
114 services = new ArrayList();
115 Service service = new Service();
116 services.add(service);
117 service.setKey("Pesc");
118 service.setName("PescService");
119 service.setComments("Derived from pesc CoreMain");
120 serviceMethods = new ArrayList();
121 ServiceMethod method = new ServiceMethod();
122 serviceMethods.add(method);
123 method.setName("dummy");
124 method.setDescription("Dummy method so validation won't fail");
125 method.setService("Pesc");
126 method.setParameters(new ArrayList());
127 ServiceMethodReturnValue rv = new ServiceMethodReturnValue();
128 rv.setType("void");
129 rv.setDescription("returns nothing");
130 method.setReturnValue(rv);
131 xmlTypeMap = new LinkedHashMap();
132 messageStructures = new ArrayList();
133
134 XSOMParser parser = new XSOMParser();
135 parser.setAnnotationParser(new DomAnnotationParserFactory());
136
137 try {
138 for (String xsdFileName : this.xsdFileNames) {
139
140 parser.parse(new File(xsdFileName));
141 }
142 } catch (SAXException ex) {
143 throw new IllegalArgumentException(ex);
144 } catch (IOException ex) {
145 throw new IllegalArgumentException(ex);
146 }
147 XSSchemaSet schemas;
148 try {
149 schemas = parser.getResult();
150 } catch (SAXException ex) {
151 throw new IllegalArgumentException(ex);
152 }
153
154
155
156 Set<SchemaDocument> schemaDocuments = parser.getDocuments();
157 for (SchemaDocument doc : schemaDocuments) {
158 XSSchema schema = doc.getSchema();
159 this.processSchema(schema);
160 }
161 }
162
163 private void processSchema(XSSchema schema) {
164 for (XSElementDecl element : schema.getElementDecls().values()) {
165 this.addElementDecl(element);
166 }
167 for (XSSimpleType st : schema.getSimpleTypes().values()) {
168
169 addSimpleType(st);
170 }
171 for (XSComplexType ct : schema.getComplexTypes().values()) {
172 if (!shouldInclude(ct)) {
173
174 continue;
175 }
176
177 addComplexType(ct);
178 }
179 }
180
181 private boolean shouldInclude(XSComplexType ct) {
182
183 return true;
184
185
186 }
187
188 private void addSimpleType(XSSimpleType simpleType) {
189 XmlType xmlType = xmlTypeMap.get(simpleType.getName());
190 if (xmlType != null) {
191
192
193 return;
194 }
195 xmlType = new XmlType();
196 xmlTypeMap.put(simpleType.getName(), xmlType);
197 xmlType.setName(simpleType.getName());
198 xmlType.setDesc(calcMissing(calcDesc(simpleType.getAnnotation())));
199 xmlType.setComments("???");
200 xmlType.setExamples("???");
201 xmlType.setService("Pesc");
202 xmlType.setPrimitive("Primitive");
203 }
204
205 private void addComplexType(XSComplexType complexType) {
206 addComplexType(complexType, complexType.getName());
207 }
208
209 private void addElementDecl(XSElementDecl element) {
210 String name = element.getName();
211 XmlType xmlType = xmlTypeMap.get(name);
212 if (xmlType != null) {
213
214 return;
215 }
216
217 xmlType = new XmlType();
218 xmlTypeMap.put(name, xmlType);
219 xmlType.setName(name);
220 xmlType.setDesc(calcMissing(calcDesc(element.getAnnotation())));
221 xmlType.setComments("???");
222 xmlType.setExamples("???");
223 xmlType.setService("Pesc");
224 xmlType.setPrimitive(XmlType.COMPLEX);
225 addMessageStructure(xmlType.getName(), element);
226 }
227
228 private void addComplexType(XSComplexType complexType, String name) {
229 XmlType xmlType = xmlTypeMap.get(name);
230 if (xmlType != null) {
231
232 return;
233 }
234
235 xmlType = new XmlType();
236 xmlTypeMap.put(name, xmlType);
237 xmlType.setName(name);
238 xmlType.setDesc(calcMissing(calcDesc(complexType.getAnnotation())));
239 xmlType.setComments("???");
240 xmlType.setExamples("???");
241 xmlType.setService("Pesc");
242 xmlType.setPrimitive(XmlType.COMPLEX);
243
244 boolean found = false;
245 XSContentType contentType = complexType.getContentType();
246 XSParticle particle = contentType.asParticle();
247 if (particle != null) {
248 XSTerm term = particle.getTerm();
249 if (term.isModelGroup()) {
250 XSModelGroup xsModelGroup = term.asModelGroup();
251 XSParticle[] particles = xsModelGroup.getChildren();
252 for (XSParticle p : particles) {
253 XSTerm pterm = p.getTerm();
254 if (pterm.isElementDecl()) {
255 XSElementDecl element = pterm.asElementDecl();
256 addMessageStructure(xmlType.getName(), element);
257 found = true;
258 }
259 }
260 }
261 }
262
263
264
265 }
266
267 private String calcMissing(String str) {
268 if (str == null) {
269 return "???";
270 }
271 if (str.trim().isEmpty()) {
272 return "???";
273 }
274 return str;
275 }
276
277 private String calcDesc(XSAnnotation annotation) {
278 if (annotation == null) {
279 return null;
280 }
281 if (annotation.getAnnotation() == null) {
282 return null;
283 }
284 return annotation.getAnnotation().toString();
285 }
286
287 private void addMessageStructure(String xmlObject, XSElementDecl element) {
288 MessageStructure ms = new MessageStructure();
289 this.messageStructures.add(ms);
290 ms.setXmlObject(xmlObject);
291 ms.setShortName(element.getName());
292 ms.setName("???");
293 ms.setId(xmlObject + "." + ms.getShortName());
294 ms.setType(calcType(element, xmlObject + "" + ms.getShortName()));
295 ms.setDescription(calcMissing(calcDesc(element.getAnnotation())));
296
297 ms.setRequired(calcRequired(element));
298 ms.setCardinality(calcCardinality(element));
299 }
300
301 private String calcType(XSElementDecl element, String inLinePrefix) {
302 String type = calcType(element.getType(), inLinePrefix);
303 if (type != null) {
304 return type;
305 }
306 return type;
307 }
308
309 private String calcType(XSType xsType, String inLinePrefix) {
310 if (xsType.isSimpleType()) {
311 XSSimpleType st = xsType.asSimpleType();
312 return st.getBaseType().getName();
313
314
315
316
317
318 }
319 String type = xsType.getName();
320 if (type != null) {
321 return type;
322 }
323 if ((xsType.isComplexType())) {
324 XSComplexType ct = xsType.asComplexType();
325 String baseType = ct.getBaseType().getName();
326 if (baseType.equals("anyType")) {
327 baseType = "";
328 }
329 String inlineTypeName = inLinePrefix + baseType;
330 addComplexType(ct, inlineTypeName);
331 return inlineTypeName;
332 }
333 throw new IllegalArgumentException("cannot calculate the type of the field " + inLinePrefix);
334 }
335
336 private String calcRequired(XSElementDecl element) {
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352 return "???";
353 }
354
355 private String calcCardinality(XSElementDecl element) {
356
357
358
359 if (this.getIsRepeated(element)) {
360 return "Many";
361 }
362
363
364
365
366
367
368
369
370
371
372 return null;
373 }
374
375 private boolean getIsRepeated (XSElementDecl element) {
376 XSType type = element.getType();
377 if (type == null) {
378 return false;
379 }
380 if (type.isComplexType()) {
381 XSContentType contentType = type.asComplexType().getContentType();
382 if (contentType == null) {
383 return false;
384 }
385 XSParticle particle = contentType.asParticle();
386 if (particle == null) {
387 return false;
388 }
389 particle.isRepeated();
390 }
391
392 return false;
393 }
394
395 private String getFacetValue(XSElementDecl element, String name) {
396 XSType type = element.getType();
397 if (type == null) {
398 return null;
399 }
400 if (type.isSimpleType()) {
401 XSFacet facet = type.asSimpleType().getFacet(name);
402 if (facet == null) {
403 return null;
404 }
405 return facet.getValue().toString();
406 }
407 if (type.isComplexType()) {
408 XSContentType contentType = type.asComplexType().getContentType();
409 if (contentType == null) {
410 return null;
411 }
412 XSSimpleType simpleType = contentType.asSimpleType();
413 if (simpleType == null) {
414 return null;
415 }
416 XSFacet facet = simpleType.getFacet(name);
417 if (facet == null) {
418 return null;
419 }
420 return facet.getValue().toString();
421 }
422 return null;
423 }
424
425
426
427
428 private static class XsdAnnotationParserFactory implements AnnotationParserFactory {
429
430 @Override
431 public AnnotationParser create() {
432 return new XsdAnnotationParser();
433 }
434 }
435
436
437
438
439 private static class XsdAnnotationParser extends AnnotationParser {
440
441 private StringBuilder documentation = new StringBuilder();
442
443 @Override
444 public ContentHandler getContentHandler(AnnotationContext context,
445 String parentElementName,
446 ErrorHandler handler,
447 EntityResolver resolver) {
448 return new XsdContentHandler(documentation);
449 }
450
451 @Override
452 public Object getResult(Object existing) {
453 return documentation.toString().trim();
454 }
455 }
456
457
458
459
460 private static class XsdContentHandler implements ContentHandler {
461
462 private StringBuilder documentation;
463
464 public XsdContentHandler(StringBuilder documentation) {
465 this.documentation = documentation;
466 }
467 private boolean parsingDocumentation = false;
468
469 @Override
470 public void characters(char[] ch, int start, int length)
471 throws SAXException {
472 if (parsingDocumentation) {
473 documentation.append(ch, start, length);
474 }
475 }
476
477 @Override
478 public void endElement(String uri, String localName, String name)
479 throws SAXException {
480 if (localName.equals("documentation")) {
481 parsingDocumentation = false;
482 }
483 }
484
485 @Override
486 public void startElement(String uri, String localName, String name,
487 Attributes atts) throws SAXException {
488 if (localName.equals("documentation")) {
489 parsingDocumentation = true;
490 }
491 }
492
493 @Override
494 public void endDocument() throws SAXException {
495
496 }
497
498 @Override
499 public void endPrefixMapping(String prefix) throws SAXException {
500
501 }
502
503 @Override
504 public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException {
505
506 }
507
508 @Override
509 public void processingInstruction(String target, String data) throws SAXException {
510
511 }
512
513 @Override
514 public void setDocumentLocator(Locator locator) {
515
516 }
517
518 @Override
519 public void skippedEntity(String name) throws SAXException {
520
521 }
522
523 @Override
524 public void startDocument() throws SAXException {
525
526 }
527
528 @Override
529 public void startPrefixMapping(String prefix, String uri) throws SAXException {
530
531 }
532 }
533 }