alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

What this is

This file is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Other links

The source code

/*
 *                 Sun Public License Notice
 * 
 * The contents of this file are subject to the Sun Public License
 * Version 1.0 (the "License"). You may not use this file except in
 * compliance with the License. A copy of the License is available at
 * http://www.sun.com/
 * 
 * The Original Code is NetBeans. The Initial Developer of the Original
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2003 Sun
 * Microsystems, Inc. All Rights Reserved.
 */

package org.netbeans.modules.schema2beansdev;

import java.util.*;
import java.io.*;

import org.netbeans.modules.schema2beans.*;
import org.netbeans.modules.schema2beansdev.metadd.*;
import org.netbeans.modules.schema2beansdev.gen.*;

public class JavaBeanClass extends AbstractCodeGeneratorClass implements CodeGeneratorClass {
    // No element type number can be this one.
    final protected int elementTypeSetnull = -1;

    JavaBeanClass(BeanBuilder.BeanElement be, GenBeans.Config config) {
        init(be, config);
    }

    /**
     *	Generate the java code in the out stream, using the optional
     *	metaDD bean graph.
     */
    public void generate(OutputStream out, MetaDD mdd) throws IOException {
        this.mdd = mdd;
        metaElement = getMetaElement(beanElement);
	
        if (metaElement != null && metaElement.isSkipGeneration()) {
            config.messageOut.println(Common.getMessage("MSG_SkippingGeneration"));
            return;
        }

        findAttributeOwners();
        
        genAllParts();

        select(DECL_SECTION);
        cr();

        printGenBuffers(out);
    }

    protected void genAllParts() throws IOException {
        genHeader(HEADER_SECTION);
        genPackage(HEADER_SECTION);
        genImports(HEADER_SECTION);
        genClassName(HEADER_SECTION);

        genConstructor();
        genAccessors();
        if (!config.isMinFeatures())
            genDeepCopy();

        if (config.isGenerateXMLIO() || config.isDumpToString()) {
            genXMLIO();
        }
        if (config.isGenerateValidate()) {
            genValidate();
        }
        if (config.isGeneratePropertyEvents()) {
            genPropertyEvents();
        }
        if (config.isGenerateStoreEvents()) {
            genStoreEvents();
        }
        if (config.isVetoable()) {
            genVetoable();
        }
        if (config.isGenerateTransactions()) {
            genTransactions();
        }
        if (config.isGenerateHasChanged()) {
            genHasChanged();
        }
        if (config.isGenerateSwitches()) {
            generateSwitches();
        }
        if (!config.isMinFeatures())
            genPropertiesByName();
        if (config.isKeepElementPositions()) {
            genElementPositions();
        }
        if (beanElement.isRoot && config.isProcessDocType()) {
            genProcessDocType();
        }

        if (!config.isMinFeatures()) {
            genName();

            genChildBeans();
        }
        genEqualsHashCode();
        if (config.isDumpToString()) {
            genToString();
        }
        if (config.isExtendBaseBean())
            genExtendBaseBean();

        genTrailer(TRAILER_SECTION);
        genFinishClass(TRAILER_SECTION);

        try {
            select(TRAILER_SECTION);
            printSchema();
        } catch (IOException ioe) {
            //	Do not generate the schema comment
        }
    }

    protected void genMadeChange() throws IOException {
        if (config.isGenerateHasChanged()) {
            jw.writeEol("_setChanged(true)");
        }
    }

    /**
     * Whenever we create a constructor, call this method first.
     */
    protected void genExtendBaseBeanConstructor() throws IOException {
        if (config.isExtendBaseBean()) {
            jw.writeEol("super(null, baseBeanRuntimeVersion)");
            //jw.writeEol("System.out.println(\"Created class \"+getClass())");
        }
    }

    public void genHeader(int out) throws IOException {
        select(out);
        gencr("/**");
        gencr(" *	This generated bean class " + className);
        gencr(" *	matches the schema element '" + beanElement.node.getName()+"'.");
        if (!beanElement.isRoot) {
            jw.writecr(" *  The root bean class is "+rootBeanElement.getClassType());
        }
        gencr(" *");
        printComment(" *	");
        if (config.isGenerateTimeStamp())
            gencr(" *	Generated on " + new Date());
        if (beanElement.isRoot) {
            gencr(" *");
            gencr(" *	This class matches the root element of the "+(config.getSchemaTypeNum() == GenBeans.Config.DTD ? "DTD" : "XML Schema")+",");
            gencr(" *	and is the root of the bean graph.");
            gencr(" *");
	    
            dumpBeanTree(jw, " * "+jw.getIndent(), jw.getIndent());
            gencr(" *");
        }
        gencr(" * @"+Common.GENERATED_TAG);
        gencr(" */"); cr();
    }

    public void genPackage(int out) {
        select(out);
        if (packageName != null) {
            gen(PACKAGE, packageName);
            eol();
            cr();
        }
    }

    public void genImports(int out) {
        select(out);
    }

    public void genClassName(int out) {
        String name = null;
        String impName = null;
	
        select(out);
        gen(PUBLIC, CLASS, className);
	
        if (mdd != null) {
            if (metaElement != null) {
                name = metaElement.getExtends();
                impName = metaElement.getImplements();
            }
            if (name == null) {
                name = mdd.getExtends();
            }
            if (impName == null) {
                impName = mdd.getImplements();
            }
        }
	
        if (name != null) {
            gen(" extends ");
            gencr(name);
        }
        if (impName != null) {
            gen(" implements ", impName);
        }

        sp();
        begin();
    }

    public void genConstructor() throws IOException {
        int size = attrList.size();
        if (!config.isMinFeatures()) {
            jw.select(DECL_SECTION);
            for (int i = 0; i < size; i++) {
                Property a = (Property)attrList.get(i);
                jw.write("public static final String ", a.constName,
                         " = \"", a.name);
                jw.writeEolNoI18N("\"");
            }
            jw.cr();
        }
        
        jw.select(CONSTRUCTOR_SECTION);
        jw.bigComment("Normal starting point constructor.");
        jw.beginConstructor(className);
        if (config.isExtendBaseBean()) {
            jw.select(DECL_SECTION);
            jw.write("private static final org.netbeans.modules.schema2beans.Version baseBeanRuntimeVersion = new org.netbeans.modules.schema2beans.Version(" +
                     Version.MAJVER, ", ");
            jw.write(Version.MINVER + ", ");
            jw.writeEol(Version.PTCVER + ")");
            jw.select(CONSTRUCTOR_SECTION);
            jw.writeEol("this(null, baseBeanRuntimeVersion)");
            jw.end();
            jw.cr();
            jw.bigComment("This constructor is here for BaseBean compatibility.");
            jw.beginConstructor(className, "java.util.Vector comps, org.netbeans.modules.schema2beans.Version baseBeanRuntimeVersion");
        }
        genExtendBaseBeanConstructor();

        if (config.isMakeDefaults() || config.isSetDefaults()) {
            for (int i = 0; i < size; i++) {
                Property a = (Property)attrList.get(i);
                boolean indexed = a.isIndexed();
                boolean isScalar = a.isScalar();
                if (indexed || isScalar || a.ored)
                    continue;
                if (a.getDefaultValue() != null)
                    continue;
                String type = a.getType();
                String attr = "_"+a.name;
                if (a.elementInstance == Common.TYPE_1) {
                    // There has to be at least 1 of them.
                    List exceps = JavaUtil.exceptionsFromParsingText(type, false);
                    if (!exceps.isEmpty()) {
                        jw.beginTry();
                    }
                    gen(attr, " = ");
                    genNewDefault(a, true);
                    eol();
                    if (a.isBean && config.isGenerateParentRefs()) {
                        jw.writeEol(attr, "._setParent(this)");
                    }
                    if (!exceps.isEmpty()) {
                        end();
                        genRethrowExceptions(exceps);
                    }
                }
            }
        }
        jw.end();
        jw.cr();

        // Create a constructor that has all of the required parameters.
        List requiredParameters = new LinkedList();
        for (int i = 0; i < size; i++) {
            Property a = (Property)attrList.get(i);
            // Is the property optional?
            if (!a.ored && (a.elementInstance == Common.TYPE_1 || a.elementInstance == Common.TYPE_1_N))
                requiredParameters.add(a);
        }
        if (!config.isMinFeatures() && requiredParameters.size() > 0) {
            String parameters = null;
            for (Iterator it = requiredParameters.iterator(); it.hasNext(); ) {
                Property a = (Property) it.next();
                if (parameters != null)
                    parameters += ", ";
                else
                    parameters = "";
                String type = a.getType();
                String baseType = type;
                if (a.isIndexed())
                    type = baseType + "[]";
                String fullClassType = getTypeFullClassName(a, type);
                parameters += fullClassType + " " + a.instanceOf();
            }
            jw.bigComment("Required parameters constructor");
            jw.beginConstructor(className, parameters);
            genExtendBaseBeanConstructor();
            for (Iterator it = requiredParameters.iterator(); it.hasNext(); ) {
                Property a = (Property) it.next();
                boolean indexed = a.isIndexed();
                String type = a.getType();
                String baseType = type;
                if (indexed)
                    type = baseType + "[]";
                String attr = "_"+a.name;
                SchemaRep.WhiteSpace ws = (SchemaRep.WhiteSpace) a.searchExtraData(SchemaRep.WhiteSpace.class);
                if (!indexed) {
                    if (ws != null)
                        genWhiteSpaceRestriction(ws, a.instanceOf(), baseType);
                    jw.write(attr, " = ");
                    jw.writeEol(a.instanceOf());
                    if (a.isBean && config.isGenerateParentRefs()) {
                        jw.beginIf(attr+" != null");
                        jw.writeEol(attr, "._setParent(this)");
                        jw.end();
                    }
                } else {
                    jw.beginIf(a.instanceOf() + "!= null");
                    if ("java.util.ArrayList".equals(config.getIndexedPropertyType())) {
                        jw.write("((", config.getIndexedPropertyType(),
                                 ") ", attr);
                        jw.writeEol(").ensureCapacity(",
                                    a.instanceOf(), ".length)");
                    }
                    jw.beginFor("int i = 0", "i < "+a.instanceOf()+".length",
                                "++i");
                    if (ws != null)
                        genWhiteSpaceRestriction(ws, a.instanceOf()+"[i]",
                                                 baseType);
                    if (a.isBean && config.isGenerateParentRefs()) {
                        jw.beginIf(a.instanceOf()+"[i] != null");
                        jw.writeEol(a.instanceOf(), "[i]._setParent(this)");
                        jw.end();
                    }
                    jw.write(attr, ".add(",
                             JavaUtil.toObject(a.instanceOf()+"[i]", baseType,
                                               config.isForME()));
                    jw.writeEol(")");
                    jw.end();
                    jw.end();
                }
            }            
            jw.end();
            jw.cr();
        }
    }

    public void genAccessors() throws IOException {
        int size = attrList.size();
        for (int i = 0; i < size; i++) {
            Property a = (Property)attrList.get(i);
            boolean indexed = a.isIndexed();
            boolean isArrayStyle = (config.getIndexedPropertyType() == null);
            boolean	isWrapper = false;
            boolean isScalar = a.isScalar();
            String 	scalarType = a.getScalarType();
            String attr = "_"+a.name;
            String propertyName = a.beanIntrospectorName();
            MetaElement	me = getMetaElement(a);

            String type = a.getType();
            String baseType = type;
            if (indexed)
                type = baseType + "[]";
            Signatures sigs = getSignatures(a);
            Signature sig;

            //System.out.println("a.name="+a.name+" a.type="+a.type+" a.dtdName="+a.dtdName+" isWrapper="+isWrapper+" a.classType="+a.classType+" me="+me);
            select(DECL_SECTION);
            if (indexed) {
                if (isArrayStyle) {
                    gen(PRIVATE, baseType+"[]", attr);
                    gen(" = new ", baseType, "[0]");
                    eol();
                } else {
                    gen(PRIVATE, "java.util.List", attr);
                    gen(" = new "+config.getIndexedPropertyType()+"();");
                    tabIn();
                    comment("List<"+baseType+">");
                }
            } else {
                gen(PRIVATE, type, attr);
                if (a.getDefaultValue() != null && (a.elementInstance == Common.TYPE_1 || a.elementInstance == Common.TYPE_1_N)) {
                    gen(" = ");
                    if (!JavaUtil.checkValueToType(type, a.getDefaultValue())) {
                        config.messageOut.println(Common.getMessage("MSG_NotAGoodValue", a.getDefaultValue(), type));
                    }
                    gen(JavaUtil.instanceFrom(type, a.getDefaultValue()));
                }
                eol();
            }

            select(ACCESS_SECTION);
            comment("This attribute is ", Common.instanceToString(a.elementInstance));
            // Generate setter
            gen(sigs.findSignature(SETTER));
            sp();
            begin();
            if (a.getPropertyInterface() != null) {
                jw.writeEol(type+" value = ("+type+") valueInterface");
            }
            if (indexed) {
                gen("if (value == null)");
                cr();
                tabIn();
                if (baseType.equals("byte[]"))
                    jw.writeEol("value = new byte[0][0]");
                else
                    jw.writeEol("value = new ", baseType, "[0]");
            }
            if (!indexed) {
                SchemaRep.WhiteSpace ws = (SchemaRep.WhiteSpace) a.searchExtraData(SchemaRep.WhiteSpace.class);
                if (ws != null)
                    genWhiteSpaceRestriction(ws, "value", baseType);
            }
            if (config.isGeneratePropertyEvents() || config.isVetoable()) {
                if (indexed) {
                    jw.beginIf("value.length == "+a.getSizeMethod()+"()");
                    jw.writeEol("boolean same = true");
                    jw.beginFor("int i = 0", "i < value.length", "++i");
                    jw.beginIf("!("+JavaUtil.genEquals(type, "value[i]",
                                                  a.getReadMethod(true) + "(i)")+")");
                    jw.writeEol("same = false");
                    jw.writeEol("break");
                    jw.end();
                    jw.end();
                    jw.beginIf("same");
                } else {
                    jw.beginIf(JavaUtil.genEquals(type, "value", attr));
                }
                jw.comment("No change.");
                jw.writeEol("return");
                jw.end();
                if (indexed)
                    jw.end();

                if (a.isBean) {
                    if (config.isGeneratePropertyEvents())
                        comment("Make the foreign beans take on our property change event listeners.");
                    if (config.isGenerateParentRefs())
                        comment("Maintain the parent reference.");
                    String iterVar = "value";
                    if (indexed) {
                        jw.beginFor("int i = 0", "i < value.length", "++i");
                        iterVar = "value[i]";
                    }
                    jw.beginIf(iterVar+" != null");
                    if (config.isGeneratePropertyEvents())
                        geneol(iterVar+"._setPropertyChangeSupport(eventListeners)");
                    if (config.isVetoable())
                        geneol(iterVar+"._setVetoableChangeSupport(vetos)");
                    if (config.isGenerateParentRefs())
                        jw.writeEol(iterVar+"._setParent(this)");
                    jw.end();
                    if (indexed)
                        jw.end();
                }

                jw.writeEol("java.beans.PropertyChangeEvent event = null");
                gen("if (");
                jw.setFirst(" || ");
                if (config.isGeneratePropertyEvents()) {
                    jw.writeNext("eventListeners != null");
                }
                if (config.isGenerateStoreEvents()) {
                    jw.writeNext("storeEvents");
                }
                if (config.isVetoable()) {
                    jw.writeNext("vetos != null");
                }
                gen(") ");
                begin();
                if (indexed) {
                    jw.comment("See if only 1 thing changed.");
                    jw.writeEol("int addIndex = -1");
                    jw.writeEol("int removeIndex = -1");
                    jw.writeEol("int oldSize = size", a.name, "()");
                    jw.writeEol("int newSize = value.length");
                    jw.beginIf("oldSize + 1 == newSize || oldSize == newSize + 1");
                    jw.writeEol("boolean checkAddOrRemoveOne = true");
                    jw.writeEol("int oldIndex = 0, newIndex = 0");
                    jw.beginFor("",
                                "oldIndex < oldSize && newIndex < newSize",
                                "++newIndex, ++oldIndex");
                    //jw.writeEol("System.out.println(\"oldIndex=\"+oldIndex+\" newIndex=\"+newIndex)");
                    //jw.writeEol("System.out.println(\"addIndex=\"+addIndex+\" removeIndex=\"+removeIndex)");
                    jw.beginIf(JavaUtil.genEquals(baseType, "value[newIndex]",
                                                  a.getReadMethod(true)+"(oldIndex)"));
                    jw.comment("Same, so just continue.");
                    jw.endElseBeginIf("addIndex != -1 || removeIndex != -1");
                    jw.comment("More than 1 difference detected.");
                    jw.writeEol("addIndex = removeIndex = -1");
                    jw.writeEol("checkAddOrRemoveOne = false");
                    jw.writeEol("break");
                    jw.endElseBeginIf("oldIndex + 1 < oldSize && ("+JavaUtil.genEquals(baseType, "value[newIndex]", a.getReadMethod(true)+"(oldIndex+1)")+")");
                    jw.writeEol("removeIndex = oldIndex");
                    jw.writeEol("++oldIndex");
                    jw.endElseBeginIf("newIndex + 1 < newSize && ("+JavaUtil.genEquals(baseType, "value[newIndex+1]", a.getReadMethod(true)+"(oldIndex)")+")");
                    jw.writeEol("addIndex = newIndex");
                    jw.writeEol("++newIndex");
                    jw.endElseBegin();
                    jw.comment("More than 1 difference.");
                    jw.writeEol("addIndex = removeIndex = -1");
                    jw.writeEol("checkAddOrRemoveOne = false");
                    jw.writeEol("break");
                    jw.end();
                    jw.end();	// for
                    // Only do this check if we fell off the end (oldIndex == newIndex)
                    jw.beginIf("checkAddOrRemoveOne && addIndex == -1 && removeIndex == -1");
                    jw.beginIf("oldSize + 1 == newSize");
                    jw.comment("Added last one");
                    jw.writeEol("addIndex = oldSize");
                    jw.endElseBeginIf("oldSize == newSize + 1");
                    jw.comment("Removed last one");
                    jw.writeEol("removeIndex = newSize");
                    jw.end();
                    jw.end();
                    jw.end();

                    //jw.writeEol("System.out.println(\"addIndex=\"+addIndex+\" removeIndex=\"+removeIndex)");
                    jw.beginIf("addIndex >= 0");
                    jw.write("event = ");
                    genNewEvent(a, "addIndex", "null", "value[addIndex]", baseType);
                    jw.eol();
                    if (!isArrayStyle && !config.isVetoable() && !config.isKeepElementPositions() && !config.isGenerateStoreEvents()) {
                        SchemaRep.WhiteSpace ws = (SchemaRep.WhiteSpace) a.searchExtraData(SchemaRep.WhiteSpace.class);
                        if (ws != null)
                            genWhiteSpaceRestriction(ws, "value[addIndex]", baseType);
                        jw.writeEol(attr+".add(addIndex, value[addIndex])");
                        genMadeChange();
                        jw.writeEol("eventListeners.firePropertyChange(event)");
                        jw.writeEol("return");
                    }
                    jw.endElseBeginIf("removeIndex >= 0");
                    jw.write("event = ");
                    genNewEvent(a, "removeIndex", a.getReadMethod(true)+"(removeIndex)", "null", baseType);
                    jw.eol();
                    if (!isArrayStyle && !config.isVetoable() && !config.isKeepElementPositions() && !config.isGenerateStoreEvents()) {
                        jw.writeEol(attr+".remove(removeIndex)");
                        genMadeChange();
                        jw.writeEol("eventListeners.firePropertyChange(event)");
                        jw.writeEol("return");
                    }
                    jw.endElseBegin();
                }
                jw.write("event = ");
                genNewEvent(a, indexed ? "-1" : "",
                            a.getReadMethod(false)+"()",
                            "value", type);
                jw.eol();
                end();
                if (indexed) {
                    jw.end();
                }
            }
            if (config.isVetoable()) {
                gencr("if (vetos != null)");
                tabIn();
                geneol("vetos.fireVetoableChange(event)");
            }
            if (indexed) {
                if (config.isKeepElementPositions()) {
                    jw.comment("Figure out where this type belongs.");
                    jw.writeEol("int elementCount = fetchChildCount()");
                    jw.writeEol("int destPos = 0");
                    jw.writeEol("int srcPos = 0");
                    // Remove all of the old entries
                    jw.beginFor("", "destPos < elementCount && srcPos < value.length",
                                "++destPos");
                    jw.beginIf("elementTypesByPosition[destPos] == "+i);
                    jw.comment("replace it");
                    jw.writeEol("elementsByPosition[destPos] = value[srcPos++]");
                    jw.end();
                    jw.end();
                    jw.comment("Handle when the replacement array is smaller.");
                    jw.beginWhile("destPos < elementCount");
                    jw.beginIf("elementTypesByPosition[destPos] == "+i);
                    jw.writeEol("deleteElement(destPos)");
                    jw.writeEol("--elementCount");
                    jw.endElseBegin();
                    jw.writeEol("++destPos");
                    jw.end();
                    jw.end();
                    jw.comment("Handle when replacement array is larger.");
                    jw.beginFor("", "srcPos < value.length", "++srcPos");
                    jw.writeEol("insertElementByPosition(destPos++, ",
                                JavaUtil.toObject("value[srcPos]", baseType,
                                                  config.isForME()),
                                ", "+i+")");
                    jw.end();
                }
                if (isArrayStyle) {
                    jw.writeEol(attr, " = value");
                } else {
                    jw.writeEol(attr, ".clear()");
                    if ("java.util.ArrayList".equals(config.getIndexedPropertyType())) {
                        jw.writeEol("((", config.getIndexedPropertyType(),
                                    ") "+attr, ").ensureCapacity(value.length)");
                    }
                    jw.beginFor("int i = 0", "i < value.length", "++i");
                    SchemaRep.WhiteSpace ws = (SchemaRep.WhiteSpace) a.searchExtraData(SchemaRep.WhiteSpace.class);
                    if (ws != null)
                        genWhiteSpaceRestriction(ws, "value[i]", baseType);
                    jw.write(attr, ".add(");
                    String objectValue = JavaUtil.toObject("value[i]", baseType,
                                                           config.isForME());
                    jw.writeEol(objectValue, ")");
                    jw.end();
                }
            } else {
                geneol(attr+" = value");
                if (config.isKeepElementPositions()) {
                    jw.comment("Figure out where this type belongs.");
                    jw.writeEol("int elementCount = fetchChildCount()");
                    jw.writeEol("int pos = findFirstOfElementType("+i+")");
                    if (!isScalar) {
                        jw.beginIf("value != null");
                    }
                    jw.beginIf("pos >= elementCount");
                    jw.comment("It's the last one to be added");
                    jw.writeEol("expandElementsByPosition(elementCount+1)");
                    jw.writeEol("elementTypesByPosition[pos] = "+i);
                    jw.end();
                    jw.writeEol("elementsByPosition[pos] = ",
                                JavaUtil.toObject("value", type,
                                                  config.isForME()));
                    if (!isScalar) {
                        jw.endElseBegin();
                        jw.beginIf("pos < elementCount");
                        jw.writeEol("deleteElement(pos)");
                        jw.end();
                        jw.end();
                    }
                }
            }
            genMadeChange();
            if (config.isGeneratePropertyEvents()) {
                if (config.isGenerateStoreEvents()) {
                    gencr("if (storeEvents)");
                    tabIn();
                    geneol("storedEvents.add(event)");
                    gen("else ");
                }
                gencr("if (event != null)");
                tabIn();
                geneol("eventListeners.firePropertyChange(event)");
            }

            genResetMutuallyExclusive(a, true);
            end();
            cr();

            if (indexed) {
                gen(sigs.findSignature(SETTERINDEXED));
                sp();
                begin();
                if (a.getPropertyInterface() != null) {
                    jw.writeEol(baseType+" value = ("+baseType+") valueInterface");
                }
                if (config.isGeneratePropertyEvents()) {
                    jw.beginIf(JavaUtil.genEquals(type, "value",
                                                  a.getReadMethod(true)+"(index)",
                                                  true));
                    jw.comment("No change.");
                    jw.writeEol("return");
                    jw.end();
                }
                if (a.isBean && config.isGenerateParentRefs()) {
                    jw.beginIf("value != null");
                    jw.writeEol("value._setParent(this)");
                    jw.end();
                }
                if (config.isGeneratePropertyEvents()) {
                    if (a.isBean) {
                        jw.beginIf("value != null");
                        comment("Make the foreign beans take on our property change event listeners.");
                        geneol("value._setPropertyChangeSupport(eventListeners)");
                        if (config.isVetoable())
                            geneol("value._setVetoableChangeSupport(vetos)");
                        jw.end();
                    }

                    gen("if (");
                    if (config.isGenerateStoreEvents()) {
                        gen("storeEvents || ");
                    }
                    gen("eventListeners != null) ");
                    begin();
                    jw.write("java.beans.PropertyChangeEvent event = ");
                    genNewEvent(a, "index", a.getReadMethod(true)+"(index)",
                                "value", baseType);
                    jw.eol();
                    if (config.isVetoable()) {
                        gencr("if (vetos != null)");
                        tabIn();
                        geneol("vetos.fireVetoableChange(event)");
                    }
                    if (config.isGenerateStoreEvents()) {
                        gencr("if (storeEvents)");
                        tabIn();
                        geneol("storedEvents.add(event)");
                        gencr("else");
                        tabIn();
                    }
                    geneol("eventListeners.firePropertyChange(event)");
                    end();
                }
                if (isArrayStyle) {
                    jw.writeEol(attr, "[index] = value");
                } else {
                    if (!a.isDirectChild()) {
                        // Check to see if we need to grow before we set.
                        jw.beginFor("int size = "+attr+".size()",
                                    "index >= size", "++size");
                        jw.writeEol(attr, ".add(null)");
                        jw.end();
                    }
                    jw.write(attr, ".set(index, ");
                    jw.write(JavaUtil.toObject("value", baseType, config.isForME()));
                    jw.writeEol(")");
                }
                if (config.isKeepElementPositions()) {
                    jw.writeEol("int pos = findElementType("+i+", index)");
                    jw.writeEol("elementsByPosition[pos] = ",
                                JavaUtil.toObject("value", baseType,
                                                  config.isForME()));
                }
                genMadeChange();
                end();
                cr();
            }

            // Generate getter
            gen(sigs.findSignature(GETTER));
            sp();
            begin();
            if (indexed && !isArrayStyle) {
                if (baseType.equals("byte[]"))
                    jw.writeEol(type, " arr = new byte[", attr, ".size()][]");
                else
                    jw.writeEol(type, " arr = new ", baseType+"["+attr, ".size()]");
                if (isScalar) {
                    jw.beginFor("int i = 0", "i < arr.length", "++i");
                    jw.write("arr[i] = ");
                    jw.write(JavaUtil.fromObject(baseType, attr+".get(i)"));
                    jw.eol();
                    jw.end();
                    jw.write("return arr");
                } else {
                    gen("return ("+type+") "+attr+".toArray(arr)");
                }
            } else
                gen("return "+attr);
            eol();
            end();
            cr();

            if (indexed) {
                if (!config.isMinFeatures() && !isArrayStyle) {
                    gen(sigs.findSignature(GETTERLIST));
                    sp();
                    begin();
                    gen("return "+attr);
                    eol();
                    end();
                    cr();
                }

                gen(sigs.findSignature(GETTERINDEXED));
                sp();
                begin();
                jw.write("return ");
                if (isArrayStyle) {
                    jw.writeEol(attr, "[index]");
                } else {
                    jw.writeEol(JavaUtil.fromObject(baseType, attr+".get(index)"));
                }
                end();
                cr();

                comment("Return the number of "+propertyName);
                gen(sigs.findSignature(SIZE));
                sp();
                begin();
                if (isArrayStyle) {
                    jw.writeEol("return ", attr, ".length");
                } else {
                    jw.writeEol("return ", attr, ".size()");
                }
                end();
                cr();

                if (!isArrayStyle) {
                    gen(sigs.findSignature(ADD));
                    sp();
                    begin();
                    if (a.getPropertyInterface() != null) {
                        jw.writeEol(baseType+" value = ("+baseType+") valueInterface");
                    }
                    if (a.isBean && config.isGenerateParentRefs()) {
                        jw.beginIf("value != null");
                        jw.writeEol("value._setParent(this)");
                        jw.end();
                    }
                    if (a.isBean && config.isGeneratePropertyEvents()) {
                        jw.beginIf("value != null");
                        comment("Make the foreign beans take on our property change event listeners.");
                        geneol("value._setPropertyChangeSupport(eventListeners)");
                        if (config.isVetoable())
                            geneol("value._setVetoableChangeSupport(vetos)");
                        jw.end();
                    }
                    jw.writeEol(attr, ".add(",
                                JavaUtil.toObject("value", baseType,
                                                  config.isForME()),
                                ")");
                    if (config.isKeepElementPositions()) {
                        GraphLink gl = a.getGraphLink();
                        //jw.comment("gl="+gl);
                        //jw.comment("gl.lastInGroup="+gl.getLastInGroup());
                        //jw.comment("gl.lastInGroup.object="+gl.getLastInGroup().getObject());
                        int lastPropNum;
                        if (gl == null) {
                            lastPropNum = i;
                        } else {
                            Property lastProp = (Property) gl.getLastSibling().getObject();
                            if (lastProp == a) {
                                lastPropNum = i;
                            } else {
                                for (lastPropNum = 0; lastPropNum < size; ++lastPropNum)
                                    if (attrList.get(lastPropNum) == lastProp)
                                        break;
                                if (lastPropNum == size) {
                                    jw.comment("Did not find lastPropNum");
                                    lastPropNum = i;
                                }
                            }
                        }
                        jw.writeEol("int pos = findLastOfElementType("+lastPropNum+")+1");
                        jw.writeEol("insertElementByPosition(pos, ",
                                    JavaUtil.toObject("value", baseType,
                                                      config.isForME()),
                                    ", "+i+")");
                    }
                    if (config.isGeneratePropertyEvents()) {
                        gen("if (");
                        if (config.isGenerateStoreEvents()) {
                            gen("storeEvents || ");
                        }
                        gen("eventListeners != null) ");
                        begin();
                        jw.write("java.beans.PropertyChangeEvent event = ");
                        genNewEvent(a, attr+".size()-1", "null",
                                    "value", baseType);
                        jw.eol();
                        if (config.isVetoable()) {
                            gencr("if (vetos != null)");
                            tabIn();
                            geneol("vetos.fireVetoableChange(event)");
                        }
                        if (config.isGenerateStoreEvents()) {
                            gencr("if (storeEvents)");
                            tabIn();
                            geneol("storedEvents.add(event)");
                            gencr("else");
                            tabIn();
                        }
                        geneol("eventListeners.firePropertyChange(event)");
                        end();
                    }
                    jw.writeEol("int positionOfNewItem = "+attr+".size()-1");
                    if (isMutuallyExclusive(a)) {
                        jw.beginIf("positionOfNewItem == 0");
                        genResetMutuallyExclusive(a, false);
                        jw.end();
                    }
                    genMadeChange();
                    geneol("return positionOfNewItem");
                    end();
                    cr();

                    jw.bigComment("Search from the end looking for @param value, and then remove it.");
                    gen(sigs.findSignature(REMOVE));
                    sp();
                    begin();
                    if (a.getPropertyInterface() != null) {
                        jw.writeEol(baseType+" value = ("+baseType+") valueInterface");
                    }
                    jw.writeEol("int pos = ", attr, ".indexOf(",
                                JavaUtil.toObject("value", baseType,
                                                  config.isForME())+")");
                    gen("if (pos >= 0) ");
                    begin();
                    geneol(attr+".remove(pos)");
                    if (config.isKeepElementPositions()) {
                        jw.writeEol("int elementPos = findElementType("+i+", pos)");
                        jw.writeEol("deleteElement(elementPos)");
                    }
                    if (config.isGeneratePropertyEvents()) {
                        gen("if (");
                        if (config.isGenerateStoreEvents()) {
                            gen("storeEvents || ");
                        }
                        gen("eventListeners != null) ");
                        begin();
                        gen("java.beans.PropertyChangeEvent event = ");
                        genNewEvent(a, "pos", "value", "null", baseType);
                        jw.eol();
                        if (config.isVetoable()) {
                            gencr("if (vetos != null)");
                            tabIn();
                            geneol("vetos.fireVetoableChange(event)");
                        }
                        if (config.isGenerateStoreEvents()) {
                            gencr("if (storeEvents)");
                            tabIn();
                            geneol("storedEvents.add(event)");
                            gencr("else");
                            tabIn();
                        }
                        geneol("eventListeners.firePropertyChange(event)");
                        end();
                    }
                    end();
                    genMadeChange();
                    geneol("return pos");
                    end();
                    cr();
                }

                MetaProperty mp = getMetaProperty(a.name);
                GraphNode graphNode = a.getGraphNode();
                SchemaRep.Key key = null;
                if (graphNode != null)
                    key = (SchemaRep.Key)
                        graphNode.searchExtraData(SchemaRep.Key.class);
                if (a.isBean &&
                    ((key != null) || (mp != null && mp.isKey()))) {
                    //System.out.println("mp for "+a.name);
                    //System.out.println(mp.dumpBeanNode());
                    config.messageOut.println("Found key: "+key);
                    SchemaRep.Selector selector = (SchemaRep.Selector)
                        key.findSubElement(SchemaRep.Selector.class);
                    SchemaRep.Field field = (SchemaRep.Field)
                        key.findSubElement(SchemaRep.Field.class);
                    genFinder(a, graphNode, attr, key.getElementName(),
                              baseType, a.name,
                              selector.getXPath(), field.getXPath(), false);
                }
            }  // end if (indexed)
            genDefaultsAccessable(a);

            if (a.isBean) {
                genNewMethod(a.getPropertyInterface(), baseType,
                             getTypeFullClassName(a));
            }
        }
        if (config.isKeepElementPositions()) {
            select(DECL_SECTION);
            jw.writeEol("private java.lang.Object[] elementsByPosition = new java.lang.Object[0]");  // we might be storing String, int's, and beans in there.
            jw.writeEol("private int[] elementTypesByPosition = new int[0]");
        }
        if (beanElement.isRoot && !config.isMinFeatures()) {
            select(DECL_SECTION);
            jw.write("private java.lang.String schemaLocation");
            if (mdd.getSchemaLocation() != null) {
                jw.write(" = ");
                jw.write(JavaUtil.instanceFrom("java.lang.String",
                                               mdd.getSchemaLocation()));
            }
            jw.eol();
            select(ACCESS_SECTION);
            jw.beginMethod("_setSchemaLocation", "String location", null, "void", jw.PUBLIC);
            jw.writeEol("schemaLocation = location");
            genMadeChange();
            jw.end();
            jw.cr();
            
            jw.beginMethod("_getSchemaLocation", "", null, "String", jw.PUBLIC);
            jw.writeEol("return schemaLocation");
            jw.endMethod();
        }
        if (config.isGenerateParentRefs()) {
            select(DECL_SECTION);
            String parentType = parentBeanType();
            jw.writeEol("private ", parentType, " parent");
            select(BODY_SECTION);
            jw.beginMethod("_setParent", parentType+" parent");
            jw.writeEol("this.parent = parent");
            jw.endMethod();

            jw.beginMethod("_getXPathExpr", "", null, "String", jw.PUBLIC);
            jw.beginIf("parent == null");
            jw.writeEol("return \"/", beanElement.node.getName(), "\"");
            jw.endElseBegin();
            jw.writeEol("String parentXPathExpr = parent._getXPathExpr()");
            jw.writeEol("String myExpr = parent.nameChild(this, false, false, true)");
            jw.writeEol("return parentXPathExpr + \"/\" + myExpr");
            jw.end();
            jw.endMethod();

            jw.beginMethod("_getXPathExpr", "Object childObj", null, "String", jw.PUBLIC);
            jw.writeEol("String childName = nameChild(childObj, false, false, true)");
            jw.beginIf("childName == null");
            jw.writeEol("throw new IllegalArgumentException(\"childObj (\"+childObj.toString()+\") is not a child of this bean ("+className+").\")");
            jw.end();
            jw.writeEol("return _getXPathExpr() + \"/\" + childName");
            jw.endMethod();
        }

        // Look for finders
        for (Iterator it = beanElement.getGraphNode().extraDataIterator(); it.hasNext(); ) {
            Object data = it.next();
            if (data instanceof BeanBuilder.Finder) {
                BeanBuilder.Finder finder = (BeanBuilder.Finder) data;
                //System.out.println("Found finder: "+finder);
                genFinder(beanElement.getGraphNode(), finder);
            }
        }
    }

    protected void genFinder(GraphNode startingGraphNode,
                             BeanBuilder.Finder finder) throws IOException {
        genFinder(startingGraphNode,
                  finder.getFindExpr(), finder.getByExpr(),
                  finder.isListFindExpr());
    }
    
    protected void genFinder(GraphNode startingGraphNode,
                             String selectorXPath, String fieldXPath,
                             boolean isListFindExpr) throws IOException {
        genFinder(null, startingGraphNode, null, null, null, null,
                  selectorXPath, fieldXPath, isListFindExpr);
    }
    
    protected void genFinder(Property a, GraphNode startingGraphNode,
                             String attr, String keyName, String returnType,
                             String nameToFind,
                             String selectorXPath, String fieldXPath,
                             boolean isListFindExpr) throws IOException {
        String dtdName = null;
        String keyVar = null;
        String keyType = null;
        String keyTypeInterface = null;
        List xpathChain = null;

        GraphNode graphNode = startingGraphNode;
        Property selectorProp = null;
        if (graphNode != null && graphNode.getGraphLink() != null) {
            xpathChain = new LinkedList();
            GraphLink gl = null;
            for (Iterator it = graphNode.getGraphLink().xPathIterator(selectorXPath);
                 it.hasNext(); ) {
                gl = (GraphLink) it.next();
                //System.out.println("selector gl="+gl);
                if (gl == null)
                    break;
                if (gl.getObject() != null)
                    xpathChain.add(gl);
            }
            if (gl != null) {
                GraphLink nextStartingLink;
                if (gl.element != null) {
                    nextStartingLink = gl.element.getGraphLink();
                } else {
                    nextStartingLink = gl;
                }
                selectorProp = (Property) gl.getObject();
                if (!fieldXPath.equals(".")) {
                    //System.out.println("nextStartingLink="+nextStartingLink);
                    for (Iterator it = nextStartingLink.xPathIterator(fieldXPath);
                         it.hasNext(); ) {
                        gl = (GraphLink) it.next();
                        //System.out.println("field gl="+gl);
                        if (gl == null) {
                            break;
                        }
                        if (gl.getObject() != null)
                            xpathChain.add(gl);
                    }
                }
                if (gl != null) {
                    //
                    // Found the final one.
                    //
                    //System.out.println("gl="+gl+" gl.name="+gl.name);
                    Property finalProp = (Property) gl.getObject();
                    if (finalProp != null) {
                        dtdName = finalProp.dtdName;
                        keyVar = finalProp.instanceOf()+"Key";
                        keyType = finalProp.getType();
                        keyTypeInterface = finalProp.getPropertyInterface();
                    } else {
                        config.messageOut.println("Warning: finalProp=null while generating finder.");
                    }
                }
            }
            if (gl == null)
                xpathChain = null;
        }
        //System.out.println("dtdName="+dtdName);

        if (dtdName == null) {
            dtdName = fieldXPath;
            keyVar = Common.convertNameInstance(dtdName);
            keyType = "String";
            jw.comment("Did not figure out proper expression to find the key.  This method may not work.");
            jw.comment("selectorXPath="+selectorXPath);
            if (selectorProp == null) {
                jw.comment("  Failed to find selector.");
            } else {
                jw.comment("  found selector property name="+selectorProp.dtdName);
            }
            jw.comment("fieldXPath="+fieldXPath);
            xpathChain = null;
        }

        if (selectorProp != null) {
            if (nameToFind == null)
                nameToFind = Common.convertName(selectorProp.dtdName);
            if (returnType == null) {
                if (selectorProp.getPropertyInterface() == null)
                    returnType = selectorProp.getType();
                else
                    returnType = selectorProp.getPropertyInterface();
            }
        }
        if (keyName == null)
            keyName = fieldXPath;
        if (returnType == null)
            returnType = "String";
        if (isListFindExpr) {
            returnType = "java.util.List/*<"+returnType+">*/";
            jw.bigComment("Search for the key.\n@return all elements found that match.");
        } else {
            jw.bigComment("Search for the key.\n@return  null if the key is not found.");
        }
        String methodName;
        if (isListFindExpr)
            methodName = "findAll"+nameToFind;
        else
            methodName = "find"+nameToFind;
        if (!keyName.equals("."))
            methodName = methodName+"By"+Common.convertName(keyName);
        String arguments;
        if (keyTypeInterface == null)
            arguments = keyType+" "+keyVar;
        else
            arguments = keyTypeInterface+" "+keyVar+"Interface";
        jw.beginMethod(methodName,
                       arguments, null, returnType,
                       jw.PUBLIC | jw.BEANINFO);
        if (keyTypeInterface != null)
            jw.writeEol(keyVar, " = ("+keyType, ") ", keyVar+"Interface");
        if (isListFindExpr)
            jw.writeEol("java.util.List _result = new java.util.ArrayList()");
        String lastVar, topVar;
        if (attr != null) {
            beginAttrIterator(attr, a, "_el");
            jw.beginIf("_el == null");
            jw.writeEol("continue");
            jw.end();
            lastVar = "_el";
            topVar = "_el";
        } else {
            lastVar = "this";
            topVar = "null";
        }
                    
        if (xpathChain != null) {
            GraphLink gl = null;
            int foundIndices = 0;
            for (Iterator it = xpathChain.iterator();
                 it.hasNext(); ) {
                gl = (GraphLink) it.next();
                Property prop = (Property) gl.getObject();
                String var = prop.instanceOf()+foundIndices;
                if (attr == null && selectorProp == prop)
                    topVar = var;
                if (prop.isIndexed()) {
                    ++foundIndices;
                    jw.beginFor("int "+var+"Index = 0",
                                var+"Index < "+lastVar+".size"+prop.name+"()",
                                var+"Index++");
                }
                jw.write(prop.getType()+" "+var);
                jw.write(" = (", prop.getType(), ") ");
                jw.write(lastVar, ".");
                jw.write(prop.getReadMethod(prop.isIndexed()));
                if (prop.isIndexed())
                    jw.write("("+var+"Index)");
                else
                    jw.write("()");
                jw.eol();
                jw.beginIf(var+" == null");
                if (!it.hasNext()) {
                    jw.beginIf(keyVar, " == null");
                    if (isListFindExpr)
                        jw.writeEol("_result.add(", topVar, ")");
                    else
                        jw.writeEol("return ", topVar);
                    jw.end();
                }
                jw.writeEol("continue");
                jw.end();
                lastVar = var;
            }
            jw.beginIf(lastVar+".equals("+keyVar+")");
            if (isListFindExpr)
                jw.writeEol("_result.add(", topVar, ")");
            else
                jw.writeEol("return ", topVar);
            jw.end();
            for (; foundIndices > 0; --foundIndices)
                jw.end();
        }

        if (attr != null)
            jw.end(); // endAttrIterator
        if (isListFindExpr)
            jw.writeEol("return _result");
        else
            jw.writeEol("return ", JavaUtil.nullValueForType(returnType));
        jw.endMethod();
    }

    public void genXMLIO() throws IOException {
        select(BODY_SECTION);
        String beanName = beanElement.node.getName();
        if (beanElement.isRoot) {
            if (!config.isStandalone()) {
                jw.beginMethod("write", "org.openide.filesystems.FileObject fo",
                               "java.io.IOException", "void", jw.PUBLIC | jw.IO);
                jw.writeEol("org.openide.filesystems.FileLock lock = fo.lock()");
                jw.beginTry();
                jw.writeEol("java.io.OutputStream out = fo.getOutputStream(lock)");
                jw.writeEol("write(out)");
                jw.writeEol("out.close()");
                jw.endFinallyBegin();
                jw.writeEol("lock.releaseLock()");
                jw.end();
                jw.endMethod();

                jw.beginMethod("write", "org.openide.filesystems.FileObject dir, String filename",
                               "java.io.IOException", "void", jw.PUBLIC | jw.IO);
                jw.writeEol("org.openide.filesystems.FileObject file = dir.getFileObject(filename)");
                jw.beginIf("file == null");
                jw.writeEol("file = dir.createData(filename)");
                jw.end();
                jw.writeEol("write(file)");
                jw.endMethod();
            }

            jw.beginMethod("write", "java.io.File f",
                           "java.io.IOException", "void", jw.PUBLIC | jw.IO);
            jw.writeEol("java.io.OutputStream out = new java.io.FileOutputStream(f)");
            jw.beginTry();
            jw.writeEol("write(out)");
            jw.endFinallyBegin();
            jw.writeEol("out.close()");
            jw.end();
            jw.endMethod();

            jw.beginMethod("write", "java.io.OutputStream out",
                           "java.io.IOException", "void", jw.PUBLIC | jw.IO);
            geneol("write(out, null)");
            jw.endMethod();

            jw.beginMethod("write", "java.io.OutputStream out, String encoding",
                           "java.io.IOException", "void", jw.PUBLIC | jw.IO);
            geneol("java.io.Writer w");
            jw.beginIf("encoding == null");
            gen("encoding = \"UTF-8\"");
            eolNoI18N();
            end();
            gen("w = new java.io.BufferedWriter(new java.io.OutputStreamWriter(out, encoding))");
            eol();
            geneol("write(w, encoding)");
            geneol("w.flush()");
            jw.endMethod();

            jw.bigComment("Print this Java Bean to @param out including an XML header.\n@param encoding is the encoding style that @param out was opened with.");
            jw.beginMethod("write", "java.io.Writer out, String encoding",
                           "java.io.IOException", "void", jw.PUBLIC | jw.IO);
            gen("out.write(\"\\n\")");
            eolNoI18N();
            if (config.isProcessDocType()) {
                jw.beginIf("docType != null");
                jw.writeEol("out.write(docType.toString())");
                jw.writeEol("out.write(\"\\n\")");
                jw.end();
            }
            jw.write("writeNode(out, \"", beanName, "\", \"\")");
            eolNoI18N();
            jw.endMethod();
        }

        jw.beginMethod("writeNode", "java.io.Writer out",
                       "java.io.IOException", "void", jw.PUBLIC | jw.IO);
        jw.writeEol("String myName");
        if (config.isGenerateParentRefs())
            jw.beginIf("parent == null");
        jw.writeEol("myName = \"", beanName, "\"");
        if (config.isGenerateParentRefs()) {
            jw.endElseBegin();
            jw.writeEol("myName = parent.nameChild(this, false, true)");
            jw.beginIf("myName == null");
            jw.writeEol("myName = \"", beanName, "\"");
            jw.end();
            jw.end();
        }
        jw.write("writeNode(out, myName, \"\")");
        eolNoI18N();
        jw.endMethod();

        jw.beginMethod("writeNode",
                       "java.io.Writer out, String nodeName, String indent",
                       "java.io.IOException", "void", jw.PUBLIC | jw.IO);
        jw.writeEol("writeNode(out, nodeName, null, indent, new java.util.HashMap())");
        jw.endMethod();

        jw.bigComment("It's not recommended to call this method directly.");
        jw.beginMethod("writeNode",
                       "java.io.Writer out, String nodeName, String namespace, String indent, java.util.Map namespaceMap",
                       "java.io.IOException", "void", jw.PUBLIC | jw.IO | jw.UNSUPPORTED);
        int size = attrList.size();
        Map namespaceToPrefixTable = new HashMap();
        geneol("out.write(indent)");
        outWrite("<");
        jw.beginIf("namespace != null");
        jw.writeEol("out.write((String)namespaceMap.get(namespace))");
        outWrite(":");
        jw.end();
        geneol("out.write(nodeName)");
        if (beanElement.isRoot && getDefaultNamespace() != null) {
            jw.writeEolNoI18N("out.write(\" xmlns='\")");
            jw.writeEolNoI18N("out.write("+JavaUtil.instanceFrom("java.lang.String", getDefaultNamespace())+")");
            jw.writeEolNoI18N("out.write(\"'\")");
        }
        if (beanElement.isRoot) {
            jw.beginIf("schemaLocation != null");
            jw.writeEol("namespaceMap.put(\"http://www.w3.org/2001/XMLSchema-instance\", \"xsi\")");
            namespaceToPrefixTable.put("http://www.w3.org/2001/XMLSchema-instance",
                                       "xsi");
            jw.writeEol("out.write(\" xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xsi:schemaLocation='\")");
            jw.writeEol("out.write(schemaLocation)");
            jw.writeEolNoI18N("out.write(\"'\")");
            jw.end();
        }

        // Deal with namespaces
        boolean firstNS = true;
        for (int i = 0; i < size; i++) {
            Property a = (Property) attrList.get(i);
            boolean indexed = a.isIndexed();
            String attr = "_" + a.name;
            String type = a.getType().intern();
            String baseType = type;
            if (indexed)
                type = (baseType + "[]").intern();
            if (isTypeQName(baseType)) {
                if (firstNS) {
                    firstNS = false;
                    jw.comment("Work out any namespaces.");
                    jw.writeEol("boolean firstNSAddition = true");
                }
                if (indexed) {
                    beginAttrIterator(attr, a, "element");
                    attr = "element";
                }
                jw.beginIf(attr+" != null && "+
                           attr+".getNamespaceURI() != null && !\"\".equals(",
                           attr, ".getNamespaceURI())");
                jw.writeEol("String prefix = (String) namespaceMap.get(", attr, ".getNamespaceURI())");
                jw.beginIf("prefix == null || \"\".equals(prefix)");
                jw.writeEol("prefix = ", attr, ".getPrefix()");
                jw.beginIf("prefix == null || \"\".equals(prefix)");
                jw.writeEol("prefix = \"", a.dtdName, "_ns__\"");
                jw.end();
                jw.comment("Need to make sure it's a unique prefix too.");
                jw.writeEol("boolean changed");
                jw.write("do ");
                jw.begin();
                jw.writeEol("changed = false");
                jw.beginFor("java.util.Iterator valueIt = namespaceMap.values().iterator()",
                            "valueIt.hasNext()", "");
                jw.writeEol("String otherPrefix = (String) valueIt.next()");
                jw.beginIf("prefix.equals(otherPrefix)");
                jw.writeEol("prefix += \"_\"");
                jw.writeEol("changed = true");
                jw.end();
                jw.end();
                jw.end(false);
                jw.writeEol(" while (changed)");
                jw.beginIf("firstNSAddition");
                jw.writeEol("firstNSAddition = false");
                jw.comment("Copy on write");
                jw.writeEol("namespaceMap = new java.util.HashMap(namespaceMap)");
                jw.end();
                jw.writeEol("namespaceMap.put(", attr,
                            ".getNamespaceURI(), prefix)");
                jw.writeEol("out.write(\" xmlns:\")");
                jw.writeEol("out.write(prefix)");
                jw.writeEol("out.write(\"='\")");
                jw.writeEol("out.write(", attr, ".getNamespaceURI())");
                jw.writeEol("out.write(\"'\")");
                jw.end();
                jw.end();
                if (indexed)
                    jw.end();
            } else if (a.getNamespace() != null && !a.getNamespace().equals(getDefaultNamespace()) && !a.getNamespace().equals("http://www.w3.org/XML/1998/namespace")) {
                if (namespaceToPrefixTable.containsKey(a.getNamespace()))
                    continue;
                if (firstNS) {
                    firstNS = false;
                    jw.comment("Work out any namespaces.");
                    jw.writeEol("boolean firstNSAddition = true");
                }
                String prefix = SchemaRep.namespaceOf(a.dtdName);
                if (prefix == null) {
                    prefix = SchemaRep.guessPrefix(a.getNamespace());
                    //config.messageOut.println("Guessing prefix for "+a.getNamespace()+" is "+prefix);
                }
                jw.beginIf("namespaceMap.get(",
                           JavaUtil.instanceFrom("String",
                                                 a.getNamespace()),
                           ") == null");
                jw.beginIf("firstNSAddition");
                jw.writeEol("firstNSAddition = false");
                jw.comment("Copy on write");
                jw.writeEol("namespaceMap = new java.util.HashMap(namespaceMap)");
                jw.end();
                jw.writeEol("namespaceMap.put(",
                            JavaUtil.instanceFrom("String",
                                                  a.getNamespace()),
                            ", \"", prefix+"\")");
                outWrite(" xmlns:"+prefix+"='");
                outWrite(a.getNamespace());
                outWrite("'");
                jw.end();
                namespaceToPrefixTable.put(a.getNamespace(), prefix);
            }
        }

        List nonDirectAttributes = new LinkedList();	// List
        boolean hasSubElements = false;
        if (size > 0) {
            // Go over the attributes
            for (int i = 0; i < size; i++) {
                Property a = (Property)attrList.get(i);
                if (!a.isAttribute()) {
                    hasSubElements = true;
                    continue;
                }
                if (!a.isDirectChild()) {
                    nonDirectAttributes.add(a);
                    continue;
                }
                genWriteAttr(a);
            }
        }
        if (hasSubElements) {
            geneol("out.write(\">\\n\")");
            
            geneol("String nextIndent = indent + \""+jw.getIndent()+"\"");
            if (config.isKeepElementPositions()) {
                jw.beginFor("int position = 0, count = fetchChildCount()",
                            "position < count", "++position");
                jw.writeEol("java.lang.Object child = elementsByPosition[position]");
                jw.writeEol("int elementType = elementTypesByPosition[position]");
                jw.write("switch (elementType) ");
                jw.begin();
            }
            boolean firstUseOfIndex = true;
            for (int i = 0; i < size; i++) {
                Property a = (Property)attrList.get(i);
                if (a.isAttribute())
                    continue;
                boolean indexed = a.isIndexed();
                String attr = "_" + a.name;
                String baseAttr = attr;
	    
                boolean isScalar = a.isScalar();
                boolean isNamespaceSignificant = (a.getNamespace() != null && !a.getNamespace().equals(getDefaultNamespace()) && !a.getNamespace().equals("http://www.w3.org/XML/1998/namespace"));

                String type = a.getType().intern();
                String baseType = type;
                if (indexed)
                    type = (baseType + "[]").intern();

                if (config.isKeepElementPositions()) {
                    jw.writecr("case "+i+":");
                    jw.indentRight();
                    jw.writeEol(baseType+" a"+a.name+" = "+JavaUtil.fromObject(baseType, "child"));
                    attr = "a"+a.name;
                } else {
                    if (indexed) {
                        if (!a.isBean && a.attributes != null && a.attributes.length > 0) {
                            if (firstUseOfIndex) {
                                firstUseOfIndex = false;
                                jw.writeEol("int index = 0");
                            } else {
                                jw.writeEol("index = 0");
                            }
                        }
                        beginAttrIterator(attr, a, "element");
                        attr = "element";
                    }
                    if (!isScalar) {
                        gen("if ("+attr+" != null) ");
                        begin();
                    }
                }
                if (a.isBean) {
                    jw.write(attr, ".writeNode(out, \"", a.dtdName);
                    jw.write("\", ");
                    if (isNamespaceSignificant)
                        jw.write(JavaUtil.instanceFrom("String",
                                                       a.getNamespace()));
                    else
                        jw.write("null");
                    jw.writeEol(", nextIndent, namespaceMap)");
                } else if (a.type == Common.TYPE_COMMENT) {
                    jw.writeEol("out.write(nextIndent)");
                    jw.writeEol("out.write(\"\\n\")");
                } else if ("org.w3c.dom.Element".equals(type)) {
                    jw.writeEol("out.write(nextIndent)");
                    if (config.isUseRuntime()) {
                        jw.writeEol("org.netbeans.modules.schema2beans.XMLUtil.DOMWriter domWriter = new org.netbeans.modules.schema2beans.XMLUtil.DOMWriter()");
                        jw.writeEol("domWriter.setWriter(out)");
                        jw.writeEol("domWriter.write(", attr, ")");
                    } else {
                        jw.writeEol("out.write(", attr, ".toString())");
                    }
                    outWrite("\n");
                } else {
                    boolean needEndTag = true;
                    if (baseType == "boolean" && a.getCanBeEmpty()) {
                        jw.beginIf(attr);
                        needEndTag = false;
                    }
                    if (!a.dtdName.equals("#PCDATA")) {
                        jw.writeEol("out.write(nextIndent)");
                        if (isNamespaceSignificant) {
                            outWrite("<");
                            jw.writeEol("out.write((String)namespaceMap.get(",
                                        JavaUtil.instanceFrom("String",
                                                              a.getNamespace()),
                                        "))");
                            jw.write("out.write(\":", a.dtdName, "\")");
                        } else {
                            jw.write("out.write(\"<", a.dtdName, "\")");
                        }
                        eolNoI18N();
                        if (isTypeQName(baseType)) {
                            jw.writeEol("String nsPrefix", attr, " = null");
                            jw.beginIf(attr+".getNamespaceURI() != null && !\"\".equals(",
                                        attr, ".getNamespaceURI())");
                            jw.write("nsPrefix", attr, " = (String) namespaceMap.get(");
                            jw.writeEol(attr, ".getNamespaceURI())");
                            jw.end();
                        }
                        for (int attrNum = 0; attrNum < a.attributes.length; ++attrNum) {
                            AttrProp myAttrProp = a.attributes[attrNum];
                            //jw.comment("myAttrProp="+myAttrProp);
                            for (Iterator it = nonDirectAttributes.iterator(); it.hasNext(); ) {
                                Property attrProperty = (Property) it.next();
                                AttrProp attrProp = attrProperty.getAttrProp();
                                if (myAttrProp == attrProp) {
                                    String varName;
                                    if (attrProperty.isIndexed()) {
                                        jw.beginIf("index < size"+attrProperty.name+"()");
                                        varName = attrProperty.getReadMethod(true)+"(index)";
                                    } else
                                        varName = "_"+attrProperty.name;
                                    genWriteAttr(attrProperty, varName);
                                    if (attrProperty.isIndexed()) {
                                        jw.end();
                                    }
                                }
                            }
                        }
                        if (needEndTag) {
                            gen("out.write(\">\")");
                            eolNoI18N();
                        }
                    }
                    if (!needEndTag) {
                        // no end tag, then no contents
                    } else {
                        genWriteType(a, attr, false);
                    }
                    if (!needEndTag) {
                        gen("out.write(\"/>\\n\")");
                        eolNoI18N();
                        end();
                    } else if (!a.dtdName.equals("#PCDATA")) {
                        if (isNamespaceSignificant) {
                            outWrite("\\n\")");
                        } else {
                            jw.write("out.write(\"\\n\")");
                        }
                        eolNoI18N();
                    }
                }
                if (config.isKeepElementPositions()) {
                    jw.writeEol("break");
                    jw.indentLeft();
                } else {
                    if (a.isNillable()) {
                        if (!isScalar) {
                            jw.endElseBegin();
                            jw.writeEol("out.write(nextIndent)");
                            jw.writeEol("out.write(\"<", a.dtdName, " xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xsi:nil='true'/>\\n\")");
                        }
                    }
                    if (!isScalar)
                        end();
                    if (indexed) {
                        if (!a.isBean && a.attributes != null && a.attributes.length > 0) {
                            jw.writeEol("++index");
                        }
                        end();
                    }
                }
            }
            if (config.isKeepElementPositions()) {
                jw.end();
                jw.end();
            }
            geneol("out.write(indent)");
            outWrite("\n");
        } else {
            geneol("out.write(\"/>\\n\")");
        }
        end();
        cr();

        // Generate for reading
        if (beanElement.isRoot) {
            String exceps = "javax.xml.parsers.ParserConfigurationException, org.xml.sax.SAXException, java.io.IOException";
            if (config.isVetoable())
                exceps += ", java.beans.PropertyVetoException";

            if (!config.isStandalone()) {
                jw.beginMethod("read", "org.openide.filesystems.FileObject fo",
                               exceps, className, jw.PUBLIC | jw.STATIC | jw.IO);
                jw.writeEol("java.io.InputStream in = fo.getInputStream()");
                jw.beginTry();
                jw.writeEol("return read(in)");
                jw.endFinallyBegin();
                jw.writeEol("in.close()");
                jw.end();
                jw.endMethod();
            }

            jw.beginMethod("read", "java.io.File f",
                           exceps, className, jw.PUBLIC | jw.STATIC | jw.IO);
            jw.writeEol("java.io.InputStream in = new java.io.FileInputStream(f)");
            jw.beginTry();
            jw.writeEol("return read(in)");
            jw.endFinallyBegin();
            jw.writeEol("in.close()");
            jw.end();
            jw.endMethod();

            jw.beginMethod("read", "java.io.InputStream in", exceps, className,
                           jw.PUBLIC | jw.STATIC | jw.IO);
            geneol("return read(new org.xml.sax.InputSource(in), false, null, null)");
            end();
            cr();

            jw.bigComment("Warning: in readNoEntityResolver character and entity references will\nnot be read from any DTD in the XML source.\nHowever, this way is faster since no DTDs are looked up\n(possibly skipping network access) or parsed.");
            jw.beginMethod("readNoEntityResolver", "java.io.InputStream in",
                           exceps, className,
                           jw.PUBLIC | jw.STATIC | jw.IO);
            gencr("return read(new org.xml.sax.InputSource(in), false,");
            tabIn();
            gen("new org.xml.sax.EntityResolver() ");
            begin();
            gen("public org.xml.sax.InputSource resolveEntity(String publicId, String systemId) ");
            begin();
            geneol("java.io.ByteArrayInputStream bin = new java.io.ByteArrayInputStream(new byte[0])");
            geneol("return new org.xml.sax.InputSource(bin)");
            end();
            end();
            tabIn();
            geneol(", null)");
            end();
            cr();

            jw.beginMethod("read",
                           "org.xml.sax.InputSource in, boolean validate, org.xml.sax.EntityResolver er, org.xml.sax.ErrorHandler eh",
                           exceps, className,
                           jw.PUBLIC | jw.STATIC | jw.IO);
            geneol("javax.xml.parsers.DocumentBuilderFactory dbf = javax.xml.parsers.DocumentBuilderFactory.newInstance()");
            geneol("dbf.setValidating(validate)");
            geneol("dbf.setNamespaceAware(true)");
            geneol("javax.xml.parsers.DocumentBuilder db = dbf.newDocumentBuilder()");
            gen("if (er != null)");
            tabIn();
            geneol("db.setEntityResolver(er)");
            gen("if (eh != null)");
            tabIn();
            geneol("db.setErrorHandler(eh)");
            geneol("org.w3c.dom.Document doc = db.parse(in)");
            geneol("return read(doc)");
            end();
            cr();

            exceps = null;
            if (config.isVetoable())
                exceps = "java.beans.PropertyVetoException";
            jw.beginMethod("read", "org.w3c.dom.Document document",
                           exceps, className, jw.PUBLIC | jw.STATIC | jw.IO);
            jw.writeEol(className, " a", className, " = new "+className+"()");
            jw.writeEol("a", className, ".readFromDocument(document)");
            jw.writeEol("return a", className);
            jw.endMethod();
            
            jw.beginMethod("readFromDocument", "org.w3c.dom.Document document",
                           exceps, "void", jw.PROTECTED);
            if (config.isProcessDocType()) {
                String fullDocTypeName;
                if (packageName == null)
                    fullDocTypeName = className+".DocType";
                else
                    fullDocTypeName = packageName+"."+className+".DocType";
                jw.writeEol("org.w3c.dom.NodeList children = document.getChildNodes()");
                jw.writeEol("int length = children.getLength()");
                jw.beginFor("int i = 0", "i < length", "++i");
                jw.beginIf("children.item(i) instanceof org.w3c.dom.DocumentType");
                jw.writeEol("docType = new "+fullDocTypeName+"((org.w3c.dom.DocumentType)children.item(i))");
                jw.writeEol("break");
                jw.end();
                jw.end();
            }
            geneol("readNode(document.getDocumentElement())");
            end();
            cr();
        }

        jw.beginMethod("readNode", "org.w3c.dom.Node node",
                       config.isVetoable() ? "java.beans.PropertyVetoException" : null,
                       "void", jw.PUBLIC | jw.IO);
        jw.writeEol("readNode(node, new java.util.HashMap())");
        jw.endMethod();

        jw.beginMethod("readNode", "org.w3c.dom.Node node, java.util.Map namespacePrefixes",
                       config.isVetoable() ? "java.beans.PropertyVetoException" : null,
                       "void", jw.PUBLIC | jw.IO);
        // Go over attributes
        beginAttrProcessing("node");
        jw.writeEol("boolean firstNamespaceDef = true");
        genUpdateNamespaces("namespacePrefixes", "firstNamespaceDef");
        
        int attrCount = 0;
        if (beanElement.isRoot) {
            ++attrCount;
            jw.writeEol("String xsiPrefix = \"xsi\"");
            jw.beginFor("java.util.Iterator it = namespacePrefixes.keySet().iterator()",
                        "it.hasNext()", "");
            jw.writeEol("String prefix = (String) it.next()");
            jw.writeEol("String ns = (String) namespacePrefixes.get(prefix)");
            jw.beginIf("\"http://www.w3.org/2001/XMLSchema-instance\".equals(ns)");
            jw.writeEol("xsiPrefix = prefix");
            jw.writeEol("break");
            jw.end();
            jw.end();
            genReadAttr("schemaLocation", "String",
                        "\"+xsiPrefix+\":schemaLocation",
                        "node", null, false, null, false, null);
        }
        boolean hasNillableElement = false;
        for (int i = 0; i < size; i++) {
            Property a = (Property)attrList.get(i);
            if (a.isNillable())
                hasNillableElement = true;
            if (!a.isAttribute())
                continue;
            if (!a.isDirectChild())
                continue;
            ++attrCount;
            genReadAttr(a, "node");
        }
        jw.end();
        if (hasSubElements) {
            // FIXME: Should deal with the situation where we get 2 "foo" elements
            //        and the schema only mentioned 1.
            Map dtdNames = new HashMap();
            boolean hasDuplicateDtdNames = config.isKeepElementPositions();
            boolean hasQNameType = false;
            for (int i = 0; i < size; i++) {
                Property a = (Property)attrList.get(i);
                if (isTypeQName(a.getType()))
                    hasQNameType = true;
                if (a.isAttribute() || a.type == Common.TYPE_COMMENT)
                    continue;
                if (dtdNames.containsKey(a.dtdName)) {
                    //jw.comment(a.dtdName+" has duplicates");
                    hasDuplicateDtdNames = true;
                }
                dtdNames.put(a.dtdName, a);
            }
            geneol("org.w3c.dom.NodeList children = node.getChildNodes()");
            if (hasDuplicateDtdNames)
                jw.writeEol("int lastElementType = -1");
            if (config.isKeepElementPositions()) {
                jw.writeEol("int elementPosition = 0");
                jw.writeEol("elementsByPosition = new java.lang.Object[children.getLength()]");
                jw.writeEol("elementTypesByPosition = new int[children.getLength()]");
            }
            jw.beginFor("int i = 0, size = children.getLength()",
                        "i < size", "++i");
            geneol("org.w3c.dom.Node childNode = children.item(i)");
            geneol("String childNodeName = (childNode.getLocalName() == null ? childNode.getNodeName().intern() : childNode.getLocalName().intern())");
            geneol("String childNodeValue = \"\"");
            jw.beginIf("childNode.getFirstChild() != null");
            geneol("childNodeValue = childNode.getFirstChild().getNodeValue()");
            jw.end();
            if (hasNillableElement || hasQNameType ||
                nonDirectAttributes.size() > 0)
                declareAttrsForRead("childNode");
            boolean first = true;
            Property anyProp = null; // Is this an any property?
            for (int i = 0; i < size; i++) {
                Property a = (Property)attrList.get(i);
                if (a.isAttribute())
                    continue;
                boolean   	indexed = a.isIndexed();
                String attr = "_" + a.name;
                String baseAttr = attr;
                boolean isScalar = a.isScalar();

                String type = a.getType().intern();
                String baseType = type;
                if (indexed)
                    type = (baseType + "[]").intern();

                if (baseType == "org.w3c.dom.Element") {
                    anyProp = a;
                    continue;
                }
                if (first) first = false; else gen("else ");
                jw.write("if (");
                if (hasDuplicateDtdNames && dtdNames.get(a.dtdName) != a) {
                    int alwaysBeforeElementType;
                    if (indexed) {
                        // Keep reading in elements into this slot, until
                        // there's another element that says to go on.
                        alwaysBeforeElementType = i + 1;
                    } else {
                        // Force it to goto the next slot.
                        alwaysBeforeElementType = i;
                    }
                    jw.write("lastElementType < "+alwaysBeforeElementType,
                             " && ");
                }
                if (a.dtdName.equals("#PCDATA"))
                    jw.write("childNode instanceof org.w3c.dom.CharacterData");
                else if (a.type == Common.TYPE_COMMENT)
                    jw.write("childNode instanceof org.w3c.dom.Comment");
                else
                    jw.write("childNodeName == \""+a.dtdName+"\"");
                jw.write(") ");
                begin();
                String var;
                if (a.isNillable()) {
                    jw.writeEol("org.w3c.dom.Attr nilAttr = (org.w3c.dom.Attr) attrs.getNamedItem(\"xsi:nil\")");
                    jw.beginIf("nilAttr == null || !\"true\".equals(nilAttr.getValue())");
                }
                if (indexed) {
                    var = "a"+a.name;
                    if (a.isBean) {
                        jw.write(baseType, " ");
                    } else {
                        geneol(baseType+" "+var);
                    }
                } else {
                    var = attr;
                }
                if (a.isBean) {
                    jw.write(var, " = ");
                    genNewDefault(a, true);
                    jw.eol();
                    if (config.isGeneratePropertyEvents()) {
                        geneol(var+"._setPropertyChangeSupport(eventListeners)");
                        if (config.isVetoable())
                            geneol(var+"._setVetoableChangeSupport(vetos)");
                    }
                    if (config.isGenerateParentRefs())
                        jw.writeEol(var+"._setParent(this)");
                }
                boolean generatedSet = true;
                if (a.isBean)
                    geneol(var+".readNode(childNode, namespacePrefixes)");
                else if (a.dtdName.equals("#PCDATA")) {
                    geneol(var+" = ((org.w3c.dom.CharacterData)childNode).getData()");
                } else if (a.type == Common.TYPE_COMMENT) {
                    geneol(var+" = ((org.w3c.dom.CharacterData)childNode).getData()");
                } else {
                    if (config.isTrimNonStrings() &&
                        baseType != "String" && baseType != "java.lang.String") {
                        jw.writeEol("childNodeValue = childNodeValue.trim()");
                    }
                    List exceps = JavaUtil.exceptionsFromParsingText(baseType);
                    if (!exceps.isEmpty()) {
                        jw.beginTry();
                    }
                    if (baseType == "boolean" || baseType == "java.lang.Boolean") {
                        gencr("if (childNode.getFirstChild() == null)");
                        tabIn();
                        if (baseType == "boolean")
                            geneol(var+" = true");
                        else
                            geneol(var+" = Boolean.TRUE");
                        gencr("else");
                        tabIn();
                    }
                    generatedSet = genReadType(baseType, var, "childNodeValue",
                                               false, null,
                                               isScalar,
                                               (SchemaRep.EncodingStyle) a.searchExtraData(SchemaRep.EncodingStyle.class));
                        SchemaRep.WhiteSpace ws = (SchemaRep.WhiteSpace) a.searchExtraData(SchemaRep.WhiteSpace.class);
                        if (ws != null)
                            genWhiteSpaceRestriction(ws, var, baseType);
                        //}
                    int directAttrCount = 0;
                    for (int attrNum = 0; attrNum < a.attributes.length; ++attrNum) {
                        AttrProp myAttrProp = a.attributes[attrNum];
                        //jw.comment("myAttrProp="+myAttrProp);
                        for (Iterator it = nonDirectAttributes.iterator(); it.hasNext(); ) {
                            Property attrProperty = (Property) it.next();
                            AttrProp attrProp = attrProperty.getAttrProp();
                            if (myAttrProp == attrProp) {
                                ++directAttrCount;
                                genReadAttr(attrProperty, "childNode");
                            }
                        }
                    }
                
                    if (!exceps.isEmpty()) {
                        end();
                        genRethrowExceptions(exceps);
                    }
                }
                if (indexed && generatedSet)
                    jw.writeEol(attr, ".add(",
                                JavaUtil.toObject(var, baseType,
                                                  config.isForME()),
                                ")");
                if (a.isNillable()) {
                    jw.endElseBegin();
                    if (indexed)
                        jw.writeEol(attr, ".add(null)");
                    else
                        jw.writeEol(var, " = ", JavaUtil.nullValueForType(baseType));
                    jw.end();
                }
                if (hasDuplicateDtdNames)
                    jw.writeEol("lastElementType = "+i);
                if (config.isKeepElementPositions()) {
                    jw.writeEol("elementsByPosition[elementPosition] = "+JavaUtil.toObject(var, type, config.isForME()));
                    jw.writeEol("elementTypesByPosition[elementPosition++] = "+i);
                }
                end();
            }
            if (anyProp != null) {
                String attr = "_" + anyProp.name;
                boolean	indexed = anyProp.isIndexed();
                if (first) first = false; else gen("else ");
                jw.beginIf("childNode instanceof org.w3c.dom.Element");
                if (indexed)
                    jw.writeEol(attr, ".add(childNode)");
                else
                    jw.writeEol(attr, " = (org.w3c.dom.Element) childNode");
                jw.end();
            }
            if (!first) {
                gen("else ");
                begin();
                comment("Found extra unrecognized childNode");
                /*
                jw.writeEol("System.out.println(\"Found extra unrecognized childNode: \"+childNodeName)");
                jw.writeEol("System.out.println(\"namespaceURI=\"+childNode.getNamespaceURI())");
                jw.writeEol("System.out.println(\"prefix=\"+childNode.getPrefix())");
                jw.writeEol("System.out.println(\"localName=\"+childNode.getLocalName())");
                jw.writeEol("System.out.println(\"nodeName=\"+childNode.getNodeName())");
                */
                end();
            }
            end();
            if (config.isKeepElementPositions()) {
                jw.beginFor("", "elementPosition < elementTypesByPosition.length",
                            "++elementPosition");
                jw.writeEol("elementTypesByPosition[elementPosition] = "+elementTypeSetnull);
                jw.end();
            }
        }
        end();
        cr();
        if (beanElement.isRoot) {
            if (!config.isUseRuntime())
                genPrintXML();
            genSpecialTypes();
        }
    }

    protected void genUpdateNamespaces(String namespaceMapName,
                                       String firstNamespaceVarName) throws IOException {
        jw.beginFor("int attrNum = 0", "attrNum < attrs.getLength()",
                    "++attrNum");
        jw.writeEol("attr = (org.w3c.dom.Attr) attrs.item(attrNum)");
        jw.writeEol("String attrName = attr.getName()");
        //jw.writeEol("System.out.println(\"attrName=\"+attrName)");
        jw.beginIf("attrName.startsWith(\"xmlns:\")");
        if (firstNamespaceVarName != null) {
            jw.beginIf(firstNamespaceVarName);
            jw.writeEol(firstNamespaceVarName, " = false");
            jw.comment("Dup prefix map, so as to not write over previous values, and to make it easy to clear out our entries.");
            jw.writeEol(namespaceMapName, " = new java.util.HashMap(", namespaceMapName, ")");
            jw.end();
        }
        jw.writeEol("String attrNSPrefix = attrName.substring(6, attrName.length())");
        jw.writeEol(namespaceMapName, ".put(attrNSPrefix, attr.getValue())");
        jw.end();
        jw.end();
    }

    protected void genWriteAttr(Property a) throws IOException {
        genWriteAttr(a, "_"+a.name);
    }
    
    protected void genWriteAttr(Property a, String varName) throws IOException {
        boolean isScalar = a.isScalar();
        String dtdName = a.dtdName;
        String namespace = a.getNamespace();

        comment(dtdName+" is an attribute with namespace "+namespace);
        if (!isScalar) {
            gen("if ("+varName+" != null) ");
            begin();
        }
        if (namespace != null && !namespace.equals(getDefaultNamespace()) && !namespace.equals("http://www.w3.org/XML/1998/namespace")) {
            dtdName = SchemaRep.removeNamespace(dtdName);
            outWrite(" ");
            jw.writeEol("out.write((String)namespaceMap.get(",
                     JavaUtil.instanceFrom("String", namespace),
                     "))");
            jw.writeEol("out.write(\":", dtdName, "='\")");
        } else {
            jw.writeEol("out.write(\" ", dtdName, "='\")");
        }
        genWriteType(a, varName, true);
        gen("out.write(\"'\")");
        eolNoI18N();
        if (!isScalar) {
            end();
        }
    }

    protected void genWriteType(Property a, String varName,
                                boolean isAttribute) throws IOException {
        String type = a.getType();
        boolean isScalar = a.isScalar();

        if (isScalar || JavaUtil.canProduceNoXMLMetaChars(type)) {
            jw.write("out.write("+JavaUtil.typeToString(type, varName));
            jw.writeEol(")");
        } else if (isTypeQName(type)) {
            jw.beginIf(varName+".getNamespaceURI() != null && !\"\".equals(",
                       varName, ".getNamespaceURI())");
            jw.writeEol("out.write((String) namespaceMap.get(", varName,
                        ".getNamespaceURI()))");
            jw.writeEol("out.write(\":\")");
            jw.end();
            if (config.isUseRuntime())
                jw.write("org.netbeans.modules.schema2beans.XMLUtil");
            else
                jw.write(getRootClassName());
            jw.write(".writeXML(out, ");
            jw.write(varName, ".getLocalPart(), "+isAttribute);
            jw.writeEol(")");
        } else if ("byte[]".equals(type)) {
            // Is this hexBinary or base64Binary?
            SchemaRep.EncodingStyle style = (SchemaRep.EncodingStyle) a.searchExtraData(SchemaRep.EncodingStyle.class);
            if (style instanceof SchemaRep.HexBinary) {
                jw.beginFor("int byteIndex = 0", "byteIndex < "+varName+".length",
                            "++byteIndex");
                jw.writeEol("int belement = (int) ", varName, "[byteIndex]");
                jw.beginIf("belement < 0");
                jw.writeEol("belement += 256");
                jw.end();
                jw.beginIf("belement < 16");
                jw.writeEol("out.write(\"0\")");
                jw.end();
                jw.writeEol("out.write(Integer.toHexString(belement).toUpperCase())");
                jw.end();
            } else if (style instanceof SchemaRep.Base64Binary) {
                jw.write("out.write(");
                jw.write(getRootClassName());
                jw.write(".encodeBase64BinaryString(");
                jw.write(varName);
                jw.write(")");
                jw.writeEol(")");
            } else {
                config.messageOut.println("Unknown encoding style for "+type+" for property "+a.name);
            }
        } else {
            if (config.isUseRuntime())
                jw.write("org.netbeans.modules.schema2beans.XMLUtil");
            else
                jw.write(getRootClassName());
            jw.write(".writeXML(out, ");
            if ("java.util.Calendar".equals(type)) {
                jw.write(getRootClassName());
                jw.write(".calendarToString(");
                jw.write(varName);
                jw.write(")");
            } else {
                jw.write(JavaUtil.typeToString(type, varName));
            }
            jw.write(", "+isAttribute);
            jw.writeEol(")");
        }
    }

    protected void beginAttrProcessing(String nodeName) throws IOException {
        jw.beginIf(nodeName, ".hasAttributes()");
        declareAttrsForRead(nodeName);
    }

    protected void genReadAttr(Property a, String nodeName) throws IOException {
        genReadAttr("_" + a.name, a.getType().intern(), a.dtdName, nodeName,
                    (SchemaRep.WhiteSpace) a.searchExtraData(SchemaRep.WhiteSpace.class),
                    a.isIndexed(), a.getAddMethod(), a.isScalar(),
                    (SchemaRep.EncodingStyle) a.searchExtraData(SchemaRep.EncodingStyle.class));
    }

    protected void genReadAttr(String attr, String type, String dtdName,
                               String nodeName,
                               SchemaRep.WhiteSpace ws,
                               boolean isIndexed,
                               String addMethod, boolean isScalar,
                               SchemaRep.EncodingStyle style) throws IOException {
        String baseType = type;
        jw.writeEol("attr = (org.w3c.dom.Attr) attrs.getNamedItem(\"",
                    dtdName, "\")");
        List exceps = JavaUtil.exceptionsFromParsingText(baseType);
        String var = "attrValue";
        jw.beginIf("attr != null");
        jw.writeEol("attrValue = attr.getValue()");
        if (ws != null) {
            genWhiteSpaceRestriction(ws, var, "java.lang.String");
        }
        if (isIndexed) {
            jw.endElseBegin();
            jw.writeEol("attrValue = null");
            jw.end();
        }
        if (!exceps.isEmpty()) {
            jw.beginTry();
        }
        genReadType(baseType, attr, var, isIndexed, addMethod, isScalar, style);
        if (!exceps.isEmpty()) {
            jw.end();
            genRethrowExceptions(exceps);
        }
        if (!isIndexed)
            jw.end();
    }

    /**
     * @return whether or not a setter was generated.
     */
    protected boolean genReadType(String type, String var, String expr,
                               boolean isIndexed, String addMethod,
                               boolean isScalar, SchemaRep.EncodingStyle style) throws IOException {
        type = type.intern();
        if (isIndexed) {
            jw.writeEol(type, " processedValueFor", var);
            if (genReadType(type, "processedValueFor"+var, expr, false, null,
                            isScalar, style)) {
                jw.writeEol(addMethod, "(processedValueFor", var, ")");
            }
        } else if (isTypeQName(type)) {
            jw.writeEol("int colonPos = ", expr, ".indexOf(':')");
            //jw.writeEol("System.out.println(\"colonPos=\"+colonPos+\" childNodeValue=\"+childNodeValue)");
            jw.beginIf("colonPos < 0");
            jw.write(var, " = new ", type);
            jw.writeEol("(", expr, ")");
            jw.endElseBegin();
            jw.writeEol("java.util.Map nsPrefixes = new java.util.HashMap(namespacePrefixes)");
            genUpdateNamespaces("nsPrefixes", null);
            jw.writeEol("String prefix = ", expr, ".substring(0, colonPos)");
            jw.writeEol("String ns = (String) nsPrefixes.get(prefix)");
            //jw.writeEol("System.out.println(\"prefix=\"+prefix+\" ns=\"+ns)");
            jw.write("String localPart = ", expr);
            jw.writeEol(".substring(colonPos+1, ", expr, ".length())");
            jw.writeEol(var, " = new ", type, "(ns, localPart, prefix)");
            jw.end();
        } else if (type == "byte[]") {
            // Is this hexBinary or base64Binary?
            if (style instanceof SchemaRep.HexBinary) {
                // example: 07FB
                jw.writeEol(var, " = new byte[(childNodeValue.length()+1) / 2]");
                jw.beginFor("int byteIndex = 0", "byteIndex < "+var+".length",
                            "++byteIndex");
                jw.writeEol("String octet = childNodeValue.substring(byteIndex * 2, byteIndex * 2 + 2)");
                jw.writeEol(var, "[byteIndex] = Integer.valueOf(octet, 16).byteValue()");
                jw.end();
            } else if (style instanceof SchemaRep.Base64Binary) {
                jw.write(var, " = ");
                jw.write(getRootClassName());
                jw.writeEol(".decodeBase64BinaryString(childNodeValue)");
            } else {
                config.messageOut.println("Unknown encoding style for "+type+" for "+var);
            }
        } else if ((!isScalar && !JavaUtil.isInstantiable(type)
                    && type != "java.util.Calendar") ||
                   type == "org.netbeans.modules.schema2beansdev.beangraph.BeanGraph" ||
                   type == "org.netbeans.modules.schema2beansdev.metadd.MetaDD" ||
                   type == "java.io.PrintStream") {
            config.messageOut.println("Warning: Don't know how to create a "+type);
            jw.comment("Don't know how to create a "+type);
            return false;
        } else {
            if (type == "java.util.Calendar") {
                jw.write(var, " = ");
                jw.write(getRootClassName());
                jw.writeEol(".stringToCalendar(", expr, ")");
            } else {
                jw.writecr(JavaUtil.genParseText(type, expr, var,
                                                 config.isForME()));
            }
        }
        return true;
    }

    protected void declareAttrsForRead(String nodeName) throws IOException {
        jw.writeEol("org.w3c.dom.NamedNodeMap attrs = ", nodeName, ".getAttributes()");
        jw.writeEol("org.w3c.dom.Attr attr");
        jw.writeEol("java.lang.String attrValue");
    }

    public void genPrintXML() throws IOException {
        jw.bigComment("Takes some text to be printed into an XML stream and escapes any\ncharacters that might make it invalid XML (like '<').");
        jw.beginMethod("writeXML", "java.io.Writer out, String msg", "java.io.IOException", "void", jw.PUBLIC | jw.STATIC | jw.IO);
        geneol("writeXML(out, msg, true)");
        end();
        cr();
        jw.beginMethod("writeXML", "java.io.Writer out, String msg, boolean attribute",  "java.io.IOException", "void", jw.PUBLIC | jw.STATIC | jw.IO);
        gencr("if (msg == null)");
        tabIn();
        geneol("return");
        geneol("int msgLength = msg.length()");
        jw.beginFor("int i = 0", "i < msgLength", "++i");
        geneol("char c = msg.charAt(i)");
        geneol("writeXML(out, c, attribute)");
        end();
        end();
        cr();
        jw.beginMethod("writeXML", "java.io.Writer out, char msg, boolean attribute", "java.io.IOException", "void", jw.PUBLIC | jw.STATIC | jw.IO);
        gencr("if (msg == '&')");
        tabIn();
        geneol("out.write(\"&\")");
        gencr("else if (msg == '<')");
        tabIn();
        geneol("out.write(\"<\")");
        gencr("else if (msg == '>')");
        tabIn();
        geneol("out.write(\">\")");
        gen("else ");
        jw.beginIf("attribute");
        gencr("if (msg == '\"')");
        tabIn();
        geneol("out.write(\""\")");
        gencr("else if (msg == '\\'')");
        tabIn();
        geneol("out.write(\"'\")");
        gencr("else if (msg == '\\n')");
        tabIn();
        geneol("out.write(\"
\")");
        gencr("else if (msg == '\\t')");
        tabIn();
        geneol("out.write(\"	\")");
        gencr("else");
        tabIn();
        geneol("out.write(msg)");
        jw.end();
        gencr("else");
        tabIn();
        geneol("out.write(msg)");
        jw.endMethod();
    }

    protected void outWrite(String text) throws IOException {
        jw.writeEol("out.write(",
                    JavaUtil.instanceFrom("String", text),
                    ")");
    }

    /**
     * Generate stuff for special types as needed.
     */
    public void genSpecialTypes() throws IOException {
        if (rootBeanElement.isUsedType("java.util.Calendar")) {
            JavaBeansUtil.genReadType(jw, "java.util.Calendar");
            JavaBeansUtil.genWriteType(jw, "java.util.Calendar");
            jw.cr();
        }
        if (rootBeanElement.isUsedType("byte[]")) {
            JavaBeansUtil.genReadType(jw, "base64Binary");
            JavaBeansUtil.genWriteType(jw, "base64Binary");
            jw.cr();
        }
    }

    public void genValidate() throws IOException {
        select(BODY_SECTION);
        if (beanElement.isRoot && !config.isUseRuntime()) {
            String commonBeanType = commonBeanType();
            jw.write("public static class ValidateException extends Exception ");
            jw.begin();
            jw.write("private ", commonBeanType);
            jw.writeEol(" failedBean");
            jw.writeEol("private String failedPropertyName");
            jw.writeEol("private FailureType failureType");
            jw.write("public ValidateException(String msg, String failedPropertyName, ", commonBeanType, " failedBean) ");
            jw.begin();
            jw.writeEol("super(msg)");
            jw.writeEol("this.failedBean = failedBean");
            jw.writeEol("this.failedPropertyName = failedPropertyName");
            jw.end();
            jw.write("public ValidateException(String msg, FailureType ft, String failedPropertyName, ", commonBeanType, " failedBean) ");
            jw.begin();
            jw.writeEol("super(msg)");
            jw.writeEol("this.failureType = ft");
            jw.writeEol("this.failedBean = failedBean");
            jw.writeEol("this.failedPropertyName = failedPropertyName");
            jw.end();
            jw.writecr("public String getFailedPropertyName() {return failedPropertyName;}");
            jw.writecr("public FailureType getFailureType() {return failureType;}");
            jw.write("public ", commonBeanType);
            jw.writecr(" getFailedBean() {return failedBean;}");
            jw.write("public static class FailureType ");
            jw.begin();
            jw.writeEol("private final String name");
            jw.writecr("private FailureType(String name) {this.name = name;}");
            jw.writecr("public String toString() { return name;}");
            jw.writeEol("public static final FailureType NULL_VALUE = new FailureType(\"NULL_VALUE\")");
            jw.writeEol("public static final FailureType DATA_RESTRICTION = new FailureType(\"DATA_RESTRICTION\")");
            jw.writeEol("public static final FailureType ENUM_RESTRICTION = new FailureType(\"ENUM_RESTRICTION\")");
            jw.writeEol("public static final FailureType MUTUALLY_EXCLUSIVE = new FailureType(\"MUTUALLY_EXCLUSIVE\")");
            jw.end();
            jw.end();
            jw.cr();
        }
        jw.beginMethod("validate", "", (config.isUseRuntime() ? "org.netbeans.modules.schema2beans" : getRootClassName())+".ValidateException", "void", jw.PUBLIC);
        genValidateProperties();
        end();
        cr();
    }

    protected void genValidateFail(String detail, String name,
                                   boolean quoteDetail,
                                   ValidateException.FailureType ft,
                                   JavaWriter out) throws IOException {
        out.write("throw new ");
        String validateException;
        if (config.isUseRuntime())
            validateException = "org.netbeans.modules.schema2beans.ValidateException";
        else
            validateException = getRootClassName()+".ValidateException";
        out.write(validateException);
        out.write("(");
        if (quoteDetail)
            out.write('"');
        out.write(detail);
        if (quoteDetail)
            out.write('"');
        out.write(", ", validateException+".FailureType.",
                 ft.toString());
        out.writeEolNoI18N(", \""+name+"\", this)");
    }

    public void genPropertyEvents() throws IOException {
        select(DECL_SECTION);
        gen(PRIVATE, "java.beans.PropertyChangeSupport", "eventListeners");
        eol();
        select(BODY_SECTION);
        jw.beginMethod("addPropertyChangeListener",
                       "java.beans.PropertyChangeListener listener", null,
                       "void", jw.PUBLIC | jw.BEANINFO);
        jw.beginIf("eventListeners == null");
        geneol("eventListeners = new java.beans.PropertyChangeSupport(this)");
        end();
        geneol("eventListeners.addPropertyChangeListener(listener)");
        genCallMethodOnBeans(".addPropertyChangeListener(listener)");
        jw.endMethod();

        jw.beginMethod("removePropertyChangeListener",
                       "java.beans.PropertyChangeListener listener", null,
                       "void", jw.PUBLIC | jw.BEANINFO);
        genCallMethodOnBeans(".removePropertyChangeListener(listener)");
        jw.beginIf("eventListeners == null");
        geneol("return");
        end();
        geneol("eventListeners.removePropertyChangeListener(listener)");
        jw.beginIf("!eventListeners.hasListeners(null)");
        geneol("eventListeners = null");
        jw.end();
        jw.endMethod();

        jw.beginMethod("_setPropertyChangeSupport",
                       "java.beans.PropertyChangeSupport listeners", null,
                       "void", jw.PUBLIC);
        jw.writeEol("eventListeners = listeners");
        genCallMethodOnBeans("._setPropertyChangeSupport(listeners)");
        jw.endMethod();
    }

    protected void genCallMethodOnBeans(String methodParams) throws IOException {
        int size = attrList.size();
        for (int i = 0; i < size; i++) {
            Property a = (Property) attrList.get(i);
            if (!a.isBean)
                continue;
            boolean indexed = a.isIndexed();
            String attr = "_" + a.name;
            String type = a.getType().intern();
            String baseType = type;
            if (indexed) {
                beginAttrIterator(attr, a, "element");
                attr = "element";
            }
            jw.beginIf(attr, " != null");
            jw.writeEol(attr, methodParams);
            jw.end();
            if (indexed)
                jw.end();
        }
    }

    public void genStoreEvents() throws IOException {
        select(DECL_SECTION);
        gen(PROTECTED, "boolean", "storeEvents = false");
        eol();
        gen(PRIVATE, "java.util.List", "storedEvents = new java.util.LinkedList()");
        eol();
        select(BODY_SECTION);
        jw.beginMethod("fireStoredEvents");
        jw.beginIf("eventListeners == null");
        geneol("storedEvents.clear()");
        geneol("return");
        end();
        /*
        comment("Compress the events");
        geneol("java.util.Map uniqueEvents = new java.util.HashMap(storedEvents.size()*4)");
        gen("for (java.util.Iterator it = storedEvents.iterator(); it.hasNext(); ) ");
        begin();
        geneol("java.beans.PropertyChangeEvent event = (java.beans.PropertyChangeEvent) it.next()");
        comment("The last event by the property name is stored in uniqueEvents");
        gencr("if (uniqueEvents.containsKey(event.getPropertyName())");
        tabIn();
        geneol("uniqueEvents.put(event.getPropertyName(), event)");
        end();
        */
        jw.beginFor("java.util.Iterator it = storedEvents.iterator()",
                    "it.hasNext()", "");
        geneol("java.beans.PropertyChangeEvent event = (java.beans.PropertyChangeEvent) it.next()");
        /*gencr("if (uniqueEvents.get(event.getPropertyName()) == event)");
          tabIn();*/
        geneol("eventListeners.firePropertyChange(event)");
        end();
        geneol("storedEvents.clear()");
        end();
        cr();
    }

    public void genVetoable() throws IOException {
        select(DECL_SECTION);
        gen(PRIVATE, "java.beans.VetoableChangeSupport", "vetos");
        eol();
        select(BODY_SECTION);
        jw.beginMethod("addVetoableChangeListener",
                       "java.beans.VetoableChangeListener listener", null,
                       "void", jw.PUBLIC | jw.BEANINFO);
        jw.beginIf("vetos == null");
        geneol("vetos = new java.beans.VetoableChangeSupport(this)");
        end();
        geneol("vetos.addVetoableChangeListener(listener)");
        end();
        cr();
        jw.beginMethod("removePropertyChangeListener",
                       "java.beans.VetoableChangeListener listener", null,
                       "void", jw.PUBLIC | jw.BEANINFO);
        jw.beginIf("vetos == null");
        geneol("return");
        end();
        geneol("vetos.removeVetoableChangeListener(listener)");
        jw.beginIf("!vetos.hasListeners(null)");
        geneol("vetos = null");
        end();
        end();
        cr();
        jw.beginMethod("_setVetoableChangeSupport",
                       "java.beans.VetoableChangeSupport vs", "void", null,
                       jw.PACKAGE_LEVEL);
        geneol("vetos = vs");
        end();
        cr();
    }

    public void genElementPositions() throws IOException {
        select(BODY_SECTION);
        jw.beginMethod("fetchChildByPosition", "int position", null,
                       "java.lang.Object", jw.PUBLIC);
        jw.beginIf("elementTypesByPosition[position] == "+elementTypeSetnull);
        jw.writeEol("throw new IndexOutOfBoundsException(\"position \"+position+\" out of bounds\")");
        jw.end();
        jw.writeEol("return elementsByPosition[position]");
        jw.endMethod();
        jw.beginMethod("fetchChildCount", "", null, "int", jw.PUBLIC);
        jw.writeEol("int position = elementTypesByPosition.length");
        jw.beginFor("", "position > 0 && elementTypesByPosition[position-1] == "+elementTypeSetnull, "--position");
        jw.writeEol("");
        jw.end();
        jw.writeEol("return position");
        jw.endMethod();
        jw.beginMethod("expandElementsByPosition", "int size", null, "void",
                       jw.PROTECTED);
        jw.beginIf("elementTypesByPosition.length >= size");
        jw.writeEol("return");
        jw.end();
        jw.writeEol("int newSize = elementTypesByPosition.length+8");
        jw.writeEol("java.lang.Object[] newElementsByPosition = new java.lang.Object[newSize]");
        jw.writeEol("int[] newElementTypesByPosition = new int[newSize]");
        jw.writeEol("System.arraycopy(elementsByPosition, 0, newElementsByPosition, 0, elementTypesByPosition.length)");
        jw.writeEol("System.arraycopy(elementTypesByPosition, 0, newElementTypesByPosition, 0, elementTypesByPosition.length)");
        jw.beginFor("int i = elementTypesByPosition.length",
                    "i < newSize", "++i");
        jw.writeEol("newElementTypesByPosition[i] = "+elementTypeSetnull);
        jw.end();
        jw.writeEol("elementTypesByPosition = newElementTypesByPosition");
        jw.writeEol("elementsByPosition = newElementsByPosition");
        jw.endMethod();

        jw.beginMethod("insertElementByPosition",
                       "int position, Object element, int elementType",
                       null, "void",
                       jw.PROTECTED);
        jw.writeEol("int childCount = fetchChildCount()");
        jw.writeEol("expandElementsByPosition(childCount+1)");
        jw.writeEol("int i = childCount - 1");
        jw.beginFor("", "i >= position", "--i");
        jw.writeEol("elementsByPosition[i + 1] = elementsByPosition[i]");
        jw.writeEol("elementTypesByPosition[i + 1] = elementTypesByPosition[i]");
        jw.end();
        jw.writeEol("elementTypesByPosition[position] = elementType");
        jw.writeEol("elementsByPosition[position] = element");
        jw.comment("assert childCount == fetchChildCount() + 1;");
        jw.endMethod();

        jw.beginMethod("deleteElement", "int position", null, "void",
                       jw.PROTECTED);
        jw.writeEol("int i = position+1");
        jw.writeEol("int size = elementTypesByPosition.length");
        jw.beginFor("", "i < size && elementTypesByPosition[i] != "+elementTypeSetnull, "++i");
        jw.writeEol("elementsByPosition[i - 1] = elementsByPosition[i]");
        jw.writeEol("elementTypesByPosition[i - 1] = elementTypesByPosition[i]");
        //jw.writeEol("System.out.println(\"elementTypesByPosition[\"+(i-1)+\"]=\"+elementTypesByPosition[i-1])");
        jw.end();
        jw.writeEol("elementTypesByPosition[i-1] = "+elementTypeSetnull);
        jw.writeEol("elementsByPosition[i - 1] = null");
        jw.comment("assert size == fetchChildCount() - 1;");
        jw.endMethod();

        jw.beginMethod("findFirstOfElementType", "int elementType", null,
                       "int", jw.PROTECTED);
        jw.writeEol("int maxPos = elementTypesByPosition.length");
        jw.writeEol("int pos = 0");
        jw.beginFor("", "pos < maxPos && elementTypesByPosition[pos] < elementType",
                    "++pos");
        jw.end();
        jw.writeEol("return pos");
        jw.endMethod();

        jw.beginMethod("findElementType", "int elementType, int index", null,
                       "int", jw.PROTECTED);
        jw.writeEol("int maxPos = elementTypesByPosition.length");
        jw.writeEol("int pos = 0");
        jw.beginFor("", "pos < maxPos", "++pos");
        jw.beginIf("elementTypesByPosition[pos] == elementType");
        jw.beginIf("index <= 0");
        jw.writeEol("return pos");
        jw.end();
        jw.writeEol("--index");
        jw.end();
        jw.end();
        jw.writeEol("return pos");
        jw.endMethod();

        jw.beginMethod("findLastOfElementType", "int elementType", null, "int",
                       jw.PROTECTED);
        jw.writeEol("int childCount = elementTypesByPosition.length");
        jw.writeEol("int pos = childCount - 1");
        // We can't do a binary search here, since the element types are
        // not always sorted.
        jw.beginFor("", "pos >=0", "--pos");
        jw.beginIf("elementTypesByPosition[pos] == "+elementTypeSetnull);
        jw.writeEol("--childCount");
        jw.writeEol("continue");
        jw.end();
        jw.beginIf("elementTypesByPosition[pos] <= elementType");
        jw.writeEol("return pos");
        jw.end();
        jw.end();
        //jw.beginIf("childCount < 0");
        //jw.writeEol("return 0");
        //jw.end();
        jw.writeEol("return childCount");
        jw.endMethod();
    }

    protected void genProcessDocType() throws IOException {
        String fullDocTypeName;
        fullDocTypeName = fullClassName+".DocType";
        select(DECL_SECTION);
        jw.writeEol("private "+fullDocTypeName+" docType = null");
        select(ACCESS_SECTION);
        jw.beginMethod("fetchDocType", "", null, fullDocTypeName, jw.PUBLIC);
        jw.writeEol("return docType");
        jw.endMethod();
        jw.beginMethod("changeDocType", fullDocTypeName+" dt", null, "void", jw.PUBLIC);
        jw.writeEol("docType = dt");
        jw.endMethod();
        jw.beginMethod("changeDocType", "String publicId, String systemId", null, "void", jw.PUBLIC);
        jw.writeEol("docType = new ", fullDocTypeName, "(publicId, systemId)");
        jw.endMethod();
        select(BODY_SECTION);
        jw.write("public static class DocType ");
        jw.begin();
        jw.writeEol("private org.w3c.dom.NamedNodeMap entities");
        jw.writeEol("private String internalSubset");
        jw.writeEol("private String name");
        jw.writeEol("private org.w3c.dom.NamedNodeMap notations");
        jw.writeEol("private String publicId");
        jw.writeEol("private String systemId");
        jw.cr();
        jw.write("public DocType("+fullDocTypeName+" docType) ");
        jw.begin();
        jw.writeEol("entities = docType.getEntities()");
        jw.writeEol("internalSubset = docType.getInternalSubset()");
        jw.writeEol("name = docType.getName()");
        jw.writeEol("notations = docType.getNotations()");
        jw.writeEol("publicId = docType.getPublicId()");
        jw.writeEol("systemId = docType.getSystemId()");
        jw.endMethod();
        jw.write("public DocType(org.w3c.dom.DocumentType docType) ");
        jw.begin();
        jw.writeEol("entities = docType.getEntities()");
        jw.writeEol("internalSubset = docType.getInternalSubset()");
        jw.writeEol("name = docType.getName()");
        jw.writeEol("notations = docType.getNotations()");
        jw.writeEol("publicId = docType.getPublicId()");
        jw.writeEol("systemId = docType.getSystemId()");
        jw.endMethod();
        jw.write("public DocType(String publicId, String systemId) ");
        jw.begin();
        jw.writeEol("this(\"",
                    beanElement.node.getName(), "\", publicId, systemId)");
        jw.end();
        jw.cr();
        jw.write("public DocType(String name, String publicId, String systemId) ");
        jw.begin();
        jw.writeEol("this.name = name");
        jw.writeEol("this.publicId = publicId");
        jw.writeEol("this.systemId = systemId");
        jw.endMethod();
        jw.write("public org.w3c.dom.NamedNodeMap getEntities() ");
        jw.begin();
        jw.writeEol("return entities");
        jw.endMethod();
        jw.write("public String getInternalSubset() ");
        jw.begin();
        jw.writeEol("return internalSubset");
        jw.endMethod();
        jw.write("public String getName() ");
        jw.begin();
        jw.writeEol("return name");
        jw.endMethod();
        jw.write("public org.w3c.dom.NamedNodeMap getNotations() ");
        jw.begin();
        jw.writeEol("return notations");
        jw.endMethod();
        jw.write("public String getPublicId() ");
        jw.begin();
        jw.writeEol("return publicId");
        jw.endMethod();
        jw.write("public String getSystemId() ");
        jw.begin();
        jw.writeEol("return systemId");
        jw.endMethod();
        jw.write("public String toString() ");
        jw.begin();
        jw.writeEol("String result = \" 0");
        jw.writeEol("result += \" [\"");
        jw.beginFor("int i = 0", "i < length", "++i");
        jw.writeEol("org.w3c.dom.Node node = entities.item(i)");
        jw.writeEol("result += \"<\"+node.getNodeName()+\">\"");
        jw.writeEol("result += node.getNodeValue()");
        jw.writeEol("result += \"\"");
        jw.end();
        jw.writeEol("result += \"]\"");
        jw.end();
        jw.end();
        jw.writeEol("result += \">\"");
        jw.writeEol("return result");
        jw.end();

        jw.endMethod();
    }

    public void genTransactions() throws IOException {
        select(BODY_SECTION);
        jw.beginMethod("beginTransaction");
        //geneol("inTransaction = true");
        geneol("storeEvents = true");
        comment("Tell each child bean to also beginTransaction");
        genCallMethodOnSubBeans("beginTransaction()");
        end();
        cr();

        jw.beginMethod("commit");
        geneol("storeEvents = false");
        comment("Tell each child bean to also commit");
        genCallMethodOnSubBeans("commit()");
        geneol("fireStoredEvents()");
        end();
        cr();

        jw.beginMethod("rollback");
        comment("Go over all of the events and put them back");
        geneol("java.beans.PropertyChangeEvent[] events = new java.beans.PropertyChangeEvent[storedEvents.size()]");
        jw.beginFor("int i = events.length-1", "i >= 0", "--i");
        geneol("java.beans.PropertyChangeEvent event = events[i]");
        //jw.beginIf("event.getOldValue() == null");
        geneol("changePropertyByName(event.getPropertyName(), event.getOldValue())");
        end();
        // we might be able to speed things up by setting eventListeners = null
        geneol("storeEvents = false");
        geneol("storedEvents.clear()");
        comment("Tell each child bean to also rollback");
        genCallMethodOnSubBeans("rollback()");
        end();
        cr();
    }

    protected void genCallMethodOnSubBeans(String methodName) throws IOException {
        int size = attrList.size();
        for (int i = 0; i < size; i++) {
            Property a = (Property)attrList.get(i);
            boolean   	indexed = a.isIndexed();
            String attr = "_" + a.name;
            String type = a.getType();
            if (a.isBean) {
                String value = attr;
                if (indexed) {
                    beginAttrIterator(attr, a, "element");
                    value = "element";
                }
                gencr("if ("+value+" != null)");
                tabIn();
                gen(value);
                gen(".");
                geneol(methodName);
                if (indexed)
                    end();
            }
        }
    }

    public void genPropertiesByName() throws IOException {
        jw.beginMethod("changePropertyByName", "String name, Object value",
                       null, "void", jw.PUBLIC);
        geneol("if (name == null) return");
        geneol("name = name.intern()");
        int size = attrList.size();
        for (int i = 0; i < size; i++) {
            Property a = (Property)attrList.get(i);
            boolean   	indexed = a.isIndexed();
            boolean isScalar = a.isScalar();
            String attr = "_" + a.name;
            String type = a.getType();
            if (i > 0)
                gen("else ");
            gencr("if (name == \""+a.beanIntrospectorName()+"\")");
            tabIn();
            if (indexed) {
                gen("add"+a.name);
                geneol("("+JavaUtil.fromObject(type, "value")+")");
                gen("else ");
                gencr("if (name == \""+a.beanIntrospectorName()+"[]\")");
                tabIn();
                gen(a.getWriteMethod()+"(");
                geneol("("+type+"[]) value)");
            } else {
                gen(a.getWriteMethod()+"(");
                gen(JavaUtil.fromObject(type, "value"));
                geneol(")");
            }
        }
        if (size > 0) {
            gencr("else");
            tabIn();
            genInvalidName("name");
        }
        genMadeChange();
        end();
        cr();

        jw.beginMethod("fetchPropertyByName", "String name", null, "Object", jw.PUBLIC);
        for (int i = 0; i < size; i++) {
            Property a = (Property)attrList.get(i);
            boolean   	indexed = a.isIndexed();
            String type = a.getType();
            gen("if (name == \""+a.beanIntrospectorName());
            if (indexed)
                gen("[]");
            gencr("\")");
            tabIn();
            jw.write("return ");
            if (indexed)
                jw.writeEol(a.getReadMethod(false)+"()");
            else
                jw.writeEol(JavaUtil.toObject(a.getReadMethod(false)+"()", type,
                                              config.isForME()));
        }
        genInvalidName("name");
        jw.endMethod();
    }

    public void genEqualsHashCode() throws IOException {
        select(EQUALS_SECTION);
        jw.beginMethod("equals", "Object o", null, "boolean", jw.PUBLIC);
        jw.write("return o instanceof ", fullClassName);
        jw.writeEol(" && equals((", fullClassName, ") o)");
        jw.endMethod();
        
        jw.beginMethod("equals", fullClassName+" inst", null, "boolean", jw.PUBLIC);
        jw.beginIf("inst == this");
        jw.writeEol("return true");
        jw.end();
        jw.beginIf("inst == null");
        jw.writeEol("return false");
        jw.end();
        
        select(HASHCODE_SECTION);
        jw.beginMethod("hashCode", "", null, "int", jw.PUBLIC);
        geneol("int result = 17");

        boolean isArrayStyle = (config.getIndexedPropertyType() == null);
        int size = attrList.size();
        for (int i = 0; i < size; i++) {
            Property a = (Property)attrList.get(i);
            boolean   	indexed = a.isIndexed();
            boolean	isWrapper = false;
            MetaElement	me = getMetaElement(a);
            boolean isScalar = a.isScalar();

            String type = a.getType().intern();
            String baseType = type;
            if (indexed)
                type = (baseType + "[]").intern();

            String attr = "_" + a.name;
            String baseAttr = attr;
            String otherAttr = "inst."+attr;
            select(EQUALS_SECTION);
            if (indexed) {
                gen("if (size"+a.name+"() != inst.size"+a.name+"())");
                cr();
                tabIn();
                gen("return false");
                eol();
                comment("Compare every element.");
                String fullType = getTypeFullClassName(a);
                if (isArrayStyle) {
                    jw.beginFor("int pos = 0, size = size"+a.name+"()",
                                "pos < size", "++pos");
                    attr = attr+"[pos]";
                    otherAttr = otherAttr+"[pos]";
                } else {
                    jw.beginFor("java.util.Iterator it = "+attr+".iterator(), it2 = inst."+attr+".iterator()",
                                "it.hasNext() && it2.hasNext()", "");
                    gen(fullType);
                    gen(" element = ");
                    geneol(JavaUtil.fromObject(fullType, "it.next()"));
                    gen(fullType);
                    gen(" element2 = ");
                    geneol(JavaUtil.fromObject(fullType, "it2.next()"));
                    attr = "element";
                    otherAttr = "element2";
                }
            }
            jw.beginIf("!("+JavaUtil.genEquals(baseType, attr, otherAttr)+")");
            jw.writeEol("return false");
            jw.end();
            if (indexed) {
                end();
            }

            select(HASHCODE_SECTION);
            gen("result = 37*result + (");
            if (isScalar)
                gen(JavaUtil.exprToInt(type, baseAttr));
            else
                gen(baseAttr+" == null ? 0 : "+baseAttr+".hashCode()");
            gen(")");
            eol();
        }
        select(EQUALS_SECTION);
        gen("return true");
        eol();
        end();
        cr();

        select(HASHCODE_SECTION);
        gen("return result");
        eol();
        end();
        cr();
    }

    void genDeepCopy() throws IOException {
        select(CONSTRUCTOR_SECTION);
        jw.bigComment("Deep copy");
        jw.beginConstructor(className, fullClassName+" source");
        jw.writeEol("this(source, false)");
        jw.end();
        jw.cr();
        jw.bigComment("Deep copy\n@param justData just copy the XML relevant data");
        jw.beginConstructor(className, fullClassName+" source, boolean justData");
        if (config.isGenerateParentRefs()) {
            jw.writeEol("this(source, null, justData)");
            jw.end();
            jw.cr();
            jw.bigComment("Deep copy");
            jw.beginConstructor(className, fullClassName+" source, "+parentBeanType()+" parent, boolean justData");
        }
        genExtendBaseBeanConstructor();
        //jw.writeEol("System.out.println(\"Deep copy for "+className+"\")");
        if (config.isGenerateParentRefs()) {
            jw.writeEol("this.parent = parent");
        }
        for (int i = 0, size = attrList.size(); i < size; i++) {
            Property 	a = (Property) attrList.get(i);
            boolean   	indexed = a.isIndexed();
            boolean isScalar = a.isScalar();
            String attr = "_" + a.name;
            String type = a.getType().intern();
            String fullClassType = getTypeFullClassName(a);
            boolean isArrayStyle = (config.getIndexedPropertyType() == null);

            String nextElement = "it.next()";
            if (indexed) {
                if (isArrayStyle) {
                    jw.writeEol(attr, " = new ", fullClassType, "[source."+attr+".length]");
                    jw.beginFor("int index = 0",
                                "index < source."+attr+".length", "++index");
                    nextElement = "source."+attr+"[index]";
                } else {
                    jw.beginFor("java.util.Iterator it = source."+attr+".iterator()",
                                "it.hasNext()", "");
                }
            }
            //System.out.println("type="+type+" needToCallClone="+needToCallClone+" mutable="+mutable);
            String getter;
            if (indexed) {
                getter = "srcElement";
                if (isScalar) {
                    // It's already in object format, it would be silly to
                    // convert back and forth.
                    jw.writeEol("Object ", getter, " = ", nextElement);
                } else {
                    jw.writeEol(fullClassType+" ", getter," = ",
                                isArrayStyle ? nextElement : JavaUtil.fromObject(fullClassType, nextElement));
                }
            } else
                getter = "source." + attr;

            if (type == "byte[]") {
                jw.writeEol("byte[] destElement"+attr, " = new byte[", getter, ".length]");
                jw.writeEol("System.arraycopy(", getter+", 0, destElement"+attr+", 0, ", getter, ".length)");
            }
            gen(attr);
            if (indexed) {
                if (isArrayStyle) {
                    jw.write("[index] = ");
                } else {
                    gen(".add(");
                }
            } else {
                gen(" = ");
            }
            if (type == "byte[]") {
                jw.write("destElement", attr);
            } else {
                genCopy(getter, a, "justData");
            }
            if (indexed && !isArrayStyle) {
                jw.write(")");
            }
            jw.eol();
            if (indexed) {
                jw.end();
            }
        }
        if (beanElement.isRoot && config.isProcessDocType()) {
            String fullDocTypeName;
            if (packageName == null)
                fullDocTypeName = className+".DocType";
            else
                fullDocTypeName = packageName+"."+className+".DocType";
            jw.beginIf("source.docType != null");
            jw.writeEol("docType = new "+fullDocTypeName+"(source.docType)");
            jw.end();
        }
        if (beanElement.isRoot) {
            jw.writeEol("schemaLocation = source.schemaLocation");
        }
        boolean firstJustData = true;
        if (config.isGenerateStoreEvents()) {
            if (firstJustData) {
                firstJustData = false;
                jw.beginIf("!justData");
            }
            geneol("storeEvents = source.storeEvents");
        }
        if (config.isVetoable()) {
            if (firstJustData) {
                firstJustData = false;
                jw.beginIf("!justData");
            }
            geneol("vetos = source.vetos");
        }
        if (config.isGeneratePropertyEvents()) {
            if (firstJustData) {
                firstJustData = false;
                jw.beginIf("!justData");
            }
            jw.beginIf("source.eventListeners != null");
            jw.writeEol("eventListeners = new java.beans.PropertyChangeSupport(this)");
            jw.writeEol("java.beans.PropertyChangeListener[] theListeners = source.eventListeners.getPropertyChangeListeners()");
            jw.beginFor("int i = 0", "i < theListeners.length", "++i");
            jw.writeEol("eventListeners.addPropertyChangeListener(theListeners[i])");
            jw.end();
            jw.end();
        }
        if (!firstJustData)
            jw.end();
        end();
        cr();
    }

    public void genHasChanged() throws IOException {
        if (beanElement.isRoot) {
            select(DECL_SECTION);
            jw.writeEol("private boolean changed");
        }
        select(BODY_SECTION);
        jw.bigComment("Change the result of _hasChanged().\nThis is done automatically when a value in this bean graph gets changed.");
        jw.beginMethod("_setChanged", "boolean changed", null, "void", jw.PUBLIC);
        if (beanElement.isRoot) {
            jw.writeEol("this.changed = changed");
        } else {
            jw.beginIf("parent != null");
            jw.writeEol("parent._setChanged(changed)");
            jw.end();
        }
        jw.endMethod();
        if (beanElement.isRoot) {
            jw.bigComment("@return true if something has changed in this bean graph.");
            jw.beginMethod("_hasChanged", "", null, "boolean", jw.PUBLIC);
            jw.writeEol("return changed");
            jw.endMethod();
        }
    }
    
    public void genChildBeans() throws IOException {
        select(BODY_SECTION);
        jw.bigComment("Return an array of all of the properties that are beans and are set.");
        String cb = config.isExtendBaseBean() ? "org.netbeans.modules.schema2beans.BaseBean" : commonBeanType();
        jw.beginMethod("childBeans", "boolean recursive", null, cb+"[]", jw.PUBLIC);
        jw.writeEol("java.util.List children = new java.util.LinkedList()");
        jw.writeEol("childBeans(recursive, children)");
        jw.writeEol(cb+"[] result = new "+cb+"[children.size()]");
        jw.writeEol("return ("+cb+"[]) children.toArray(result)");
        jw.endMethod();
        jw.bigComment("Put all child beans into the beans list.");
        jw.beginMethod("childBeans", "boolean recursive, java.util.List beans", null, "void", jw.PUBLIC);
        for (int i = 0, size = attrList.size(); i < size; i++) {
            Property 	a = (Property) attrList.get(i);
            if (!a.isBean)
                continue;
            boolean   	indexed = a.isIndexed();
            String type = a.getType().intern();
            String attr = "_" + a.name;
            if (indexed) {
                beginAttrIterator(attr, a, "element");
                attr = "element";
            }
            jw.beginIf(attr+" != null");
            jw.beginIf("recursive");
            jw.writeEol(attr+".childBeans(true, beans)");
            jw.end();
            jw.writeEol("beans.add("+attr+")");
            jw.end();
            if (indexed) {
                jw.end();
            }
        }
        jw.endMethod();
    }

    public void genName() throws IOException {
        select(BODY_SECTION);
        jw.beginMethod("nameSelf", "", null, "String", jw.PUBLIC);
        if (config.isGenerateParentRefs()) {
            jw.beginIf("parent != null");
            jw.writeEol("String parentName = parent.nameSelf()");
            jw.writeEol("String myName = parent.nameChild(this, false, false)");
            jw.writeEol("return parentName + \"/\" + myName");
            jw.end();
        }
        String beanName = Common.convertName(beanElement.node.getName());
        if (beanElement.isRoot)
            jw.writeEol("return \"/"+beanName+"\"");
        else
            jw.writeEol("return \""+beanName+"\"");
        jw.endMethod();

        jw.beginMethod("nameChild", "Object childObj", null, "String", jw.PUBLIC);
        jw.writeEol("return nameChild(childObj, false, false)");
        jw.endMethod();
        
        jw.bigComment("@param childObj  The child object to search for\n@param returnSchemaName  Whether or not the schema name should be returned or the property name\n@return null if not found");
        jw.beginMethod("nameChild", "Object childObj, boolean returnConstName, boolean returnSchemaName", null, "String", jw.PUBLIC);
        jw.writeEol("return nameChild(childObj, returnConstName, returnSchemaName, false)");
        jw.endMethod();

        jw.bigComment("@param childObj  The child object to search for\n@param returnSchemaName  Whether or not the schema name should be returned or the property name\n@return null if not found");
        jw.beginMethod("nameChild", "Object childObj, boolean returnConstName, boolean returnSchemaName, boolean returnXPathName", null, "String", jw.PUBLIC);
        // Sort by type
        Map typeMap = new HashMap();	// Map>
        for (int i = 0, size = attrList.size(); i < size; i++) {
            Property prop = (Property) attrList.get(i);
            String type = JavaUtil.toObjectType(prop.getType());
            if (type.equals("String"))
                type = "java.lang.String";  // normalize
            List lst = (List) typeMap.get(type);
            if (lst == null) {
                lst = new LinkedList();
                typeMap.put(type, lst);
            }
            lst.add(prop);
        }
        for (Iterator types = typeMap.keySet().iterator(); types.hasNext(); ) {
            String type = (String) types.next();
            jw.beginIf("childObj instanceof "+type);
            jw.writeEol(type, " child = (", type, ") childObj");
            boolean firstUseOfIndex = true;
            for (Iterator props = ((List)typeMap.get(type)).iterator(); props.hasNext(); ) {
                Property prop = (Property) props.next();
                String attr = "_" + prop.name;
                String childExpr = "child";
                if (JavaUtil.isPrimitiveType(prop.getType()))
                    childExpr = JavaUtil.fromObject(prop.getType(), "child");
                if (prop.isIndexed()) {
                    if (firstUseOfIndex) {
                        firstUseOfIndex = false;
                        jw.writeEol("int index = 0");
                    } else {
                        jw.writeEol("index = 0");
                    }
                    beginAttrIterator(attr, prop, "element");
                    jw.beginIf(childExpr+" == element");
                    jw.beginIf("returnConstName");
                    jw.writeEol("return ", prop.constName);
                    if (prop.type != Common.TYPE_COMMENT) {
                        jw.endElseBeginIf("returnSchemaName");
                        jw.writeEol("return \"", prop.dtdName, "\"");
                        jw.endElseBeginIf("returnXPathName");
                        jw.write("return \"");
                        if (prop.isAttribute())
                            jw.write("@");
                        jw.writeEol(prop.dtdName,
                                    "[position()=\"+index+\"]\"");
                    }
                    jw.endElseBegin();
                    jw.writeEol("return \""+prop.getEventName()+".\"+Integer.toHexString(index)");
                    jw.end();
                    jw.end();
                    jw.writeEol("++index");
                    jw.end();
                } else {
                    jw.beginIf(childExpr+" == "+attr);
                    jw.beginIf("returnConstName");
                    jw.writeEol("return ", prop.constName);
                    if (prop.type != Common.TYPE_COMMENT) {
                        jw.endElseBeginIf("returnSchemaName");
                        jw.writeEol("return \"", prop.dtdName, "\"");
                        jw.endElseBeginIf("returnXPathName");
                        jw.write("return \"");
                        if (prop.isAttribute())
                            jw.write("@");
                        jw.writeEol(prop.dtdName, "\"");
                    }
                    jw.endElseBegin();
                    jw.writeEol("return \""+prop.getEventName()+"\"");
                    jw.end();
                    jw.end();
                }
            }
            jw.end();
        }
        jw.writeEol("return null");
        jw.endMethod();
    }

    public void genToString() throws IOException {
        jw.beginMethod("toString", "", null, "String", jw.PUBLIC);
        jw.writeEol("java.io.StringWriter sw = new java.io.StringWriter()");
        jw.beginTry();
        jw.writeEol("writeNode(sw)");
        jw.endCatch("java.io.IOException e");
        jw.comment("How can we actually get an IOException on a StringWriter?");
        jw.writeEol("throw new RuntimeException(e)");
        jw.end();
        jw.writeEol("return sw.toString()");
        jw.endMethod();
    }

    public void genExtendBaseBean() throws IOException {
        int size = attrList.size();
        jw.beginMethod("dump", "StringBuffer str, String indent", null,
                       "void", jw.PUBLIC);
        jw.writeEol("str.append(toString())");
        jw.endMethod();

        jw.pushSelect(jw.DECL_SECTION);
        String[] propByNameKeys = new String[size+1];
        for (int i = 0; i < size; i++) {
            Property a = (Property)attrList.get(i);
            propByNameKeys[i] = a.name;
        }
        propByNameKeys[size] = "";
        jw.writeEol("private java.util.Map propByName = new java.util.HashMap("+(JavaUtil.getOptimialHashMapSize(propByNameKeys)), ", 1.0f)");
        jw.popSelect();
        jw.beginMethod("beanProp", "String name", null, "org.netbeans.modules.schema2beans.BeanProp", jw.PUBLIC);
        jw.writeEol("if (name == null) return null");
        jw.writeEol("org.netbeans.modules.schema2beans.BeanProp prop = (org.netbeans.modules.schema2beans.BeanProp) propByName.get(name)");
        jw.beginIf("prop == null");
        jw.writeEol("name = name.intern()");
        jw.writeEol("boolean indexed");
        jw.writeEol("int options");
        jw.writeEol("String constName");
        jw.writeEol("String schemaName");
        jw.writeEol("java.lang.reflect.Method writer = null");
        jw.writeEol("java.lang.reflect.Method arrayWriter = null");
        jw.writeEol("java.lang.reflect.Method reader = null");
        jw.writeEol("java.lang.reflect.Method arrayReader = null");
        jw.writeEol("java.lang.reflect.Method adder = null");
        jw.writeEol("java.lang.reflect.Method remover = null");
        boolean defaultKey = true;
        if (metaElement != null) {
            MetaProperty[] mp = metaElement.getMetaProperty();
            for (int i=0; i");
        jw.popSelect();
        jw.beginMethod("prepareBeanPropList", "", null, "void", jw.PRIVATE);
        jw.beginIf("beanPropList == null");
        jw.writeEol("beanPropList = new java.util.ArrayList("+size+")");
        for (int i = 0; i < size; i++) {
            Property a = (Property)attrList.get(i);
            jw.writeEol("beanPropList.add(beanProp(", a.constName, "))");
        }
        jw.end();
        jw.endMethod();

        jw.beginMethod("beanPropsIterator", "", null, "java.util.Iterator",
                       jw.PROTECTED);
        jw.writeEol("prepareBeanPropList()");
        jw.writeEol("return beanPropList.iterator()");
        jw.endMethod();

        jw.beginMethod("beanProps", "", null, "org.netbeans.modules.schema2beans.BeanProp[]", jw.PUBLIC);
        jw.writeEol("prepareBeanPropList()");
        jw.writeEol("org.netbeans.modules.schema2beans.BeanProp[] ret = new org.netbeans.modules.schema2beans.BeanProp["+size+"]");
        jw.writeEol("ret = (org.netbeans.modules.schema2beans.BeanProp[]) beanPropList.toArray(ret)");
        jw.writeEol("return ret");
        jw.endMethod();

        jw.beginMethod("setValue", "String name, Object value", null, "void", jw.PUBLIC);
        new NamePropertyVisitor("name") {
                public void generateProp() throws IOException {
                    if (curProp.isIndexed()) {
                        jw.write(curProp.getWriteMethod(), "(");
                        jw.writeEol("(", curProp.getType(), "[]) value)");
                    } else {
                        jw.write(curProp.getWriteMethod(), "(");
                        jw.write(JavaUtil.fromObject(curProp.getType(), "value"));
                        jw.writeEol(")");
                    }
                }
            }.generate();
        jw.endMethod();

        jw.beginMethod("setValue", "String name, int index, Object value", null, "void", jw.PUBLIC);
        new NamePropertyVisitor("name") {
                public void generateProp() throws IOException {
                    if (curProp.isIndexed()) {
                        jw.write(curProp.getWriteMethod(), "(index, ");
                        jw.write(JavaUtil.fromObject(curProp.getType(), "value"));
                        jw.writeEol(")");
                    } else {
                        jw.writeEol("throw new IllegalArgumentException(name+\" is not an indexed property for ",
                                    className, "\")");
                    }
                }
            }.generate();
        jw.endMethod();

        jw.beginMethod("getValue", "String name", null, "Object", jw.PUBLIC);
        new NamePropertyVisitor("name") {
                public void generateProp() throws IOException {
                    jw.write("return ");
                    if (curProp.isIndexed())
                        jw.writeEol(curProp.getReadMethod(false)+"()");
                    else
                        jw.writeEol(JavaUtil.toObject(curProp.getReadMethod(false)+"()",
                                                      curProp.getType(),
                                                      config.isForME()));
                }
            }.generate();
        jw.endMethod();

        jw.beginMethod("getValue", "String name, int index", null, "Object", jw.PUBLIC);
        new NamePropertyVisitor("name") {
                public boolean skip() {
                    return !curProp.isIndexed();
                }
                
                public void generateProp() throws IOException {
                    jw.write("return ");
                    jw.writeEol(JavaUtil.toObject(curProp.getReadMethod(true)+"(index)",
                                                  curProp.getType(),
                                                  config.isForME()));
                }

                public void postGenerate() throws IOException {}
            }.generate();
        new NamePropertyVisitor("name") {
                public void preGenerate() throws IOException {}
                
                public boolean skip() {
                    return curProp.isIndexed();
                }
                
                public void generateProp() throws IOException {
                    jw.beginIf("index > 0");
                    jw.writeEol("throw new IllegalArgumentException(\"index > 0\")");
                    jw.end();
                    jw.write("return ");
                    jw.writeEol(JavaUtil.toObject(curProp.getReadMethod(false)+"()",
                                                  curProp.getType(),
                                                  config.isForME()));
                }
            }.generate();
        jw.endMethod();

        jw.beginMethod("mergeUpdate",
                       "org.netbeans.modules.schema2beans.BaseBean sourceBean",
                       null, "void", jw.PUBLIC);
        //jw.writeEol("System.out.println(\"mergeUpdate for \"+getClass())");
        jw.writeEol(fullClassName, " source = (", fullClassName, ") sourceBean");
        boolean isArrayStyle = (config.getIndexedPropertyType() == null);
        for (int i = 0; i < size; i++) {
            Property 	a = (Property) attrList.get(i);
            boolean   	indexed = a.isIndexed();
            String type = a.getType().intern();
            boolean willCopy = genCopyWillCopy(a);
            String getter = "source."+a.getReadMethod(false)+"()";
            String signatureType = a.getSignatureType(packageName);
            String baseFullClassName = a.getTypeFullClassName(packageName);
            String fullClassName;
            if (indexed) {
                fullClassName = baseFullClassName + "[]";
            } else
                fullClassName = baseFullClassName;
            jw.begin();
            jw.write(fullClassName, " srcProperty = ");
            if (!signatureType.equals(baseFullClassName))
                jw.write("(", fullClassName, ") ");
            jw.writeEol(getter);
            String srcProperty = "srcProperty";
            if (a.isBean) {
                if (indexed) {
                    jw.writeEol("int destSize = ", a.getSizeMethod(), "()");
                    jw.beginIf("destSize == srcProperty.length");
                    srcProperty = "srcProperty[i]";
                    jw.beginFor("int i = 0", "i < srcProperty.length", "++i");
                    genMergeUpdateBean(a, srcProperty, indexed, signatureType,
                                       baseFullClassName, isArrayStyle, true);
                    jw.endElseBegin();
                    jw.writeEol(fullClassName, " destArray = new ",
                                baseFullClassName,
                                "[srcProperty.length]");
                    jw.beginFor("int i = 0", "i < srcProperty.length", "++i");
                    genMergeUpdateBean(a, srcProperty, indexed, signatureType,
                                       baseFullClassName, isArrayStyle, false);
                    jw.end();
                    jw.writeEol(a.getWriteMethod(), "(destArray)");
                    jw.end();
                } else {
                    genMergeUpdateBean(a, srcProperty, indexed, signatureType,
                                       baseFullClassName, isArrayStyle, false);
                }

            } else if (indexed && (willCopy || isArrayStyle)) {
                jw.writeEol(fullClassName, " destArray = new ",
                            baseFullClassName,
                            "[srcProperty.length]");
                jw.beginFor("int i = 0", "i < srcProperty.length", "++i");
                srcProperty = "srcProperty[i]";
                jw.write("destArray[i] = ");
                genCopy(srcProperty, a, "false");
                jw.eol();
                jw.end();
                jw.writeEol(a.getWriteMethod(), "(destArray)");
            } else {
                jw.write(a.getWriteMethod(), "(");
                genCopy(srcProperty, a, "false");
                jw.writeEol(")");
            }
            jw.end();
        }
        jw.endMethod();

        if (beanElement.isRoot()) {
            jw.beginMethod("isRoot", "", null, "boolean", jw.PUBLIC);
            jw.writeEol("return true");
            jw.endMethod();

            jw.beginMethod("createGraph",
                           "java.io.InputStream in, boolean validate",
                           "java.io.IOException, javax.xml.parsers.ParserConfigurationException, org.xml.sax.SAXException",
                           className, jw.PUBLIC | jw.STATIC | jw.IO);
            //jw.beginTry();
            jw.writeEol("return read(new org.xml.sax.InputSource(in), validate, null, null)");
            /*
            jw.endCatch("javax.xml.parsers.ParserConfigurationException e");
            jw.writeEol("throw new java.lang.RuntimeException(e)");
            jw.endCatch("org.xml.sax.SAXException e");
            jw.writeEol("throw new java.lang.RuntimeException(e)");
            jw.endCatch("java.io.IOException e");
            jw.writeEol("throw new java.lang.RuntimeException(e)");
            jw.end();
            */
            jw.endMethod();

            jw.beginMethod("createGraph", "java.io.InputStream in",
                           "java.io.IOException, javax.xml.parsers.ParserConfigurationException, org.xml.sax.SAXException",
                           className, jw.PUBLIC | jw.STATIC | jw.IO);
            jw.writeEol("return createGraph(in, false)");
            jw.endMethod();

            jw.beginMethod("createGraph", "", null, className, jw.PUBLIC | jw.STATIC | jw.IO);
            jw.writeEol("return new ", className, "()");
            jw.endMethod();

            jw.beginMethod("createGraph", "org.w3c.dom.Document document", null, className, jw.PUBLIC | jw.STATIC);
            jw.writeEol("return read(document)");
            jw.endMethod();

            jw.pushSelect(CONSTRUCTOR_SECTION);
            jw.beginConstructor(className, "org.w3c.dom.Node doc, int currentlyUnusedOptions");
            jw.writeEol("this()");
            jw.writeEol("readFromDocument((org.w3c.dom.Document) doc)");
            jw.end();
            jw.cr();
            jw.popSelect();
        } else {
            jw.bigComment("@deprecated");
            jw.beginMethod("write", "java.io.Writer out, String encoding",
                           "java.io.IOException", "void", jw.PUBLIC | jw.IO);
            jw.writeEol("writeNode(out)");
            jw.endMethod();

            jw.bigComment("@deprecated");
            jw.beginMethod("write", "java.io.OutputStream out",
                           "java.io.IOException", "void", jw.PUBLIC | jw.IO);
            jw.writeEol("java.io.PrintWriter pw = new java.io.PrintWriter(out)");
            jw.writeEol("writeNode(pw)");
            jw.writeEol("pw.flush()");
            jw.endMethod();
        }
    }

    private void genMergeUpdateBean(Property a, String srcProperty,
                                    boolean indexed, String signatureType,
                                    String baseFullClassName,
                                    boolean isArrayStyle,
                                    boolean mergeEach) throws IOException {
        //jw.writeEol("System.out.println(\"mergeEach="+mergeEach+"\")");
        String attr = "_" + a.name;
        jw.writeEol(baseFullClassName, " dest");
        if (!indexed)
            jw.writeEol("boolean needToSet = false");
        jw.beginIf(srcProperty+" == null");
        jw.writeEol("dest = null");
        if (!indexed)
            jw.writeEol("needToSet = true");
        jw.endElseBegin();
        if (indexed) {
            jw.beginIf("i < destSize");
        }
        jw.write("dest = ");
        if (!signatureType.equals(baseFullClassName))
            jw.write("(", baseFullClassName, ") ");
        jw.write(a.getReadMethod(indexed), "(");
        if (indexed)
            jw.write("i");
        jw.writeEol(")");
        if (indexed) {
            if (!mergeEach) {
                jw.beginIf("!"+srcProperty+".equals(dest)");
                jw.comment("It's different, so have it just dup the source one.");
                jw.writeEol("dest = null");
                jw.end();
            }
            jw.endElseBegin();
            jw.writeEol("dest = null");
            jw.end();
        }
        //jw.writeEol("System.out.println(\"dest=\"+dest)");
        jw.beginIf("dest == null");
        jw.comment("Use a temp variable, and store it after we've merged everything into it, so as to make it only 1 change event.");
        jw.writeEol("dest = new ", baseFullClassName, "(", srcProperty+", this, false)");
        if (!indexed) {
            jw.writeEol("needToSet = true");
            jw.endElseBegin();
            jw.writeEol("dest.mergeUpdate(", srcProperty, ")");
            jw.end();
        } else {
            if (mergeEach) {
                jw.endElseBegin();
                jw.writeEol("dest.mergeUpdate(", srcProperty, ")");
                jw.end();
            }
        }
        jw.end();
        if (indexed) {
            if (mergeEach) {
                jw.comment("Merge events were generated by the above dest.mergeUpdate, so just set it directly now.");
                if (isArrayStyle) {
                    jw.writeEol(attr, "[index] = value");
                } else {
                    jw.writeEol(attr, ".set(i, dest)");
                }
            } else {
                jw.writeEol("destArray[i] = dest");
            }
            jw.end();
        } else {
            jw.beginIf("needToSet");
            jw.write(a.getWriteMethod(), "(");
            jw.writeEol("dest)");
            jw.end();
        }
    }

    public void genTrailer(int out) {
        select(out);
        if (metaElement != null && metaElement.getUserCode() != null) {
            String userCode = metaElement.getUserCode();
            cr(); gencr(userCode);
        }
    }

    public void genFinishClass(int out) {
        select(out);
        end();
        cr();
    }

    public void setInvalidPropertyNames(Map invalidNames) {
        invalidNames.put("Class", null);
        if (config.isExtendBaseBean()) {
            invalidNames.put("Property", null);
            invalidNames.put("AttributeNames", null);
        }
    }

    protected void beginAttrIterator(String attr, Property a,
                                     String elementName) throws IOException {
        String fullType = getTypeFullClassName(a);
        boolean isArrayStyle = (config.getIndexedPropertyType() == null);
        if (isArrayStyle) {
            jw.beginFor("int elementIndex = 0", "elementIndex < "+attr+".length",
                        "++elementIndex");
        } else {
            jw.beginFor("java.util.Iterator it = "+attr+".iterator()",
                        "it.hasNext()", "");
        }
        jw.write(fullType);
        jw.write(" ", elementName, " = ");
        if (isArrayStyle) {
            jw.writeEol(attr, "[elementIndex]");
        } else {
            jw.writeEol(JavaUtil.fromObject(fullType, "it.next()"));
        }
    }

    protected void genNewEvent(Property a, String index,
                               String oldValue, String newValue,
                               String type) throws IOException {
        jw.write("new java.beans.PropertyChangeEvent(this, nameSelf()+\"/");
        jw.write(a.getEventName());
        if (index.equals(""))
            jw.write("\"");
        else if (index.equals("-1"))
            jw.write(".", index, "\"");
        else
            jw.write(".\"+Integer.toHexString(", index, ")");
        jw.write(", ");
        if ("null".equals(oldValue))
            jw.write("null");
        else
            jw.write(JavaUtil.toObject(oldValue, type, config.isForME()));
        jw.write(", ");
        if ("null".equals(newValue))
            jw.write("null");
        else
            jw.write(JavaUtil.toObject(newValue, type, config.isForME()));
        jw.write(")");
    }

    protected boolean hasDeepCopyConstructor() {
        return true;
    }
}
... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.