/*
 * Copyright 2001-2004 The Apache Software Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.axis.wsdl.toJava;

import org.apache.axis.components.logger.LogFactory;
import org.apache.axis.utils.JavaUtils;
import org.apache.axis.utils.Messages;
import org.apache.axis.wsdl.gen.Generator;
import org.apache.axis.wsdl.gen.GeneratorFactory;
import org.apache.axis.wsdl.gen.NoopGenerator;
import org.apache.axis.wsdl.symbolTable.BaseTypeMapping;
import org.apache.axis.wsdl.symbolTable.BindingEntry;
import org.apache.axis.wsdl.symbolTable.ContainedAttribute;
import org.apache.axis.wsdl.symbolTable.Element;
import org.apache.axis.wsdl.symbolTable.ElementDecl;
import org.apache.axis.wsdl.symbolTable.FaultInfo;
import org.apache.axis.wsdl.symbolTable.MessageEntry;
import org.apache.axis.wsdl.symbolTable.Parameter;
import org.apache.axis.wsdl.symbolTable.Parameters;
import org.apache.axis.wsdl.symbolTable.PortTypeEntry;
import org.apache.axis.wsdl.symbolTable.SchemaUtils;
import org.apache.axis.wsdl.symbolTable.ServiceEntry;
import org.apache.axis.wsdl.symbolTable.SymTabEntry;
import org.apache.axis.wsdl.symbolTable.SymbolTable;
import org.apache.axis.wsdl.symbolTable.Type;
import org.apache.axis.wsdl.symbolTable.TypeEntry;
import org.apache.commons.logging.Log;

import javax.wsdl.Binding;
import javax.wsdl.Definition;
import javax.wsdl.Fault;
import javax.wsdl.Message;
import javax.wsdl.Operation;
import javax.wsdl.OperationType;
import javax.wsdl.Port;
import javax.wsdl.PortType;
import javax.wsdl.Service;
import javax.xml.namespace.QName;
import javax.xml.rpc.holders.BooleanHolder;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Vector;

/**
 * This is Wsdl2java's implementation of the GeneratorFactory
 */
public class JavaGeneratorFactory implements GeneratorFactory {
    private static final Log log_ =
        LogFactory.getLog(JavaGeneratorFactory.class.getName());

    /** Field emitter */
    protected Emitter emitter;

    /** Field symbolTable */
    protected SymbolTable symbolTable;

    /** Field COMPLEX_TYPE_FAULT */
    public static String COMPLEX_TYPE_FAULT = "ComplexTypeFault";

    /** Field EXCEPTION_CLASS_NAME */
    public static String EXCEPTION_CLASS_NAME = "ExceptionClassName";

    /** Field EXCEPTION_DATA_TYPE */
    public static String EXCEPTION_DATA_TYPE = "ExceptionDataType";
    
    /* Name suffixes for collision */
    private static final String SERVICE_SUFFIX = "_Service";
    private static final String PORT_TYPE_SUFFIX = "_PortType";     // "_Port" (Axis classic) --> "_PortType" (JAX-RPC 1.1)
    private static final String TYPE_SUFFIX = "_Type";
    private static final String ELEMENT_SUFFIX = "_Element";        // "_ElemType (Axis classic) --> "_Element" (JAX-RPC 1.1)
    private static final String EXCEPTION_SUFFIX = "_Exception";   
    private static final String BINDING_SUFFIX = "_Binding";


    /**
     * Default constructor.  Note that this class is unusable until setEmitter
     * is called.
     */
    public JavaGeneratorFactory() {
        addGenerators();
    }    // ctor

    /**
     * Constructor JavaGeneratorFactory
     *
     * @param emitter
     */
    public JavaGeneratorFactory(Emitter emitter) {

        this.emitter = emitter;

        addGenerators();
    }    // ctor

    /**
     * Method setEmitter
     *
     * @param emitter
     */
    public void setEmitter(Emitter emitter) {
        this.emitter = emitter;
    }    // setEmitter

    /**
     * Method addGenerators
     */
    private void addGenerators() {

        addMessageGenerators();
        addPortTypeGenerators();
        addBindingGenerators();
        addServiceGenerators();
        addTypeGenerators();
        addDefinitionGenerators();
    }                                            // addGenerators

    /**
     * These addXXXGenerators are called by the constructor.
     * If an extender of this factory wants to CHANGE the set
     * of generators that are called per WSDL construct, they
     * should override these addXXXGenerators methods.  If all
     * an extender wants to do is ADD a generator, then the
     * extension should simply call addGenerator.
     * (NOTE:  It doesn't quite work this way, yet.  Only the
     * Definition generators fit this model at this point in
     * time.)
     */
    protected void addMessageGenerators() {
    }     // addMessageGenerators

    /**
     * Method addPortTypeGenerators
     */
    protected void addPortTypeGenerators() {
    }    // addPortTypeGenerators

    /**
     * Method addBindingGenerators
     */
    protected void addBindingGenerators() {
    }     // addBindingGenerators

    /**
     * Method addServiceGenerators
     */
    protected void addServiceGenerators() {
    }     // addServiceGenerators

    /**
     * Method addTypeGenerators
     */
    protected void addTypeGenerators() {
    }        // addTypeGenerators

    /**
     * Method addDefinitionGenerators
     */
    protected void addDefinitionGenerators() {

        addGenerator(Definition.class, JavaDefinitionWriter.class);    // for faults
        addGenerator(Definition.class,
                JavaDeployWriter.class);      // for deploy.wsdd
        addGenerator(Definition.class,
                JavaUndeployWriter.class);    // for undeploy.wsdd
        addGenerator(Definition.class,
                JavaBuildFileWriter.class); //add a build file writer

    }                                              // addDefinitionGenerators


    /**
     * Do the Wsdl2java generator pass:
     * - resolve name clashes
     * - construct signatures
     *
     * @param def
     * @param symbolTable
     */
    public void generatorPass(Definition def, SymbolTable symbolTable) {

        this.symbolTable = symbolTable;

        javifyNames(symbolTable);
        setFaultContext(symbolTable);
        resolveNameClashes(symbolTable);
        determineInterfaceNames(symbolTable);

        if (emitter.isAllWanted()) {
            setAllReferencesToTrue();
        } else {
            ignoreNonSOAPBindings(symbolTable);
        }

        constructSignatures(symbolTable);
        determineIfHoldersNeeded(symbolTable);
    }    // generatorPass

    /** Since Wsdl2java doesn't emit anything for Messages, return the No-op generator. */
    private Writers messageWriters = new Writers();

    /**
     * Method getGenerator
     *
     * @param message
     * @param symbolTable
     * @return
     */
    public Generator getGenerator(Message message, SymbolTable symbolTable) {
        if (include(message.getQName())) {
            MessageEntry mEntry = symbolTable.getMessageEntry(message.getQName());
            messageWriters.addStuff(new NoopGenerator(), mEntry, symbolTable);
            return messageWriters;
        }
        else {
            return new NoopGenerator();
        }
    }    // getGenerator

    /** Return Wsdl2java's JavaPortTypeWriter object. */
    private Writers portTypeWriters = new Writers();

    /**
     * Method getGenerator
     *
     * @param portType
     * @param symbolTable
     * @return
     */
    public Generator getGenerator(PortType portType, SymbolTable symbolTable) {
        if (include(portType.getQName())) {
            PortTypeEntry ptEntry =
                    symbolTable.getPortTypeEntry(portType.getQName());
            portTypeWriters.addStuff(new NoopGenerator(), ptEntry, symbolTable);
            return portTypeWriters;
        }
        else {
            return new NoopGenerator();
        }
    }    // getGenerator

    /** Return Wsdl2java's JavaBindingWriter object. */
    protected Writers bindingWriters = new Writers();

    /**
     * Method getGenerator
     *
     * @param binding
     * @param symbolTable
     * @return
     */
    public Generator getGenerator(Binding binding, SymbolTable symbolTable) {
        if (include(binding.getQName())) {
            Generator writer = new JavaBindingWriter(emitter, binding,
                    symbolTable);
            BindingEntry bEntry = symbolTable.getBindingEntry(binding.getQName());
            bindingWriters.addStuff(writer, bEntry, symbolTable);
            return bindingWriters;
        }
        else {
            return new NoopGenerator();
        }
    }    // getGenerator

    /** Return Wsdl2java's JavaServiceWriter object. */
    protected Writers serviceWriters = new Writers();

    /**
     * Method getGenerator
     *
     * @param service
     * @param symbolTable
     * @return
     */
    public Generator getGenerator(Service service, SymbolTable symbolTable) {
        if (include(service.getQName())) {
            Generator writer = new JavaServiceWriter(emitter, service,
                    symbolTable);
            ServiceEntry sEntry = symbolTable.getServiceEntry(service.getQName());
            serviceWriters.addStuff(writer, sEntry, symbolTable);
            return serviceWriters;
        }
        else {
            return new NoopGenerator();
        }
    }    // getGenerator

    /** Return Wsdl2java's JavaTypeWriter object. */
    private Writers typeWriters = new Writers();

    /**
     * Method getGenerator
     *
     * @param type
     * @param symbolTable
     * @return
     */
    public Generator getGenerator(TypeEntry type, SymbolTable symbolTable) {
        if (include(type.getQName())) {
            Generator writer = new JavaTypeWriter(emitter, type, symbolTable);
            typeWriters.addStuff(writer, type, symbolTable);
            return typeWriters;
        }
        else {
            return new NoopGenerator();
        }
    }    // getGenerator

    /** Return Wsdl2java's JavaDefinitionWriter object. */
    private Writers defWriters = new Writers();

    /**
     * Method getGenerator
     *
     * @param definition
     * @param symbolTable
     * @return
     */
    public Generator getGenerator(Definition definition,
                                  SymbolTable symbolTable) {
        if (include(definition.getQName())) {
            defWriters.addStuff(null, definition, symbolTable);
            return defWriters;
        }
        else {
            return new NoopGenerator();
        }
    }    // getGenerator

    // Hack class just to play with the idea of adding writers

    /**
     * Class Writers
     *
     * @version %I%, %G%
     */
    protected class Writers implements Generator {

        /** Field writers */
        Vector writers = new Vector();

        /** Field symbolTable */
        SymbolTable symbolTable = null;

        /** Field baseWriter */
        Generator baseWriter = null;

        // entry or def, but not both, will be a parameter.

        /** Field entry */
        SymTabEntry entry = null;

        /** Field def */
        Definition def = null;

        /**
         * Method addGenerator
         *
         * @param writer
         */
        public void addGenerator(Class writer) {
            writers.add(writer);
        }    // addWriter

        /**
         * Method addStuff
         *
         * @param baseWriter
         * @param entry
         * @param symbolTable
         */
        public void addStuff(Generator baseWriter, SymTabEntry entry,
                             SymbolTable symbolTable) {

            this.baseWriter = baseWriter;
            this.entry = entry;
            this.symbolTable = symbolTable;
        }    // addStuff

        /**
         * Method addStuff
         *
         * @param baseWriter
         * @param def
         * @param symbolTable
         */
        public void addStuff(Generator baseWriter, Definition def,
                             SymbolTable symbolTable) {

            this.baseWriter = baseWriter;
            this.def = def;
            this.symbolTable = symbolTable;
        }    // addStuff

        /**
         * Method generate
         *
         * @throws IOException
         */
        public void generate() throws IOException {

            if (baseWriter != null) {
                baseWriter.generate();
            }

            Class[] formalArgs;
            Object[] actualArgs;

            if (entry != null) {
                formalArgs = new Class[]{Emitter.class, entry.getClass(),
                                         SymbolTable.class};
                actualArgs = new Object[]{emitter, entry, symbolTable};
            } else {
                formalArgs = new Class[]{Emitter.class, Definition.class,
                                         SymbolTable.class};
                actualArgs = new Object[]{emitter, def, symbolTable};
            }

            for (int i = 0; i < writers.size(); ++i) {
                Class wClass = (Class) writers.get(i);
                Generator gen;

                try {
                    Constructor ctor = wClass.getConstructor(formalArgs);

                    gen = (Generator) ctor.newInstance(actualArgs);
                } catch (Throwable t) {
                    throw new IOException(Messages.getMessage("exception01",
                            t.getMessage()));
                }

                gen.generate();
            }
        }    // generate
    }    // class Writers

    /**
     * Method addGenerator
     *
     * @param wsdlClass
     * @param generator
     */
    public void addGenerator(Class wsdlClass, Class generator) {

        // This is just a hack right now... it just works with Service
        if (Message.class.isAssignableFrom(wsdlClass)) {
            messageWriters.addGenerator(generator);
        } else if (PortType.class.isAssignableFrom(wsdlClass)) {
            portTypeWriters.addGenerator(generator);
        } else if (Binding.class.isAssignableFrom(wsdlClass)) {
            bindingWriters.addGenerator(generator);
        } else if (Service.class.isAssignableFrom(wsdlClass)) {
            serviceWriters.addGenerator(generator);
        } else if (TypeEntry.class.isAssignableFrom(wsdlClass)) {
            typeWriters.addGenerator(generator);
        } else if (Definition.class.isAssignableFrom(wsdlClass)) {
            defWriters.addGenerator(generator);
        }
    }    // addGenerator

    /**
     * Fill in the names of each SymTabEntry with the javaified name.
     * Note: This method also ensures that anonymous types are
     * given unique java type names.
     *
     * @param symbolTable
     */
    protected void javifyNames(SymbolTable symbolTable) {

        int uniqueNum = 0;
        HashMap anonQNames = new HashMap();
        Iterator it = symbolTable.getHashMap().values().iterator();

        while (it.hasNext()) {
            Vector v = (Vector) it.next();

            for (int i = 0; i < v.size(); ++i) {
                SymTabEntry entry = (SymTabEntry) v.elementAt(i);

                if (entry.getName() != null) {
                    continue;
                }

                // Use the type or the referenced type's QName to generate the java name.
                if (entry instanceof TypeEntry) {
                    uniqueNum = javifyTypeEntryName(symbolTable, (TypeEntry) entry, anonQNames, uniqueNum);
                }

                // If it is not a type, then use this entry's QName to
                // generate its name.
                else {
                    entry.setName(emitter.getJavaName(entry.getQName()));
                }
            }
        }
    }    // javifyNames

    /** Refactored to call recursively for JAX-RPC 1.1 spec 4.2.5. */
    protected int javifyTypeEntryName(SymbolTable symbolTable, TypeEntry entry, HashMap anonQNames, int uniqueNum) {
        TypeEntry tEntry = entry;
        String dims = tEntry.getDimensions();
        TypeEntry refType = tEntry.getRefType();
        while (refType != null) {
            tEntry = refType;
            dims += tEntry.getDimensions();
            refType = tEntry.getRefType();
        }

        TypeEntry te = tEntry;
        while (te != null) {
            TypeEntry base = SchemaUtils.getBaseType(te, symbolTable);
            if (base == null)
                break;

            uniqueNum = javifyTypeEntryName(symbolTable, base, anonQNames, uniqueNum);

            if (Utils.getEnumerationBaseAndValues(te.getNode(), symbolTable) == null
                    &&SchemaUtils.getComplexElementExtensionBase(te.getNode(), symbolTable) == null
					&& te.getContainedAttributes() == null) {
                if(!SchemaUtils.isSimpleTypeWithUnion(te.getNode())) {
                    if (base.isSimpleType()) {
                        // Case 1:
                        // <simpleType name="mySimpleStringType">
                        //   <restriction base="xs:string">
                        //   </restriction>
                        // </simpleType>
                        te.setSimpleType(true);
                        te.setName(base.getName());
                        te.setRefType(base);
                    }
    
                    if (base.isBaseType()) {
                        // Case 2:
                        // <simpleType name="FooString">
                        //   <restriction base="foo:mySimpleStringType">
                        //   </restriction>
                        // </simpleType>
                        te.setBaseType(true);
                        te.setName(base.getName());
                        te.setRefType(base);
                    }
                }
            }

            if (!te.isSimpleType())
                break;

            te = base;
        }

        // Need to javify the ref'd TypeEntry if it was not
        // already processed
        if (tEntry.getName() == null) {
            boolean processed = false;	// true if the java name is already determined
            // Get the QName of the ref'd TypeEntry, which
            // is will be used to javify the name
            QName typeQName = tEntry.getQName();

            // In case of <xsd:list itemType="...">,
            // set typeQName to the value of the itemType attribute.
            QName itemType = SchemaUtils.getListItemType(tEntry.getNode());
            if (itemType != null) {
                // Get the typeEntry so we know the absolute base type
                TypeEntry itemEntry = symbolTable.getTypeEntry(itemType, false);
		// TODO - If the itemEntry is not found, we need to throw
		// an exception.  "Item is referenced, but not defined"
                javifyTypeEntryName(symbolTable, itemEntry, anonQNames, uniqueNum);
                // Grab the referenced type, If it's there.
                TypeEntry refedEntry = itemEntry.getRefType();
                QName baseName = refedEntry == null ? itemEntry.getQName() : 
                        refedEntry.getQName();
                typeQName = new QName(baseName.getNamespaceURI(),
                                        baseName.getLocalPart() + "[]");
            }
            
            if (emitter.isDeploy()) {				
                Class class1 = (Class) emitter.getQName2ClassMap().get(typeQName);				
				if (class1 != null && !class1.isArray()) {                    
                    tEntry.setName(getJavaClassName(class1));
                    processed = true;
                }                            
            }
            
            if (!processed) {
	            if ((typeQName.getLocalPart().
	                    indexOf(SymbolTable.ANON_TOKEN) < 0)) {
	                // Normal Case: The ref'd type is not anonymous
	                // Simply construct the java name from
	                // the qName
	                tEntry.setName(emitter.getJavaName(typeQName));
	            } else {
	                // This is an anonymous type name.
	                // Axis uses '>' as a nesting token to generate
	                // unique qnames for anonymous types.
	                // Only consider the localName after the last '>'
	                // when generating the java name
	                // String localName = typeQName.getLocalPart();
	                // localName =
	                // localName.substring(
	                // localName.lastIndexOf(
	                // SymbolTable.ANON_TOKEN)+1);
	                // typeQName = new QName(typeQName.getNamespaceURI(),
	                // localName);
	                String localName = typeQName.getLocalPart();
	
	                // Check to see if this is an anonymous type,
	                // if it is, replace Axis' ANON_TOKEN with
	                // an underscore to make sure we don't run
	                // into name collisions with similarly named
	                // non-anonymous types
	                StringBuffer sb = new StringBuffer(localName);
	                int aidx;
	
	                while ((aidx = sb.toString().indexOf(SymbolTable.ANON_TOKEN)) > -1) {
	                    sb.replace(aidx, aidx + SymbolTable.ANON_TOKEN.length(), "");
	                    char c = sb.charAt(aidx);
	                    if (Character.isLetter(c) && Character.isLowerCase(c)) {
	                        sb.setCharAt(aidx, Character.toUpperCase(c));
	                    }
	                }
	                        
	                localName = sb.toString();
	                typeQName = new QName(typeQName.getNamespaceURI(),
	                        localName);
	
	                if (emitter.isTypeCollisionProtection() &&
	                        !emitter.getNamespaceExcludes().contains(new NamespaceSelector(typeQName.getNamespaceURI()))) {
	                    // If there is already an existing type,
	                    // there will be a collision.
	                    // If there is an existing anon type,
	                    // there will be a  collision.
	                    // In both cases, mangle the name.
	                    if (symbolTable.getType(typeQName) != null ||
	                            anonQNames.get(typeQName) != null) {
	                        localName += "Type" + uniqueNum++;
	                        typeQName =
	                            new QName(typeQName.getNamespaceURI(),
	                                      localName);
	                    }
	                    
	                    anonQNames.put(typeQName, typeQName);
	                }
	
	                // Now set the name with the constructed qname
	                tEntry.setName(emitter.getJavaName(typeQName));
	            }
            }   // if (!processed)
        
            Vector elements = tEntry.getContainedElements();
            if (elements != null) {
                for (int i = 0; i < elements.size(); i++) {
                    ElementDecl elem = (ElementDecl) elements.get(i);
                    String varName = emitter.getJavaVariableName(typeQName, elem.getQName(), true);
                    elem.setName(varName);
                }
            }
            
            Vector attributes = tEntry.getContainedAttributes();
            if (attributes != null) {
                for (int i = 0; i < attributes.size(); i++) {
                    ContainedAttribute attr = (ContainedAttribute) attributes.get(i);
                    String varName = emitter.getJavaVariableName(typeQName, attr.getQName(), false);
                    attr.setName(varName);
                }
            }
        }

        // Set the entry with the same name as the ref'd entry
        // but add the appropriate amount of dimensions
        entry.setName(tEntry.getName() + dims);

        return uniqueNum;
    }
    
    /**  
     * Gets class name from Java class.
     * If the class is an array, get its component type's name
     * @param clazz a java class
     * @return the class name in string
     */
    private static String getJavaClassName(Class clazz) {
        Class class1 = clazz;
        
        while (class1.isArray()) {
            class1 = class1.getComponentType();
        }
        
        String name = class1.getName();        
        name.replace('$', '.');
        return name;
    }

    /**
     * setFaultContext:
     * Processes the symbol table and sets the COMPLEX_TYPE_FAULT
     * on each TypeEntry that is a complexType and is referenced in
     * a fault message.  TypeEntries that are the base or derived
     * from such a TypeEntry are also marked with COMPLEX_TYPE_FAULT.
     * The containing MessageEntry is marked with cOMPLEX_TYPE_FAULT, and
     * all MessageEntries for faults are tagged with the
     * EXCEPTION_CLASS_NAME variable, which indicates the java exception
     * class name.
     *
     * @param symbolTable SymbolTable
     */
    private void setFaultContext(SymbolTable symbolTable) {

        Iterator it = symbolTable.getHashMap().values().iterator();

        while (it.hasNext()) {
            Vector v = (Vector) it.next();

            for (int i = 0; i < v.size(); ++i) {
                SymTabEntry entry = (SymTabEntry) v.elementAt(i);

                // Inspect each BindingEntry in the Symbol Table
                if (entry instanceof BindingEntry) {
                    BindingEntry bEntry = (BindingEntry) entry;
                    HashMap allOpFaults = bEntry.getFaults();
                    Iterator ops = allOpFaults.values().iterator();

                    // set the context for all faults for this binding.
                    while (ops.hasNext()) {
                        ArrayList faults = (ArrayList) ops.next();

                        for (int j = 0; j < faults.size(); ++j) {
                            FaultInfo info = (FaultInfo) faults.get(j);

                            setFaultContext(info, symbolTable);
                        }
                    }
                }
            }
        }
    }    // setFaultContext

    /**
     * setFaultContext:
     * Helper routine for the setFaultContext method above.
     * Examines the indicated fault and sets COMPLEX_TYPE_FAULT
     * EXCEPTION_DATA_TYPE and EXCEPTION_CLASS_NAME as appropriate.
     *
     * @param fault       FaultInfo to analyze
     * @param symbolTable SymbolTable
     */
    private void setFaultContext(FaultInfo fault, SymbolTable symbolTable) {

        QName faultXmlType = null;
        Vector parts = new Vector();

        // Get the parts of the fault's message.
        // An IOException is thrown if the parts cannot be
        // processed.  Skip such parts for this analysis
        try {
            symbolTable.getParametersFromParts(
                    parts, fault.getMessage().getOrderedParts(null), false,
                    fault.getName(), null);
        } catch (IOException e) {
        }

        // Inspect each TypeEntry referenced in a Fault Message Part
        String exceptionClassName = null;

        for (int j = 0; j < parts.size(); j++) {
            TypeEntry te = ((Parameter) (parts.elementAt(j))).getType();

            // If the TypeEntry is an element, advance to the type.
            // This occurs if the message part uses the element= attribute
            TypeEntry elementTE = null;

            if (te instanceof Element) {
                elementTE = te;
                te = te.getRefType();
            }

            // remember the QName of the type.
            faultXmlType = te.getQName();

            // Determine if the te should be processed using the
            // simple type mapping or the complex type mapping
            // NOTE: treat array types as simple types
            if ((te.getBaseType() != null) || te.isSimpleType()
                    || ((te.getDimensions().length() > 0)
                    && (te.getRefType().getBaseType() != null))) {

                // Simple Type Exception
            } else {

                // Complex Type Exception
                Boolean isComplexFault = (Boolean) te.getDynamicVar(
                        JavaGeneratorFactory.COMPLEX_TYPE_FAULT);

                if ((isComplexFault == null) || !isComplexFault.booleanValue()) {

                    // Mark the type as a complex type fault
                    te.setDynamicVar(JavaGeneratorFactory.COMPLEX_TYPE_FAULT,
                            Boolean.TRUE);

                    if (elementTE != null) {
                        te.setDynamicVar(
                                JavaGeneratorFactory.COMPLEX_TYPE_FAULT,
                                Boolean.TRUE);
                    }

                    // Mark all derived types as Complex Faults
                    HashSet derivedSet =
                            org.apache.axis.wsdl.symbolTable.Utils.getDerivedTypes(
                                    te, symbolTable);
                    Iterator derivedI = derivedSet.iterator();

                    while (derivedI.hasNext()) {
                        TypeEntry derivedTE = (TypeEntry) derivedI.next();

                        derivedTE.setDynamicVar(
                                JavaGeneratorFactory.COMPLEX_TYPE_FAULT,
                                Boolean.TRUE);
                    }

                    // Mark all base types as Complex Faults
                    TypeEntry base =
                            SchemaUtils.getComplexElementExtensionBase(te.getNode(),
                                    symbolTable);

                    while (base != null) {
                        base.setDynamicVar(
                                JavaGeneratorFactory.COMPLEX_TYPE_FAULT,
                                Boolean.TRUE);

                        base = SchemaUtils.getComplexElementExtensionBase(
                                base.getNode(), symbolTable);
                    }
                }

                // The exception class name is the name of the type
                exceptionClassName = te.getName();
            }
        }

        String excName = getExceptionJavaNameHook(fault.getMessage().getQName());     //     for derived class
        if (excName != null) {
            exceptionClassName = excName;
        }

        // Set the name of the exception and
        // whether the exception is a complex type
        MessageEntry me =
                symbolTable.getMessageEntry(fault.getMessage().getQName());

        if (me != null) {
            me.setDynamicVar(JavaGeneratorFactory.EXCEPTION_DATA_TYPE,
                    faultXmlType);

            if (exceptionClassName != null) {
                me.setDynamicVar(JavaGeneratorFactory.COMPLEX_TYPE_FAULT,
                        Boolean.TRUE);
                me.setDynamicVar(JavaGeneratorFactory.EXCEPTION_CLASS_NAME,
                        exceptionClassName);
            } else {
                me.setDynamicVar(JavaGeneratorFactory.EXCEPTION_CLASS_NAME,
                        emitter.getJavaName(me.getQName()));
            }
        }
    }

    protected String getExceptionJavaNameHook(QName qname) {
        return null;
    }

    /**
     * Method determineInterfaceNames
     *
     * @param symbolTable
     */
    protected void determineInterfaceNames(SymbolTable symbolTable) {

        Iterator it = symbolTable.getHashMap().values().iterator();

        while (it.hasNext()) {
            Vector v = (Vector) it.next();

            for (int i = 0; i < v.size(); ++i) {
                SymTabEntry entry = (SymTabEntry) v.elementAt(i);

                if (entry instanceof BindingEntry) {

                    // The SEI (Service Endpoint Interface) name
                    // is always the portType name.
                    BindingEntry bEntry = (BindingEntry) entry;
                    PortTypeEntry ptEntry = symbolTable.getPortTypeEntry(
                            bEntry.getBinding().getPortType().getQName());

                    String seiName = getServiceEndpointInterfaceJavaNameHook(ptEntry, bEntry);
                    if (seiName == null) {
                        seiName = ptEntry.getName();
                    }

                    bEntry.setDynamicVar(JavaBindingWriter.INTERFACE_NAME,
                            seiName);
                } else if (entry instanceof ServiceEntry) {
                    ServiceEntry sEntry = (ServiceEntry) entry;
                    String siName = getServiceInterfaceJavaNameHook(sEntry);    // for derived class
                    if (siName != null) {
                        sEntry.setName(siName);
                    }

                    Service service = sEntry.getService();
                    Map portMap = service.getPorts();
                    Iterator portIterator = portMap.values().iterator();

                    while (portIterator.hasNext()) {
                        Port p = (Port) portIterator.next();

                        Binding binding = p.getBinding();
                        BindingEntry bEntry =
                                symbolTable.getBindingEntry(binding.getQName());

                        // If this isn't a SOAP binding, skip it
                        if (bEntry.getBindingType() != BindingEntry.TYPE_SOAP) {
                            continue;
                        }

                        String portName = getPortJavaNameHook(p.getName());   // for derived class
                        if (portName != null) {
                            bEntry.setDynamicVar(JavaServiceWriter.PORT_NAME + ":" + p.getName(),
                                    portName);
                        }
                    }
                }
            }
        }
    }    // determineInterfaceNames

    protected String getServiceEndpointInterfaceJavaNameHook(PortTypeEntry ptEntry, BindingEntry bEntry) {
        return null;
    }

    protected String getServiceInterfaceJavaNameHook(ServiceEntry sEntry) {
        return null;
    }

    protected String getPortJavaNameHook(String portName) {
        return null;
    }
    
    /**
     * Messages, PortTypes, Bindings, and Services can share the same name.  If they do in this
     * Definition, force their names to be suffixed with _PortType and _Service, respectively.
     *
     * @param symbolTable
     */
    protected void resolveNameClashes(SymbolTable symbolTable) {

        // Keep a list of anonymous types so we don't try to resolve them twice.
        HashSet anonTypes = new HashSet();
        List collisionCandidates = new ArrayList();      // List of vector of SymbolTable entry
        
        List localParts = new ArrayList();      // all localparts in all symboltable entries        
        for (Iterator i = symbolTable.getHashMap().keySet().iterator(); i.hasNext(); ) {
            QName qName = (QName)i.next();
            String localPart = qName.getLocalPart();
            if (!localParts.contains(localPart))
                localParts.add(localPart);
        }
            
        Map pkg2NamespacesMap = emitter.getNamespaces().getPkg2NamespacesMap();
        for (Iterator i = pkg2NamespacesMap.values().iterator(); i.hasNext(); ) {            
            Vector namespaces = (Vector)i.next();  // namepaces mapped to same package
                    
            // Combine entry vectors, which have the same entry name, into a new entry vector.
            for (int j = 0; j < localParts.size(); j++) {
                Vector v = new Vector();
                for (int k = 0; k < namespaces.size(); k++) {
                    QName qName = new QName((String)namespaces.get(k), (String)localParts.get(j));
                    if (symbolTable.getHashMap().get(qName) != null) {
                        v.addAll((Vector)symbolTable.getHashMap().get(qName));
                    }
                }
                if(v.size()>0) {
                    collisionCandidates.add(v);
                }
            }
        }
        Iterator it = collisionCandidates.iterator();
        
        while (it.hasNext()) {
            Vector v = new Vector(
                    (Vector) it.next());    // New vector we can temporarily add to it
          
            // Remove MessageEntries since they are not mapped
            int index = 0;

            while (index < v.size()) {
                if (v.elementAt(index) instanceof MessageEntry) {
                    // Need to resolve a Exception message.
                    MessageEntry msgEntry = (MessageEntry) v.elementAt(index);                    
                    if (msgEntry.getDynamicVar(EXCEPTION_CLASS_NAME) == null) {
                        v.removeElementAt(index);
                    } else {                        
                        index++;
                    }
                } else {
                    index++;
                }
            }

            if (v.size() > 1) {
                boolean resolve = true;

                // Common Special Case:
                // If a Type and Element have the same QName, and the Element
                // references the Type, then they are the same class so
                // don't bother mangling.
                if (v.size() == 2 &&
                    ((v.elementAt(0) instanceof Element &&
                      v.elementAt(1) instanceof Type) ||
                     (v.elementAt(1) instanceof Element &&
                      v.elementAt(0) instanceof Type))) {
                    Element e;
                    if (v.elementAt(0) instanceof Element) {
                        e = (Element) v.elementAt(0);
                    } else {
                        e = (Element) v.elementAt(1);
                    }

                    BooleanHolder forElement = new BooleanHolder();
                    QName eType = Utils.getTypeQName(e.getNode(),
                            forElement, false);

                    if ((eType != null) 
                            && !forElement.value) {
                        resolve = false;
                    }
                }

                // Other Special Case:
                // If the names are already different, no mangling is needed.
                if (resolve) {
                    resolve = false;           // Assume false

                    String name = null;

                    for (int i = 0; (i < v.size()) && !resolve; ++i) {
                        SymTabEntry entry = (SymTabEntry) v.elementAt(i);

                        if ((entry instanceof MessageEntry)
                                || (entry instanceof BindingEntry)) {                            
                            // Need to resolve a exception class name                            
                            String exceptionClassName = (String) entry.getDynamicVar(EXCEPTION_CLASS_NAME);
                            if (exceptionClassName != null) {                                
                                if (name == null) {
                                    name = exceptionClassName;
                                } else if (name.equals(exceptionClassName)) {
                                    resolve = true;
                                }
                            }
                        } else if (name == null) {
                            name = entry.getName();
                        } else if (name.equals(entry.getName())) {
                            resolve = true;    // Need to do resolution
                        }
                    }
                }

                // Full Mangle if resolution is necessary.
                if (resolve) {
                    boolean firstType = true;

                    for (int i = 0; i < v.size(); ++i) {
                        SymTabEntry entry = (SymTabEntry) v.elementAt(i);

                        if (entry instanceof Element) {
                            entry.setName(mangleName(entry.getName(), ELEMENT_SUFFIX));

                            // If this global element was defined using
                            // an anonymous type, then need to change the
                            // java name of the anonymous type to match.
                            QName anonQName =
                                    new QName(entry.getQName().getNamespaceURI(),
                                            SymbolTable.ANON_TOKEN
                                    + entry.getQName().getLocalPart());
                            
                            TypeEntry anonType =
                                    symbolTable.getType(anonQName);

                            if (anonType != null) {
                                anonType.setName(entry.getName());
                                anonTypes.add(anonType);
                            }                            
                        } else if (entry instanceof TypeEntry) {

                            // Search all other types for java names that match this one.
                            // The sameJavaClass method returns true if the java names are
                            // the same (ignores [] ).
                            if (firstType) {
                                firstType = false;

                                Iterator types =
                                        symbolTable.getTypeIndex().values().iterator();

                                while (types.hasNext()) {
                                    TypeEntry type = (TypeEntry) types.next();

                                    if ((type != entry)
                                            && (type.getBaseType() == null)
                                            && sameJavaClass(entry.getName(),
                                                    type.getName())) {
                                        v.add(type);
                                    }
                                }
                            }

                            // If this is an anonymous type, it's name was resolved in
                            // the previous if block.  Don't reresolve it.
                            if (!anonTypes.contains(entry)) {
                                // In case that other entry in name collision among 
                                // PortTypeEntry, ServiceEntry and BindingEntry
                                
                                boolean needResolve = false;
                                
                                // check collision of TypeEntry with PortTypeEntry, ServiceEtnry and/or BindingEntry 
                                for (int j = 0; j < v.size(); j++) {
                                    SymTabEntry e = (SymTabEntry) v.elementAt(j);
                                    if ((e instanceof PortTypeEntry 
                                            || e instanceof ServiceEntry
                                            || e instanceof BindingEntry)) {
                                        needResolve = true;
                                        break;
                                    }
                                }
                                
                                if (!needResolve) {
                                    continue;
                                }                                                                
                                
                                // Appended Suffix for avoiding name collisions (JAX-RPC 1.1)
                                Boolean isComplexTypeFault = (Boolean)entry.getDynamicVar(COMPLEX_TYPE_FAULT);
                                if ((isComplexTypeFault != null) && isComplexTypeFault.booleanValue()) {
                                    entry.setName(mangleName(entry.getName(), EXCEPTION_SUFFIX));
                                } 
                                else {
                                    entry.setName(mangleName(entry.getName(), TYPE_SUFFIX));
                                }
                                
                                // should update the class name of ElementEntry which references this type entry
                                Map elementIndex = symbolTable.getElementIndex();
                                List elements = new ArrayList(elementIndex.values());
                                for (int j = 0; j < elementIndex.size(); j++) {
                                    TypeEntry te = (TypeEntry) elements.get(j);
                                    TypeEntry ref = te.getRefType();
                                    if (ref != null && entry.getQName().equals(ref.getQName())) {
                                        te.setName(entry.getName());
                                    }
                                }           
                                
                                // Need to resolve a complex-type exception message.
                                if ((isComplexTypeFault != null) && isComplexTypeFault.booleanValue()) {
                                    // SHOULD update the exception class name of a referencing message entry.
                                    List messageEntries = symbolTable.getMessageEntries();
                                    for (int j = 0; j < messageEntries.size(); j++) {
                                        MessageEntry messageEntry = (MessageEntry)messageEntries.get(j);
                                        Boolean isComplexTypeFaultMsg = (Boolean)messageEntry.getDynamicVar(COMPLEX_TYPE_FAULT);
                                        if ((isComplexTypeFaultMsg != null) && (isComplexTypeFaultMsg.booleanValue())) {
                                            QName exceptionDataType = (QName)messageEntry.getDynamicVar(EXCEPTION_DATA_TYPE);
                                            if (((TypeEntry)entry).getQName().equals(exceptionDataType)) {
                                                String className = (String)messageEntry.getDynamicVar(EXCEPTION_CLASS_NAME);
                                                messageEntry.setDynamicVar(EXCEPTION_CLASS_NAME, className + EXCEPTION_SUFFIX);
                                            }
                                        }
                                    }
                                }
                            }
                        } else if (entry instanceof PortTypeEntry) {
                            entry.setName(mangleName(entry.getName(), PORT_TYPE_SUFFIX));   // "_Port" --> "_PortType" for JAX-RPC 1.1
                        } else if (entry instanceof ServiceEntry) {
                            entry.setName(mangleName(entry.getName(), SERVICE_SUFFIX));
                        } else if (entry instanceof MessageEntry) {
                            Boolean complexTypeFault = 
                                (Boolean) entry.getDynamicVar(COMPLEX_TYPE_FAULT);
                            if ((complexTypeFault == null) || !complexTypeFault.booleanValue()) {
                                String exceptionClassName = (String) entry.getDynamicVar(EXCEPTION_CLASS_NAME);
                                entry.setDynamicVar(EXCEPTION_CLASS_NAME, exceptionClassName + EXCEPTION_SUFFIX);
                            }                            
                        }
                        // else if (entry instanceof MessageEntry) {
                        // we don't care about messages
                        // }
                        else if (entry instanceof BindingEntry) {
                            BindingEntry bEntry = (BindingEntry) entry;

                            // If there is no literal use, then we never see a
                            // class named directly from the binding name.  They
                            // all have suffixes:  Stub, Skeleton, Impl.
                            // If there IS literal use, then the SDI will be
                            // named after the binding name, so there is the
                            // possibility of a name clash.
                            if (bEntry.hasLiteral()) {
                                entry.setName(mangleName(entry.getName(),
                                        BINDING_SUFFIX));
                            }
                        }
                    }
                }
            }
        }
    }                                          // resolveNameClashes

    /**
     * Change the indicated type name into a mangled form using the mangle string.
     *
     * @param name
     * @param mangle
     * @return
     */
    private String mangleName(String name, String mangle) {

        int index = name.indexOf("[");

        if (index >= 0) {
            String pre = name.substring(0, index);
            String post = name.substring(index);

            return pre + mangle + post;
        } else {
            return name + mangle;
        }
    }

    /**
     * Returns true if same java class, ignore []
     *
     * @param one
     * @param two
     * @return
     */
    private boolean sameJavaClass(String one, String two) {

        int index1 = one.indexOf("[");
        int index2 = two.indexOf("[");

        if (index1 > 0) {
            one = one.substring(0, index1);
        }

        if (index2 > 0) {
            two = two.substring(0, index2);
        }

        return one.equals(two);
    }

    /**
     * The --all flag is set on the command line (or generateAll(true) is called
     * on WSDL2Java). Set all symbols as referenced (except nonSOAP bindings
     * which we don't know how to deal with).
     */
    protected void setAllReferencesToTrue() {

        Iterator it = symbolTable.getHashMap().values().iterator();

        while (it.hasNext()) {
            Vector v = (Vector) it.next();

            for (int i = 0; i < v.size(); ++i) {
                SymTabEntry entry = (SymTabEntry) v.elementAt(i);

                if ((entry instanceof BindingEntry)
                        && ((BindingEntry) entry).getBindingType()
                        != BindingEntry.TYPE_SOAP) {
                    entry.setIsReferenced(false);
                } else {
                    entry.setIsReferenced(true);
                }
            }
        }
    }    // setAllReferencesToTrue

    /**
     * If a binding's type is not TYPE_SOAP, then we don't use that binding
     * or that binding's portType.
     *
     * @param symbolTable
     */
    protected void ignoreNonSOAPBindings(SymbolTable symbolTable) {

        // Look at all uses of the portTypes.  If none of the portType's bindings are of type
        // TYPE_SOAP, then turn off that portType's isReferenced flag.
        Vector unusedPortTypes = new Vector();
        Vector usedPortTypes = new Vector();
        Iterator it = symbolTable.getHashMap().values().iterator();

        while (it.hasNext()) {
            Vector v = (Vector) it.next();

            for (int i = 0; i < v.size(); ++i) {
                SymTabEntry entry = (SymTabEntry) v.elementAt(i);

                if (entry instanceof BindingEntry) {
                    BindingEntry bEntry = (BindingEntry) entry;
                    Binding binding = bEntry.getBinding();
                    PortType portType = binding.getPortType();
                    PortTypeEntry ptEntry =
                            symbolTable.getPortTypeEntry(portType.getQName());

                    if (bEntry.getBindingType() == BindingEntry.TYPE_SOAP) {

                        // If a binding is of type TYPE_SOAP, then mark its portType used
                        // (ie., add it to the usedPortTypes list.  If the portType was
                        // previously marked as unused, unmark it (in other words, remove it
                        // from the unusedPortTypes list).
                        usedPortTypes.add(ptEntry);

                        if (unusedPortTypes.contains(ptEntry)) {
                            unusedPortTypes.remove(ptEntry);
                        }
                    } else {
                        bEntry.setIsReferenced(false);

                        // If a binding is not of type TYPE_SOAP, then mark its portType as
                        // unused ONLY if it hasn't already been marked as used.
                        if (!usedPortTypes.contains(ptEntry)) {
                            unusedPortTypes.add(ptEntry);
                        }
                    }
                }
            }
        }

        // Go through all the portTypes that are marked as unused and set their isReferenced flags
        // to false.
        for (int i = 0; i < unusedPortTypes.size(); ++i) {
            PortTypeEntry ptEntry = (PortTypeEntry) unusedPortTypes.get(i);

            ptEntry.setIsReferenced(false);
        }
    }    // ignoreNonSOAPBindings

    /**
     * Method constructSignatures
     *
     * @param symbolTable
     */
    protected void constructSignatures(SymbolTable symbolTable) {

        Iterator it = symbolTable.getHashMap().values().iterator();

        while (it.hasNext()) {
            Vector v = (Vector) it.next();

            for (int i = 0; i < v.size(); ++i) {
                SymTabEntry entry = (SymTabEntry) v.elementAt(i);

                if (entry instanceof BindingEntry) {
                    BindingEntry bEntry = (BindingEntry) entry;
                    Binding binding = bEntry.getBinding();
                    PortType portType = binding.getPortType();
                    Iterator operations =
                            portType.getOperations().iterator();

                    while (operations.hasNext()) {
                        Operation operation =
                                (Operation) operations.next();
                        String wsdlOpName = operation.getName();
                        OperationType type = operation.getStyle();

                        String javaOpName = getOperationJavaNameHook(bEntry, wsdlOpName);      // for derived class
                        if (javaOpName == null) {
                            javaOpName = operation.getName();
                        }

                        Parameters parameters =
                                bEntry.getParameters(operation);

                        if (OperationType.SOLICIT_RESPONSE.equals(type)) {
                            parameters.signature =
                                    "    // "
                                    + Messages.getMessage("invalidSolResp00", javaOpName);

                            System.err.println(
                                    Messages.getMessage("invalidSolResp00", javaOpName));
                        } else if (OperationType.NOTIFICATION.equals(type)) {
                            parameters.signature =
                                    "    // "
                                    + Messages.getMessage("invalidNotif00", javaOpName);

                            System.err.println(
                                    Messages.getMessage("invalidNotif00", javaOpName));
                        } else {    // ONE_WAY or REQUEST_RESPONSE
                            if (parameters != null) {
                                String returnType = getReturnTypeJavaNameHook(bEntry, wsdlOpName);
                                if (returnType != null) {
                                    if (parameters.returnParam != null) {   // 'void' return type???
                                        parameters.returnParam.getType().setName(returnType);
                                    }
                                }
                                for (int j = 0; j < parameters.list.size(); ++j) {
                                    Parameter p = (Parameter) parameters.list.get(j);
                                    String paramType = getParameterTypeJavaNameHook(bEntry, wsdlOpName, j);
                                    if (paramType != null) {
                                        p.getType().setName(paramType);
                                    }
                                }
                                parameters.signature =
                                        constructSignature(parameters, javaOpName);
                            }
                        }
                    }
                }
            }
        }
    }                               // constructSignatures

    protected String getOperationJavaNameHook(BindingEntry bEntry, String wsdlOpName) {
        return null;
    }

    protected String getReturnTypeJavaNameHook(BindingEntry bEntry, String wsdlOpName) {
        return null;
    }

    protected String getParameterTypeJavaNameHook(BindingEntry bEntry, String wsdlOpName, int pos) {
        return null;
    }

    /**
     * Construct the signature, which is used by both the interface and the stub.
     *
     * @param parms
     * @param opName
     * @return
     */
    private String constructSignature(Parameters parms, String opName) {

        String name = Utils.xmlNameToJava(opName);
        String ret = "void";

        if ((parms != null) && (parms.returnParam != null)) {
            ret = Utils.getParameterTypeName(parms.returnParam);
        }

        String signature = "    public " + ret + " " + name + "(";
        boolean needComma = false;

        for (int i = 0; (parms != null) && (i < parms.list.size()); ++i) {
            Parameter p = (Parameter) parms.list.get(i);

            if (needComma) {
                signature = signature + ", ";
            } else {
                needComma = true;
            }

            String javifiedName = Utils.xmlNameToJava(p.getName());

            if (p.getMode() == Parameter.IN) {
                signature += Utils.getParameterTypeName(p) + " " + javifiedName;
            } else {
                signature += Utils.holder(p, emitter) + " " + javifiedName;
            }
        }

        signature = signature + ") throws java.rmi.RemoteException";

        if ((parms != null) && (parms.faults != null)) {

            // Collect the list of faults into a single string, separated by commas.
            Iterator i = parms.faults.values().iterator();

            while (i.hasNext()) {
                Fault fault = (Fault) i.next();
                String exceptionName =
                        Utils.getFullExceptionName(fault.getMessage(), symbolTable);

                if (exceptionName != null) {
                    signature = signature + ", " + exceptionName;
                }
            }
        }

        return signature;
    }    // constructSignature

    /**
     * Find all inout/out parameters and add a flag to the Type of that parameter saying a holder
     * is needed.
     *
     * @param symbolTable
     */
    protected void determineIfHoldersNeeded(SymbolTable symbolTable) {

        Iterator it = symbolTable.getHashMap().values().iterator();

        while (it.hasNext()) {
            Vector v = (Vector) it.next();

            for (int i = 0; i < v.size(); ++i) {
                if (v.get(i) instanceof BindingEntry) {

                    // If entry is a BindingEntry, look at all the Parameters
                    // in its portType
                    BindingEntry bEntry = (BindingEntry) v.get(i);

                    // PortTypeEntry ptEntry =
                    // symbolTable.getPortTypeEntry(bEntry.getBinding().getPortType().getQName());
                    Iterator operations =
                            bEntry.getParameters().values().iterator();

                    while (operations.hasNext()) {
                        Parameters parms = (Parameters) operations.next();

                        for (int j = 0; j < parms.list.size(); ++j) {
                            Parameter p = (Parameter) parms.list.get(j);

                            // If the given parameter is an inout or out parameter, then
                            // set a HOLDER_IS_NEEDED flag using the dynamicVar design.
                            if (p.getMode() != Parameter.IN) {
                                TypeEntry typeEntry = p.getType();

                                typeEntry.setDynamicVar(
                                        JavaTypeWriter.HOLDER_IS_NEEDED,
                                        Boolean.TRUE);

                                // If this is a complex then set the HOLDER_IS_NEEDED
                                // for the reftype too.
                                if (!typeEntry.isSimpleType()
                                        && (typeEntry.getRefType() != null)) {
                                    typeEntry.getRefType().setDynamicVar(
                                            JavaTypeWriter.HOLDER_IS_NEEDED,
                                            Boolean.TRUE);
                                }

                                // If the type is a DefinedElement, need to
                                // set HOLDER_IS_NEEDED on the anonymous type.
                                QName anonQName =
                                        SchemaUtils.getElementAnonQName(
                                                p.getType().getNode());

                                if (anonQName != null) {
                                    TypeEntry anonType =
                                            symbolTable.getType(anonQName);

                                    if (anonType != null) {
                                        anonType.setDynamicVar(
                                                JavaTypeWriter.HOLDER_IS_NEEDED,
                                                Boolean.TRUE);
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }    // determineIfHoldersNeeded

    /**
     * Get TypeMapping to use for translating
     * QNames to java base types
     */
    BaseTypeMapping btm = null;

    /**
     * Method setBaseTypeMapping
     *
     * @param btm
     */
    public void setBaseTypeMapping(BaseTypeMapping btm) {
        this.btm = btm;
    }

    /**
     * Method getBaseTypeMapping
     *
     * @return
     */
    public BaseTypeMapping getBaseTypeMapping() {
        if (btm == null) {
            btm = new BaseTypeMapping() {

                public String getBaseName(QName qNameIn) {

                    javax.xml.namespace.QName qName =
                            new javax.xml.namespace.QName(qNameIn.getNamespaceURI(),
                                    qNameIn.getLocalPart());
                    Class cls =
                            emitter.getDefaultTypeMapping().getClassForQName(qName);

                    if (cls == null) {
                        return null;
                    } else {
                        return JavaUtils.getTextClassName(cls.getName());
                    }
                }
            };
        }

        return btm;
    }

    /**
     * Determines whether the QName supplied should be generated by comparing
     * the namespace for the QName against the included and excluded names.
     <p/>
     <ul>
     <li>if both the includes and excludes are both empty,
             the element is generated</li>
     <li>if the namespace is in the includes,
             the element is generated</li>
     <li>if the namespace is not in the excludes and the includes are empty,
             the element will be generated.
     <li>if the namespace is only in the excludes,
             the element is not generated</li>
     <li>if the namespace is not in the includes and the includes are not
             empty, the element is not generated</li>
        @param qName
        @return
     */
    protected boolean include(QName qName) {
        String namespace =
            (qName != null && qName.getNamespaceURI() != null)
                ? qName.getNamespaceURI()
                : "";

        boolean doInclude = false;
        NamespaceSelector selector = new NamespaceSelector(namespace);
        if (qName == null
            || emitter == null
            || emitter.getNamespaceIncludes().contains(selector)
            || (emitter.getNamespaceIncludes().size() == 0
                && !emitter.getNamespaceExcludes().contains(selector))) {
            doInclude = true;
        }
        else {
            log_.info(
                "excluding code generation for non-included QName:" + qName);

        }
        return doInclude;
    }

}    // class JavaGeneratorFactory
