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