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 027package org.eigenbase.xom; 028import java.io.*; 029import 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 **/ 037public 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