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