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