KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jibx > binding > SchemaGenerator


1 /*
2 Copyright (c) 2004-2005, Dennis M. Sosnoski
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without modification,
6 are permitted provided that the following conditions are met:
7
8  * Redistributions of source code must retain the above copyright notice, this
9    list of conditions and the following disclaimer.
10  * Redistributions in binary form must reproduce the above copyright notice,
11    this list of conditions and the following disclaimer in the documentation
12    and/or other materials provided with the distribution.
13  * Neither the name of JiBX nor the names of its contributors may be used
14    to endorse or promote products derived from this software without specific
15    prior written permission.
16
17 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
21 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
24 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */

28
29 package org.jibx.binding;
30
31 import java.io.File JavaDoc;
32 import java.io.FileInputStream JavaDoc;
33 import java.io.FileNotFoundException JavaDoc;
34 import java.io.FileOutputStream JavaDoc;
35 import java.io.IOException JavaDoc;
36 import java.net.MalformedURLException JavaDoc;
37 import java.net.URL JavaDoc;
38 import java.util.ArrayList JavaDoc;
39 import java.util.HashMap JavaDoc;
40 import java.util.Iterator JavaDoc;
41
42 import javax.xml.parsers.DocumentBuilderFactory JavaDoc;
43 import javax.xml.parsers.FactoryConfigurationError JavaDoc;
44 import javax.xml.parsers.ParserConfigurationException JavaDoc;
45 import javax.xml.transform.Result JavaDoc;
46 import javax.xml.transform.Transformer JavaDoc;
47 import javax.xml.transform.TransformerConfigurationException JavaDoc;
48 import javax.xml.transform.TransformerException JavaDoc;
49 import javax.xml.transform.TransformerFactory JavaDoc;
50 import javax.xml.transform.TransformerFactoryConfigurationError JavaDoc;
51 import javax.xml.transform.dom.DOMSource JavaDoc;
52 import javax.xml.transform.stream.StreamResult JavaDoc;
53
54 import org.jibx.binding.classes.ClassCache;
55 import org.jibx.binding.classes.ClassFile;
56 import org.jibx.binding.model.BindingElement;
57 import org.jibx.binding.model.ClassWrapper;
58 import org.jibx.binding.model.CollectionElement;
59 import org.jibx.binding.model.ContainerElementBase;
60 import org.jibx.binding.model.DefinitionContext;
61 import org.jibx.binding.model.ElementBase;
62 import org.jibx.binding.model.IClass;
63 import org.jibx.binding.model.IClassLocator;
64 import org.jibx.binding.model.MappingElement;
65 import org.jibx.binding.model.NestingAttributes;
66 import org.jibx.binding.model.NestingElementBase;
67 import org.jibx.binding.model.StructureElement;
68 import org.jibx.binding.model.StructureElementBase;
69 import org.jibx.binding.model.TemplateElementBase;
70 import org.jibx.binding.model.ValidationContext;
71 import org.jibx.binding.model.ValidationProblem;
72 import org.jibx.binding.model.ValueElement;
73 import org.jibx.binding.util.ObjectStack;
74 import org.jibx.runtime.JiBXException;
75 import org.jibx.runtime.ValidationException;
76 import org.w3c.dom.Document JavaDoc;
77 import org.w3c.dom.Element JavaDoc;
78
79 /**
80  * Binding generator. This loads the specified input classes and processes them
81  * to generate a default binding definition.
82  *
83  * @author Dennis M. Sosnoski
84  * @version 1.0
85  */

86  
87 public class SchemaGenerator
88 {
89     /** Generator version. */
90     private static String JavaDoc CURRENT_VERSION = "0.2";
91     
92     /** Schema namespace URI. */
93     private static final String JavaDoc XSD_URI = "http://www.w3.org/2001/XMLSchema";
94     
95     /** Fixed XML namespace. */
96     public static final String JavaDoc XML_URI = "http://www.w3.org/XML/1998/namespace";
97     
98     /** Fixed XML namespace namespace. */
99     public static final String JavaDoc XMLNS_URI = "http://www.w3.org/2000/xmlns/";
100     
101     /** Set of object types mapped to schema types. */
102     private static HashMap JavaDoc s_objectTypeMap = new HashMap JavaDoc();
103     
104     static {
105         s_objectTypeMap.put("java.lang.Boolean", "xsd:boolean");
106         s_objectTypeMap.put("java.lang.Byte", "xsd:byte");
107         s_objectTypeMap.put("java.lang.Char", "xsd:unsignedInt");
108         s_objectTypeMap.put("java.lang.Double", "xsd:double");
109         s_objectTypeMap.put("java.lang.Float", "xsd:float");
110         s_objectTypeMap.put("java.lang.Integer", "xsd:int");
111         s_objectTypeMap.put("java.lang.Long", "xsd:long");
112         s_objectTypeMap.put("java.lang.Short", "xsd:short");
113         s_objectTypeMap.put("java.math.BigDecimal", "xsd:decimal");
114         s_objectTypeMap.put("java.math.BigInteger", "xsd:integer");
115         s_objectTypeMap.put("java.sql.Date", "xsd:date");
116         s_objectTypeMap.put("java.sql.Time", "xsd:time");
117         s_objectTypeMap.put("java.sql.Timestamp", "xsd:dateTime");
118         s_objectTypeMap.put("java.util.Date", "xsd:dateTime");
119         s_objectTypeMap.put("byte[]", "xsd:base64");
120     }
121     
122     /** Set of primitive types mapped to schema types. */
123     private static HashMap JavaDoc s_primitiveTypeMap = new HashMap JavaDoc();
124     
125     static {
126         s_primitiveTypeMap.put("boolean", "xsd:boolean");
127         s_primitiveTypeMap.put("byte", "xsd:byte");
128         s_primitiveTypeMap.put("char", "xsd:unsignedInt");
129         s_primitiveTypeMap.put("double", "xsd:double");
130         s_primitiveTypeMap.put("float", "xsd:float");
131         s_primitiveTypeMap.put("int", "xsd:int");
132         s_primitiveTypeMap.put("long", "xsd:long");
133         s_primitiveTypeMap.put("short", "xsd:short");
134     }
135     
136     /** Show verbose output flag. */
137     private boolean m_verbose;
138     
139     /** Use qualified elements default in schema flag. */
140     private boolean m_isElementQualified;
141     
142     /** Use qualified attributes default in schema flag. */
143     private boolean m_isAttributeQualified;
144     
145     /** Indentation sequence per level of nesting. */
146     private String JavaDoc m_indentSequence;
147     
148     /** Map from namespaces to schemas. */
149     private HashMap JavaDoc m_schemaMap;
150     
151     /** Locator for finding classes referenced by binding. */
152     private IClassLocator m_classLocator;
153     
154     /** Document used for all schema definitions. */
155     private Document JavaDoc m_document;
156     
157     /** Stack of structure definitions in progress (used to detect cycles). */
158     private ObjectStack m_structureStack;
159     
160     /**
161      * Constructor with only paths supplied. This just initializes all other
162      * options disabled.
163      *
164      * @param paths class paths to be checked for classes referenced by bindings
165      */

166     public SchemaGenerator(ArrayList JavaDoc paths) {
167         m_structureStack = new ObjectStack();
168         m_schemaMap = new HashMap JavaDoc();
169         
170         // set paths to be used for loading referenced classes
171
String JavaDoc[] parray = (String JavaDoc[])paths.toArray(new String JavaDoc[paths.size()]);
172         ClassCache.setPaths(parray);
173         ClassFile.setPaths(parray);
174         
175         // set class locator
176
m_classLocator = new IClassLocator() {
177             public IClass getClassInfo(String JavaDoc name) {
178                 try {
179                     return new ClassWrapper(ClassCache.getClassFile(name));
180                 } catch (JiBXException e) {
181                     throw new IllegalStateException JavaDoc("Class not found " + name);
182                 }
183             }
184         };
185         try {
186             
187             // create the document used for all schemas
188
DocumentBuilderFactory JavaDoc dbf = DocumentBuilderFactory.newInstance();
189             dbf.setNamespaceAware(true);
190             m_document = dbf.newDocumentBuilder().newDocument();
191             
192         } catch (ParserConfigurationException JavaDoc e) {
193             throw new IllegalStateException JavaDoc("Parser configuration error " +
194                 e.getMessage());
195         } catch (FactoryConfigurationError JavaDoc e) {
196             throw new IllegalStateException JavaDoc("Factory configuration error " +
197                 e.getMessage());
198         }
199     }
200     
201     /**
202      * Constructor with settings specified.
203      *
204      * @param verbose report binding details and results
205      * @param equal use element form default qualified flag
206      * @param aqual use attribute form default qualified flag
207      * @param paths class paths to be checked for classes referenced by bindings
208      */

209     public SchemaGenerator(boolean verbose, boolean equal, boolean aqual,
210         ArrayList JavaDoc paths) {
211         this(paths);
212         m_verbose = verbose;
213         m_isElementQualified = equal;
214         m_isAttributeQualified = aqual;
215         m_indentSequence = " ";
216     }
217
218     /**
219      * Set control flag for verbose processing reports.
220      *
221      * @param verbose report verbose information in processing bindings flag
222      */

223     public void setVerbose(boolean verbose) {
224         m_verbose = verbose;
225     }
226
227     /**
228      * Set control flag for element qualified default schema.
229      *
230      * @param qual element qualified default schemas flag
231      */

232     public void setElementQualified(boolean qual) {
233         m_isElementQualified = qual;
234     }
235
236     /**
237      * Set control flag for attribute qualified default schema.
238      *
239      * @param qual attribute qualified default schemas flag
240      */

241     public void setAttributeQualified(boolean qual) {
242         m_isAttributeQualified = qual;
243     }
244
245     /**
246      * Get array of generated schemas.
247      *
248      * @return array of schema elements
249      */

250     public Element[] getSchemas() {
251         Element[] schemas = new Element[m_schemaMap.size()];
252         int fill = 0;
253         for (Iterator JavaDoc iter = m_schemaMap.values().iterator(); iter.hasNext();) {
254             schemas[fill++] = (Element)iter.next();
255         }
256         return schemas;
257     }
258     
259     /**
260      * Generate indentation to proper depth for current item. This creates the
261      * indentation text and appends it to the supplied parent. The generated
262      * indentation is appropriate for the close tag of the parent element; if
263      * a child element is to be added following this indentation it needs to
264      * use an additional leading indent.
265      *
266      * @param parent element to contain indented child item
267      */

268     private void indentForClose(Element parent) {
269         StringBuffer JavaDoc buff = new StringBuffer JavaDoc(20);
270         buff.append('\n');
271         Element ancestor = parent;
272         boolean count = false;
273         while (ancestor != null) {
274             if (count) {
275                 buff.append(m_indentSequence);
276             }
277             ancestor = (Element)ancestor.getParentNode();
278             count = true;
279         }
280         parent.appendChild(m_document.createTextNode(buff.toString()));
281     }
282     
283     /**
284      * Add comment with appropriate indentation.
285      *
286      * @param parent element to contain indented child item
287      * @param text comment text
288      */

289     private void addComment(Element parent, String JavaDoc text) {
290         if (parent.getChildNodes().getLength() == 0) {
291             indentForClose(parent);
292         }
293         parent.appendChild(m_document.createTextNode(m_indentSequence));
294         parent.appendChild(m_document.createComment(text));
295         indentForClose(parent);
296     }
297     
298     /**
299      * Add child element with appropriate indentation. This generates and
300      * returns the child element after adding it to the supplied parent,
301      * allowing further modification of the new child element.
302      *
303      * @param parent element to contain indented child item
304      * @param text comment text
305      */

306     private Element addChildElement(Element parent, String JavaDoc name) {
307         if (parent.getChildNodes().getLength() == 0) {
308             indentForClose(parent);
309         }
310         parent.appendChild(m_document.createTextNode(m_indentSequence));
311         Element element = m_document.createElementNS(XSD_URI, name);
312         parent.appendChild(element);
313         indentForClose(parent);
314         return element;
315     }
316     
317     /**
318      * Get innermost containing definition context.
319      *
320      * @return innermost definition context containing this element
321      */

322     public DefinitionContext getDefinitions() {
323         int index = 0;
324         while (index < m_structureStack.size()) {
325             NestingElementBase nest =
326                 (NestingElementBase)m_structureStack.peek(index++);
327             if (nest.getDefinitions() != null) {
328                 return nest.getDefinitions();
329             }
330         }
331         throw new IllegalStateException JavaDoc
332             ("Internal error: no definition context");
333     }
334
335     /**
336      * Process a structure component (structure or collection element) with no
337      * name and no child components. This adds the appropriate type of element
338      * or any definition to the container schema element.
339      *
340      * @param comp structure component to be processed
341      * @param egroup schema element to contain element definitions
342      * @param agroup schema element to contain attribute definitions
343      */

344     private void defineEmptyStructureComponent(StructureElementBase comp,
345         Element egroup, Element agroup) {
346         NestingElementBase parent =
347             (NestingElementBase)m_structureStack.peek(0);
348         boolean only = parent.children().size() == 1;
349         if (comp.type() == ElementBase.COLLECTION_ELEMENT) {
350             
351             // collection may define type or not
352
CollectionElement collection = (CollectionElement)comp;
353             String JavaDoc itype = collection.getItemTypeClass().getName();
354             DefinitionContext dctx = getDefinitions();
355             TemplateElementBase templ = dctx.getSpecificTemplate(itype);
356             Element element = null;
357             if (! (templ instanceof MappingElement)) {
358                 if (only) {
359                     addComment(egroup, " Replace \"any\" with details of " +
360                         "content to complete schema ");
361                     element = addChildElement(egroup, "any");
362                 } else {
363                     addComment(egroup,
364                         " No mapping for items of collection at " +
365                         ValidationException.describe(collection) + " ");
366                     addComment(egroup,
367                         " Fill in details of content to complete schema ");
368                 }
369             } else {
370                 element = addChildElement(egroup, "element");
371                 element.setAttribute("ref", "tns:" +
372                     ((MappingElement)templ).getName());
373             }
374             if (element != null) {
375                 element.setAttribute("minOccurs", "0");
376                 element.setAttribute("maxOccurs", "unbounded");
377             }
378             
379         } else {
380             
381             // check for reference to a mapped class
382
StructureElement structure = (StructureElement)comp;
383             TemplateElementBase templ = structure.getMapAsMapping();
384             if (! (templ instanceof MappingElement)) {
385                 
386                 // unknown content, leave it to user to fill in details
387
if (only) {
388                     addComment(egroup, " Replace \"any\" with details of " +
389                         "content to complete schema ");
390                     addChildElement(egroup, "any");
391                 } else {
392                     addComment(egroup, " No mapping for structure at " +
393                         ValidationException.describe(structure) + " ");
394                     addComment(egroup,
395                         " Fill in details of content here to complete schema ");
396                 }
397                 
398             } else {
399                 MappingElement mapping = (MappingElement)templ;
400                 if (mapping.isAbstract()) {
401                     
402                     // check name to be used for instance of type
403
String JavaDoc ename = structure.getName();
404                     if (ename == null) {
405                         ename = mapping.getName();
406                     }
407                     if (ename == null) {
408                         
409                         // no schema equivalent, embed definition directly
410
addComment(egroup, "No schema representation for " +
411                             "directly-embedded type, inlining definition");
412                         addComment(egroup, "Add element name to structure at " +
413                             ValidationException.describe(structure) +
414                             " to avoid inlining");
415                         defineList(mapping.children(), egroup, agroup, false);
416                         
417                     } else {
418                         
419                         // handle abstract mapping element as reference to type
420
Element element = addChildElement(egroup, "element");
421                         String JavaDoc tname = simpleClassName(mapping.getClassName());
422                         element.setAttribute("type", "tns:" + tname);
423                         String JavaDoc name = structure.getName();
424                         if (name == null) {
425                             name = mapping.getName();
426                         }
427                         element.setAttribute("name", name);
428                         if (structure.isOptional()) {
429                             element.setAttribute("minOccurs", "0");
430                         }
431                     }
432                     
433                 } else {
434                     
435                     // concrete mapping, check for name overridden
436
String JavaDoc sname = structure.getName();
437                     String JavaDoc mname = mapping.getName();
438                     if (sname != null && !sname.equals(mname)) {
439                         
440                         // inline definition for overridden name
441
addComment(egroup, "No schema representation for " +
442                             "element reference with different name, inlining " +
443                             "definition");
444                         addComment(egroup,
445                             "Remove name on mapping reference at " +
446                             ValidationException.describe(structure) +
447                             " to avoid inlining");
448                         defineList(mapping.children(), egroup, agroup, false);
449                         
450                     } else {
451                         
452                         // use element reference for concrete mapping
453
Element element = addChildElement(egroup, "element");
454                         String JavaDoc tname = simpleClassName(mapping.getClassName());
455                         element.setAttribute("ref", "tns:" + mname);
456                         if (structure.isOptional()) {
457                             element.setAttribute("minOccurs", "0");
458                         }
459                     }
460                     
461                 }
462             }
463             
464         }
465     }
466
467     /**
468      * Process a structure component (structure or collection element) within a
469      * list of child components. This adds the appropriate type of element or
470      * any definition to the container, if necessary calling other methods for
471      * recursive handling of nested child components.
472      *
473      * @param comp structure component to be processed
474      * @param egroup schema element to contain element definitions
475      * @param agroup schema element to contain attribute definitions
476      * @param mult allow any number of occurrences of components flag
477      */

478     private void defineStructureComponent(StructureElementBase comp,
479         Element egroup, Element agroup, boolean mult) {
480         
481         // check for element defined by binding component
482
if (comp.getName() != null) {
483             
484             // create basic element definition for name
485
Element element = addChildElement(egroup, "element");
486             element.setAttribute("name", comp.getName());
487             if (mult) {
488                 element.setAttribute("minOccurs", "0");
489                 element.setAttribute("maxOccurs", "unbounded");
490             } else if (comp.isOptional()) {
491                 element.setAttribute("minOccurs", "0");
492             }
493             
494             // check for children present
495
if (comp.children().size() > 0) {
496                 defineNestedStructure(comp, element);
497             } else {
498                 
499                 // nest complex type definition for actual content
500
Element type = addChildElement(element, "complexType");
501                 Element seq = addChildElement(type, "sequence");
502                 
503                 // process the content description
504
defineEmptyStructureComponent(comp, seq, type);
505             }
506             
507         } else if (comp.children().size() > 0) {
508             
509             // handle child components with recursive call
510
boolean coll = comp.type() == ElementBase.COLLECTION_ELEMENT;
511             m_structureStack.push(comp);
512             defineList(comp.children(), egroup, agroup, coll);
513             m_structureStack.pop();
514             
515         } else {
516             
517             // handle empty structure definition inline
518
defineEmptyStructureComponent(comp, egroup, agroup);
519         }
520     }
521
522     /**
523      * Create the schema definition list for a binding component list. This
524      * builds the sequence of elements and attributes defined by the binding
525      * components, including nested complex types for elements with structure.
526      *
527      * @param comps binding component list
528      * @param egroup schema element to contain element definitions
529      * @param agroup schema element to contain attribute definitions
530      * @param mult allow any number of occurrences of components flag
531      */

532     private void defineList(ArrayList JavaDoc comps, Element egroup, Element agroup,
533         boolean mult) {
534         
535         // handle all nested elements of container
536
for (int i = 0; i < comps.size(); i++) {
537             ElementBase child = (ElementBase)comps.get(i);
538             switch (child.type()) {
539                 
540                 case ElementBase.COLLECTION_ELEMENT:
541                 case ElementBase.STRUCTURE_ELEMENT:
542                 {
543                     defineStructureComponent((StructureElementBase)child,
544                         egroup, agroup, mult);
545                     break;
546                 }
547                     
548                 case ElementBase.MAPPING_ELEMENT:
549                 {
550                     // nested mapping definitions not handled
551
System.err.println("Error: nested mapping not supported " +
552                         "(class " + ((MappingElement)child).getClassName() +
553                         ")");
554                     break;
555                 }
556                     
557                 case ElementBase.TEMPLATE_ELEMENT:
558                 {
559                     // templates to be added once usable in binding
560
System.err.println
561                         ("Error: template component not yet supported");
562                     break;
563                 }
564                     
565                 case ElementBase.VALUE_ELEMENT:
566                 {
567                     // get type information for value
568
ValueElement value = (ValueElement)child;
569                     String JavaDoc tname = value.getType().getName();
570                     String JavaDoc stype = (String JavaDoc)s_primitiveTypeMap.get(tname);
571                     if (stype == null) {
572                         stype = (String JavaDoc)s_objectTypeMap.get(tname);
573                         if (stype == null) {
574                             stype = "xsd:string";
575                         }
576                     }
577                     
578                     // build schema element or attribute for value
579
Element element;
580                     int style = value.getStyle();
581                     if (style == NestingAttributes.ATTRIBUTE_STYLE) {
582                         
583                         // append attribute as child of type
584
element = addChildElement(agroup, "attribute");
585                         if (!value.isOptional()) {
586                             element.setAttribute("use", "required");
587                         }
588                         
589                     } else if (style == NestingAttributes.ELEMENT_STYLE) {
590                         
591                         // append simple element as child of grouping
592
element = addChildElement(egroup, "element");
593                         if (mult) {
594                             element.setAttribute("minOccurs", "0");
595                             element.setAttribute("maxOccurs", "unbounded");
596                         } else if (value.isOptional()) {
597                             element.setAttribute("minOccurs", "0");
598                         }
599                         
600                     } else {
601                         
602                         // other types are not currently handled
603
System.err.println("Error: value type " +
604                             value.getEffectiveStyleName() + " not supported");
605                         break;
606                         
607                     }
608                     
609                     // set common attributes on definition
610
element.setAttribute("name", value.getName());
611                     element.setAttribute("type", stype);
612                     break;
613                 }
614             }
615         }
616     }
617
618     /**
619      * Create the schema definition for a nested structure. This defines a
620      * complex type, if necessary calling itself recursively for elements which
621      * are themselves complex types. In the special case where the container
622      * element is a mapping which extends an abstract base class this generates
623      * the complex type as an extension of the base class complex type.
624      *
625      * @param container binding definition element containing nested structure
626      * @param parent schema element to hold the definition
627      * @return constructed complex type
628      */

629     private Element defineNestedStructure(ContainerElementBase container,
630         Element parent) {
631         
632         // create complex type as holder for definition
633
Element type = addChildElement(parent, "complexType");
634         
635         // check whether ordered or unordered container
636
Element group;
637         ArrayList JavaDoc childs = container.children();
638         if (container.isOrdered()) {
639             
640             // define content list as sequence
641
group = addChildElement(type, "sequence");
642             
643             // check for mapping which extends another mapping
644
/* if (container instanceof MappingElement) {
645                 MappingElement mapping = (MappingElement)container;
646                 MappingElement extended = mapping.getExtendsMapping();
647                 if (extended != null) {
648                     
649                     // now see if the mapping can extend base complex type
650                     boolean extend = false;
651                     for (int i = 0; i < childs.size(); i++) {
652                         ElementBase child = (ElementBase)childs.get(i);
653                         if (child instanceof StructureElement) {
654                             StructureElement struct = (StructureElement)child;
655                             if (struct.getMapAsMapping() == extended) {
656                                 if (struct.getName() == null) {
657                                     extend = true;
658                                     
659                                 }
660                             }
661                         }
662                         if (child instanceof IComponent) {
663                             
664                         }
665                     }
666                 }
667             } */

668             
669         } else {
670             group = addChildElement(type, "all");
671         }
672         
673         // handle all nested elements of container
674
m_structureStack.push(container);
675         defineList(childs, group, type,
676             container.type() == ElementBase.COLLECTION_ELEMENT);
677         m_structureStack.pop();
678         return type;
679     }
680     
681     /**
682      * Generate a schema from a binding using supplied classpaths. If the schema
683      * for the binding namespace (or default namespace) already exists the
684      * definitions from this binding are added to the existing schema; otherwise
685      * a new schema is created and added to the collection defined.
686      *
687      * @param binding root element of binding
688      */

689     private void generateSchema(BindingElement binding) {
690         
691         // process each mapping definition for binding
692
m_structureStack.push(binding);
693         ArrayList JavaDoc tops = binding.topChildren();
694         for (int i = 0; i < tops.size(); i++) {
695             ElementBase top = (ElementBase)tops.get(i);
696             if (top.type() == ElementBase.MAPPING_ELEMENT) {
697                 
698                 // find or create schema for mapped class
699
MappingElement mapping = (MappingElement)top;
700                 String JavaDoc uri = mapping.getNamespace().getUri();
701                 Element schema = (Element)m_schemaMap.get(uri);
702                 if (schema == null) {
703                     
704                     // build new schema element for this namespace
705
schema = m_document.createElementNS(XSD_URI, "schema");
706                     if (uri != null) {
707                         schema.setAttribute("targetNamespace", uri);
708                     }
709                     m_schemaMap.put(uri, schema);
710                     
711                     // set qualification attributes if needed
712
if (m_isElementQualified) {
713                         schema.setAttribute("elementFormDefault", "qualified");
714                     }
715                     if (m_isAttributeQualified) {
716                         schema.setAttribute("attributeFormDefault",
717                             "qualified");
718                     }
719                     
720                     // add namespace declarations to element
721
if (uri != null) {
722                         schema.setAttributeNS(XMLNS_URI, "xmlns:tns", uri);
723                     }
724                     schema.setAttributeNS(XMLNS_URI, "xmlns:xsd", XSD_URI);
725                     schema.setAttributeNS(XMLNS_URI, "xmlns", XSD_URI);
726                     
727                     // add spacing for first child node
728
indentForClose(schema);
729                 }
730                 
731                 // add spacer and comment before actual definition
732
indentForClose(schema);
733                 String JavaDoc cname = mapping.getClassName();
734                 addComment(schema, " Created from mapping for class " +
735                     cname + " ");
736                 if (mapping.isAbstract()) {
737                     
738                     // add mapping as global type in binding
739
Element type = defineNestedStructure(mapping, schema);
740                     type.setAttribute("name", simpleClassName(cname));
741                     
742                 } else {
743                     
744                     // add mapping as global element in binding
745
Element element = addChildElement(schema, "element");
746                     element.setAttribute("name", mapping.getName());
747                     
748                     // check type of mapping definition
749
if (mapping.getMarshaller() != null ||
750                         mapping.getUnmarshaller() != null) {
751                         
752                         // use "any" for custom marshaller/unmarshaller
753
Element type = addChildElement(element, "complexType");
754                         Element seq = addChildElement(type, "sequence");
755                         addComment(seq, " Replace \"any\" with details of " +
756                             "content to complete schema ");
757                         addChildElement(seq, "any");
758                         
759                     } else {
760                         
761                         // use complex type for embedded definition
762
defineNestedStructure(mapping, element);
763                         
764                     }
765                 }
766             }
767         }
768         m_structureStack.pop();
769     }
770     
771     /**
772      * Process a binding definition for schema generation. This first validates
773      * the binding definition, and if it is valid then handles schema generation
774      * from the binding.
775      *
776      * @param binding root element of binding
777      * @exception JiBXException if error in generating the schema
778      */

779     public void generate(BindingElement binding) throws JiBXException {
780         
781         // validate the binding definition
782
ValidationContext vctx = new ValidationContext(m_classLocator);
783         binding.runValidation(vctx);
784         boolean usable = true;
785         if (vctx.getProblems().size() > 0) {
786             
787             // report problems found
788
System.err.println("Problems found in binding " +
789                 binding.getName());
790             ArrayList JavaDoc probs = vctx.getProblems();
791             for (int i = 0; i < probs.size(); i++) {
792                 ValidationProblem prob = (ValidationProblem)probs.get(i);
793                 System.err.println(prob.getDescription());
794                 if (prob.getSeverity() > ValidationProblem.WARNING_LEVEL) {
795                     usable = false;
796                 }
797             }
798         }
799         
800         // check if binding usable for schema generation
801
if (usable) {
802             generateSchema(binding);
803         } else {
804             System.err.println
805                 ("Binding validation errors prevent schema generation");
806             System.exit(1);
807         }
808     }
809
810     /**
811      * @param cname
812      * @return
813      */

814     private String JavaDoc simpleClassName(String JavaDoc cname) {
815         int split = cname.lastIndexOf('.');
816         if (split >= 0) {
817             cname = cname.substring(split+1);
818         }
819         return cname;
820     }
821
822     /**
823      * Main method for running compiler as application.
824      *
825      * @param args command line arguments
826      */

827     public static void main(String JavaDoc[] args) {
828         if (args.length > 0) {
829             try {
830                 
831                 // check for various flags set
832
boolean verbose = false;
833                 boolean edflt = true;
834                 boolean adflt = false;
835                 ArrayList JavaDoc paths = new ArrayList JavaDoc();
836                 int offset = 0;
837                 for (; offset < args.length; offset++) {
838                     String JavaDoc arg = args[offset];
839                     if ("-v".equalsIgnoreCase(arg)) {
840                         verbose = true;
841                     } else if ("-e".equalsIgnoreCase(arg)) {
842                         edflt = false;
843                     } else if ("-a".equalsIgnoreCase(arg)) {
844                         adflt = true;
845                     } else if ("-p".equalsIgnoreCase(arg)) {
846                         paths.add(args[++offset]);
847                     } else {
848                         break;
849                     }
850                 }
851                 
852                 // set up path and binding lists
853
String JavaDoc[] vmpaths = Utility.getClassPaths();
854                 for (int i = 0; i < vmpaths.length; i++) {
855                     paths.add(vmpaths[i]);
856                 }
857                 ArrayList JavaDoc bindings = new ArrayList JavaDoc();
858                 for (int i = offset; i < args.length; i++) {
859                     bindings.add(args[i]);
860                 }
861                 
862                 // report on the configuration
863
System.out.println("Running schema generator version " +
864                     CURRENT_VERSION);
865                 if (verbose) {
866                     System.out.println("Using paths:");
867                     for (int i = 0; i < paths.size(); i++) {
868                         System.out.println(" " + paths.get(i));
869                     }
870                     System.out.println("Using input bindings:");
871                     for (int i = 0; i < bindings.size(); i++) {
872                         System.out.println(" " + bindings.get(i));
873                     }
874                 }
875                 
876                 // process all specified binding files
877
SchemaGenerator schemagen = new SchemaGenerator(verbose, edflt,
878                     adflt, paths);
879                 for (int i = 0; i < bindings.size(); i++) {
880                     
881                     // read binding from file
882
String JavaDoc bpath = (String JavaDoc)bindings.get(i);
883                     String JavaDoc name = Utility.convertName(Utility.fileName(bpath));
884                     File JavaDoc file = new File JavaDoc(bpath);
885                     BindingElement binding = Utility.validateBinding(name,
886                         new URL JavaDoc("file://" + file.getAbsolutePath()),
887                         new FileInputStream JavaDoc(file));
888                     
889                     // convert the binding to a schema
890
if (binding != null) {
891                         schemagen.generate(binding);
892                     }
893                 }
894                 
895                 // output each schema to separate file
896
Element[] schemas = schemagen.getSchemas();
897                 for (int i = 0; i < schemas.length; i++) {
898                     
899                     // get base name for output file from last part of namespace
900
Element schema = schemas[i];
901                     String JavaDoc tns = schema.getAttribute("targetNamespace");
902                     String JavaDoc name = tns;
903                     if (name.length() == 0) {
904                         // fix this to relate back to binding
905
name = (String JavaDoc)bindings.get(0);
906                         int split = name.lastIndexOf('.');
907                         if (split >= 0) {
908                             name = name.substring(0, split);
909                         }
910                     } else {
911                         int split = name.lastIndexOf('/');
912                         if (split >= 0) {
913                             name = name.substring(split+1);
914                         }
915                     }
916                     try {
917                         
918                         // write schema to output file
919
name += ".xsd";
920                         FileOutputStream JavaDoc out = new FileOutputStream JavaDoc(name);
921                         Transformer JavaDoc transformer =
922                             TransformerFactory.newInstance().newTransformer();
923                         transformer.setOutputProperty("indent", "no");
924                         DOMSource JavaDoc source = new DOMSource JavaDoc(schema);
925                         Result JavaDoc result = new StreamResult JavaDoc(out);
926                         transformer.transform(source, result);
927                         out.close();
928                         System.out.print("Wrote schema " + name);
929                         if (tns.length() == 0) {
930                             System.out.println(" for default namespace");
931                         } else {
932                             System.out.println(" for namespace " + tns);
933                         }
934                         
935                     } catch (TransformerConfigurationException JavaDoc e) {
936                         e.printStackTrace();
937                     } catch (TransformerFactoryConfigurationError JavaDoc e) {
938                         e.printStackTrace();
939                     } catch (TransformerException JavaDoc e) {
940                         e.printStackTrace();
941                     } catch (IOException JavaDoc e) {
942                         e.printStackTrace();
943                     }
944                 }
945                 
946             } catch (JiBXException ex) {
947                 ex.printStackTrace();
948                 System.exit(1);
949             } catch (FileNotFoundException JavaDoc e) {
950                 e.printStackTrace();
951                 System.exit(2);
952             } catch (MalformedURLException JavaDoc e) {
953                 e.printStackTrace();
954                 System.exit(3);
955             }
956             
957         } else {
958             System.out.println
959                 ("\nUsage: java org.jibx.binding.SchemaGenerator [-v] [-e]" +
960                 " [-a] [-p path]* binding1 binding2 ...\nwhere:" +
961                 "\n -v turns on verbose output," +
962                 "\n -e sets elementFormDefault=\"false\" for the schemas," +
963                 "\n -a sets attributeFormDefault=\"true\" for the schemas, " +
964                 "and\n -p gives a path component for looking up the classes " +
965                 "referenced in the binding\nThe binding# files are " +
966                 "different bindings to be used for schema generation.\n");
967             System.exit(1);
968         }
969     }
970 }
Popular Tags