001 /*
002 // $Id: //open/util/resgen/src/org/eigenbase/xom/MetaGenerator.java#7 $
003 // package org.eigenbase.xom is an XML Object Mapper
004 // Copyright (C) 2005-2008 The Eigenbase Project
005 // Copyright (C) 2005-2008 Disruptive Tech
006 // Copyright (C) 2005-2008 Red Square, Inc.
007 // Portions Copyright (C) 2000-2008 Kana Software, Inc. and others.
008 // All Rights Reserved.
009 //
010 // This library is free software; you can redistribute it and/or modify it
011 // under the terms of the GNU Lesser General Public License as published by
012 // the Free Software Foundation; either version 2.1 of the License, or
013 // (at your option) any later version.
014 //
015 // This library is distributed in the hope that it will be useful, but
016 // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
017 // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
018 // License for more details.
019 //
020 // You should have received a copy of the GNU Lesser General Public License
021 // along with this library; if not, write to the Free Software Foundation, Inc.,
022 // 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
023 //
024 // dsommerfield, 26 December, 2000
025 */
026
027 package org.eigenbase.xom;
028 import java.io.*;
029 import java.util.Date;
030 import java.util.Hashtable;
031 import java.util.Vector;
032
033 /**
034 * <code>MetaGenerator</code> is a utility class which reads a XOM Meta
035 * Model description in XML and generates the corresponding .dtd and .java
036 * definition files. MetaGenerator is invoked during the build process to help
037 * generate files for the build.
038 **/
039 public class MetaGenerator {
040
041 /**
042 * Private member to hold the active model to be generated.
043 */
044 private MetaDef.Model model;
045
046 /**
047 * Private member. This is model.prefix, except that it is "" if
048 * model.prefix is null, rather than null.
049 */
050 private String prefix;
051
052 private Hashtable keywordMap;
053 private Hashtable typeMap;
054 private Hashtable infoMap;
055 private Hashtable subclassMap;
056 private Vector allTypes;
057 private boolean testMode;
058
059 private static final String newLine = System.getProperty("line.separator");
060 private static final char fileSep = System.getProperty("file.separator").charAt(0);
061
062 /**
063 * This helper class contains all necessary information about a type.
064 * The information is collected here to help support inheritence and
065 * other advanced features.
066 */
067 private class TypeInfo
068 {
069 // XML definition of the type. Includes defined attributes,
070 // content, and other information.
071 public MetaDef.Definition def;
072
073 // Documentation and code, here for easy reference.
074 public String doc;
075 public String code;
076
077 // Name of the class and associated XML tag.
078 public String name;
079 public String className;
080 public String tagName;
081
082 // This array holds all attributes, inherited or otherwise, that may
083 // be used by this type.
084 public MetaDef.Attribute[] allAttributes;
085
086 // This array holds all attributes that are overridden by this type.
087 public MetaDef.Attribute[] ovrAttributes;
088
089 // This array holds all new attributes defined only in this type
090 // and not overriding any inherited attributes.
091 public MetaDef.Attribute[] newAttributes;
092
093 // This array holds all content, inherited or otherwise, that may
094 // be used by this type.
095 public MetaDef.Content[] allContent;
096
097 // This array holds all new content defined only in this type.
098 public MetaDef.Content[] newContent;
099
100 // True if content is <Any> (either defined or inherited).
101 public boolean isAny;
102
103 // True if content is <CData> (either defined or inherited).
104 public boolean isCData;
105
106 // Reference to superclass info (if any)
107 public TypeInfo superInfo;
108
109 // Class to use when importing elements.
110 public Class impClass;
111 public String impName; // e.g. "foo.MetaDef.Tag"
112
113 public String contentModel;
114
115 public TypeInfo(MetaDef.Definition elt)
116 throws XOMException
117 {
118 def = elt;
119
120 // Get the name and superclass name
121 name = null;
122 String superName = null;
123 MetaDef.Attribute[] attributes = null;
124 MetaDef.Content[] content = null;
125 contentModel = "sequential";
126 if (elt instanceof MetaDef.Element) {
127 MetaDef.Element element = (MetaDef.Element) elt;
128 name = element.type;
129 if (element.dtdName != null) {
130 tagName = element.dtdName;
131 } else {
132 tagName = prefix + name;
133 }
134 superName = element._class;
135 attributes = element.attributes;
136 content = element.content;
137 contentModel = element.contentModel;
138 doc = element.doc;
139 code = element.code;
140 impClass = null;
141 impName = null;
142 } else if (elt instanceof MetaDef.Plugin) {
143 name = ((MetaDef.Plugin)elt).type;
144 tagName = prefix + name;
145 superName = ((MetaDef.Plugin)elt)._class;
146 attributes = ((MetaDef.Plugin)elt).attributes;
147 content = new MetaDef.Content[0];
148 doc = ((MetaDef.Plugin)elt).doc;
149 code = ((MetaDef.Plugin)elt).code;
150 impClass = null;
151 impName = null;
152 } else if (elt instanceof MetaDef.Class) {
153 name = ((MetaDef.Class)elt)._class;
154 tagName = "(%" + name + ";)";
155 superName = ((MetaDef.Class)elt).superclass;
156 attributes = ((MetaDef.Class)elt).attributes;
157 content = ((MetaDef.Class)elt).content;
158 doc = ((MetaDef.Class)elt).doc;
159 code = ((MetaDef.Class)elt).code;
160 impClass = null;
161 impName = null;
162 } else if (elt instanceof MetaDef.StringElement) {
163 name = ((MetaDef.StringElement)elt).type;
164 tagName = prefix + name;
165 superName = null;
166 attributes = new MetaDef.Attribute[0];
167 content = new MetaDef.Content[0];
168 doc = ((MetaDef.StringElement)elt).doc;
169 code = null;
170 impClass = null;
171 impName = null;
172 } else if (elt instanceof MetaDef.Import) {
173 MetaDef.Import imp = (MetaDef.Import)elt;
174 name = imp.type;
175 if (imp.dtdName != null) {
176 tagName = imp.dtdName;
177 } else {
178 tagName = prefix + name;
179 }
180 superName = null;
181 attributes = new MetaDef.Attribute[0];
182 content = new MetaDef.Content[0];
183 doc = null;
184 code = null;
185 try {
186 impName = imp.defPackage + "." + imp.defClass + "." + name;
187 impClass = Class.forName(imp.defPackage + "."
188 + imp.defClass + "$"
189 + name);
190 } catch (ClassNotFoundException ex) {
191 // throw new XOMException(
192 // "Import " + name + " references Java Class "
193 // + imp.defPackage + "." + imp.defClass
194 // + "." + name + " that does not exist.");
195 }
196 } else {
197 throw new XOMException("Illegal element type "
198 + elt.getClass().getName());
199 }
200 className = XOMUtil.capitalize(name);
201
202 // Get the TypeInfo record for the superclass. If we don't find
203 // it, we'll have to create it by looking up its definition.
204 superInfo = null;
205 if (superName != null) {
206 superInfo = (TypeInfo)(infoMap.get(superName));
207 if (superInfo == null) {
208 MetaDef.Definition superDef =
209 (MetaDef.Definition)(infoMap.get(superName));
210 if (superDef == null) {
211 throw new XOMException(
212 "Parent class " + superName + " of element "
213 + name + " was never defined.");
214 }
215 superInfo = new TypeInfo(superDef);
216 }
217 }
218
219 // Check for special content (<Any> or <CData>). If we find it,
220 // it must be the only content defined.
221 boolean newAny = false;
222 boolean newCData = false;
223 if (content.length == 1) {
224 if (content[0] instanceof MetaDef.CData) {
225 newCData = true;
226 } else if (content[0] instanceof MetaDef.Any) {
227 newAny = true;
228 }
229 }
230
231 // Make sure that <Any> or <CData> occurs only by itself.
232 if (!newAny && !newCData) {
233 for (int i = 0; i < content.length; i++) {
234 if (content[i] instanceof MetaDef.CData
235 || content[i] instanceof MetaDef.Any) {
236 throw new XOMException(
237 "Type " + name + " defines <Any> or <CData> "
238 + "content as well as other content.");
239 }
240 }
241 }
242
243 // Do we have a superclass/supertype?
244 if (superInfo == null) {
245 // No supertype, so consider this type by itself.
246 allAttributes = attributes;
247 ovrAttributes = new MetaDef.Attribute[0];
248 newAttributes = allAttributes;
249
250 if (newAny || newCData) {
251 isAny = newAny;
252 isCData = newCData;
253 allContent = new MetaDef.Content[0];
254 } else {
255 isAny = isCData = false;
256 allContent = content;
257 }
258 newContent = allContent;
259 } else {
260 // Reconcile attributes.
261 Hashtable attrHash = new Hashtable();
262 Hashtable ovrHash = new Hashtable();
263 Vector allAttrs = new Vector();
264 Vector ovrAttrs = new Vector();
265 Vector newAttrs = new Vector();
266
267 for (int i = 0; i < superInfo.allAttributes.length; i++) {
268 attrHash.put(
269 superInfo.allAttributes[i].name,
270 superInfo.allAttributes[i]);
271 }
272 for (int i = 0; i < attributes.length; i++) {
273 // Does the attribute already exist?
274 MetaDef.Attribute inhAttr =
275 (MetaDef.Attribute)(attrHash.get(attributes[i].name));
276 if (inhAttr == null) {
277 // attribute doesn't exist, so add to all and new.
278 allAttrs.addElement(attributes[i]);
279 newAttrs.addElement(attributes[i]);
280 } else {
281 // attribute does exist. Type must match exactly.
282 if (!(attributes[i].type.equals(inhAttr.type))) {
283 throw new XOMException(
284 "Element " + name + " inherits attribute "
285 + inhAttr.name + " of type " + inhAttr.type
286 + " but redefines it to be of type "
287 + attributes[i].type);
288 }
289 // Add to overridden vector and overridden hashtable
290 ovrAttrs.addElement(attributes[i]);
291 ovrHash.put(attributes[i].name,
292 attributes[i]);
293 }
294 }
295
296 // Add all non-overridden attributes to the allAttributes vector
297 for (int i = 0; i < superInfo.allAttributes.length; i++) {
298 if (ovrHash.get(superInfo.allAttributes[i].name) == null) {
299 allAttrs.addElement(superInfo.allAttributes[i]);
300 }
301 }
302
303 // Add all overridden attributes to the allAttributes vector
304 for (int i = 0; i < ovrAttrs.size(); i++) {
305 allAttrs.addElement(ovrAttrs.elementAt(i));
306 }
307 allAttributes = new MetaDef.Attribute[allAttrs.size()];
308 for (int i = 0; i < allAttributes.length; i++) {
309 allAttributes[i] =
310 (MetaDef.Attribute) allAttrs.elementAt(i);
311 }
312 ovrAttributes = new MetaDef.Attribute[ovrAttrs.size()];
313 for (int i = 0; i < ovrAttributes.length; i++) {
314 ovrAttributes[i] =
315 (MetaDef.Attribute) ovrAttrs.elementAt(i);
316 }
317 newAttributes = new MetaDef.Attribute[newAttrs.size()];
318 for (int i = 0; i < newAttributes.length; i++) {
319 newAttributes[i] =
320 (MetaDef.Attribute) newAttrs.elementAt(i);
321 }
322 // Reconcile content. First check for specials.
323 if (newAny || newCData) {
324 if (superInfo.isAny || superInfo.isCData) {
325 throw new XOMException(
326 "Element " + name + " both defines and inherits "
327 + "<CData> or <Any> content.");
328 }
329 if (superInfo.allContent.length > 0) {
330 throw new XOMException(
331 "Element " + name + " inherits standard content "
332 + "but defines <CData> or <Any> content.");
333 }
334 isAny = newAny;
335 isCData = newCData;
336 allContent = new MetaDef.Content[0];
337 newContent = new MetaDef.Content[0];
338 } else if (superInfo.isAny || superInfo.isCData) {
339 if (content.length > 0) {
340 throw new XOMException(
341 "Element " + name + " inherits <CData> or <Any> "
342 + "content but defines standard content.");
343 }
344 isAny = superInfo.isAny;
345 isCData = superInfo.isCData;
346 allContent = new MetaDef.Content[0];
347 newContent = new MetaDef.Content[0];
348 } else {
349 isAny = isCData = false;
350
351 // Overriding of content is forbidden.
352 Hashtable contentHash = new Hashtable();
353 Vector allContentVec = new Vector();
354 for (int i = 0; i < superInfo.allContent.length; i++) {
355 contentHash.put(
356 getContentName(superInfo.allContent[i]),
357 superInfo.allContent[i]);
358 allContentVec.addElement(superInfo.allContent[i]);
359 }
360 for (int i = 0; i < content.length; i++) {
361 MetaDef.Content inhContent =
362 (MetaDef.Content)
363 (contentHash.get(getContentName(content[i])));
364 if (inhContent != null) {
365 throw new XOMException(
366 "Content named " + getContentName(content[i])
367 + " defined in element " + name + " was "
368 + "already defined in an inherited element.");
369 }
370 allContentVec.addElement(content[i]);
371 }
372 allContent = new MetaDef.Content[allContentVec.size()];
373 for (int i = 0; i < allContent.length; i++) {
374 allContent[i] =
375 (MetaDef.Content) allContentVec.elementAt(i);
376 }
377 newContent = content;
378 }
379 }
380
381 // Add ourself to the hashtable if we're not already there
382 if (infoMap.get(name) == null) {
383 infoMap.put(name, this);
384 }
385 }
386
387 public void writeJavaClass(PrintWriter out)
388 throws XOMException
389 {
390 // Documentation first
391 if (doc != null) {
392 writeJavaDoc(out, 1, doc);
393 }
394 // Then create the inner class.
395 String abs = (def instanceof MetaDef.Class) ? "abstract " :
396 "";
397 out.print("\tpublic static " + abs + "class " + className + " extends ");
398 if (superInfo == null) {
399 out.println("org.eigenbase.xom.ElementDef");
400 } else {
401 out.println(superInfo.className);
402 }
403 if (isAny) {
404 out.println("\t\timplements org.eigenbase.xom.Any");
405 }
406 out.println("\t{");
407
408 // Default constructor
409 out.println("\t\tpublic " + className + "()");
410 out.println("\t\t{");
411 out.println("\t\t}");
412 out.println();
413
414 // org.eigenbase.xom.DOMWrapper Constructor
415 out.println("\t\tpublic " + className
416 + "(org.eigenbase.xom.DOMWrapper _def)");
417 out.println("\t\t\tthrows org.eigenbase.xom.XOMException");
418 out.println("\t\t{");
419
420 // Body of constructor. Special case for completely empty
421 // model (no content and no attributes) to avoid warnings
422 // about unused things.
423 boolean mixed = contentModel.equals("mixed");
424 if (allContent.length == 0 && allAttributes.length == 0 &&
425 !isAny && !isCData &&
426 !(def instanceof MetaDef.Plugin)) {
427 // constructor has no body
428 } else {
429 if (def instanceof MetaDef.Element &&
430 booleanValue(
431 new Boolean[] {
432 ((MetaDef.Element) def).keepDef,
433 model.defaultKeepDef,
434 Boolean.FALSE})) {
435 out.println("\t\t\tthis._def = _def;");
436 }
437
438 out.println("\t\t\ttry {");
439
440 // Plugins: read defPackage and defClass here.
441 if (def instanceof MetaDef.Plugin) {
442 out.println("\t\t\t\tdefPackage = "
443 + "org.eigenbase.xom.DOMElementParser."
444 + "requiredDefAttribute("
445 + "_def, \"defPackage\", \"org.eigenbase.xom\");");
446 out.println("\t\t\t\tdefClass = org.eigenbase.xom.DOMElementParser."
447 + "requiredDefAttribute("
448 + "_def, \"defClass\", null);");
449
450 // Get the enclosure class we'll be using
451 out.println("\t\t\t\tClass _pluginClass = "
452 + "org.eigenbase.xom.DOMElementParser.getPluginClass("
453 + "defPackage, defClass);");
454 }
455
456 // Create the parser. If using a Plugin, parse from a
457 // different enclosure class.
458 out.print("\t\t\t\torg.eigenbase.xom.DOMElementParser _parser "
459 + "= new org.eigenbase.xom.DOMElementParser("
460 + "_def, ");
461 if (def instanceof MetaDef.Plugin) {
462 out.println("\"\", _pluginClass);");
463 } else {
464 if (model.prefix == null) {
465 out.print("\"\", ");
466 } else {
467 out.print("\"" + model.prefix + "\", ");
468 }
469 out.println(model.className + ".class);");
470 }
471
472 // Define a temp array if any Array elements are used
473 if (hasContentType(allContent, MetaDef.Array.class)) {
474 out.println("\t\t\t\torg.eigenbase.xom.NodeDef[] "
475 + "_tempArray;");
476 }
477
478 // Generate statements to read in all attributes.
479 for (int i = 0; i < allAttributes.length; i++) {
480 writeJavaGetAttribute(out, allAttributes[i]);
481 }
482
483 // Generate statements to read in all content.
484 if (def instanceof MetaDef.Plugin) {
485 writeJavaGetPluginContent(out, mixed);
486 } else if (isAny) {
487 writeJavaGetAnyContent(out, mixed);
488 } else if (isCData) {
489 writeJavaGetCDataContent(out);
490 } else {
491 for (int i = 0; i < allContent.length; i++) {
492 writeJavaGetContent(out, allContent[i]);
493 }
494 }
495
496 out.println("\t\t\t} catch(org.eigenbase.xom.XOMException _ex) {");
497 out.println("\t\t\t\tthrow new org.eigenbase.xom.XOMException("
498 + "\"In \" + getName() + \": \" + _ex.getMessage());");
499 out.println("\t\t\t}");
500 }
501
502 // Finish the constructor
503 out.println("\t\t}");
504 out.println();
505
506 // Declare all new attributes
507 for (int i = 0; i < newAttributes.length; i++) {
508 writeJavaDeclareAttribute(out, newAttributes[i]);
509 }
510 if (def instanceof MetaDef.Plugin) {
511 writeJavaDeclarePluginAttributes(out);
512 }
513 if (def instanceof MetaDef.Element &&
514 booleanValue(
515 new Boolean[] {
516 ((MetaDef.Element) def).keepDef,
517 model.defaultKeepDef,
518 Boolean.FALSE})) {
519 out.println("\t\tpublic org.eigenbase.xom.DOMWrapper _def;");
520 }
521 out.println();
522
523 // Declare all new content
524 if (def instanceof MetaDef.Plugin) {
525 writeJavaDeclarePluginContent(out, mixed);
526 } else if (isAny) {
527 writeJavaDeclareAnyContent(out, mixed);
528 } else if (isCData) {
529 writeJavaDeclareCDataContent(out);
530 } else {
531 for (int i = 0; i < newContent.length; i++) {
532 writeJavaDeclareContent(out, newContent[i]);
533 }
534 }
535 out.println();
536
537 // Create the getName() function
538 out.println("\t\tpublic String getName()");
539 out.println("\t\t{");
540 out.println("\t\t\treturn \"" + className + "\";");
541 out.println("\t\t}");
542 out.println();
543
544 // Create the display() function
545 out.println("\t\tpublic void display(java.io.PrintWriter _out, "
546 + "int _indent)");
547 out.println("\t\t{");
548 if (def instanceof MetaDef.Class && !isAny && !isCData &&
549 allContent.length == 0 && allAttributes.length == 0) {
550 } else {
551 out.println("\t\t\t_out.println(getName());");
552 }
553 for (int i = 0; i < allAttributes.length; i++) {
554 writeJavaDisplayAttribute(out, allAttributes[i]);
555 }
556 if (def instanceof MetaDef.Plugin) {
557 writeJavaDisplayPluginAttributes(out);
558 }
559 if (def instanceof MetaDef.Plugin) {
560 writeJavaDisplayPluginContent(out);
561 } else if (isAny) {
562 writeJavaDisplayAnyContent(out);
563 } else if (isCData) {
564 writeJavaDisplayCDataContent(out);
565 } else {
566 for (int i = 0; i < allContent.length; i++) {
567 writeJavaDisplayContent(out, allContent[i]);
568 }
569 }
570 out.println("\t\t}");
571
572 // Create the displayXML() function
573 out.println("\t\tpublic void displayXML("
574 + "org.eigenbase.xom.XMLOutput _out, "
575 + "int _indent)");
576 out.println("\t\t{");
577 out.println("\t\t\t_out.beginTag(\""
578 + tagName + "\", "
579 + "new org.eigenbase.xom.XMLAttrVector()");
580 for (int i = 0; i < allAttributes.length; i++) {
581 writeJavaDisplayXMLAttribute(out, allAttributes[i]);
582 }
583 if (def instanceof MetaDef.Plugin) {
584 writeJavaDisplayXMLPluginAttributes(out);
585 }
586 out.println("\t\t\t\t);");
587
588 if (def instanceof MetaDef.Plugin) {
589 writeJavaDisplayXMLPluginContent(out);
590 } else if (isAny) {
591 writeJavaDisplayXMLAnyContent(out);
592 } else if (isCData) {
593 writeJavaDisplayXMLCDataContent(out);
594 } else {
595 for (int i = 0; i < allContent.length; i++) {
596 writeJavaDisplayXMLContent(out, allContent[i]);
597 }
598 }
599 out.println("\t\t\t_out.endTag(\"" + tagName + "\");");
600 out.println("\t\t}");
601
602 // Create the displayDiff() function
603 out.println("\t\tpublic boolean displayDiff("
604 + "org.eigenbase.xom.ElementDef _other, "
605 + "java.io.PrintWriter _out, "
606 + "int _indent)");
607 out.println("\t\t{");
608 if (allAttributes.length > 0 ||
609 allContent.length > 0 || isAny || isCData ||
610 def instanceof MetaDef.Plugin) {
611 out.println("\t\t\t" + className + " _cother = ("
612 + className + ")_other;");
613 }
614 int[] diffCount = {0};
615 for (int i = 0; i < newAttributes.length; i++) {
616 writeJavaDisplayDiffAttribute(out, diffCount, allAttributes[i]);
617 }
618 if (def instanceof MetaDef.Plugin) {
619 writeJavaDisplayDiffPluginAttributes(out, diffCount);
620 }
621 if (def instanceof MetaDef.Plugin) {
622 writeJavaDisplayDiffPluginContent(out, diffCount);
623 } else if (isAny) {
624 writeJavaDisplayDiffAnyContent(out, diffCount);
625 } else if (isCData) {
626 writeJavaDisplayDiffCDataContent(out, diffCount);
627 } else {
628 for (int i = 0; i < allContent.length; i++) {
629 writeJavaDisplayDiffContent(out, diffCount, allContent[i]);
630 }
631 }
632 out.println("\t\t\treturn "
633 + (diffCount[0] > 0 ? "_diff" : "true")
634 + ";");
635 out.println("\t\t}");
636
637 // Add the code section, if defined
638 if (code != null) {
639 writeJavaCode(out, 2, code);
640 }
641
642 // Complete the class definition and finish with a blank.
643 out.println("\t}");
644 out.println();
645 }
646 }
647
648 /**
649 * Converts a {@link Boolean} object into a {@code boolean} value,
650 * falling back to successive defaults if values are null.
651 *
652 * <p>If all of the values are null, returns {@code false}; but we
653 * recommend passing in an explicit {@code true} or {@code false} as the
654 * last argument.</p>
655 *
656 * <p>For example,
657 * {@code booleanValue(null, true, false)} returns {@code true};
658 * {@code booleanValue(null, null)} returns {@code false}.</p>
659 *
660 * @param bs One or more boolean values
661 * @return Boolean value
662 */
663 private static boolean booleanValue(Boolean[] bs)
664 {
665 for (int i = 0; i < bs.length; i++) {
666 Boolean b = bs[i];
667 if (b != null) {
668 return b.booleanValue();
669 }
670 }
671 return false;
672 }
673
674 /**
675 * Get the name of any piece of content of any type.
676 * @return the name of the piece of content.
677 * @throws XOMException if the content is <Any> or <CData>.
678 */
679 private static String getContentName(MetaDef.Content content)
680 throws XOMException
681 {
682 if (content instanceof MetaDef.Object) {
683 return ((MetaDef.Object)content).name;
684 } else if (content instanceof MetaDef.Array) {
685 return ((MetaDef.Array)content).name;
686 } else {
687 throw new XOMException(
688 "Content of type " + content.getClass().getName()
689 + " does not have a name.");
690 }
691 }
692
693 /**
694 * Return the TypeInfo class associated with the given name.
695 *
696 * @post fail == false || return != null
697 * @exception XOMException if the type has not been defined
698 */
699 public TypeInfo getTypeInfo(String name, boolean fail)
700 throws XOMException
701 {
702 TypeInfo info = (TypeInfo) infoMap.get(name);
703 if (info == null && fail == true) {
704 throw new XOMException(
705 "Type " + name + " does not exist.");
706 }
707 return info;
708 }
709
710 /**
711 * Construct a MetaGenerator from an XML file. The XML should meet the
712 * specifications of the XOM Meta Model.
713 * @param xmlFile a filename for the xml description of the model to be
714 * processed.
715 */
716 public MetaGenerator(String xmlFile, boolean testMode)
717 throws XOMException, IOException {
718 this(xmlFile, testMode, null);
719 }
720
721 protected MetaGenerator(String xmlFile, boolean testMode, String className)
722 throws XOMException, IOException {
723 this.testMode = testMode;
724 // Create a non-validating XML parser to parse the file
725 FileInputStream in = new FileInputStream(xmlFile);
726 Parser parser = XOMUtil.createDefaultParser();
727 try {
728 DOMWrapper def = parser.parse(in);
729 model = new MetaDef.Model(def);
730 } catch (XOMException ex) {
731 throw new XOMException(ex, "Failed to parse XML file: " + xmlFile);
732 }
733
734 // check that class names are consistent
735 if (className != null) {
736 if (model.className == null) {
737 model.className = className;
738 } else {
739 String modelClassName = model.className;
740 if (model.packageName != null &&
741 !model.packageName.equals("")) {
742 modelClassName = model.packageName + "." +
743 model.className;
744 }
745 if (!className.equals(modelClassName)) {
746 throw new XOMException(
747 "className parameter (" + className +
748 ") is inconsistent with model's packageName and " +
749 "className attributes (" + modelClassName + ")");
750 }
751 }
752 }
753
754 // Construct the meta model from its XML description
755 prefix = model.prefix;
756 if (prefix == null) {
757 prefix = "";
758 }
759 // Setup the Hashtable maps
760 initKeywordMap();
761 initTypeMap();
762 initSubclassMap();
763 }
764
765 /**
766 * Initialize the keyword map. This class maps all Java keywords to safe
767 * versions (prepended with an underscore) which may be used for generated
768 * names. Java keywords are listed in the java spec at
769 * <a href="http://java.sun.com/docs/books/jls/html/3.doc.html#229308">
770 * http://java.sun.com/docs/books/jls/html/3.doc.html#229308</a>
771 */
772 private void initKeywordMap()
773 {
774 keywordMap = new Hashtable();
775 keywordMap.put("abstract", "_abstract");
776 keywordMap.put("boolean", "_boolean");
777 keywordMap.put("break", "_break");
778 keywordMap.put("byte", "_byte");
779 keywordMap.put("case", "_case");
780 keywordMap.put("catch", "_catch");
781 keywordMap.put("char", "_char");
782 keywordMap.put("class", "_class");
783 keywordMap.put("const", "_const");
784 keywordMap.put("continue", "_continue");
785 keywordMap.put("default", "_default");
786 keywordMap.put("do", "_do");
787 keywordMap.put("double", "_double");
788 keywordMap.put("else", "_else");
789 keywordMap.put("extends", "_extends");
790 keywordMap.put("final", "_final");
791 keywordMap.put("finally", "_finally");
792 keywordMap.put("float", "_float");
793 keywordMap.put("for", "_for");
794 keywordMap.put("if", "_if");
795 keywordMap.put("implements", "_implements");
796 keywordMap.put("import", "_import");
797 keywordMap.put("instanceof", "_instanceof");
798 keywordMap.put("int", "_int");
799 keywordMap.put("interface", "_interface");
800 keywordMap.put("long", "_long");
801 keywordMap.put("native", "_native");
802 keywordMap.put("new", "_new");
803 keywordMap.put("goto", "_goto");
804 keywordMap.put("package", "_package");
805 keywordMap.put("private", "_private");
806 keywordMap.put("protected", "_protected");
807 keywordMap.put("public", "_public");
808 keywordMap.put("return", "_return");
809 keywordMap.put("short", "_short");
810 keywordMap.put("static", "_static");
811 keywordMap.put("super", "_super");
812 keywordMap.put("switch", "_switch");
813 keywordMap.put("synchronized", "_synchronized");
814 keywordMap.put("this", "_this");
815 keywordMap.put("throw", "_throw");
816 keywordMap.put("throws", "_throws");
817 keywordMap.put("transient", "_transient");
818 keywordMap.put("try", "_try");
819 keywordMap.put("void", "_void");
820 keywordMap.put("volatile", "_volatile");
821 keywordMap.put("while", "_while");
822 keywordMap.put("true", "_true");
823 keywordMap.put("false", "_false");
824 keywordMap.put("null", "_null");
825 }
826
827 /**
828 * All Elements in the meta model have an associated type name which
829 * identifies the element. The type map allows the XMLDef.ElementType
830 * object describing an element to be retrieved from its name. It is
831 * used to resolve references to element type names appearing
832 * throughout a model.
833 */
834 private void initTypeMap()
835 throws XOMException
836 {
837 typeMap = new Hashtable();
838 allTypes = new Vector();
839 for (int i = 0; i < model.elements.length; i++) {
840 MetaDef.Definition elt = model.elements[i];
841 String name = null;
842 if (elt instanceof MetaDef.Element) {
843 name = ((MetaDef.Element)elt).type;
844 } else if (elt instanceof MetaDef.Plugin) {
845 name = ((MetaDef.Plugin)elt).type;
846 } else if (elt instanceof MetaDef.Class) {
847 name = ((MetaDef.Class)elt)._class;
848 } else if (elt instanceof MetaDef.StringElement) {
849 name = ((MetaDef.StringElement)elt).type;
850 } else if (elt instanceof MetaDef.Import) {
851 name = ((MetaDef.Import)elt).type;
852 } else {
853 throw new XOMException(
854 "Illegal element type "
855 + elt.getClass().getName());
856 }
857 typeMap.put(name, elt);
858 allTypes.addElement(name);
859 }
860
861 infoMap = new Hashtable();
862 for (int i = 0; i < model.elements.length; i++) {
863 // Get the element
864 MetaDef.Definition elt = model.elements[i];
865
866 // Construct the new TypeInfo object and add to the hashtable
867 TypeInfo info = new TypeInfo(elt);
868 infoMap.put(info.name, info);
869 }
870 }
871
872 /**
873 * In a few cases, a complete list of all subclasses of a class
874 * object is required. The subclass map maps each class object
875 * (identified by its name) to a Vector containing all of its
876 * subclasses. Currently, all subclasses must be Element types.
877 */
878 private void initSubclassMap()
879 throws XOMException
880 {
881 subclassMap = new Hashtable();
882
883 // First, iterate through all Class elements in the model,
884 // initializing a location in the hashtable for each.
885 for (int i = 0; i < model.elements.length; i++) {
886 MetaDef.Definition elt = model.elements[i];
887 if (elt instanceof MetaDef.Class) {
888 MetaDef.Class _class = (MetaDef.Class)elt;
889 subclassMap.put(_class._class, new Vector());
890 }
891 }
892
893 // Now, iterate through all Element elements in the model.
894 // For each one, go through all of its superclasses and add itself to
895 // the vector of each.
896 // If a class is not found, it is an error.
897 for (int i = 0; i < model.elements.length; i++) {
898 MetaDef.Definition elt = model.elements[i];
899 if (elt instanceof MetaDef.Element) {
900 MetaDef.Element elem = (MetaDef.Element)elt;
901 TypeInfo info = getTypeInfo(elem.type, true);
902 addToSubclassMap(elem, info);
903 }
904 }
905 }
906
907 /**
908 * Helper method for initSubclassMap:
909 * Add this element to the subclass map for each superclass of info.
910 */
911 private void addToSubclassMap(MetaDef.Element elem, TypeInfo info)
912 throws XOMException
913 {
914 while (info.superInfo != null) {
915 // Add the element to this class's vector.
916 Vector vec = (Vector)(subclassMap.get(info.superInfo.name));
917 if (vec == null) {
918 throw new XOMException("Class " + info.superInfo.name +
919 " of element " + elem.type
920 + " is not defined.");
921 }
922 vec.addElement(elem);
923
924 // Add to all superclasses as well
925 info = info.superInfo;
926 }
927 }
928
929 /**
930 * Create all files associated with the metamodel, including a Java class
931 * and a DTD file. The DTD is primarily for reference--it will not work
932 * if any advanced features (plugins, includes) are used.
933 * @param outputDirName the output directory in which to generate the files.
934 */
935 public void writeFiles(String outputDirName, String dtdFileName)
936 throws XOMException, IOException
937 {
938 // Compute the output file names
939 if (dtdFileName != null) {
940 if (model.dtdName == null) {
941 model.dtdName = dtdFileName;
942 } else {
943 if (!dtdFileName.equals(model.dtdName)) {
944 throw new XOMException(
945 "dtdFileName parameter (" + dtdFileName +
946 ") is inconsistent with model's dtdName " +
947 "attribute (" + model.dtdName + ")");
948 }
949 }
950 }
951 File javaOutputDir = new File(outputDirName);
952
953 if (!testMode &&
954 model.packageName != null &&
955 !model.packageName.equals("")) {
956 javaOutputDir = new File(
957 javaOutputDir, model.packageName.replace('.',fileSep));
958 }
959 File javaFile = new File(javaOutputDir, model.className + ".java");
960 File outputDir = javaFile.getParentFile();
961 File dtdFile = new File(outputDir, model.dtdName);
962
963 // If the output file is MetaDef.java, and we start writing to
964 // MetaDef.java before we have loaded MetaDef.class, the system thinks
965 // that the class is out of date. So load MetaDef.class before that
966 // point.
967 XOMUtil.discard(new MetaDef());
968
969 // Create directories if necessary.
970 outputDir.mkdir();
971
972 // Open the files for writing
973 FileWriter dtdWriter = new FileWriter(dtdFile);
974 PrintWriter dtdOut = new PrintWriter(dtdWriter);
975 FileWriter javaWriter = new FileWriter(javaFile);
976 PrintWriter javaOut = new PrintWriter(javaWriter);
977
978 if (!testMode) {
979 System.out.println("Writing " + dtdFile);
980 }
981 writeDtd(dtdOut);
982 dtdOut.flush();
983 dtdWriter.close();
984
985 if (!testMode) {
986 System.out.println("Writing " + javaFile);
987 }
988 writeJava(javaOut);
989 javaOut.flush();
990 javaWriter.close();
991
992 if (!testMode) {
993 System.out.println("Done");
994 }
995 }
996
997 public void writeDtd(PrintWriter out)
998 throws XOMException
999 {
1000 // Write header information for the dtd
1001 out.println("<!--");
1002 out.println(" This dtd file was automatically generated from "
1003 + "XOM model " + model.name + ".");
1004 out.println(" Do not edit this file by hand.");
1005 out.println(" -->");
1006 out.println();
1007
1008 // Write toplevel documentation here
1009 writeDtdDoc(out, model.doc);
1010
1011 // For each CLASS definition, write an entity definition. These must
1012 // be done before regular elements because entities must be defined
1013 // before use.
1014 for (int i = 0; i < model.elements.length; i++) {
1015 if (model.elements[i] instanceof MetaDef.Class) {
1016 writeDtdEntity(out, (MetaDef.Class)(model.elements[i]));
1017 }
1018 }
1019
1020 // Write each element in turn
1021 for (int i = 0; i < model.elements.length; i++) {
1022 writeDtdElement(out, model.elements[i]);
1023 }
1024 }
1025
1026 public void writeJava(PrintWriter out)
1027 throws XOMException
1028 {
1029 // Write header information for the java file
1030 out.println("/" + "*");
1031 out.println("/" + "/ This java file was automatically generated");
1032 out.println("/" + "/ from XOM model '" + model.name + "'");
1033 if (!testMode) {
1034 out.println("/" + "/ on " + new Date().toString());
1035 }
1036 out.println("/" + "/ Do not edit this file by hand.");
1037 out.println("*" + "/");
1038 out.println();
1039
1040 if (!testMode &&
1041 !(model.packageName == null || model.packageName.equals(""))) {
1042 out.println("package " + model.packageName + ";");
1043 }
1044 if (!testMode &&
1045 !(model.importName == null || model.importName.equals(""))) {
1046 // generate import statements (separated by : when more than one)
1047 int colonLoc = model.importName.indexOf(":");
1048 int start = 0;
1049 while (colonLoc != -1) {
1050 out.println("import " + model.importName.substring(start, colonLoc) + ";");
1051 start = colonLoc + 1;
1052 colonLoc = model.importName.indexOf(":", start);
1053 }
1054 out.println("import " + model.importName.substring(start) + ";");
1055 }
1056
1057 // Write the toplevel documentation for the package. This becomes
1058 // the toplevel documentation for the class and is also placed at
1059 // the top of the Dtd.
1060 String extraDoc = newLine + "<p>This class was generated from XOM model '"
1061 + model.name + "' on " + new Date().toString();
1062 if (testMode) {
1063 extraDoc = "";
1064 }
1065 writeJavaDoc(out, 0, model.doc + extraDoc);
1066
1067 // Begin the class. Include a getXMLDefClass() function which
1068 // simply returns this class.
1069 out.println("public class " + model.className + " {");
1070 out.println();
1071 out.println("\tpublic static java.lang.Class getXMLDefClass()");
1072 out.println("\t{");
1073 out.println("\t\treturn " + model.className + ".class;");
1074 out.println("\t}");
1075 out.println();
1076
1077 // Create a static member that names all Elements that may be
1078 // used within this class.
1079 out.println("\tpublic static String[] _elements = {");
1080 for (int i = 0; i < allTypes.size(); i++) {
1081 String type = (String) allTypes.elementAt(i);
1082 out.print("\t\t\"" + type + "\"");
1083 if (i < allTypes.size() - 1) {
1084 out.println(",");
1085 } else {
1086 out.println();
1087 }
1088 }
1089 out.println("\t};");
1090 out.println();
1091
1092 // Create an inner class for each Class/Object definition.
1093 for (int i = 0; i < model.elements.length; i++) {
1094 writeJavaElement(out, model.elements[i]);
1095 }
1096
1097 // End the class
1098 out.println();
1099 out.println("}");
1100 }
1101
1102 /**
1103 * Writes an entity definition based on a defined Class. Because entity
1104 * definitions must appear before use in a DTD, this function must be
1105 * called for each defined class before processing the rest of the model.
1106 * @param out PrintWriter to write the DTD.
1107 * @param _class Class definition on which the Entity will be based.
1108 */
1109 private void writeDtdEntity(PrintWriter out, MetaDef.Class _class)
1110 {
1111 // Documentation first
1112 if (_class.doc != null) {
1113 writeDtdDoc(out, _class.doc);
1114 }
1115
1116 // Lookup the subclass vector for this class. Use this to generate
1117 // the entity definition.
1118 Vector subclassVec = (Vector)(subclassMap.get(_class._class));
1119 out.print("<!ENTITY % " + _class._class + " \"");
1120 if (subclassVec == null) {
1121 throw new AssertFailure(
1122 "Missing subclass vector for class " + _class._class);
1123 }
1124
1125 for (int i = 0; i < subclassVec.size(); i++) {
1126 MetaDef.Element elem =
1127 (MetaDef.Element)(subclassVec.elementAt(i));
1128
1129 // Print the dtd version of the element name
1130 if (elem.dtdName != null) {
1131 out.print(elem.dtdName);
1132 } else {
1133 out.print(prefix + elem.type);
1134 }
1135 if (i < subclassVec.size() - 1) {
1136 out.print("|");
1137 }
1138 }
1139 out.println("\">");
1140 out.println();
1141 }
1142
1143 private void writeDtdElement(PrintWriter out, MetaDef.Definition elt)
1144 throws XOMException
1145 {
1146 // What is written into the dtd depends on the class of elt.
1147 if (elt instanceof MetaDef.Element) {
1148 // Get the info class for this element.
1149 MetaDef.Element element = (MetaDef.Element)elt;
1150 TypeInfo info = getTypeInfo(element.type, false);
1151 if (info == null) {
1152 throw new AssertFailure(
1153 "Element type " + element.type + " is missing from the "
1154 + "type map.");
1155 }
1156
1157 // Documentation first
1158 if (element.doc != null) {
1159 writeDtdDoc(out, element.doc);
1160 }
1161
1162 // Then content model. Special case empty models.
1163 out.print("<!ELEMENT " + info.tagName + " ");
1164 if (info.allContent.length == 0 && !info.isAny && !info.isCData) {
1165 out.print("EMPTY");
1166 } else {
1167 if (info.isAny) {
1168 out.print("ANY");
1169 } else if (info.isCData) {
1170 out.print("(#PCDATA)");
1171 } else {
1172 out.print("(");
1173 for (int i = 0; i < info.allContent.length; i++) {
1174 writeDtdContent(out, info.allContent[i]);
1175 if (i < info.allContent.length - 1) {
1176 out.print(",");
1177 }
1178 }
1179 out.print(")");
1180 }
1181 }
1182 out.println(">");
1183
1184 // Finally, attribute list
1185 if (info.allAttributes.length > 0) {
1186 out.println("<!ATTLIST " + info.tagName);
1187 for (int i = 0; i < info.allAttributes.length; i++) {
1188 writeDtdAttribute(out, info.allAttributes[i]);
1189 }
1190 out.println(">");
1191 }
1192
1193 // Finish with a blank
1194 out.println();
1195 } else if (elt instanceof MetaDef.Class) {
1196 // Do nothing--entities are handled ahead of time.
1197 } else if (elt instanceof MetaDef.StringElement) {
1198 // Get the info class for this element.
1199 MetaDef.StringElement element = (MetaDef.StringElement)elt;
1200 TypeInfo info = (TypeInfo)(infoMap.get(element.type));
1201 if (info == null) {
1202 throw new AssertFailure(
1203 "StringElement type " + element.type +
1204 " is missing from the type map.");
1205 }
1206
1207 // Documentation first
1208 if (element.doc != null) {
1209 writeDtdDoc(out, element.doc);
1210 }
1211
1212 // Then content model. It is always (#PCDATA).
1213 out.println("<!ELEMENT " + info.tagName + " (#PCDATA)>");
1214 out.println();
1215 } else if (elt instanceof MetaDef.Plugin) {
1216 // Get the info class for this element.
1217 MetaDef.Plugin plugin = (MetaDef.Plugin)elt;
1218 TypeInfo info = (TypeInfo)(infoMap.get(plugin.type));
1219 if (info == null) {
1220 throw new AssertFailure(
1221 "Plugin element " + plugin.type +
1222 " is missing from the type map.");
1223 }
1224
1225 // Documentation first
1226 if (plugin.doc != null) {
1227 writeDtdDoc(out, plugin.doc);
1228 }
1229
1230 // Then content model. It is always ANY.
1231 out.println("<!ELEMENT " + info.tagName + " ANY>");
1232
1233 // Finally, attribute list. Don't allow use of plugin reserved
1234 // attributes defPackage and defClass.
1235 out.println("<!ATTLIST " + info.tagName);
1236 for (int i = 0; i < info.allAttributes.length; i++) {
1237 if (info.allAttributes[i].name.equals("defPackage") ||
1238 info.allAttributes[i].name.equals("defClass"))
1239 throw new XOMException(
1240 "The attribute \"" + info.allAttributes[i].name
1241 + "\" is reserved and may not be redefined in "
1242 + "or inherited by a Plugin.");
1243 writeDtdAttribute(out, info.allAttributes[i]);
1244 }
1245
1246 // Add attribute definitions for defPackage and defClass
1247 out.println("defPackage CDATA \"org.eigenbase.xom\"");
1248 out.println("defClass CDATA #REQUIRED");
1249
1250 // Complete the attribute list
1251 out.println(">");
1252 out.println();
1253 } else if (elt instanceof MetaDef.Import) {
1254 // Get the info class for this element.
1255 MetaDef.Import imp = (MetaDef.Import)elt;
1256 TypeInfo info = getTypeInfo(imp.type, true);
1257
1258 // Imports can't really be handled, so just generate a placeholder
1259 // ANY element for show.
1260 out.println("<!ELEMENT " + info.name + " ANY>");
1261 out.println();
1262 } else {
1263 throw new XOMException("Unrecognized element type definition: "
1264 + elt.getClass().getName());
1265 }
1266 }
1267
1268 private void writeDtdDoc(PrintWriter out, String doc)
1269 {
1270 out.println("<!--");
1271
1272 // Process the String line-by-line. Trim whitespace from each
1273 // line and ignore fully blank lines.
1274 try {
1275 LineNumberReader reader = new LineNumberReader(new StringReader(doc));
1276 String line;
1277 while ((line = reader.readLine()) != null) {
1278 String trimLine = line.trim();
1279 if (!trimLine.equals("")) {
1280 out.print(" ");
1281 out.println(trimLine);
1282 }
1283 }
1284 } catch (IOException ex) {
1285 throw new AssertFailure(ex);
1286 }
1287
1288 out.println(" -->");
1289 }
1290
1291 private void writeJavaDoc(PrintWriter out, int indent, String doc)
1292 {
1293 for (int i = 0; i < indent; i++) {
1294 out.print("\t");
1295 }
1296 out.println("/" + "**");
1297
1298 // Process the String line-by-line. Trim whitespace from each
1299 // line and ignore fully blank lines.
1300 try {
1301 LineNumberReader reader = new LineNumberReader(new StringReader(doc));
1302 String line;
1303 while ((line = reader.readLine()) != null) {
1304 String trimLine = line.trim();
1305 if (!trimLine.equals("")) {
1306 for (int i = 0; i < indent; i++) {
1307 out.print("\t");
1308 }
1309 out.print(" * ");
1310 out.println(trimLine);
1311 }
1312 }
1313 } catch (IOException ex) {
1314 throw new AssertFailure(ex);
1315 }
1316
1317 for (int i = 0; i < indent; i++) {
1318 out.print("\t");
1319 }
1320 out.println(" *" + "/");
1321 }
1322
1323 private void writeJavaCode(PrintWriter out, int indent, String code)
1324 {
1325 for (int i = 0; i < indent; i++) {
1326 out.print("\t");
1327 }
1328 out.println("/" + "/ BEGIN pass-through code block ---");
1329
1330 // Process the String line-by-line. Don't trim lines--just echo
1331 try {
1332 LineNumberReader reader = new LineNumberReader(new StringReader(code));
1333 String line;
1334 while ((line = reader.readLine()) != null) {
1335 out.println(line);
1336 }
1337 } catch (IOException ex) {
1338 throw new AssertFailure(ex);
1339 }
1340
1341 for (int i = 0; i < indent; i++) {
1342 out.print("\t");
1343 }
1344 out.println("/" + "/ END pass-through code block ---");
1345 }
1346
1347 private MetaDef.Definition getType(String name)
1348 throws XOMException
1349 {
1350 // The type mapping hash table maps element type names to their
1351 // MetaDef.Definition objects. First, look up the element type associated
1352 // with the name.
1353 MetaDef.Definition type = (MetaDef.Definition) typeMap.get(name);
1354 if (type == null) {
1355 throw new XOMException(
1356 "Element type name " + name + " was never defined.");
1357 }
1358 return type;
1359 }
1360
1361 /**
1362 * Deterimines if a name conflicts with a Java keyword. If so, it returns
1363 * an alternate form of the name (typically the same name with an
1364 * underscore preprended).
1365 * @param name a name to be used in a Java program.
1366 * @return a safe form of the name; either the name itself or a modified
1367 * version if the name is a keyword.
1368 */
1369 private String getDeclaredName(String name)
1370 {
1371 String mappedName = (String) keywordMap.get(name);
1372 if (mappedName == null) {
1373 return name;
1374 } else {
1375 return mappedName;
1376 }
1377 }
1378
1379 private void writeDtdContent(PrintWriter out, MetaDef.Content content)
1380 throws XOMException
1381 {
1382 if (content instanceof MetaDef.Object) {
1383 MetaDef.Object obj = (MetaDef.Object)content;
1384 TypeInfo info = (TypeInfo)(infoMap.get(obj.type));
1385 if (info == null) {
1386 throw new XOMException(
1387 "Object " + obj.name + " has undefined type "
1388 + obj.type);
1389 }
1390 out.print(info.tagName);
1391 if (!obj.required.booleanValue()) {
1392 out.print("?");
1393 }
1394 } else if (content instanceof MetaDef.Array) {
1395 MetaDef.Array array = (MetaDef.Array)content;
1396 TypeInfo info = (TypeInfo)(infoMap.get(array.type));
1397 if (info == null) {
1398 throw new XOMException(
1399 "Array " + array.name + " has undefined type "
1400 + array.type);
1401 }
1402 out.print("(" + info.tagName + ")");
1403 if (array.min.intValue() > 0) {
1404 out.print("+");
1405 } else {
1406 out.print("*");
1407 }
1408 } else {
1409 throw new XOMException("Unrecognized content type definition: "
1410 + content.getClass().getName());
1411 }
1412 }
1413
1414 private void writeDtdAttribute(PrintWriter out, MetaDef.Attribute attr)
1415 {
1416 // Attribute name
1417 out.print(attr.name + " ");
1418
1419 // Values, or CDATA if unspecified
1420 if (attr.values == null || attr.values.length == 0) {
1421 if (attr.type.equalsIgnoreCase("Boolean")) {
1422 out.print("(true|false) ");
1423 } else {
1424 out.print("CDATA ");
1425 }
1426 } else {
1427 out.print("(");
1428 for (int i = 0; i < attr.values.length; i++) {
1429 out.print(attr.values[i]);
1430 if (i < attr.values.length - 1) {
1431 out.print("|");
1432 }
1433 }
1434 out.print(") ");
1435 }
1436
1437 // Default value
1438 if (attr._default == null) {
1439 if (attr.required.booleanValue()) {
1440 out.println("#REQUIRED");
1441 } else {
1442 out.println("#IMPLIED");
1443 }
1444 } else {
1445 out.print("\"" + attr._default + "\"");
1446 out.println();
1447 }
1448 }
1449
1450 /**
1451 * This helper function returns true if any member of the given content
1452 * array is of the specified type.
1453 * @param content an array of content descriptors.
1454 * @param match a Class describing the class to match.
1455 * @return true if any member of the given content array matches
1456 * the given match type.
1457 */
1458 private static boolean hasContentType(MetaDef.Content[] content,
1459 Class match)
1460 {
1461 for (int i = 0; i < content.length; i++) {
1462 if (content[i].getClass() == match) {
1463 return true;
1464 }
1465 }
1466 return false;
1467 }
1468
1469 private void writeJavaElement(PrintWriter out, MetaDef.Definition elt)
1470 throws XOMException
1471 {
1472 // What is written into the dtd depends on the class of elt.
1473 if (elt instanceof MetaDef.Element) {
1474 MetaDef.Element element = (MetaDef.Element)elt;
1475 TypeInfo info = (TypeInfo)(infoMap.get(element.type));
1476 if (info == null) {
1477 throw new XOMException(
1478 "Element type " + element.type + " was never defined.");
1479 }
1480 info.writeJavaClass(out);
1481 } else if (elt instanceof MetaDef.Plugin) {
1482 MetaDef.Plugin plugin = (MetaDef.Plugin)elt;
1483 TypeInfo info = (TypeInfo)(infoMap.get(plugin.type));
1484 if (info == null) {
1485 throw new XOMException(
1486 "Plugin type " + plugin.type + " was never defined.");
1487 }
1488 info.writeJavaClass(out);
1489 } else if (elt instanceof MetaDef.Class) {
1490 MetaDef.Class _class = (MetaDef.Class)elt;
1491 TypeInfo info = (TypeInfo)(infoMap.get(_class._class));
1492 if (info == null) {
1493 throw new XOMException(
1494 "Class type " + _class._class + " was never defined.");
1495 }
1496 info.writeJavaClass(out);
1497 } else if (elt instanceof MetaDef.StringElement) {
1498 // Documentation first
1499 MetaDef.StringElement element = (MetaDef.StringElement)elt;
1500 if (element.doc != null) {
1501 writeJavaDoc(out, 1, element.doc);
1502 }
1503
1504 // Declare the name as a constant
1505 out.println("\tpublic static final String "
1506 + element.type + " = \""
1507 + element.type + "\";");
1508 out.println();
1509 } else if (elt instanceof MetaDef.Import) {
1510 // Do nothing--imports are handled inline
1511 } else {
1512 throw new XOMException("Unrecognized element type definition: "
1513 + elt.getClass().getName());
1514 }
1515 }
1516
1517 public void writeJavaGetAttribute(PrintWriter out,
1518 MetaDef.Attribute attr)
1519 throws XOMException
1520 {
1521 out.print("\t\t\t\t" + getDeclaredName(attr.name) + " = ");
1522 out.print("(" + attr.type + ")_parser.getAttribute(");
1523 out.print("\"" + attr.name + "\", \"" + attr.type + "\", ");
1524 if (attr._default == null) {
1525 out.print("null, ");
1526 } else {
1527 out.print("\"" + attr._default + "\", ");
1528 }
1529 if (attr.values == null || attr.values.length == 0) {
1530 out.print("null, ");
1531 } else {
1532 out.print("_" + getDeclaredName(attr.name)
1533 + "_values, ");
1534 }
1535 if (attr.required.booleanValue()) {
1536 out.print("true");
1537 } else {
1538 out.print("false");
1539 }
1540 out.println(");");
1541 }
1542
1543 public void writeJavaDeclareAttribute(PrintWriter out,
1544 MetaDef.Attribute attr)
1545 throws XOMException
1546 {
1547 // Setup an array for attribute values if required
1548 if (attr.values != null && attr.values.length > 0) {
1549 out.println("\t\t/** Allowable values for {@link #"
1550 + getDeclaredName(attr.name) + "}. */");
1551 out.print("\t\tpublic static final String[] _"
1552 + getDeclaredName(attr.name) + "_values = {");
1553 for (int i = 0; i < attr.values.length; i++) {
1554 out.print("\"" + attr.values[i] + "\"");
1555 if (i < attr.values.length - 1) {
1556 out.print(", ");
1557 }
1558 }
1559 out.println("};");
1560 }
1561
1562 // Generate the declaration, including a quick comment
1563 out.print("\t\tpublic " + attr.type + " "
1564 + getDeclaredName(attr.name) + "; /" + "/ ");
1565 if (attr._default != null) {
1566 out.print("attribute default: " + attr._default);
1567 } else if (attr.required.booleanValue()) {
1568 out.print("required attribute");
1569 } else {
1570 out.print("optional attribute");
1571 }
1572 out.println();
1573 }
1574
1575 public void writeJavaDisplayAttribute(PrintWriter out,
1576 MetaDef.Attribute attr)
1577 throws XOMException
1578 {
1579 // Generate the display line
1580 out.println("\t\t\tdisplayAttribute(_out, \"" + attr.name + "\", "
1581 + getDeclaredName(attr.name) + ", _indent+1);");
1582 }
1583
1584 public void writeJavaDisplayXMLAttribute(PrintWriter out,
1585 MetaDef.Attribute attr)
1586 throws XOMException
1587 {
1588 out.println("\t\t\t\t.add(\"" + attr.name
1589 + "\", " + getDeclaredName(attr.name) + ")");
1590 }
1591
1592 public void writeJavaDisplayDiffAttribute(
1593 PrintWriter out,
1594 int[] diffCount, MetaDef.Attribute attr)
1595 throws XOMException
1596 {
1597 out.println("\t\t\t" + prefix(diffCount) + "displayAttributeDiff(\"" + attr.name
1598 + "\", " + getDeclaredName(attr.name)
1599 + ", _cother." + getDeclaredName(attr.name)
1600 + ", _out, _indent+1);");
1601 }
1602
1603 public void writeJavaGetContent(PrintWriter out,
1604 MetaDef.Content content)
1605 throws XOMException
1606 {
1607 if (content instanceof MetaDef.Object) {
1608 // Get the object and its type
1609 MetaDef.Object obj = (MetaDef.Object)content;
1610 MetaDef.Definition type = getType(obj.type);
1611 TypeInfo info = getTypeInfo(obj.type, true);
1612
1613 out.print("\t\t\t\t"
1614 + getDeclaredName(obj.name) + " = ");
1615
1616 // Behavior depends on the type
1617 if (type != null && type instanceof MetaDef.Import) {
1618 // Get the info object for the import
1619 info = getTypeInfo(((MetaDef.Import)type).type, true);
1620
1621 // Call the class constructor directly.
1622 out.print("(" + info.impName + ")_parser.getElement(");
1623 out.print(info.impName + ".class, ");
1624 } else if (type != null && type instanceof MetaDef.StringElement) {
1625 out.print("_parser.getString(" + info.className + ", ");
1626 } else {
1627 out.print("(" + info.className + ")_parser.getElement(");
1628 out.print(info.className + ".class, ");
1629 }
1630
1631 if (obj.required.booleanValue()) {
1632 out.print("true");
1633 } else {
1634 out.print("false");
1635 }
1636 out.println(");");
1637 } else if (content instanceof MetaDef.Array) {
1638 // Get the object and its type
1639 MetaDef.Array array = (MetaDef.Array)content;
1640 MetaDef.Definition type = getType(array.type);
1641 String typeName = getTypeInfo(array.type, true).className;
1642
1643 if (type instanceof MetaDef.Import) {
1644 // Get the info object for the import
1645 TypeInfo info = getTypeInfo(((MetaDef.Import)type).type, true);
1646
1647 // Construct the array
1648 out.print("\t\t\t\t_tempArray = _parser.getArray(");
1649 out.print(info.impName + ".class, ");
1650 out.println(array.min + ", " + array.max + ");");
1651 out.println("\t\t\t\t"
1652 + getDeclaredName(array.name)
1653 + " = new " + info.impName + "[_tempArray.length];");
1654 out.println("\t\t\t\tfor (int _i = 0; _i < "
1655 + getDeclaredName(array.name)
1656 + ".length; _i++)");
1657 out.println("\t\t\t\t\t" + getDeclaredName(array.name) + "[_i] = "
1658 + "(" + typeName + ")_tempArray[_i];");
1659 } else if (type instanceof MetaDef.StringElement) {
1660 out.print("\t\t\t\t" + getDeclaredName(array.name)
1661 + " = _parser.getStringArray(");
1662 out.println("\"" + typeName + "\", " + array.min
1663 + ", " + array.max + ");");
1664 } else {
1665 out.print("\t\t\t\t_tempArray = _parser.getArray(");
1666 out.print(typeName + ".class, ");
1667 out.println(array.min + ", " + array.max + ");");
1668 out.println("\t\t\t\t"
1669 + getDeclaredName(array.name)
1670 + " = new " + typeName + "[_tempArray.length];");
1671 out.println("\t\t\t\tfor (int _i = 0; _i < "
1672 + getDeclaredName(array.name)
1673 + ".length; _i++)");
1674 out.println("\t\t\t\t\t" + getDeclaredName(array.name) + "[_i] = "
1675 + "(" + typeName + ")_tempArray[_i];");
1676 }
1677 } else {
1678 throw new XOMException("Unrecognized content type definition: "
1679 + content.getClass().getName());
1680 }
1681 }
1682
1683 public void writeJavaGetAnyContent(PrintWriter out, boolean mixed)
1684 {
1685 if (mixed) {
1686 out.println("\t\t\t\tchildren = getMixedChildren(" +
1687 "_def, " +
1688 model.className + ".class, " +
1689 "\"" + prefix + "\");");
1690 } else {
1691 out.println("\t\t\t\tchildren = getElementChildren(" +
1692 "_def, " +
1693 model.className + ".class, " +
1694 "\"" + prefix + "\");");
1695 }
1696 }
1697
1698 public void writeJavaGetCDataContent(PrintWriter out)
1699 {
1700 out.println("\t\t\t\tcdata = _parser.getText();");
1701 }
1702
1703 public void writeJavaDeclareContent(PrintWriter out,
1704 MetaDef.Content content)
1705 throws XOMException
1706 {
1707 if (content instanceof MetaDef.Object) {
1708 // Write documentation (if any)
1709 MetaDef.Object obj = (MetaDef.Object)content;
1710 if (obj.doc != null) {
1711 writeJavaDoc(out, 2, obj.doc);
1712 }
1713
1714 // Handle includes
1715 MetaDef.Definition type = getType(obj.type);
1716 String typeName = getTypeInfo(obj.type, true).className;
1717
1718 // Write content declaration.
1719 if (type instanceof MetaDef.Import) {
1720 // Get the info object for the import
1721 TypeInfo info = getTypeInfo(((MetaDef.Import)type).type, true);
1722 typeName = info.impName;
1723 out.print("\t\tpublic " + typeName + " "
1724 + getDeclaredName(obj.name) + "; /" + "/");
1725 } else if (type instanceof MetaDef.StringElement) {
1726 out.print("\t\tpublic String "
1727 + getDeclaredName(obj.name) + "; /" + "/");
1728 } else {
1729 out.print("\t\tpublic " + typeName + " "
1730 + getDeclaredName(obj.name) + "; /" + "/");
1731 }
1732 // Write a brief comment.
1733 if (obj.required.booleanValue()) {
1734 out.println("required element");
1735 } else {
1736 out.println("optional element");
1737 }
1738 } else if (content instanceof MetaDef.Array) {
1739 // Write documentation (if any)
1740 MetaDef.Array array = (MetaDef.Array)content;
1741 if (array.doc != null) {
1742 writeJavaDoc(out, 2, array.doc);
1743 }
1744
1745 MetaDef.Definition type = getType(array.type);
1746 String typeName = getTypeInfo(array.type, true).className;
1747
1748 // Write content declaration.
1749 if (type instanceof MetaDef.Import) {
1750 // Get the info object for the import
1751 TypeInfo info = getTypeInfo(((MetaDef.Import)type).type, true);
1752 typeName = info.impName;
1753 out.print("\t\tpublic " + typeName + "[] "
1754 + getDeclaredName(array.name) + "; /" + "/");
1755 } else if (type instanceof MetaDef.StringElement) {
1756 out.print("\t\tpublic String[] "
1757 + getDeclaredName(array.name) + "; /" + "/");
1758 } else {
1759 out.print("\t\tpublic " + typeName + "[] "
1760 + getDeclaredName(array.name) + "; /" + "/");
1761 }
1762 // Write a brief comment.
1763 if (array.min.intValue() <= 0 &&
1764 array.max.intValue() <= 0) {
1765 out.println("optional array");
1766 } else {
1767 if (array.min.intValue() > 0) {
1768 out.print("min " + array.min);
1769 }
1770 if (array.max.intValue() > 0) {
1771 out.print("max " + array.max);
1772 }
1773 out.println();
1774 }
1775 } else {
1776 throw new XOMException("Unrecognized content type definition: "
1777 + content.getClass().getName());
1778 }
1779 }
1780
1781 public void writeJavaDeclareAnyContent(PrintWriter out, boolean mixed)
1782 {
1783 out.println("\t\tpublic org.eigenbase.xom." +
1784 (mixed ? "NodeDef" : "ElementDef") +
1785 "[] children; /" + "/holder for variable-type children");
1786 out.println("\t\t// implement Any");
1787 out.println("\t\tpublic org.eigenbase.xom.NodeDef[] getChildren()");
1788 out.println("\t\t{");
1789 out.println("\t\t\treturn children;");
1790 out.println("\t\t}");
1791 out.println("\t\t// implement Any");
1792 out.println("\t\tpublic void setChildren(org.eigenbase.xom.NodeDef[] children)");
1793 out.println("\t\t{");
1794 out.println("\t\t\tthis.children = " +
1795 (mixed ? "" : "(org.eigenbase.xom.ElementDef[]) ") +
1796 "children;");
1797 out.println("\t\t}");
1798 }
1799
1800 public void writeJavaDeclareCDataContent(PrintWriter out)
1801 {
1802 out.print("\t\tpublic String cdata; /"
1803 + "/ All text goes here");
1804 }
1805
1806 public void writeJavaDisplayContent(PrintWriter out,
1807 MetaDef.Content content)
1808 throws XOMException
1809 {
1810 if (content instanceof MetaDef.Object) {
1811 MetaDef.Object obj = (MetaDef.Object)content;
1812 MetaDef.Definition type = getType(obj.type);
1813
1814 if (type instanceof MetaDef.StringElement) {
1815 out.println("\t\t\tdisplayString(_out, \""
1816 + obj.name + "\", " + getDeclaredName(obj.name)
1817 + ", _indent+1);");
1818 } else {
1819 out.println("\t\t\tdisplayElement(_out, \""
1820 + obj.name + "\", " + getDeclaredName(obj.name)
1821 + ", _indent+1);");
1822 }
1823 } else if (content instanceof MetaDef.Array) {
1824 MetaDef.Array array = (MetaDef.Array)content;
1825 MetaDef.Definition type = getType(array.type);
1826
1827 if (type instanceof MetaDef.StringElement) {
1828 out.println("\t\t\tdisplayStringArray(_out, \""
1829 + array.name + "\", " + getDeclaredName(array.name)
1830 + ", _indent+1);");
1831 } else {
1832 out.println("\t\t\tdisplayElementArray(_out, \""
1833 + array.name + "\", " + getDeclaredName(array.name)
1834 + ", _indent+1);");
1835 }
1836 } else {
1837 throw new XOMException("Unrecognized content type definition: "
1838 + content.getClass().getName());
1839 }
1840 }
1841
1842 public void writeJavaDisplayAnyContent(PrintWriter out)
1843 {
1844 // Display the fixed children array
1845 out.println("\t\t\tdisplayElementArray(_out, \"children\""
1846 + ", children, _indent+1);");
1847 }
1848
1849 public void writeJavaDisplayCDataContent(PrintWriter out)
1850 {
1851 // Display the text as "cdata"
1852 out.println("\t\t\tdisplayString(_out, \"cdata\", "
1853 + "cdata, _indent+1);");
1854 }
1855
1856 public void writeJavaDisplayXMLContent(PrintWriter out,
1857 MetaDef.Content content)
1858 throws XOMException
1859 {
1860 if (content instanceof MetaDef.Object) {
1861 MetaDef.Object obj = (MetaDef.Object)content;
1862 MetaDef.Definition type = getType(obj.type);
1863
1864 if (type instanceof MetaDef.StringElement) {
1865 out.println("\t\t\tdisplayXMLString(_out, \""
1866 + getTypeInfo(obj.type, true).tagName + "\", "
1867 + getDeclaredName(obj.name) + ");");
1868 } else {
1869 out.println("\t\t\tdisplayXMLElement(_out, "
1870 + getDeclaredName(obj.name) + ");");
1871 }
1872 } else if (content instanceof MetaDef.Array) {
1873 MetaDef.Array array = (MetaDef.Array)content;
1874 MetaDef.Definition type = getType(array.type);
1875
1876 if (type instanceof MetaDef.StringElement) {
1877 out.println("\t\t\tdisplayXMLStringArray(_out, \""
1878 + getTypeInfo(array.type, true).tagName + "\", "
1879 + getDeclaredName(array.name) + ");");
1880 } else {
1881 out.println("\t\t\tdisplayXMLElementArray(_out, "
1882 + getDeclaredName(array.name) + ");");
1883 }
1884 } else if (content instanceof MetaDef.Any) {
1885 // Display the fixed children array
1886 out.println("\t\t\tdisplayXMLElementArray(_out, children);");
1887 } else if (content instanceof MetaDef.CData) {
1888 // Display the CDATA section
1889 out.println("\t\t\t_out.cdata(cdata);");
1890 } else {
1891 throw new XOMException("Unrecognized content type definition: "
1892 + content.getClass().getName());
1893 }
1894 }
1895
1896 public void writeJavaDisplayXMLAnyContent(PrintWriter out)
1897 {
1898 // Display the fixed children array
1899 out.println("\t\t\tdisplayXMLElementArray(_out, children);");
1900 }
1901
1902 public void writeJavaDisplayXMLCDataContent(PrintWriter out)
1903 {
1904 // Display the CDATA section
1905 out.println("\t\t\t_out.cdata(cdata);");
1906 }
1907
1908 public void writeJavaDisplayDiffContent(
1909 PrintWriter out,
1910 int[] diffCount, MetaDef.Content content)
1911 throws XOMException
1912 {
1913 if (content instanceof MetaDef.Object) {
1914 MetaDef.Object obj = (MetaDef.Object)content;
1915 MetaDef.Definition type = getType(obj.type);
1916
1917 if (type instanceof MetaDef.StringElement) {
1918 out.println("\t\t\t" + prefix(diffCount) + "displayStringDiff(\""
1919 + obj.name + "\", "
1920 + getDeclaredName(obj.name) + ", "
1921 + "_cother." + getDeclaredName(obj.name) + ", "
1922 + "_out, _indent+1);");
1923 } else {
1924 out.println("\t\t\t" + prefix(diffCount) + "displayElementDiff(\""
1925 + obj.name + "\", "
1926 + getDeclaredName(obj.name) + ", "
1927 + "_cother." + getDeclaredName(obj.name) + ", "
1928 + "_out, _indent+1);");
1929 }
1930 } else if (content instanceof MetaDef.Array) {
1931 MetaDef.Array array = (MetaDef.Array)content;
1932 MetaDef.Definition type = getType(array.type);
1933
1934 if (type instanceof MetaDef.StringElement) {
1935 out.println("\t\t\t" + prefix(diffCount) + "displayStringArrayDiff(\""
1936 + array.name + "\", "
1937 + getDeclaredName(array.name) + ", "
1938 + "_cother." + getDeclaredName(array.name) + ", "
1939 + "_out, _indent+1);");
1940 } else {
1941 out.println("\t\t\t" + prefix(diffCount) + "displayElementArrayDiff(\""
1942 + array.name + "\", "
1943 + getDeclaredName(array.name) + ", "
1944 + "_cother." + getDeclaredName(array.name) + ", "
1945 + "_out, _indent+1);");
1946 }
1947 } else {
1948 throw new XOMException("Unrecognized content type definition: "
1949 + content.getClass().getName());
1950 }
1951 }
1952
1953 private String prefix(int[] diffCount) {
1954 if (diffCount[0]++ == 0) {
1955 return "boolean _diff = ";
1956 } else {
1957 return "_diff = _diff && ";
1958 }
1959 }
1960
1961 public void writeJavaDisplayDiffAnyContent(
1962 PrintWriter out, int[] diffCount)
1963 {
1964 // Display the fixed children array
1965 out.println("\t\t\t" + prefix(diffCount) + "displayElementArrayDiff(\"children\", "
1966 + "children, _cother.children, _out, _indent+1);");
1967 }
1968
1969 public void writeJavaDisplayDiffCDataContent(
1970 PrintWriter out, int[] diffCount)
1971 {
1972 out.println("\t\t\t" + prefix(diffCount) + "displayStringDiff(\"cdata\", "
1973 + "cdata, _cother.cdata, _out, _indent+1);");
1974 }
1975
1976 public void writeJavaDeclarePluginAttributes(PrintWriter out)
1977 {
1978 writeJavaDoc(out, 2, "defPackage is a built-in attribute "
1979 + "defining the package of the plugin class.");
1980 out.println("\t\tpublic String defPackage;");
1981 out.println();
1982
1983 writeJavaDoc(out, 2, "defClass is a built-in attribute "
1984 + "definition the plugin parser class.");
1985 out.println("\t\tpublic String defClass;");
1986 out.println();
1987 }
1988
1989 public void writeJavaDisplayPluginAttributes(PrintWriter out)
1990 {
1991 // Generate two display lines
1992 out.println("\t\t\tdisplayAttribute(_out, \"defPackage\", "
1993 + "defPackage, _indent+1);");
1994 out.println("\t\t\tdisplayAttribute(_out, \"defClass\", "
1995 + "defClass, _indent+1);");
1996 }
1997
1998 public void writeJavaDisplayXMLPluginAttributes(PrintWriter out)
1999 {
2000 out.println("\t\t\t\t.add(\"defPackage\", defPackage)");
2001 out.println("\t\t\t\t.add(\"defClass\", defClass)");
2002 }
2003
2004 public void writeJavaDisplayDiffPluginAttributes(
2005 PrintWriter out, int[] diffCount)
2006 {
2007 out.println("\t\t\t" + prefix(diffCount) + "displayAttributeDiff(\""
2008 + "defPackage\", defPackage, _cother.defPackage"
2009 + ", _out, _indent+1);");
2010 out.println("\t\t\t" + prefix(diffCount) + "displayAttributeDiff(\""
2011 + "defClass\", defClass, _cother.defClass"
2012 + ", _out, _indent+1);");
2013 }
2014
2015 public void writeJavaGetPluginContent(PrintWriter out, boolean mixed)
2016 {
2017 if (mixed) {
2018 out.println("\t\t\t\tchildren = getMixedChildren(" +
2019 "_def, _pluginClass, \"\");");
2020 } else {
2021 out.println("\t\t\t\tchildren = getElementChildren(" +
2022 "_def, _pluginClass, \"\");");
2023 }
2024 }
2025
2026 public void writeJavaDeclarePluginContent(PrintWriter out, boolean mixed)
2027 {
2028 out.println("\t\tpublic org.eigenbase.xom." +
2029 (mixed ? "NodeDef" : "ElementDef") +
2030 "[] children; /" + "/holder for variable-type children");
2031 }
2032
2033 public void writeJavaDisplayPluginContent(PrintWriter out)
2034 {
2035 // Display the fixed children array
2036 out.println("\t\t\tdisplayElementArray(_out, \"children\""
2037 + ", children, _indent+1);");
2038 }
2039
2040 public void writeJavaDisplayXMLPluginContent(PrintWriter out)
2041 {
2042 // Display the fixed children array
2043 out.println("\t\t\tdisplayXMLElementArray(_out, children);");
2044 }
2045
2046 public void writeJavaDisplayDiffPluginContent(
2047 PrintWriter out, int[] diffCount)
2048 {
2049 // Display the fixed children array
2050 out.println("\t\t\t" + prefix(diffCount) + "displayElementArrayDiff(\"children\", "
2051 + "children, _cother.children, _out, _indent+1);");
2052 }
2053
2054 /**
2055 * Write the name of the dtd file and java class to standard output.
2056 * This output is used by shell scripts to grab these values.
2057 * The output is only produced in test mode.
2058 */
2059 public void writeOutputs()
2060 {
2061 if (testMode) {
2062 System.out.println(model.dtdName + " " + model.className);
2063 }
2064 }
2065
2066 /**
2067 * Main function for MetaGenerator. Arguments:
2068 * <ol>
2069 * <li>Name of XML file describing input model.
2070 * <li>Name of output file directory.
2071 * </ol>
2072 */
2073 public static void main(String[] args)
2074 {
2075 int firstArg = 0;
2076 boolean testMode = false;
2077 if (firstArg < args.length && args[firstArg].equals("-debug")) {
2078 System.err.println("MetaGenerator pausing for debugging. "
2079 + "Attach your debugger "
2080 + "and press return.");
2081 try {
2082 System.in.read();
2083 firstArg++;
2084 } catch (IOException ex) {
2085 // Do nothing
2086 }
2087 }
2088 if (firstArg < args.length && args[firstArg].equals("-test")) {
2089 System.err.println("Ignoring package name.");
2090 testMode = true;
2091 firstArg++;
2092 }
2093
2094 if (args.length != 2 + firstArg) {
2095 System.err.println(
2096 "Usage: java MetaGenerator [-debug] [-test] " +
2097 "<XML model file> <output directory>");
2098 System.exit(2);
2099 }
2100
2101 try {
2102 MetaGenerator generator = new MetaGenerator(
2103 args[0 + firstArg], testMode);
2104 generator.writeFiles(args[1 + firstArg], null);
2105 generator.writeOutputs();
2106 } catch (XOMException ex) {
2107 System.err.println("Generation of model failed:");
2108 System.err.println(ex.toString());
2109 ex.printStackTrace();
2110 System.exit(1);
2111 } catch (IOException ex) {
2112 System.err.println("Generation of model failed:");
2113 System.err.println(ex.toString());
2114 ex.printStackTrace();
2115 System.exit(1);
2116 }
2117 }
2118
2119 /**
2120 * Display information about this generator for debug purposes.
2121 */
2122 public void debugDisplay()
2123 {
2124 System.out.println("Model:");
2125 System.out.println(model.toString());
2126 }
2127 }
2128
2129
2130 // End MetaGenerator.java