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