All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.netbeans.modules.schema2beansdev.AbstractCodeGeneratorClass Maven / Gradle / Ivy

/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
 *
 * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
 * Other names may be trademarks of their respective owners.
 *
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common
 * Development and Distribution License("CDDL") (collectively, the
 * "License"). You may not use this file except in compliance with the
 * License. You can obtain a copy of the License at
 * http://www.netbeans.org/cddl-gplv2.html
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
 * specific language governing permissions and limitations under the
 * License.  When distributing the software, include this License Header
 * Notice in each file and include the License file at
 * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the GPL Version 2 section of the License file that
 * accompanied this code. If applicable, add the following below the
 * License Header, with the fields enclosed by brackets [] replaced by
 * your own identifying information:
 * "Portions Copyrighted [year] [name of copyright owner]"
 *
 * Contributor(s):
 *
 * The Original Software is NetBeans. The Initial Developer of the Original
 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
 * Microsystems, Inc. All Rights Reserved.
 *
 * If you wish your version of this file to be governed by only the CDDL
 * or only the GPL Version 2, indicate your decision by adding
 * "[Contributor] elects to include this software in this distribution
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
 * single choice of license, a recipient has the option to distribute
 * your version of this file under either the CDDL, the GPL Version 2 or
 * to extend the choice of license to its licensees as provided above.
 * However, if you add GPL Version 2 code and therefore, elected the GPL
 * Version 2 license, then the option applies only if the new code is
 * made subject to such option by the copyright holder.
 */

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 abstract class AbstractCodeGeneratorClass {
    static class Property {
        String	dtdName;
        private String namespace;
        String 	name;
        String 	classType;
        int	type;
        int	elementInstance;
        int    	groupInstance;
        int	level;
        boolean	isBean;
        boolean	ored;
        boolean isUnion = false;
        String constName;
        private boolean nillable;
        private boolean _isAttribute;
        private AttrProp attrProp;
        private Property attributeOwner = null;
        private String defaultValue;
        private boolean directChild;
        private GraphNode graphNode;
        private GraphLink graphLink;
        private List extraData;
        private boolean canBeEmpty = false;
        private String propertyInterface = null;
        private transient List mutuallyExclusiveProperties;
        private BeanBuilder.BeanElement beanElement;
        //private String orGroupName;
	
        //  List of attributes for this property (might be empty)
        AttrProp[]	attributes;
	
        Property(String propName, String dtdName, String namespace,
                 GraphNode graphNode,
                 GraphLink graphLink, String classType,
                 int eInst, int gInst, int level, int type, boolean ored,
                 AttrProp[] attrs, String constName, String defaultValue,
                 boolean directChild, List extraData, boolean isUnion) {
            //
            //	If the group instance is array, the element instance
            //	becomes an array.
            //
            if (gInst == Common.TYPE_0_N)
                eInst = gInst;
            else
                if (gInst == Common.TYPE_1_N) {
                    if (eInst == Common.TYPE_0_1)
                        eInst = Common.TYPE_0_N;
                    else
                        eInst = Common.TYPE_1_N;
                }
	    
            this.name = propName;
            this.isUnion = isUnion;
            this.dtdName = dtdName;
            this.namespace = namespace;
            this.graphNode = graphNode;
            this.graphLink = graphLink;
            this.classType = classType;
            this.type = type;
            this.elementInstance = eInst;
            this.groupInstance = gInst;
            this.level = level;
            this.attributes = attrs;
            this.ored = ored;
            this.constName = constName;
            this.isBean = Common.isBean(type);
            if (isScalar()) {
                this.classType = Common.wrapperClass(type);
            }
            this.defaultValue = defaultValue;
            this.directChild = directChild;
            this.extraData = extraData;
            //System.out.println("New property: name="+name+" type="+type);
        }

        public boolean isIndexed() {
            if (elementInstance == Common.TYPE_1_N) {
                return true;
            } else if (elementInstance == Common.TYPE_0_N) {
                return true;
            }
            return false;
        }

        public void setIndexed(boolean value) {
            if (isIndexed() == value)
                return;
            if (value)
                elementInstance = Common.TYPE_0_N;
            else
                elementInstance = Common.TYPE_0_1;
        }

        public boolean isNillable() {
            return nillable;
        }

        public void setNillable(boolean value) {
            nillable = value;
        }

        public boolean isUnion() {
            return isUnion;
        }

        public void setUnion(boolean value) {
            isUnion = value;
        }

        public boolean isScalar() {
            return Common.isScalar(type);
        }

        public String getScalarType() {
            if (!isScalar())
                return null;
            return Common.scalarType(type);
        }

        /**
         * The java type used for this bean.  @see getSignatureType()
         */
        public String getType() {
            if (isScalar())
                return getScalarType();
            else
                return classType;
        }

        public void setAttribute(boolean value) {
            _isAttribute = value;
        }

        public boolean isAttribute() {
            return _isAttribute;
        }

        public void setAttrProp(AttrProp ap) {
            attrProp = ap;
            setAttribute(ap != null);
        }

        public AttrProp getAttrProp() {
            return attrProp;
        }

        public void setAttributeOwner(Property owner) {
            attributeOwner = owner;
        }

        public Property getAttributeOwner() {
            return attributeOwner;
        }

        public String getDefaultValue() {
            return defaultValue;
        }

        public boolean isDirectChild() {
            return directChild;
        }

        public int getGroupInstance() {
            return groupInstance;
        }

        /**
         * The canBeEmpty property is true only if this node can be EMPTY
         * or not there.  This only occurs for when a DTD says that an
         * element is EMPTY and that maps into a boolean.
         */
        public void setCanBeEmpty(boolean value) {
            canBeEmpty = value;
        }

        public boolean getCanBeEmpty() {
            return canBeEmpty;
        }

        /**
         * This may return null.
         */
        public GraphNode getGraphNode() {
            return graphNode;
        }

        /**
         * This GraphLink is the one that defined this property's name.
         * It's siblings are the siblings in the schema.
         * This may return null.
         * getGraphLink().element == getGraphNode()
         */
        public GraphLink getGraphLink() {
            return graphLink;
        }

        public void setPropertyInterface(String iface) {
            propertyInterface = iface;
        }

        /**
         * The property interface is nonnull if the getters/setters
         * are suppose to use this interface.
         */
        public String getPropertyInterface() {
            return propertyInterface;
        }

        /**
         * This is the java type name as seen in the signature.  Usually, this
         * is the same as getTypeFullClassName(), but can
         * differ if -useInterfaces was set.
         */
        public String getSignatureType(String packageName) {
            if (getPropertyInterface() == null)
                return getTypeFullClassName(packageName);
            else
                return getPropertyInterface();
        }

        public String getTypeFullClassName(String packageName) {
            return getTypeFullClassName(packageName, getType());
        }
        
        public String getTypeFullClassName(String packageName, String typeName) {
            if (isBean && getGraphNode().isCreated() && packageName != null)
                return packageName+"."+typeName;
            return typeName;
        }

        public String getDTDName() {
            return dtdName;
        }

        public String getNamespace() {
            return namespace;
        }

        public BeanBuilder.BeanElement getBeanElement() {
            return beanElement;
        }

        public void setBeanElement(BeanBuilder.BeanElement be) {
            beanElement = be;
        }

        public String instanceOf() {
            String result = java.beans.Introspector.decapitalize(name);
            while (JavaUtil.reservedWord(result))
                result = "a_"+result;
            return result;
        }

        public String beanIntrospectorName() {
            return java.beans.Introspector.decapitalize(name);
        }

        public String getEventName() {/*
            if (isAttribute() && getAttributeOwner() != null &&
                getAttributeOwner() != this) {
                return getAttributeOwner().constName+"@"+getAttrProp().getDtdName();
                } else */
                return name;
        }

        /**
         * @param withIndexedParameter whether or not this getter
         * is going to be called with an index as a parameter.
         * @return the method to be called to do a read.
         */
        public String getReadMethod(boolean withIndexParameter) {
            if (!withIndexParameter && isIndexed())
                return "get"+name;
            else if (isScalar() && Common.isBoolean(type))
                return "is"+name;
            else
                return "get"+name;
        }

        public String getWriteMethod() {
            return "set"+name;
        }

        public String getAddMethod() {
            return "add"+name;
        }

        public String getRemoveMethod() {
            return "remove"+name;
        }

        public String getSizeMethod() {
            return "size"+name;
        }

        public String getScalarIsSet() {
            return "_isSet_"+name;
        }

        public List getMutuallyExclusiveProperties() {
            if (mutuallyExclusiveProperties == null && graphLink != null) {
                // Get the mutually exclusive GraphLink's and extract
                // our properties out of them.
                List mutuallyExclusiveGraphLinks = new ArrayList();
                graphLink.getMutuallyExclusiveLinks(mutuallyExclusiveGraphLinks);
                mutuallyExclusiveProperties = new ArrayList(mutuallyExclusiveGraphLinks.size());
                for (Iterator it = mutuallyExclusiveGraphLinks.iterator(); it.hasNext(); ) {
                    GraphLink l = (GraphLink) it.next();
                    if (l.getObject() != null)
                        mutuallyExclusiveProperties.add(l.getObject());
                }
            }
            return mutuallyExclusiveProperties;
        }

        /*
        public String getOrGroupName() {
            if (orGroupName == null) {
                orGroupName = name;
                for (Iterator it = getMutuallyExclusiveProperties().iterator(); it.hasNext(); ) {
                    Property p = (Property) it.next();
                    orGroupName += p.name;
                }
                for (Iterator it = getMutuallyExclusiveProperties().iterator(); it.hasNext(); ) {
                    Property p = (Property) it.next();
                    p.orGroupName = orGroupName;
                }
            }
            return orGroupName;
        }
        */

        public boolean canBeNull() {
            boolean canBeNull = false;
            boolean isPrimitiveType = JavaUtil.isPrimitiveType(getType());
            if (ored) {
                canBeNull = !isPrimitiveType;
            } else {
                switch (elementInstance & Common.MASK_INSTANCE) {
                case Common.TYPE_0_1:
                case Common.TYPE_1_N:
                case Common.TYPE_0_N:
                    canBeNull = !isPrimitiveType;
                    break;
                }
            }
            // What about group instance?
            return canBeNull;
        }
        
        public Object searchExtraData(Class type) {
            for (Iterator it = extraData.iterator(); it.hasNext(); ) {
                Object o = it.next();
                //System.out.println("searchExtraData: o="+o);
                if (type.isAssignableFrom(o.getClass()))
                    return o;
            }
            return null;
        }

        public Iterator extraDataIterator() {
            return extraData.iterator();
        }
    }

    class PropertyVisitor {
        protected Property curProp;
        protected int propNum;
        protected int propCount;

        public PropertyVisitor() {
        }

        public void generate() throws IOException {
            propCount = attrList.size();
            preGenerate();
            for (propNum = 0; propNum < propCount; ++propNum) {
                curProp = (Property) attrList.get(propNum);
                if (skip())
                    continue;
                preGenerateProp();
                generateProp();
                postGenerateProp();
            }
            postGenerate();
        }

        public void preGenerate() throws IOException {}

        public boolean skip() {
            return false;
        }

        public void preGenerateProp() throws IOException {}

        public void generateProp() throws IOException {}

        public void postGenerateProp() throws IOException {}

        public void postGenerate() throws IOException {}
    }

    class NamePropertyVisitor extends PropertyVisitor {
        protected String nameVar;

        public NamePropertyVisitor(String nameVar) {
            this.nameVar = nameVar;
        }

        public void preGenerate() throws IOException {
            jw.writeEol(nameVar+" = "+nameVar+".intern()");
        }

        public void preGenerateProp() throws IOException {
            if (curProp.name.equals(curProp.dtdName))
                jw.beginIf(nameVar+" == "+curProp.constName);
            else
                jw.beginIf(nameVar+" == "+curProp.constName+" || "+nameVar+" == \""+curProp.dtdName+"\"");
        }

        public void postGenerateProp() throws IOException {
            jw.endElse();
        }

        public void postGenerate() throws IOException {
            genInvalidName(nameVar);
        }
    }

    protected void genInvalidName(String var) throws IOException {
        jw.writeEol("throw new IllegalArgumentException(",
                    var, "+\" is not a valid property name for ",
                    className+"\")");
    }
    
    protected GenBeans.Config 	config;
    protected String  		packageName;
    protected String		className;
    protected String		fullClassName;

    protected BeanBuilder.BeanElement 	beanElement;
    protected BeanBuilder.BeanElement   rootBeanElement;

    private String defaultNamespace = null;

    // the graph of meta-elements
    protected MetaDD			mdd;
    
    // the meta-element for this class
    protected MetaElement		metaElement;
    
    // the set of types we've generated create methods for.
    protected Map generatedNewMethods = new HashMap();	// Map

    //	The list of all the attribute of this bean class
    protected ArrayList			attrList;
    
    protected PrefixGuesser prefixGuesser;
    
    //	Current building stream
    protected int		HEADER_SECTION 	= 0;
    protected int		DECL_SECTION	= 1;
    protected int		CONSTRUCTOR_SECTION	= 2;
    protected int		INITIALIZE_SECTION	= 3;
    protected int		ACCESS_SECTION	= 4;
    protected int		NEW_METHOD_SECTION = 5;
    protected int		BODY_SECTION	= 6;
    protected int		EQUALS_SECTION	= 7;
    protected int		HASHCODE_SECTION	= 8;
    protected int		TRAILER_SECTION	= 9;
    protected int		MAXVALUE	= 10;

    JavaWriter jw;

    private Map mutableTypes = new HashMap();
    private Map needToCallClone = new HashMap();

    protected boolean isMutableType(Property prop) {
        String type = prop.getType();
        Boolean mutable = (Boolean) mutableTypes.get(type);
        if (mutable == null) {
            if (prop.isBean)
                mutable = Boolean.TRUE;
            else if (prop.isScalar() || JavaUtil.isImmutable(type))
                mutable = Boolean.FALSE;
            else
                mutable = Boolean.TRUE;
            mutableTypes.put(type, mutable);
        }
        return mutable.booleanValue();
    }

    protected boolean isCloneCallNeededOnType(Property prop) {
        String type = prop.getType();
        Boolean callClone = (Boolean) needToCallClone.get(type);
        if (callClone == null) {
            if (prop.isBean || !isMutableType(prop))
                callClone = Boolean.FALSE;
            else
                callClone = JavaUtil.isCloneable(type) ? Boolean.TRUE : Boolean.FALSE;
            needToCallClone.put(type, callClone);
        }
        return callClone.booleanValue();
    }

    protected boolean genCopyWillCopy(Property a) {
        String type = a.getType();
        boolean mutable = isMutableType(a);
        boolean needToCallClone = isCloneCallNeededOnType(a);
        if ((mutable || needToCallClone)
            && !a.isBean && !JavaUtil.isInstantiable(type)) {
            mutable = false;
            needToCallClone = false;
        }
        if (type == "java.io.File") {
            return true;
        } else if (needToCallClone) {
            return true;
        } else if (mutable) {
            return true;
        } else {
            return false;
        }
    }

    protected void genCopy(String src, Property a, String justData) throws IOException {
        String type = a.getType().intern();
        String fullClassType = getTypeFullClassName(a);
        boolean mutable = isMutableType(a);
        boolean needToCallClone = isCloneCallNeededOnType(a);
        if ((mutable || needToCallClone)
            && !a.isBean && !JavaUtil.isInstantiable(type)) {
            mutable = false;
            needToCallClone = false;
        }
        if (type == "java.io.File") {
            jw.write("(", src, " == null) ? null : ");
            gen("new ");
            gen(fullClassType);
            PO();
            jw.write(src);
            jw.write(".getAbsolutePath()");
            PC();
        } else if (needToCallClone) {
            jw.write("(", src, " == null) ? null : ");
            PO();
            gen(fullClassType);
            PC();
            gen(src);
            gen(".clone()");
        } else if (mutable) {
            jw.write("(", src, " == null) ? null : ");
            String castSourceTo = null;
            if (a.isBean && hasDeepCopyConstructor()) {
                castSourceTo = a.getPropertyInterface();
                if (a.getPropertyInterface() != null && !type.equals(a.getPropertyInterface()))
                    jw.write("(", type, ") ");
                jw.write(genNewMethod(a.getPropertyInterface(), type));
            } else {
                gen("new ");
                gen(fullClassType);
            }
            
            PO();
            if (castSourceTo != null)
                jw.write("(", castSourceTo, ") ");
            jw.write(src);
            if (a.isBean) {
                if (config.isGenerateParentRefs()) {
                    jw.write(", this");
                }
                jw.write(", ", justData);
            }
            PC();
        } else {
            jw.write(src);
        }
    }

    protected boolean isTypeQName(String type) {
        type = type.intern();
        if (type == "javax.xml.namespace.QName")
            return true;
        if (type == "org.netbeans.modules.schema2beans.QName")
            return true;
        return false;
    }

    //
    //	Initial values for tabulations. Only header is 0, all other
    //	parts of the class start at one tabulation
    //
    
    static protected final int	   	PUBLIC 		= 0;
    static protected final int		PRIVATE 	= 1;
    static protected final int		VOID 		= 2;
    static protected final int		CLASS 		= 3;
    static protected final int		IMPORT 		= 4;
    static protected final int		PACKAGE    	= 5;
    static protected final int		STRING 		= 6;
    static protected final int		BOOLEAN		= 7;
    static protected final int		STATIC		= 8;
    static protected final int		FINAL		= 9;
    static protected final int		INT			= 10;
    static protected final int		PROTECTED	= 11;
    
    static protected final String arrKeywords[] = {
        "public",
        "private",
        "void",
        "class",
        "import",
        "package",
        "String",
        "boolean",
        "static",
        "final",
        "int",
        "protected"
    };

    protected void init(BeanBuilder.BeanElement be, GenBeans.Config config) {
        this.config = config;
        beanElement = be;
        packageName = null;
        className = be.getClassType();
        fullClassName = className;
        attrList = new ArrayList();
        jw = new JavaWriter();
        HEADER_SECTION = jw.HEADER_SECTION;
        DECL_SECTION = jw.DECL_SECTION;
        CONSTRUCTOR_SECTION = jw.CONSTRUCTOR_SECTION;
        INITIALIZE_SECTION = jw.insertSectionAfter(jw.CONSTRUCTOR_SECTION);
        ACCESS_SECTION = jw.insertSectionAfter(INITIALIZE_SECTION);
        NEW_METHOD_SECTION = jw.insertSectionAfter(ACCESS_SECTION);
        BODY_SECTION = jw.BODY_SECTION;
        EQUALS_SECTION = jw.insertSectionAfter(BODY_SECTION);
        HASHCODE_SECTION = jw.insertSectionAfter(EQUALS_SECTION);
        resetGenBuffers();
    }

    protected void resetGenBuffers() {
        jw.reset();
        jw.select(HEADER_SECTION);
    }

    protected void printGenBuffers(OutputStream out) throws IOException {
        jw.writeTo(out);
    }
    
    public void setPackageName(String n) {
        if (n == null || "".equals(n)) {
            packageName = null;
            fullClassName = className;
        } else {
            packageName = n.replace('/', '.');
            fullClassName = packageName + "." + className;
        }
    }

    public void setDefaultNamespace(String ns) {
        defaultNamespace = ns;
    }

    public String getDefaultNamespace() {
        return defaultNamespace;
    }
    
    /**
     * @param a is the Property in question
     * @param typeName is the name of the type of @param a, could include "[]"
     * @return Only if @param a is a bean will we add the packageName
     * to it's front.
     */
    protected String getTypeFullClassName(Property a) {
        return a.getTypeFullClassName(packageName);
    }
    
    protected String getTypeFullClassName(Property a, String typeName) {
        return a.getTypeFullClassName(packageName, typeName);
    }

    public void setIndent(String indent) {
        jw.setIndent(indent);
    }

    public void setRootBeanElement(BeanBuilder.BeanElement element) {
        rootBeanElement = element;
    }

    private transient String cachedRootClassName = null;
    protected String getRootClassName() {
        if (cachedRootClassName == null) {
            String rootClassName = rootBeanElement.getClassType();
            if (packageName == null)
                cachedRootClassName = rootClassName;
            else
                cachedRootClassName = packageName + "." + rootClassName;
        }
        return cachedRootClassName;
    }

    /**
     * Once all properties have been added to this Bean, call this method
     * to figure out for attribute property who it's owner is.
     * That is, make Property.getAttributeOwner() work.
     */
    protected void findAttributeOwners() {
        Property attributeOwner;
        int size = attrList.size();
        for (int i = 0; i < size; i++) {
            Property a = (Property)attrList.get(i);
            if (a.isAttribute()) {
                attributeOwner = a;
                AttrProp attrProp = a.getAttrProp();
            propertyLoop:
                for (int propNum = 0; propNum < size; ++propNum) {
                    Property prop = (Property) attrList.get(propNum);
                    if (prop.attributes == null)
                        continue;
                    for (int attrNum = 0; attrNum < prop.attributes.length; ++attrNum) {
                        AttrProp propAttr = prop.attributes[attrNum];
                        if (propAttr == attrProp) {
                            // Found it!
                            attributeOwner = prop;
                            break propertyLoop;
                        }
                    }
                }
                a.setAttributeOwner(attributeOwner);
                a.setIndexed(attributeOwner.isIndexed());
            }
        }
    }
    
    /**
     * @return null if not found
     */
    protected Property findProperty(AttrProp attr) {
        int size = attrList.size();
        for (int j = 0; j < size; j++) {
            Property p = (Property)attrList.get(j);
            if (p.getAttrProp() == attr) {
                // Found it
                return p;
            }
        }
        return null;
    }

    /*
     * Set of helpers to generate the classe content
     */
    protected void select(int o) {
        jw.select(o);
    }
    
    protected void gen(String s) {
        try {
            jw.write(s);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    
    protected void gen(StringBuffer s) {
        try {
            jw.write(s);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    
    protected void gen(String s1, String s2) { gen(s1); gen(s2); }
    
    protected void gen(String s1, String s2, String s3) {
        gen(s1); gen(s2); gen(s3);
    }

    protected void gen(int a)	{ gen(arrKeywords[a]); }
    
    protected void gen(int a, String s) { gen(a); sp(); gen(s); }
    
    protected void gen(int a, String s, String s2) { gen(a, s); sp(); gen(s2); }
    
    protected void gen(int a, int b, String s, String s2) {
        gen(a, b, s); gen(s2);
    }
    
    protected void gen(int a, int b, String s) {
        gen(a); sp(); gen(b); sp(); gen(s);
    }
    
    protected void gen(int a, int b, int c, String s) {
        gen(a); sp(); gen(b); sp(); gen(c); sp(); gen(s);
    }
    
    protected void gen(int a, int b, int c, int d, String s) {
        gen(a); sp(); gen(b); sp(); gen(c); sp(); gen(d); sp(); gen(s);
    }
    
    protected void gencr(String s) { gen(s); cr(); }
    
    protected void gencr(String s, String s2) { gen(s, s2); cr(); }
    
    protected void gencr(int a, String s) { gen(a, s); cr(); }
    
    protected void gencr(int a, String s, String s2) { gen(a, s, s2); cr(); }
    
    protected void gencr(int a, int b, String s, String s2) {
        gen(a, b, s, s2); cr();
    }
    
    protected void gencr(int a, int b, String s) { gen(a, b, s); cr(); }
    
    protected void gencr(int a, int b, int c, String s) {gen(a, b, c, s); cr();}
    
    protected void get(String s) {gen(" get"); gen(s); PO(); PC();}
    protected void geti(String s) {gen(" get"); gen(s, "(int index)");}
    protected void getidx(String s, boolean b) {if (b) geti(s); else get(s); }
    
    protected void cr() {
        try {
            jw.cr();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    
    protected void geneol(String s) { gen(s); eol(); }

    protected void PO() {	gen("("); }
    
    protected void PC() {	gen(")"); }
    
    protected void begin() {
        try {
            jw.begin();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    
    protected void end() { end(true); };
    
    protected void end(boolean cr) {
        try {
            jw.end(cr);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    
    protected void comment() { gencr("//"); }

    protected void gencrNoI18N(String s) {gen(s); noI18N();}
    protected void gencrNoI18N(String s, String s2) {gen(s); gen(s2); noI18N();}

    protected void beginNoI18N() { gencr("// BEGIN" + "_NOI18N"); }
    protected void endNoI18N() { gencr("// END" + "_NOI18N"); }
    protected void noI18N()  {
        try {
            jw.noI18N();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    
    protected void comment(String s) {
        try {
            jw.comment(s);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    
    protected void comment(String s, String s2) { comment(s + s2); }
    
    protected void eol() {
        try {
            jw.eol();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    protected void eol(boolean cr) { gen(";"); if (cr) cr(); }
    
    protected void eolNoI18N() {
        try {
            jw.eolNoI18N();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    
    protected void sp() { gen(" "); }
    
    protected void genforprop() {gencr("for (int i=0; i");
        out.write(" : ");
        out.write(className);
        if (!beanElement.node.getExtraData().isEmpty()) {
            out.write(" \t");
            out.write(beanElement.node.getExtraData().toString());
        }
        out.write("\n");
        StringBuffer str = new StringBuffer();
        int lineCount = 1;
        lineCount = dumpAttributes(beanElement.getGraphNode(), str, indent+indentBy, lineCount);
        lineCount = dumpBeanTree(beanElement, str,
                 indent+indentBy, indentBy, lineCount);
        out.write(str.toString());
        if (lineCount >= MAX_DUMP_TREE_LINE_COUNT) {
            out.write(indent);
            out.write("... etc ...\n");
        }
    }
    
    protected int dumpBeanTree(BeanBuilder.BeanElement be, StringBuffer str,
            String indent, String indentBy, int lineCount) {
        lineCount = beanTree(be.getGraphNode().getGraphLink(), str,
                 indent, indentBy, lineCount);
        if (be.getExtension() != null) {
            //lineCount = dumpAttributes(be.getExtension().getGraphNode(), str, indent, lineCount);
            lineCount = dumpBeanTree(be.getExtension(), str, indent, indentBy, lineCount);
        }
        return lineCount;
    }

    protected int dumpAttributes(GraphNode elt, StringBuffer str, String indent, int lineCount) {
        AttrProp[] attrList = elt.getAttributes();
	
        for (int i = 0; i < attrList.length; i++) {
            AttrProp attr = attrList[i];
            str.append(indent + "[attr: " + attr  + "]");
            if (!attr.getExtraData().isEmpty()) {
                str.append(" \t");
                str.append(attr.getExtraData().toString());
            }
            str.append("\n");
            ++lineCount;
        }
        if (false && elt.getExtension() != null)
            lineCount = dumpAttributes(elt.getExtension(), str, indent, lineCount);
        return lineCount;
    }
    
    protected int beanTree(GraphLink l, StringBuffer str,
                            String indent, String indentBy, int lineCount) {
        if (lineCount >= MAX_DUMP_TREE_LINE_COUNT)
            return lineCount;  // Enough, already.
        for (; l != null; l = l.getSibling()) {
            //str.append("l="+l+"\n");
            //str.append("l.object="+l.getObject()+"\n");
            //str.append("l.lastInGroup="+l.getLastInGroup()+"\n");
            String nextIndent = indent + indentBy;
            if (l.element != null) {
                BeanBuilder.BeanElement be =
                    (BeanBuilder.BeanElement)l.element.getObject();
		
                if (be == null)
                    continue;
                Property prop = (Property) l.getObject();
                String type = be.getClassType();
                String name = l.name;
                if ("#PCDATA".equals(l.name) && "String".equals(type))
                    continue;
                if (prop != null) {
                    type = prop.getType();
                    if ("EMPTY".equals(prop.dtdName))
                        name = prop.dtdName;
                    else
                        name = prop.beanIntrospectorName() + " <"+prop.dtdName+">";
                }
			
                str.append(indent);
                str.append(name);
                str.append(" : ");
                str.append(type);
                str.append(TreeBuilder.instanceToString(l.getElementInstance(),
                                                        true));
                if (l.element.getMarked())
                    str.append("...");
                if (!l.extraData.isEmpty()) {
                    str.append(" \t");
                    str.append(l.extraData.toString());
                }
                if (!be.node.getExtraData().isEmpty()) {
                    str.append(" \t");
                    str.append(be.node.getExtraData().toString());
                }
                str.append("\n");
                ++lineCount;
                
                if (config.isRespectExtension() && be.getExtension() != null)
                    lineCount = dumpBeanTree(be.getExtension(),
                            str, nextIndent, indentBy, lineCount);
		    
                lineCount = this.dumpAttributes(l.element, str, nextIndent, lineCount);
		    
                if (l.element.getGraphLink() != null) {
                    if (l.element.getMarked() == false) {
                        l.element.setMarked(true);
                        lineCount =
                            beanTree(l.element.getGraphLink(), str, nextIndent +
                                 TreeBuilder.instanceToString(l.getGroupInstance(),
                                                              true) +
                                 (l.isSequenceOr() ? "| " : ""), indentBy, lineCount);
                        l.element.setMarked(false);
                    }
                }
            }

            String groupInstance = TreeBuilder.instanceToString(l.getGroupInstance(), true);
            if (!"".equals(groupInstance)) {
                str.append(indent);
                str.append("(\n");
                ++lineCount;
            }
            if (l.getFirstChild() != null) {
                lineCount = beanTree(l.getFirstChild(), str, indent + (("".equals(groupInstance)) ? "" : "  ") + (l.isSequenceOr() ? "| " : ""), indentBy, lineCount);
            }
            if (!"".equals(groupInstance)) {
                str.append(indent);
                str.append(")");
                str.append(groupInstance);
                str.append("\n");
                ++lineCount;
            }
        }
        return lineCount;
    }

    public String toString() {
        if (packageName == null)
            return "Class " + className;
        else
            return "Class " + packageName + "." + className;
    }

    protected void gen(Signature sig) throws IOException {
        sig.writeMethod(jw);
    }

    public static final int MAX_DUMP_TREE_LINE_COUNT = 512;

    protected static final Signature.TypeOfMethod SETTER = Signature.TypeOfMethod.SETTER;
    protected static final Signature.TypeOfMethod SETTERINDEXED = Signature.TypeOfMethod.SETTERINDEXED;
    protected static final Signature.TypeOfMethod GETTER = Signature.TypeOfMethod.GETTER;
    protected static final Signature.TypeOfMethod GETTERLIST = Signature.TypeOfMethod.GETTERLIST;
    protected static final Signature.TypeOfMethod GETTERINDEXED = Signature.TypeOfMethod.GETTERINDEXED;
    protected static final Signature.TypeOfMethod SIZE = Signature.TypeOfMethod.SIZE;
    protected static final Signature.TypeOfMethod ADD = Signature.TypeOfMethod.ADD;
    protected static final Signature.TypeOfMethod REMOVE = Signature.TypeOfMethod.REMOVE;
    protected static final Signature.TypeOfMethod OTHER = Signature.TypeOfMethod.OTHER;

    protected static class Signature {
        public static class TypeOfMethod {
            private final String name;
            private TypeOfMethod(String name) { this.name = name; }
            public String toString() { return "TypeOfMethod "+name; }
            public static final TypeOfMethod SETTER = new TypeOfMethod("setter");
            public static final TypeOfMethod SETTERINDEXED = new TypeOfMethod("setterindexed");
            public static final TypeOfMethod GETTER = new TypeOfMethod("getter");
            public static final TypeOfMethod GETTERLIST = new TypeOfMethod("getterlist");
            public static final TypeOfMethod GETTERINDEXED = new TypeOfMethod("getterindexed");
            public static final TypeOfMethod SIZE = new TypeOfMethod("size");
            public static final TypeOfMethod ADD = new TypeOfMethod("add");
            public static final TypeOfMethod REMOVE = new TypeOfMethod("remove");
            public static final TypeOfMethod OTHER = new TypeOfMethod("other");
        }

        private String returnType;
        private String methodName;
        private TypeOfMethod methodType;
        private List parameterTypes;
        private List parameterNames;
        private List throwTypes;
        private boolean _isStatic;

        public Signature(String returnType, String methodName, TypeOfMethod methodType) {
            this.returnType = returnType;
            this.methodName = methodName;
            this.methodType = methodType;
            this.parameterTypes = new LinkedList();
            this.parameterNames = new LinkedList();
            this.throwTypes = new LinkedList();
            this._isStatic = false;
        }

        public Signature(String returnType, String methodName) {
            this.returnType = returnType;
            this.methodName = methodName;
            this.methodType = OTHER;
            this.parameterTypes = new LinkedList();
            this.parameterNames = new LinkedList();
            this.throwTypes = new LinkedList();
            this._isStatic = false;
        }

        public String getMethodName() {
            return methodName;
        }

        public String getReturnType() {
            return returnType;
        }

        public TypeOfMethod getMethodType() {
            return methodType;
        }

        public boolean isStatic() {
            return _isStatic;
        }

        public void setStatic() {
            _isStatic = true;
        }

        public boolean isVoidReturnType() {
            return "void".equals(returnType);
        }

        public void addParameter(String type, String name) {
            parameterTypes.add(type);
            parameterNames.add(name);
        }

        public void addThrows(String type) {
            throwTypes.add(type);
        }

        public void writeMethod(JavaWriter jw) throws IOException {
            StringBuffer parameters = new StringBuffer();
            Iterator itTypes = parameterTypes.iterator();
            Iterator itNames = parameterNames.iterator();
            boolean first = true;
            while (itTypes.hasNext() && itNames.hasNext()) {
                if (first)
                    first = false;
                else
                    parameters.append(", ");
                parameters.append((String) itTypes.next());
                parameters.append(" ");
                parameters.append((String) itNames.next());
            }
            String exceptions = null;
            Iterator itThrows = throwTypes.iterator();
            if (itThrows.hasNext()) {
                exceptions = "";
                first = true;
                do {
                    if (first)
                        first = false;
                    else
                        exceptions += ", ";
                    exceptions += ((String) itThrows.next());
                } while (itThrows.hasNext());
            }
            int options = jw.PUBLIC | jw.BEANINFO;
            if (_isStatic)
                options |= jw.STATIC;
            jw.writeMethod(methodName, parameters.toString(), exceptions,
                           returnType, options);
        }

        /**
         *  int sizeFoo()
         *  int addFoo(Foo value)
         */
        public String toString() {
            StringBuffer str = new StringBuffer();
            if (_isStatic)
                str.append("static ");
            str.append(returnType);
            str.append(" ");
            str.append(methodName);
            str.append("(");
            Iterator itTypes = parameterTypes.iterator();
            Iterator itNames = parameterNames.iterator();
            boolean first = true;
            while (itTypes.hasNext() && itNames.hasNext()) {
                if (first)
                    first = false;
                else
                    str.append(", ");
                str.append((String) itTypes.next());
                str.append(" ");
                str.append((String) itNames.next());
            }
            str.append(")");
            Iterator itThrows = throwTypes.iterator();
            if (itThrows.hasNext()) {
                str.append(" throws ");
                first = true;
                do {
                if (first)
                    first = false;
                else
                    str.append(", ");
                str.append((String) itThrows.next());
                } while (itThrows.hasNext());
            }
            return str.toString();
        }

        /**
         * Generate what's needed to call the method.
         * sizeFoo()
         * addFoo(value)
         */
        public String callMethod() {
            StringBuffer str = new StringBuffer();
            str.append(methodName);
            str.append("(");
            Iterator itTypes = parameterTypes.iterator();
            Iterator itNames = parameterNames.iterator();
            boolean first = true;
            while (itTypes.hasNext() && itNames.hasNext()) {
                if (first)
                    first = false;
                else
                    str.append(", ");
                str.append((String) itNames.next());
            }
            str.append(")");
            return str.toString();
        }
    }

    protected static class Signatures {
        Map signatureTable;
        List others;

        public Signatures() {
            signatureTable = new HashMap();
            others = new LinkedList();
        }

        public void add(Signature sig) {
            if (sig.getMethodType() == OTHER)
                others.add(sig);
            else
                signatureTable.put(sig.getMethodType(), sig);
        }

        public Signature findSignature(Signature.TypeOfMethod methodType) {
            Signature sig = null;
            if (methodType == OTHER) {
                Iterator it = others.iterator();
                if (it.hasNext())
                    sig = (Signature) it.next();
            } else
                sig = (Signature) signatureTable.get(methodType);
            if (sig == null)
                throw new IllegalStateException("Unable to find "+methodType);
            return sig;
        }

        public Iterator iterator() {
            return new SignaturesIterator();
            //return signatureTable.values().iterator();
        }

        public class SignaturesIterator implements Iterator {
            Iterator tableIterator;
            Iterator othersIterator;

            public SignaturesIterator() {
                tableIterator = signatureTable.values().iterator();
                othersIterator = others.iterator();
            }
            
            public boolean hasNext() {
                if (tableIterator.hasNext())
                    return true;
                return othersIterator.hasNext();
            }

            public Object next() {
                if (tableIterator.hasNext())
                    return tableIterator.next();
                return othersIterator.next();
            }

            public void remove() {
                throw new UnsupportedOperationException();
            }
        }
    }

    protected Signatures getSignatures(Property a) {
        Signatures result = new Signatures();
        Signature sig;

        boolean indexed = a.isIndexed();
        boolean isScalar = a.isScalar();
        String type = getTypeFullClassName(a);
        String typeVariable = "value";
        //System.out.println("a.name="+a.name+" a.dtdName="+a.dtdName+" a.type="+a.getType());
        if (a.isBean && config.isUseInterfaces()) {
            MetaElement me = getMetaElement(a);
            if (me != null) {
                String firstInterface = firstInCommaSeparatedList(me.getImplements());
                if (firstInterface != null &&
                    !firstInterface.equals(config.getGenerateCommonInterface()) &&
                    !firstInterface.equals(packageName+"."+config.getGenerateCommonInterface())) {
                    type = firstInterface;
                    typeVariable = "valueInterface";
                    a.setPropertyInterface(firstInterface);
                }
            }
        }
        String baseType = type;
        if (indexed)
            type = baseType + "[]";

        // the setter
        sig = new Signature("void", "set"+a.name, SETTER);
        sig.addParameter(type, typeVariable);
        if (config.isVetoable())
            sig.addThrows("java.beans.PropertyVetoException");
        result.add(sig);
        if (indexed) {
            sig = new Signature("void", "set"+a.name, SETTERINDEXED);
            sig.addParameter("int", "index");
            sig.addParameter(baseType, typeVariable);
            if (config.isVetoable())
                sig.addThrows("java.beans.PropertyVetoException");
            result.add(sig);
        }

        // the getter
        String getterName = a.getReadMethod(false);
        result.add(new Signature(type, getterName, GETTER));
        if (indexed) {
            String returnType = "java.util.List";
            if (config.jdkTarget >= 150)
                returnType += "<"+JavaUtil.toObjectType(baseType)+">";
            result.add(new Signature(returnType, "fetch"+a.name+"List", GETTERLIST));
            sig = new Signature(baseType, a.getReadMethod(true), GETTERINDEXED);
            sig.addParameter("int", "index");
            result.add(sig);
            result.add(new Signature("int", "size"+a.name, SIZE));
            sig = new Signature("int", "add"+a.name, ADD);
            sig.addParameter(baseType, typeVariable);
            if (config.isVetoable())
                sig.addThrows("java.beans.PropertyVetoException");
            result.add(sig);
            sig = new Signature("int", "remove"+a.name, REMOVE);
            sig.addParameter(baseType, typeVariable);
            if (config.isVetoable())
                sig.addThrows("java.beans.PropertyVetoException");
            result.add(sig);
        }

        return result;
    }

    public void generateDelegator(OutputStream out, MetaDD mdd,
                                  String delegatorClassName,
                                  String delegatorPackageName) throws IOException {
        Collection generatedMethods = jw.getStoredMethods();
        resetGenBuffers();
        
        select(HEADER_SECTION);
        jw.bigComment("Delegate for "+className+"\n\n@"+Common.GENERATED_TAG);
        jw.cr();
        if (delegatorPackageName != null) {
            jw.writePackage(delegatorPackageName);
            cr();
        }
        gen(PUBLIC, CLASS, delegatorClassName);
        if (metaElement.getDelegatorExtends() != null) {
            jw.write(" extends ");
            jw.write(metaElement.getDelegatorExtends());
        }
        if (config.getGenerateCommonInterface() != null) {
            jw.write(" implements ");
            jw.write(config.getGenerateCommonInterface());
        }
        sp();
        begin();

        select(DECL_SECTION);
        String delegator = "_"+className;	// NOI18N
        gen(PROTECTED, fullClassName, delegator);
        eol();
        cr();

        generateDelegatorConstructors(delegatorClassName);

        List sortedMethods = new LinkedList(generatedMethods);
        Collections.sort(sortedMethods);
        for (Iterator it = sortedMethods.iterator(); it.hasNext(); ) {
            JavaWriter.Method method = (JavaWriter.Method) it.next();
            if (method.isPublic())
                generateDelegator(method, delegatorClassName);
        }

        select(TRAILER_SECTION);
        end();

        printGenBuffers(out);
    }

    protected void generateDelegatorConstructors(String delegatorClassName) throws IOException {
        select(CONSTRUCTOR_SECTION);
        String delegator = "_"+className;	// NOI18N
        gen(PUBLIC, delegatorClassName);
        PO();
        gen(fullClassName);
        gen(" delegator");
        PC(); sp();
        begin();
        geneol(delegator+" = delegator");
        end();
        cr();
    }

    protected void generateDelegator(JavaWriter.Method method, String delegatorClassName) throws IOException {
        if ("".equals(method.getReturnType())) {
            if (method.getParameters().indexOf(',') < 0 &&
                (method.getParameters().startsWith(className+" ") ||
                 method.getParameters().startsWith(fullClassName+" "))) {
                // We already have a constructor with that parameter
                return;
            }
            select(CONSTRUCTOR_SECTION);
            String delegator = "_"+className;	// NOI18N
            jw.write("public ");
            jw.write(delegatorClassName);
            jw.write("(");
            jw.write(method.getParameters());
            jw.write(") ");
            if (method.getExceptions() != null) {
                jw.write("throws ", method.getExceptions(), " ");
            }
            jw.begin();
            jw.write(delegator, " = new ", fullClassName);
            jw.write("(");
            method.writeParametersNoTypes(jw);
            jw.writeEol(")");
            jw.end();
            jw.cr();
            return;
        }
        select(BODY_SECTION);
        boolean returnsDelegation = false;
        if (className.equals(method.getReturnType()) ||
            fullClassName.equals(method.getReturnType())) {
            returnsDelegation = true;
        }
        jw.beginMethod(method.getName(), method.getParameters(),
                       method.getExceptions(),
                       returnsDelegation ? delegatorClassName : method.getReturnType(),
                       method.getOptions());
        if (!"void".equals(method.getReturnType())) {
            gen("return ");
        }
        if (returnsDelegation)
            jw.write("new ", delegatorClassName, "(");
        if (!method.isStatic())
            jw.write("_", className);
        else
            jw.write(fullClassName);
        jw.write(".");
        method.writeCall(jw);
        if (returnsDelegation)
            jw.write(")");
        jw.eol();
        jw.end();
        jw.cr();
    }

    /**
     * @param var The name of a variable.
     */
    protected void genWhiteSpaceRestriction(SchemaRep.WhiteSpace ws, String var,
                                            String type) throws IOException {
        if (!("String".equals(type) || "java.lang.String".equals(type)))
            return;
        if (ws.isPreserve())
            return;
        if (ws.isReplace()) {
            jw.beginIf(var+" != null");
            jw.comment("Whitespace Replace due to whitespace restriction.");
            jw.writeEol(var+" = "+var+".replace('\\n', ' ').replace('\\t', ' ')");
            jw.end();
        } else if (ws.isCollapse()) {
            jw.beginIf(var+" != null");
            jw.comment("Whitespace Collapse due to whitespace restriction.");
            jw.writeEol(var+" = "+var+".replace('\\n', ' ').replace('\\t', ' ').trim()");
            jw.beginFor("int pos = "+var+".indexOf(\"  \")", "pos >= 0",
                        "pos = "+var+".indexOf(\"  \", pos)");
            jw.writeEol(var+" = "+var+".substring(0, pos) + "+var+".substring(pos+1, "+var+".length())");
            jw.end();
            jw.end();
        }
    }

    protected void genRethrowExceptions(List exceps) {
        for (Iterator it = exceps.iterator(); it.hasNext(); ) {
            gen("catch (");
            gen((String) it.next());
            gen(" e) ");
            begin();
            geneol("throw new java.lang.RuntimeException(e)");
            end();
        }
    }

    protected void genValidateProperties() throws IOException {
        jw.writeEol("boolean restrictionFailure = false");
        jw.writeEol("boolean restrictionPassed = false");
        Set requiredPropertySet = new HashSet();
        Map requiredProperty = new HashMap();
        int size = attrList.size();
        for (int i = 0; i < size; i++) {
            Property a = (Property)attrList.get(i);
            boolean indexed = a.isIndexed();
            String attr = a.getReadMethod(false)+"()";
            String type = a.getType().intern();
            boolean mightBeNull = a.canBeNull();
            boolean isPrimitiveType = JavaUtil.isPrimitiveType(type);
            String propertyName = a.beanIntrospectorName();
            boolean hasDataEnumRestriction = false;
            String enumArray = "enumRestriction"+a.name;
            //boolean checkOrCount = a.ored && !isPrimitiveType;
            boolean checkOrCount = a.ored;
            if (checkOrCount) {
                //jw.comment("a.groupInstance="+a.getGroupInstance());
                // If there can be zero of them, then don't check the or.
                if (a.getGroupInstance() == Common.TYPE_0_N ||
                    a.getGroupInstance() == Common.TYPE_0_1) {
                    checkOrCount = false;
                }
            }
            jw.comment("Validating property "+propertyName);
            //jw.writeEol("System.out.println(\"Validating property "+propertyName+"\")");
            if (a.isUnion())
                jw.writeEol("restrictionPassed = false");
            if (a.ored) {
            } else {
                switch (a.elementInstance & Common.MASK_INSTANCE) {
                case Common.TYPE_1:
                    if (isPrimitiveType) {
                        // There is always one of them (no null).
                        break;
                    }
                    if (a.isNillable())
                        break;
                    genValidateIf(attr+" == null", propertyName,
                                  ValidateException.FailureType.NULL_VALUE,
                                  jw);
                    break;
                case Common.TYPE_0_1:
                    break;
                case Common.TYPE_0_N:
                    // Never a problem.
                    break;
                case Common.TYPE_1_N:
                    genValidateIf("size"+a.name+"() == 0", propertyName,
                                  ValidateException.FailureType.NULL_VALUE, jw);
                    break;
                }
            }
            if (indexed && a.isAttribute())
                continue;
            // Test children
            int markedPosition = -1;
            if (indexed) {
                for (Iterator it = a.extraDataIterator(); it.hasNext(); ) {
                    Object extraData = it.next();
                    if (extraData instanceof DataListRestriction) {
                        DataListRestriction dlr = (DataListRestriction) extraData;
                        dlr.genRestriction(jw, "size"+a.name+"()", a.getReadMethod(false), type, "restrictionFailure", false);
                        jw.beginIf("restrictionFailure");
                        genValidateFail(JavaUtil.instanceFrom("java.lang.String", attr+" "+dlr.toString()),
                                        propertyName, false,
                                        ValidateException.FailureType.DATA_RESTRICTION,
                                        jw);
                        jw.end();
                    }
                }
                markedPosition = jw.getCurrentPosition();
                jw.beginFor("int _index = 0",
                            "_index < size"+a.name+"()", "++_index");
                jw.write(getTypeFullClassName(a));
                jw.write(" element = ");
                if (a.getPropertyInterface() != null) {
                    jw.write("(", getTypeFullClassName(a), ") ");
                }
                jw.writeEol(a.getReadMethod(true)+"(_index)");
                attr = "element";
            }
            if (mightBeNull) {
                if (markedPosition == -1)
                    markedPosition = jw.getCurrentPosition();
                jw.beginIf(attr+" != null");
            }

            int marked2Position = jw.getCurrentPosition();
            if (a.isBean) {
                if (a.getPropertyInterface() == null) {
                    if (!a.getGraphNode().isCreated()) {
                        jw.beginTry();
                        jw.comment("Catch and deal with any foreign validate exceptions.");
                    }
                    jw.writeEol(attr, ".validate()");
                    if (!a.getGraphNode().isCreated()) {
                        jw.endCatch("java.lang.Exception e");
                        jw.writeEol("throw new java.lang.RuntimeException(e)");
                        jw.end();
                    }
                } else
                    jw.writeEol("(("+type+")", attr, ").validate()");
            }
            genForRestrictions(a, attr);
            //System.out.println("  a.name="+a.name);
            for (Iterator it = a.extraDataIterator(); it.hasNext(); ) {
                Object extraData = it.next();
                //System.out.println("  Found extraData="+extraData);
                //jw.comment("name="+a.name+" Found extraData="+extraData);
                if (extraData instanceof DataTypeRestriction) {
                    DataTypeRestriction dtr = (DataTypeRestriction) extraData;
                    dtr.genRestriction(jw, attr, type, "restrictionFailure", false);
                    jw.beginIf("restrictionFailure");
                    genValidateFail(JavaUtil.instanceFrom("java.lang.String", attr+" "+dtr.toString()),
                                    propertyName, false,
                                    ValidateException.FailureType.DATA_RESTRICTION,
                                    jw);
                    jw.end();
                }
            }
            for (Iterator it = a.extraDataIterator(); it.hasNext(); ) {
                Object extraData = it.next();
                if (extraData instanceof DataEnumRestriction) {
                    DataEnumRestriction der = (DataEnumRestriction) extraData;
                    if (!hasDataEnumRestriction) {
                        // first one
                        hasDataEnumRestriction = true;
                        jw.write("final "+type+"[] "+enumArray+" = {");
                    } else {
                        jw.write(", ");
                    }
                    der.genRestriction(jw, type);
                }
            }
            if (hasDataEnumRestriction) {
                jw.writeEol("}");
                jw.writeEol("restrictionFailure = true");
                jw.beginFor("int _index2 = 0", "_index2 < "+enumArray+".length",
                            "++_index2");
                jw.beginIf(JavaUtil.genEquals(type, enumArray+"[_index2]",
                                              attr, false));
                jw.writeEol("restrictionFailure = false");
                jw.writeEol("break");
                jw.end();
                jw.end();
                jw.beginIf("restrictionFailure");
                genValidateFail(JavaUtil.instanceFrom("java.lang.String", attr+" enumeration test"),
                                propertyName, false,
                                ValidateException.FailureType.ENUM_RESTRICTION,
                                jw);
                jw.end();
            }

            if (marked2Position != jw.getCurrentPosition()) {
                if (mightBeNull) {
                    jw.end();
                }
                if (indexed) {
                    jw.end();
                }
            } else {
                if (markedPosition >= 0) {
                    // We didn't write anything since marked2Position, which
                    // means that we didn't need the stuff after markedPosition
                    jw.truncateAtPosition(markedPosition);
                }
                if (mightBeNull)
                    jw.indentLeft();
                if (indexed)
                    jw.indentLeft();
            }

            if (checkOrCount) {
                GraphLink gl = a.getGraphLink();
                //jw.comment("checkOrCount: gl="+gl);
                GraphLink parentgl = null;
                if (gl != null) {
                    parentgl = gl.getParent();
                }
                //if (parentgl == null || parentgl.getGroupInstance() == Common.TYPE_1) {
                List requiredPropertyTest = new ArrayList();
                jw.beginIf(testIfPropertySet(a));
                requiredPropertyTest.add(testIfPropertyNotSet(a));
                for (Iterator it = a.getMutuallyExclusiveProperties().iterator(); it.hasNext(); ) {
                    Property prop = (Property) it.next();
                    jw.beginIf(testIfPropertySet(prop));
                    requiredPropertyTest.add(testIfPropertyNotSet(prop));
                    genValidateFail("mutually exclusive properties: "+a.name+" and "+prop.name,
                                    prop.name, true,
                                    ValidateException.FailureType.MUTUALLY_EXCLUSIVE,
                                    jw);
                    jw.end();
                }
                jw.end();

                //
                // This is preparing for the check that at least 1
                // of the properties are set.
                // Sort our list of property checks and store the
                // if expression into a Set, so that we generate
                // only one if per group of properties.
                //
                Collections.sort(requiredPropertyTest);
                StringBuffer requiredExpr = new StringBuffer();
                boolean first = true;
                for (Iterator it = requiredPropertyTest.iterator(); it.hasNext(); ) {
                    if (first)
                        first = false;
                    else
                        requiredExpr.append(" && ");
                    requiredExpr.append((String) it.next());
                }
                String requiredExprString = requiredExpr.toString();
                requiredPropertySet.add(requiredExprString);
                requiredProperty.put(requiredExprString, a);
            }
        }
        for (Iterator it = requiredPropertySet.iterator(); it.hasNext(); ) {
            String required = (String) it.next();
            Property prop = (Property) requiredProperty.get(required);
            jw.beginIf(required);
            genValidateFail("required properties: "+required,
                            prop.name, true,
                            ValidateException.FailureType.NULL_VALUE,
                            jw);
            jw.end();
        }
    }

    protected void genForRestrictions(Property a, String attr)
            throws IOException {
        boolean isUnion = a.isUnion();
        String propertyName = a.beanIntrospectorName();
        String enumArray = "enumRestriction"+a.name;
        String type = a.getType().intern();
        SchemaRep.Restriction restrict = null;
        for (Iterator it = a.extraDataIterator(); it.hasNext(); ) {
            boolean hasDataEnumRestriction = false;
            Object extraData = it.next();
            if (extraData instanceof SchemaRep.Restriction)
                restrict = (SchemaRep.Restriction)extraData;
            else
                continue;
            if (isUnion) {
                // There is no type associated with the union
                // So get the type of the restriction
                String tempType = restrict.getJavaTypeName();
                if (tempType != null)
                    type = tempType.intern();
                jw.write("{\n");
            }
            boolean firstPattern = true;
            for (Iterator itr = restrict.subElementsIterator(); itr.hasNext(); ) {
                Object rType = itr.next();
                if (rType instanceof SchemaRep.Pattern) {
                    if (firstPattern) {
                        jw.write("{\n");
                        jw.writeEol("boolean patternPassed = false");
                        firstPattern = false;
                    }
                    DataTypeRestriction dtr = (DataTypeRestriction) rType;
                    dtr.genRestriction(jw, attr, type, "patternPassed", true);
                }
            }
            if (!firstPattern) {
                jw.writeEol("restrictionFailure = !patternPassed");
                jw.write("}\n");
                if (!isUnion) {
                    jw.beginIf("restrictionFailure");
                    genValidateFail(JavaUtil.instanceFrom("java.lang.String", attr),
                                    propertyName, false,
                                    ValidateException.FailureType.DATA_RESTRICTION,
                                    jw);
                    jw.end();
                }
            }
            for (Iterator itr = restrict.subElementsIterator(); itr.hasNext(); ) {
                Object rType = itr.next();
                if (rType instanceof DataListRestriction) {
                    DataListRestriction dlr = (DataListRestriction) rType;
                    dlr.genRestriction(jw, "size"+a.name+"()", a.getReadMethod(false), type, "restrictionFailure", false);
                    if (!isUnion) {
                        jw.beginIf("restrictionFailure");
                        genValidateFail(JavaUtil.instanceFrom("java.lang.String", attr+" "+dlr.toString()),
                                        propertyName, false,
                                        ValidateException.FailureType.DATA_RESTRICTION,
                                        jw);
                        jw.end();
                    }
                }
                if (rType instanceof DataTypeRestriction && !(rType instanceof SchemaRep.Pattern)) {
                    DataTypeRestriction dtr = (DataTypeRestriction) rType;
                    String typeAttr = attr;
                    if (isUnion) {
                        // for an element having a uniontype the getXXX function would return String 
                        // So for the actual validation we need to convert the string to the
                        // restriction's type so that we can compare
                        jw.beginTry();
                        typeAttr = "("+JavaUtil.genParseText(type, attr, config.isJava5())+")";
                    }
                    dtr.genRestriction(jw, typeAttr, type, "restrictionFailure", false);
                    if (isUnion) {
                        // Catch any exception during the comparison
                        // An exception will be thrown only for the conversion of the type
                        // so assume failure if an exception occurs, since comparison did not
                        // occur
                        jw.endCatch("Exception e");
                        jw.writeEol("restrictionFailure = true");
                        jw.end();
                    }
                    if (!isUnion) {
                        jw.beginIf("restrictionFailure");
                        genValidateFail(JavaUtil.instanceFrom("java.lang.String", attr+" "+dtr.toString()),
                                        propertyName, false,
                                        ValidateException.FailureType.DATA_RESTRICTION,
                                        jw);
                        jw.end();
                    }
                }
            }
            for (Iterator itr = restrict.subElementsIterator(); itr.hasNext(); ) {
                Object rType = itr.next();
                if (rType instanceof DataEnumRestriction) {
                    DataEnumRestriction der = (DataEnumRestriction) rType;
                    if (!hasDataEnumRestriction) {
                        // first one
                        hasDataEnumRestriction = true;
                        jw.write("final "+type+"[] "+enumArray+" = {");
                    } else {
                        jw.write(", ");
                    }
                    der.genRestriction(jw, type);
                }
            }
            if (hasDataEnumRestriction) {
                jw.writeEol("}");
                jw.writeEol("restrictionFailure = true");
                jw.beginFor("int _index2 = 0", "_index2 < "+enumArray+".length",
                            "++_index2");
                jw.beginIf(JavaUtil.genEquals(type, enumArray+"[_index2]",
                                              attr, false));
                jw.writeEol("restrictionFailure = false");
                jw.writeEol("break");
                jw.end();
                jw.end();
                if (!isUnion) {
                    jw.beginIf("restrictionFailure");
                    genValidateFail(JavaUtil.instanceFrom("java.lang.String", attr+" enumeration test"),
                                    propertyName, false,
                                    ValidateException.FailureType.ENUM_RESTRICTION,
                                    jw);
                    jw.end();
                }
            }
            if (isUnion) {
                // Set restrictionPassed only if it is not already set to true
                jw.beginIf("!restrictionPassed");
                jw.writeEol("restrictionPassed = !restrictionFailure");
                jw.end();
                jw.writeEol("restrictionFailure = false");
                jw.write("}\n");
            }
        }
        if (isUnion) {
            jw.beginIf("!restrictionPassed");
            genValidateFail(JavaUtil.instanceFrom("java.lang.String", attr),
                            propertyName, false,
                            ValidateException.FailureType.ALL_RESTRICTIONS,
                            jw);
            jw.end();
        }
    }

    protected void genValidateIf(String test, String name,
                                 ValidateException.FailureType ft,
                                 JavaWriter out) throws IOException {
        jw.beginIf(test);
        genValidateFail(test, name, true, ft, out);
        jw.end();
    }

    protected abstract void genValidateFail(String detail, String name,
                                            boolean quoteDetail,
                                            ValidateException.FailureType ft,
                                            JavaWriter out) throws IOException;

    public Collection getGeneratedMethods() {
        return jw.getStoredMethods();
    }

    protected void genDefaultsAccessable(Property a) throws IOException {
        String type = a.getType();
        boolean mustHaveOneInstance = (!a.ored && a.elementInstance == Common.TYPE_1);
        if (config.isDefaultsAccessable() && !a.isIndexed() &&
            (a.isScalar() || a.getDefaultValue() != null ||
             mustHaveOneInstance)) {
            jw.beginMethod("fetchDefault"+a.name, "", null, type, jw.PUBLIC);
            List exceps = JavaUtil.exceptionsFromParsingText(type, false);
            if (!exceps.isEmpty()) {
                jw.beginTry();
            }
            jw.write("return ");
            if (a.getDefaultValue() != null)
                jw.write(JavaUtil.instanceFrom(type, a.getDefaultValue()));
            else if (config.isMakeDefaults())
                jw.write(JavaUtil.genNewDefault(type));
            else
                jw.write(JavaUtil.nullValueForType(type));
            jw.eol();
            if (!exceps.isEmpty()) {
                end();
                genRethrowExceptions(exceps);
            }
            jw.end();
            jw.cr();
        }
    }

    protected void generateSwitches() throws IOException {
        select(jw.BODY_SECTION);
        jw.bigComment("@return true if error, then should display help");
        jw.beginMethod("parseArguments", "String[] args", null, "boolean");
        jw.beginFor("int argNum = 0, size = args.length", "argNum < size",
                    "++argNum");
        jw.writeEol("String arg = args[argNum].toLowerCase().intern()");
        int size = attrList.size();
        Map mandatoryProperties = new LinkedHashMap();
        StringBuffer helpParams = new StringBuffer();
        int lastHelpParamsPos = 0;
        StringBuffer helpText = new StringBuffer();
        for (int i = 0; i < size; i++) {
            Property a = (Property)attrList.get(i);
            XMLSchemaParser.SwitchData sd = (XMLSchemaParser.SwitchData) a.searchExtraData(XMLSchemaParser.SwitchData.class);
            if (sd == null)
                continue;
            if (sd.isMandatory())
                mandatoryProperties.put(sd.getName(), a);
            String sw = sd.getName();
            sw = sw.toLowerCase();
            String type = a.getType().intern();
            boolean indexed = a.isIndexed();
            String writeMethod;
            if (indexed)
                writeMethod = a.getAddMethod();
            else
                writeMethod = a.getWriteMethod();
            //jw.comment("a.name="+a.name+" sw="+sw+" sd.help="+sd.getHelp()+" mandatory="+sd.isMandatory());
            jw.beginIf(JavaUtil.instanceFrom("String", "-"+sw) + ".equals(arg)");
            boolean isBoolean = (type == "boolean" || type == "Boolean" || type == "java.lang.Boolean");
            helpParams.append(" ");
            if (!sd.isMandatory())
                helpParams.append("[");
            helpParams.append("-");
            if (isBoolean) {
                jw.writeEol(writeMethod+"(true)");
                helpParams.append(sd.getName());
            } else {
                jw.beginIf("argNum+1 >= size");
                jw.writeEol("missingArgument(args, arg)");
                jw.writeEol("continue");
                jw.end();
                jw.writeEol(writeMethod+"("+JavaUtil.genParseText(type,
                                                                         "args[++argNum]",
                                                                         config.isForME())+")");
                helpParams.append(sd.getName());
                helpParams.append(" ");
                if (type == "java.io.File")
                    helpParams.append("filename");
                else
                    helpParams.append(a.dtdName);
            }
            if (!sd.isMandatory())
                helpParams.append("]");
            jw.writeEol("continue");
            jw.end();
            helpText.append(" -");
            helpText.append(sd.getName());
            helpText.append("\t");
            if (sd.getHelp() != null) {
                helpText.append(sd.getHelp());
            } else {
                helpText.append(a.name);
            }
            helpText.append('\n');
            if (isBoolean) {
                jw.beginIf(JavaUtil.instanceFrom("String", "-no"+sw) + ".equals(arg)");
                jw.writeEol(writeMethod+"(false)");
                jw.writeEol("continue");
                jw.end();
                helpParams.append(" [-no");
                helpParams.append(sd.getName());
                helpParams.append("]");
            }
            if (helpParams.length() - lastHelpParamsPos > 63) {
                helpParams.append("\n");
                lastHelpParamsPos = helpParams.length();
            }
        }
        jw.beginIf("arg == \"-help\" || arg == \"--help\"");
        jw.writeEol("return true");
        jw.end();
        jw.writeEol("argNum = unknownArgument(args, arg, argNum)");
        jw.end();
        for (Iterator it = mandatoryProperties.keySet().iterator(); it.hasNext(); ) {
            String sw = (String) it.next();
            Property a = (Property) mandatoryProperties.get(sw);
            jw.beginIf(testIfPropertyNotSet(a));
            jw.writeEol("missingMandatoryArgument(", JavaUtil.instanceFrom("java.lang.String", "-"+sw),
                        ")");
            jw.end();
        }
        jw.writeEol("return false");
        jw.end();
        jw.cr();
        jw.beginMethod("unknownArgument",
                       "String[] args, String arg, int argNum", null, "int",
                       jw.PROTECTED);
        jw.writeEol("throw new IllegalArgumentException(\"Found unknown argument '\"+arg+\"'\")");
        jw.end();
        jw.cr();
        jw.beginMethod("missingArgument",
                       "String[] args, String arg", null, "void",
                       jw.PROTECTED);
        jw.writeEol("throw new IllegalArgumentException(\"Not enough arguments.  Need 1 more for '\"+arg+\"'\")");
        jw.end();
        jw.cr();
        jw.beginMethod("missingMandatoryArgument",
                       "String arg", null, "void",
                       jw.PROTECTED);
        jw.writeEol("throw new IllegalArgumentException(\"Missing argument '\"+arg+\"'\")");
        jw.end();
        jw.cr();
        jw.beginMethod("showHelp", "java.io.PrintStream out");
        if (helpParams.length() > 0) {
            if (lastHelpParamsPos < helpParams.length())
                helpParams.append("\n");
            jw.writeEol("out.println(",
                        JavaUtil.instanceFrom("java.lang.String",
                                              helpParams.toString()),
                        ")");
        }
        if (helpText.length() > 0) {
            jw.writeEol("out.print(",
                        JavaUtil.instanceFrom("java.lang.String",
                                              helpText.toString()),
                        ")");
        }
        jw.end();
        jw.cr();
    }

    protected boolean isMutuallyExclusive(Property a) {
        return (a.ored && !a.getMutuallyExclusiveProperties().isEmpty());
    }

    /**
     * Generate commands for resetting the mutually exclusive properties,
     * only if isMutuallyExclusive(a) returns true.
     */
    protected void genResetMutuallyExclusive(Property a, boolean genTest) throws IOException {
        if (isMutuallyExclusive(a)) {
            if (genTest) {
                if (a.isIndexed()) {
                    jw.beginIf("value != null && value.length > 0");
                } else {
                    jw.beginIf("value != "+JavaUtil.nullValueForType(a.getType()));
                }
            }
            jw.comment("It's a mutually exclusive property.");
            for (Iterator it = a.getMutuallyExclusiveProperties().iterator(); it.hasNext(); ) {
                Property prop = (Property) it.next();
                jw.writeEol(prop.getWriteMethod(), "(",
                            prop.isIndexed() ? "null" : JavaUtil.nullValueForType(prop.getType()),
                            ")");
            }
            if (genTest)
                jw.end();
        }
    }

    /**
     * All generated beans are at least this type.
     */
    protected String commonBeanType() {
        String cb = "java.lang.Object";
        if (config.getGenerateCommonInterface() != null) {
            if (packageName == null)
                cb = config.getGenerateCommonInterface();
            else
                cb = packageName + "." + config.getGenerateCommonInterface();
        }
        return cb;
    }

    protected String parentBeanType() {
        if (config.isExtendBaseBean())
            return "org.netbeans.modules.schema2beans.BaseBean";
        else
            return commonBeanType();
    }

    /**
     * Returns the first element in a command separated list
     */
    protected static String firstInCommaSeparatedList(String lst) {
        if (lst == null)
            return null;
        int pos = lst.indexOf(',');
        if (pos < 0)
            return lst;
        return lst.substring(0, pos);
    }

    protected String genNewMethod(String abstractType, String concreteType) throws IOException {
        return genNewMethod(abstractType, concreteType, concreteType);
    }

    /**
     * Generate a method that will get a new instance of some type.
     * Only 1 method will be generated per abstractType.
     * @param abstractType interface name to use as return type, if
     *                     null, then concreteType is used.
     * @param concreteType the class to get a new instance of
     * @param concreteFullTypeName the full name of the concreteType
     */
    protected String genNewMethod(String abstractType, String concreteType,
                                  String concreteFullTypeName) throws IOException {
        if (abstractType == null)
            abstractType = concreteType;
        abstractType = abstractType.trim();
        concreteType = concreteType.trim();
        String returnType = abstractType;
        boolean abstractConcreteSame = abstractType.equals(concreteType);
        if (abstractConcreteSame)
            returnType = concreteFullTypeName;
        String methodName = (String) generatedNewMethods.get(abstractType);
        if (methodName == null) {
            if (abstractType.indexOf('.') >= 0) {
                String base = JavaUtil.baseName(abstractType);
                if (generatedNewMethods.containsKey(base)) {
                    methodName = "new"+(abstractType.replace('.', '_'));
                } else {
                    methodName = "new"+base;
                }
            } else {
                methodName = "new"+abstractType;
            }
            jw.pushSelect(NEW_METHOD_SECTION);
            jw.bigComment("Create a new bean using it's default constructor.\nThis does not add it to any bean graph.");
            jw.beginMethod(methodName, "", null, returnType, jw.PUBLIC | jw.BEANINFO);
            jw.writeEol("return new ", concreteFullTypeName, "()");
            jw.endMethod();

            if (hasDeepCopyConstructor()) {
                jw.bigComment("Create a new bean, copying from another one.\nThis does not add it to any bean graph.");
                String formalParam = abstractType + " source";
                String actualParam;
                if (abstractConcreteSame)
                    actualParam = "source";
                else
                    actualParam = "("+concreteType+") source";
                if (config.isGenerateParentRefs()) {
                    formalParam += ", "+parentBeanType()+" parent";
                    actualParam += ", parent";
                }
                formalParam += ", boolean justData";
                actualParam += ", justData";
                jw.beginMethod(methodName, formalParam, null, returnType, jw.PUBLIC | jw.BEANINFO);
                jw.write("return new ", concreteFullTypeName);
                jw.writeEol("(", actualParam, ")");
                jw.endMethod();
            }
            jw.popSelect();
            generatedNewMethods.put(abstractType, methodName);
        }
        return methodName;
    }

    protected void genNewDefault(Property prop,
                                 boolean wantConcreteType) throws IOException {
        String type = prop.getType();
        if (prop.isBean) {
            String abstractType = prop.getPropertyInterface();
            String methodName = genNewMethod(abstractType, type,
                                             getTypeFullClassName(prop));
            if (wantConcreteType) {
                if (abstractType != null && !type.equals(abstractType))
                    jw.write("(", type, ") ");
            }
            jw.write(methodName, "()");
        } else {
            jw.write(JavaUtil.genNewDefault(type));
        }
    }

    protected boolean hasDeepCopyConstructor() {
        return false;
    }

    protected String testIfPropertySet(Property prop) {
        if (prop.isIndexed()) {
            return "size"+prop.name+"() > 0";
        } else {
            return prop.getReadMethod(false)+"() != "+JavaUtil.nullValueForType(prop.getType());
        }
    }

    protected String testIfPropertyNotSet(Property prop) {
        if (prop.isIndexed()) {
            return "size"+prop.name+"() == 0";
        } else {
            return prop.getReadMethod(false)+"() == "+JavaUtil.nullValueForType(prop.getType());
        }
    }

    protected int countNumberOfNonAttributeProperties() {
        int count = beanElement.getNonAttributePropertyCount();
        /*
        int count = 0;
        for (int i = 0; i < attrList.size(); i++) {
            Property prop = (Property)attrList.get(i);
            if (prop.isAttribute())
                continue;
            ++count;
        }
        */
        if (config.isRespectExtension()) {
            count += countNumberOfNonAttributePropertiesRecurse(beanElement.getExtension());
        }
        return count;
    }

    protected int countNumberOfNonAttributePropertiesRecurse(BeanBuilder.BeanElement be) {
        int count = 0;
        while (be != null) {
            //config.messageOut.println("extensionBE="+be);
            count += be.getNonAttributePropertyCount();
            be = be.getExtension();
            //config.messageOut.println("count="+count);
        }
        return count;
    }
    
    public void setPrefixGuesser(PrefixGuesser guesser) {
        if (guesser == null) {
            if (prefixGuesser == null) {
                prefixGuesser = new PrefixGuesser() {
                    public String guessPrefixFromURI(String uri) {
                        return SchemaRep.guessPrefix(uri);
                    }
                };
            }
        } else {
            prefixGuesser = guesser;
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy