Package org.jpox.jpa.metadata

Source Code of org.jpox.jpa.metadata.JPAMetaDataHandler

/**********************************************************************
Copyright (c) 2006 Andy Jefferson and others. All rights reserved.
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.

Contributors:
    ...
**********************************************************************/
package org.jpox.jpa.metadata;

import org.xml.sax.Attributes;
import org.xml.sax.EntityResolver;
import org.xml.sax.SAXException;

import org.jpox.metadata.AbstractClassMetaData;
import org.jpox.metadata.AbstractMemberMetaData;
import org.jpox.metadata.ClassMetaData;
import org.jpox.metadata.ClassPersistenceModifier;
import org.jpox.metadata.ColumnMetaData;
import org.jpox.metadata.DiscriminatorMetaData;
import org.jpox.metadata.DiscriminatorStrategy;
import org.jpox.metadata.ElementMetaData;
import org.jpox.metadata.EventListenerMetaData;
import org.jpox.metadata.FieldPersistenceModifier;
import org.jpox.metadata.FileMetaData;
import org.jpox.metadata.IdentityStrategy;
import org.jpox.metadata.IdentityType;
import org.jpox.metadata.InheritanceMetaData;
import org.jpox.metadata.InheritanceStrategy;
import org.jpox.metadata.JoinMetaData;
import org.jpox.metadata.KeyMetaData;
import org.jpox.metadata.MetaData;
import org.jpox.metadata.MetaDataManager;
import org.jpox.metadata.OrderMetaData;
import org.jpox.metadata.PackageMetaData;
import org.jpox.metadata.QueryMetaData;
import org.jpox.metadata.QueryResultMetaData;
import org.jpox.metadata.SequenceMetaData;
import org.jpox.metadata.TableGeneratorMetaData;
import org.jpox.metadata.UniqueMetaData;
import org.jpox.metadata.VersionMetaData;
import org.jpox.metadata.VersionStrategy;
import org.jpox.metadata.xml.AbstractMetaDataHandler;
import org.jpox.util.StringUtils;
import org.jpox.util.JPOXLogger;

/**
* Parser handler for JPA MetaData.
* Implements DefaultHandler and handles the extracting of MetaData for JPA
* from the XML elements/attributes. This class simply constructs the MetaData
* representation mirroring what is in the MetaData file. It has no knowledge
* of the class(es) that it represents, simply the information in the MetaData
* file. The knowledge of the classes is imposed on the representation at a
* later stage where necessary.
* <P>Operates the parse process using a Stack. MetaData components are added
* to the stack as they are encountered and created. They are then popped off
* the stack when the end element is encountered.</P>
*
* @since 1.1
* @version $Revision: 1.1 $
*/
public class JPAMetaDataHandler extends AbstractMetaDataHandler
{
    /** Default package name for the entity-mappings (if any). */
    String defaultPackageName = null;

    /** Flag for whether the MetaData in this file is "metadata-complete" */
    boolean metaDataComplete = false;

    /** Default value for whether to cascade-persist. */
    boolean defaultCascadePersist = false;

    /** Whether this file is using property access. */
    boolean propertyAccess = false;

    /** Current query result entity (persistent class), during parse process. */
    String queryResultEntityName = null;

    /**
     * Constructor. Protected to prevent instantiation.
     * @param mgr the metadata manager
     * @param filename The name of the file to parse
     * @param resolver Entity Resolver to use (null if not available)
     */
    public JPAMetaDataHandler(MetaDataManager mgr, String filename, EntityResolver resolver)
    {
        super(mgr, filename, resolver);
        metadata = new FileMetaData(filename, mgr, null, null);
        pushStack(metadata); // Start with FileMetaData on the stack
    }

    /**
     * Utility to create a new class component.
     * @param pmd The parent PackageMetaData
     * @param attrs The attributes
     * @param embeddedOnly Whether this class is embedded-only
     * @return The ClassMetaData
     */
    protected ClassMetaData newClassObject(PackageMetaData pmd, Attributes attrs, boolean embeddedOnly)
    {
        String className = getAttr(attrs, "class");
        if (className.indexOf('.') > 0)
        {
            // Strip off any package info
            className = className.substring(className.lastIndexOf('.')+1);
        }

        ClassMetaData cmd = mgr.getMetaDataFactory().newClassObject(pmd,
            className,
            embeddedOnly ? IdentityType.NONDURABLE.toString() : IdentityType.APPLICATION.toString(),
            null, // PK class specified on <id-class>
            "true", // All classes require an extent
            "true", // All classes are detachable in JPA
            "" + embeddedOnly,
            ClassPersistenceModifier.PERSISTENCE_CAPABLE.toString(), // JPA only has "persistence-capable"
            null, // pc-superclass is not needed
            null, // Catalog specified on <table>
            null, // Schema specified on <table>
            null, // Table specified on <table>
            getAttr(attrs, "name")); // Entity name for use by JPQL

        String classMetaDataComplete = getAttr(attrs, "metadata-complete");
        if (metaDataComplete || (classMetaDataComplete != null && classMetaDataComplete.equalsIgnoreCase("true")))
        {
            // Ignore any annotations since either the class or the whole file is "metadata-complete"
            cmd.setMetaDataComplete();
        }

        return cmd;
    }

    /**
     * Utility to create a new field/property component and add it to the class as required.
     * If the field/property already exists
     * @param acmd The parent class MetaData
     * @param attrs The attributes
     * @return The FieldMetaData/PropertyMetaData
     */
    protected AbstractMemberMetaData newFieldObject(AbstractClassMetaData acmd, Attributes attrs)
    {
        String fetch = getAttr(attrs, "fetch");
        String dfg = "true";
        if (fetch != null && fetch.equalsIgnoreCase("LAZY"))
        {
            dfg = "false";
        }

        AbstractMemberMetaData mmd = null;
        mmd = acmd.getMetaDataForMember(getAttr(attrs, "name"));
        if (mmd != null)
        {
            // Member exists, so add all attributes required
            if (dfg != null)
            {
                mmd.setDefaultFetchGroup(dfg.equals("true") ? true : false);
            }

            String depString = getAttr(attrs,"dependent");
            if (!StringUtils.isWhitespace(depString))
            {
                mmd.setDependent((depString.trim().equalsIgnoreCase("true") ? true : false));
            }

            mmd.setMappedBy(getAttr(attrs,"mapped-by"));

            String loadFg = getAttr(attrs,"load-fetch-group");
            if (!StringUtils.isWhitespace(loadFg))
            {
                mmd.setLoadFetchGroup(loadFg);
            }
        }
        else
        {
            if (propertyAccess)
            {
                mmd = mgr.getMetaDataFactory().newPropertyObject(acmd,
                    getAttr(attrs,"name"),
                    null, // primary-key is specified using "id"
                    FieldPersistenceModifier.PERSISTENT.toString(), // transient go through a different method
                    dfg,
                    null, // No such concept in JPA
                    null, // Specified via "embedded"
                    null, // Specified via "lob"
                    getAttr(attrs,"dependent"),
                    getAttr(attrs,"mapped-by"),
                    null, // Specified via "column"
                    null, // Specified via "secondary-table" or "join-table"
                    null, // Specified via "secondary-table" or "join-table"
                    null, // Specified via "secondary-table" or "join-table"
                    null, // JPA has no delete-action
                    null, // JPA has no index option
                    null, // unique is specified elsewhere
                    null, // JPA has no recursion depth
                    getAttr(attrs,"load-fetch-group"),
                    null, // value strategy is specified elsewhere
                    null, // sequence is specified elsewhere
                    null, // JPA has no field-type
                    null); // JPA has no field-name
            }
            else
            {
                mmd = mgr.getMetaDataFactory().newFieldObject(acmd,
                    getAttr(attrs,"name"),
                    null, // primary-key is specified using "id"
                    FieldPersistenceModifier.PERSISTENT.toString(), // transient go through a different method
                    dfg,
                    null, // No such concept in JPA
                    null, // Specified via "embedded"
                    null, // Specified via "lob"
                    getAttr(attrs,"dependent"),
                    getAttr(attrs,"mapped-by"),
                    null, // Specified via "column"
                    null, // Specified via "secondary-table" or "join-table"
                    null, // Specified via "secondary-table" or "join-table"
                    null, // Specified via "secondary-table" or "join-table"
                    null, // JPA has no delete-action
                    null, // JPA has no index option
                    null, // unique is specified elsewhere
                    null, // JPA has no recursion depth
                    getAttr(attrs,"load-fetch-group"),
                    null, // value strategy is specified elsewhere
                    null, // sequence is specified elsewhere
                    null); // JPA has no field-type
            }
            acmd.addMember(mmd);
        }
        if (defaultCascadePersist)
        {
            // This file has <persistence-unit-defaults> set to cascade-persist all fields
            mmd.setCascadePersist(true);
        }
        return mmd;
    }

    /**
     * Utility to create a new primary key field/property component.
     * @param acmd The parent class MetaData
     * @param attrs Attributes of the "id" element
     * @return The FieldMetaData/PropertyMetaData
     */
    protected AbstractMemberMetaData newPKFieldObject(AbstractClassMetaData acmd, Attributes attrs)
    {
        AbstractMemberMetaData mmd = null;

        mmd = acmd.getMetaDataForMember(getAttr(attrs, "name"));
        if (mmd != null)
        {
            // Member exists, so mark as PK
            mmd.setPrimaryKey();
        }
        else
        {
            // Create new property/field
            if (propertyAccess)
            {
                mmd = mgr.getMetaDataFactory().newPropertyObject(acmd, getAttr(attrs, "name"), "true",
                    FieldPersistenceModifier.PERSISTENT.toString(), null, null, null, null, null, null,
                    null, null, null, null, null, null, null, null, null, null, null, null, null);
            }
            else
            {
                mmd = mgr.getMetaDataFactory().newFieldObject(acmd, getAttr(attrs, "name"), "true",
                    FieldPersistenceModifier.PERSISTENT.toString(), null, null, null, null, null, null,
                    null, null, null, null, null, null, null, null, null, null, null, null);
            }
            if (defaultCascadePersist)
            {
                // This file has <persistence-unit-defaults> set to cascade-persist all fields
                mmd.setCascadePersist(true);
            }
            acmd.addMember(mmd);
        }
        return mmd;
    }

    /**
     * Utility to create a new transient field/property component.
     * @param md The parent MetaData
     * @param name Name of the transient field
     * @return The FieldMetaData/PropertyMetaData
     */
    protected AbstractMemberMetaData newTransientFieldObject(MetaData md, String name)
    {
        AbstractMemberMetaData mmd = null;
        if (propertyAccess)
        {
            mmd = mgr.getMetaDataFactory().newPropertyObject(md, name, null,
                FieldPersistenceModifier.NONE.toString(), null, null, null, null, null, null, null,
                null, null, null, null, null, null, null, null, null, null, null, null);
        }
        else
        {
            mmd = mgr.getMetaDataFactory().newFieldObject(md, name, null,
                FieldPersistenceModifier.NONE.toString(), null, null, null, null, null, null, null,
                null, null, null, null, null, null, null, null, null, null, null);
        }
        if (defaultCascadePersist)
        {
            // This file has <persistence-unit-defaults> set to cascade-persist all fields
            mmd.setCascadePersist(true);
        }
        return mmd;
    }

    /**
     * Utility to create a new field entry for a field/property in a superclass.
     * @param md The parent MetaData
     * @param attrs Attributes of the "id" element
     * @return The FieldMetaData/PropertyMetaData
     */
    protected AbstractMemberMetaData newOverriddenFieldObject(MetaData md, Attributes attrs)
    {
        AbstractMemberMetaData mmd = null;
        if (propertyAccess)
        {
            mmd = mgr.getMetaDataFactory().newPropertyObject(md, "#UNKNOWN." + getAttr(attrs, "name"), null,
                FieldPersistenceModifier.PERSISTENT.toString(), null, null, null, null, null, null, null, null,
                null, null, null, null, null, null, null, null, null, null, null);
        }
        else
        {
            mmd = mgr.getMetaDataFactory().newFieldObject(md, "#UNKNOWN." + getAttr(attrs, "name"), null,
                FieldPersistenceModifier.PERSISTENT.toString(), null, null, null, null, null, null, null, null,
                null, null, null, null, null, null, null, null, null, null);
        }
        if (defaultCascadePersist)
        {
            // This file has <persistence-unit-defaults> set to cascade-persist all fields
            mmd.setCascadePersist(true);
        }
        return mmd;
    }

    /**
     * Handler method called at the start of an element.
     * @param uri URI of the tag
     * @param localName Local name
     * @param qName Element name
     * @param attrs Attributes for this element
     * @throws SAXException in parsing errors
     */
    public void startElement(String uri, String localName, String qName, Attributes attrs)
    throws SAXException
    {
        if (JPOXLogger.METADATA.isDebugEnabled())
        {
            StringBuffer sb = new StringBuffer();
            sb.append("<" + qName);
            for (int i=0; i<attrs.getLength(); i++)
            {
                sb.append(" ");
                sb.append(attrs.getQName(i)).append("=\"").append(attrs.getValue(i)).append("\"");
            }
            sb.append(">");
            JPOXLogger.METADATA.debug(LOCALISER.msg("044034",sb.toString(), "" + stack.size()));
        }
        if (localName.length()<1)
        {
            localName = qName;
        }
        try
        {
            if (localName.equals("entity-mappings"))
            {
                FileMetaData filemd = (FileMetaData)getStack();
                filemd.setType(FileMetaData.JPA_FILE);
            }
            else if (localName.equals("description"))
            {
                // Of no practical use so ignored
            }
            else if (localName.equals("persistence-unit-metadata"))
            {
                // Nothing to do - we use subelements
            }
            else if (localName.equals("xml-mapping-metadata-complete"))
            {
                // All classes in the file are complete without any annotations
                metaDataComplete = true;
            }
            else if (localName.equals("persistence-unit-defaults"))
            {
                // Nothing to do - we use subelements
            }
            else if (localName.equals("package"))
            {
                // Processed in endElement()
            }
            else if (localName.equals("schema"))
            {
                // Processed in endElement()
            }
            else if (localName.equals("catalog"))
            {
                // Processed in endElement()
            }
            else if (localName.equals("access"))
            {
                // Processed in endElement()
            }
            else if (localName.equals("sequence-generator"))
            {
                // Sequence generator (add to the default package whether they are specified there are not)
                MetaData md = getStack();
                String initValue = getAttr(attrs, "initial-value");
                if (StringUtils.isWhitespace(initValue))
                {
                    initValue = "1"; // JPA default
                }
                String allocSize = getAttr(attrs, "allocation-size");
                if (StringUtils.isWhitespace(allocSize))
                {
                    allocSize = "50"; // JPA default
                }
                SequenceMetaData seqmd = new SequenceMetaData(md, getAttr(attrs, "name"),
                    getAttr(attrs, "sequence-name"), null, null, initValue, allocSize);
                PackageMetaData pmd = null;
                if (defaultPackageName != null)
                {
                    pmd = ((FileMetaData)metadata).getPackage(defaultPackageName);
                }
                else
                {
                    if (((FileMetaData)metadata).getNoOfPackages() > 0)
                    {
                        pmd = ((FileMetaData)metadata).getPackage(0);
                    }
                    else
                    {
                        // Add a dummy (root) package to hold our sequences since no default package name set
                        pmd = new PackageMetaData((FileMetaData)metadata, "", null, null);
                        ((FileMetaData)metadata).addPackage(pmd);
                    }
                }
                pmd.addSequence(seqmd);
            }
            else if (localName.equals("table-generator"))
            {
                // Table generator (add to the default package whether they are specified there or not)
                MetaData md = getStack();
                TableGeneratorMetaData tgmd = new TableGeneratorMetaData(md, getAttr(attrs, "name"),
                    getAttr(attrs, "table"), getAttr(attrs, "catalog"), getAttr(attrs, "schema"), getAttr(attrs, "pk-column-name"),
                    getAttr(attrs, "value-column-name"), getAttr(attrs, "pk-column-value"), getAttr(attrs, "initial-value"),
                    getAttr(attrs, "allocation-size"));

                PackageMetaData pmd = null;
                if (defaultPackageName != null)
                {
                    pmd = ((FileMetaData)metadata).getPackage(defaultPackageName);
                }
                else
                {
                    if (((FileMetaData)metadata).getNoOfPackages() > 0)
                    {
                        pmd = ((FileMetaData)metadata).getPackage(0);
                    }
                    else
                    {
                        // Add a dummy (root) package to hold our sequences since no default package name set
                        pmd = new PackageMetaData((FileMetaData)metadata, "", null, null);
                        ((FileMetaData)metadata).addPackage(pmd);
                    }
                }
                pmd.addTableGenerator(tgmd);
            }
            else if (localName.equals("named-query"))
            {
                // Named JPQL query
                MetaData md = getStack();
                if (md instanceof FileMetaData)
                {
                    FileMetaData filemd = (FileMetaData)md;
                    QueryMetaData qmd = new QueryMetaData(filemd, null, getAttr(attrs, "name"), "javax.jdo.query.JPQL",
                        null, null, null, null, null);
                    filemd.addQuery(qmd);
                    pushStack(qmd);
                }
                else if (md instanceof ClassMetaData)
                {
                    ClassMetaData cmd = (ClassMetaData)md;
                    QueryMetaData qmd = new QueryMetaData(cmd, null, getAttr(attrs, "name"), "javax.jdo.query.JPQL",
                        null, null, null, null, null);
                    cmd.addQuery(qmd);
                    pushStack(qmd);
                }
            }
            else if (localName.equals("named-native-query"))
            {
                // Named SQL query
                MetaData md = getStack();
                if (md instanceof FileMetaData)
                {
                    FileMetaData filemd = (FileMetaData)md;
                    QueryMetaData qmd = new QueryMetaData(filemd, null, getAttr(attrs, "name"), "javax.jdo.query.SQL", null,
                        getAttr(attrs, "result-class"), getAttr(attrs, "result-set-mapping"), null, null);
                    filemd.addQuery(qmd);
                    pushStack(qmd);
                }
                else if (md instanceof ClassMetaData)
                {
                    ClassMetaData cmd = (ClassMetaData)md;
                    QueryMetaData qmd = new QueryMetaData(cmd, null, getAttr(attrs, "name"), "javax.jdo.query.SQL", null,
                        getAttr(attrs, "result-class"), getAttr(attrs, "result-set-mapping"), null, null);
                    cmd.addQuery(qmd);
                    pushStack(qmd);
                }
            }
            else if (localName.equals("sql-result-set-mapping"))
            {
                MetaData md = getStack();
                if (md instanceof FileMetaData)
                {
                    FileMetaData filemd = (FileMetaData)md;
                    QueryResultMetaData qrmd = new QueryResultMetaData(filemd, getAttr(attrs, "name"));
                    filemd.addQueryResultMetaData(qrmd);
                    pushStack(qrmd);
                }
                else if (md instanceof ClassMetaData)
                {
                    ClassMetaData cmd = (ClassMetaData)md;
                    QueryResultMetaData qrmd = new QueryResultMetaData(cmd, getAttr(attrs, "name"));
                    cmd.addQueryResultMetaData(qrmd);
                    pushStack(qrmd);
                }
            }
            else if (localName.equals("entity-result"))
            {
                // Add an entity (persistent class) mapping
                QueryResultMetaData qrmd = (QueryResultMetaData)getStack();
                queryResultEntityName = getAttr(attrs, "entity-class"); // Save this for any field-result that arrives
                qrmd.addPersistentTypeMapping(queryResultEntityName,
                    null, // No field-column mappings info at this point
                    getAttr(attrs, "discriminator-column"));
            }
            else if (localName.equals("field-result"))
            {
                // Add a field-column mapping for the entity (persistent class)
                QueryResultMetaData qrmd = (QueryResultMetaData)getStack();
                qrmd.addMappingForPersistentTypeMapping(queryResultEntityName,
                    getAttr(attrs, "name"), getAttr(attrs, "column"));
            }
            else if (localName.equals("column-result"))
            {
                // Add a scalar column mapping
                QueryResultMetaData qrmd = (QueryResultMetaData)getStack();
                qrmd.addScalarColumn(getAttr(attrs, "name"));
            }
            else if (localName.equals("mapped-superclass"))
            {
                // New entity for this package
                FileMetaData filemd = (FileMetaData)getStack();
                String className = getAttr(attrs, "class");
                String packageName = null;
                if (className.indexOf('.') > 0)
                {
                    // Fully-qualified so use package name from class
                    packageName = className.substring(0, className.lastIndexOf('.'));
                }
                PackageMetaData pmd = null;
                if (packageName != null)
                {
                    pmd = filemd.getPackage(packageName);
                }
                if (pmd == null)
                {
                    if (packageName != null)
                    {
                        // Class fully qualified so add its package
                        pmd = new PackageMetaData(filemd, packageName, null, null);
                    }
                    else if (defaultPackageName != null)
                    {
                        // Use default package for entity-mappings
                        pmd = filemd.getPackage(defaultPackageName);
                    }
                    else
                    {
                        // Add root package
                        pmd = new PackageMetaData(filemd, "", null, null);
                    }
                }

                ClassMetaData cmd = newClassObject(pmd, attrs, false);
                pmd.addClass(cmd);

                // Set to use "subclass-table" since all subclasses inherit these fields
                cmd.setInheritanceMetaData(new InheritanceMetaData(cmd, InheritanceStrategy.SUBCLASS_TABLE.toString()));

                pushStack(cmd);
            }
            else if (localName.equals("query"))
            {
                // Processed in endElement()
            }
            else if (localName.equals("entity"))
            {
                // New entity for this package
                FileMetaData filemd = (FileMetaData)getStack();
                String className = getAttr(attrs, "class");
                String packageName = null;
                if (className.indexOf('.') > 0)
                {
                    // Fully-qualified so use package name from class
                    packageName = className.substring(0, className.lastIndexOf('.'));
                }
                PackageMetaData pmd = null;
                if (packageName != null)
                {
                    pmd = filemd.getPackage(packageName);
                }
                if (pmd == null)
                {
                    if (packageName != null)
                    {
                        // Class fully qualified so add its package
                        pmd = new PackageMetaData(filemd, packageName, null, null);
                    }
                    else if (defaultPackageName != null)
                    {
                        // Use default package for entity-mappings
                        pmd = filemd.getPackage(defaultPackageName);
                    }
                    else
                    {
                        // Add root package
                        pmd = new PackageMetaData(filemd, "", null, null);
                    }
                }

                ClassMetaData cmd = newClassObject(pmd, attrs, false);
                pmd.addClass(cmd);

                pushStack(cmd);
            }
            else if (localName.equals("embeddable"))
            {
                // New embedded-only entity for this package
                FileMetaData filemd = (FileMetaData)getStack();
                String className = getAttr(attrs, "class");
                String packageName = null;
                if (className.indexOf('.') > 0)
                {
                    // Fully-qualified so use package name from class
                    packageName = className.substring(0, className.lastIndexOf('.'));
                }
                PackageMetaData pmd = null;
                if (packageName != null)
                {
                    pmd = filemd.getPackage(packageName);
                }
                if (pmd == null)
                {
                    if (packageName != null)
                    {
                        // Class fully qualified so add its package
                        pmd = new PackageMetaData(filemd, packageName, null, null);
                    }
                    else if (defaultPackageName != null)
                    {
                        // Use default package for entity-mappings
                        pmd = filemd.getPackage(defaultPackageName);
                    }
                    else
                    {
                        // Add root package
                        pmd = new PackageMetaData(filemd, "", null, null);
                    }
                }

                ClassMetaData cmd = newClassObject(pmd, attrs, true);
                pmd.addClass(cmd);

                pushStack(cmd);
            }
            else if (localName.equals("attributes"))
            {
                // Nothing to do since is just a holder of other elements
            }
            else if (localName.equals("embeddable-attributes"))
            {
                // Nothing to do since is just a holder of other elements
            }
            else if (localName.equals("id-class"))
            {
                // Identity class
                ClassMetaData cmd = (ClassMetaData)getStack();
                cmd.setObjectIdClass(getAttr(attrs, "class"));
            }
            else if (localName.equals("inheritance"))
            {
                // Inheritance - only for root class
                ClassMetaData cmd = (ClassMetaData)getStack();
                String strategy = getAttr(attrs, "strategy");
                String strategyType = null;
                if (strategy.equalsIgnoreCase("JOINED"))
                {
                    strategyType = InheritanceStrategy.NEW_TABLE.toString();
                }
                else if (strategy.equalsIgnoreCase("TABLE_PER_CLASS"))
                {
                    strategyType = InheritanceStrategy.COMPLETE_TABLE.toString();
                }
                else
                {
                  // SINGLE_TABLE (default), so implies nothing needs setting since thats the default
                }
                InheritanceMetaData inhmd = new InheritanceMetaData(cmd, getAttr(attrs, strategyType));
                inhmd.setStrategyForTree(strategy.toUpperCase());
                cmd.setInheritanceMetaData(inhmd);
            }
            else if (localName.equals("table"))
            {
                // Table for this entity
                ClassMetaData cmd = (ClassMetaData)getStack();
                cmd.setCatalog(getAttr(attrs, "catalog"));
                cmd.setSchema(getAttr(attrs, "schema"));
                cmd.setTable(getAttr(attrs, "name"));
            }
            else if (localName.equals("secondary-table"))
            {
                // Join for this entity
                ClassMetaData cmd = (ClassMetaData)getStack();
                JoinMetaData joinmd = new JoinMetaData(cmd,
                    getAttr(attrs, "name"), getAttr(attrs, "catalog"), getAttr(attrs, "schema"),
                    null, null, null, null, null);
                cmd.addJoin(joinmd);
                pushStack(joinmd);
            }
            else if (localName.equals("primary-key-join-column"))
            {
                MetaData md = getStack();
                if (md instanceof ClassMetaData)
                {
                    // Join columns between PK of subclass table and PK of base class table
                    ClassMetaData cmd = (ClassMetaData)md;
                    ColumnMetaData colmd = new ColumnMetaData(cmd.getInheritanceMetaData().getJoinMetaData(),
                        getAttr(attrs, "name"),
                        getAttr(attrs, "referenced-column-name"), // Column in primary table
                        null, null, null, null, null, null, null, null, null, null, null);
                    cmd.getInheritanceMetaData().getJoinMetaData().addColumn(colmd);
                }
                else if (md instanceof JoinMetaData)
                {
                    // Join columns between PK of secondary table and PK of primary table
                    JoinMetaData joinmd = (JoinMetaData)md;
                    ColumnMetaData colmd = new ColumnMetaData(joinmd,
                            getAttr(attrs, "name"),
                            getAttr(attrs, "referenced-column-name"), // Column in primary table
                            null, null, null, null, null, null, null, null, null, null, null);
                    joinmd.addColumn(colmd);
                }
            }
            else if (localName.equals("id"))
            {
                // Identity field
                ClassMetaData cmd = (ClassMetaData)getStack();
                AbstractMemberMetaData mmd = newPKFieldObject(cmd, attrs);

                pushStack(mmd);
            }
            else if (localName.equals("embedded-id"))
            {
                // Embedded identity field
                ClassMetaData cmd = (ClassMetaData)getStack();
                AbstractMemberMetaData mmd = newPKFieldObject(cmd, attrs);

                pushStack(mmd);
            }
            else if (localName.equals("basic"))
            {
                // Basic field
                AbstractClassMetaData cmd = (AbstractClassMetaData)getStack();
                AbstractMemberMetaData mmd = newFieldObject(cmd, attrs);

                pushStack(mmd);
            }
            else if (localName.equals("lob"))
            {
                AbstractMemberMetaData fmd = (AbstractMemberMetaData)getStack();
                fmd.setStoreInLob(); // Just mark it as to be stored in a "lob" and let the MetaData sort it out
            }
            else if (localName.equals("enumerated"))
            {
                // Processed elsewhere
            }
            else if (localName.equals("temporal"))
            {
                // Processed elsewhere
            }
            else if (localName.equals("transient"))
            {
                // Transient field
                ClassMetaData cmd = (ClassMetaData)getStack();
                AbstractMemberMetaData mmd = newTransientFieldObject(cmd, getAttr(attrs, "name"));
                cmd.addMember(mmd);

                pushStack(mmd);
            }
            else if (localName.equals("one-to-many"))
            {
                // 1-N field
                ClassMetaData cmd = (ClassMetaData)getStack();
                AbstractMemberMetaData mmd = newFieldObject(cmd, attrs);
                mmd.setTargetClassName(getAttr(attrs, "target-entity"));
                mmd.setOrdered();
                if (mmd.getMappedBy() == null && mmd.getJoinMetaData() == null &&
                    !mgr.getOMFContext().getPersistenceConfiguration().getBooleanProperty("org.jpox.jpa.oneToManyUniFkRelations"))
                {
                    // Strict JPA : 1-N uni with no join specified (yet) so add one (see JPA spec [9.1.24])
                    mmd.setJoinMetaData(new JoinMetaData(mmd, null, null, null, null, null, null, null, null));
                }

                pushStack(mmd);
            }
            else if (localName.equals("one-to-one"))
            {
                // 1-1 field
                ClassMetaData cmd = (ClassMetaData)getStack();
                AbstractMemberMetaData mmd = newFieldObject(cmd, attrs);
                mmd.setTargetClassName(getAttr(attrs, "target-entity"));

                pushStack(mmd);
            }
            else if (localName.equals("many-to-one"))
            {
                // N-1 field
                ClassMetaData cmd = (ClassMetaData)getStack();
                AbstractMemberMetaData mmd = newFieldObject(cmd, attrs);
                mmd.setTargetClassName(getAttr(attrs, "target-entity"));

                pushStack(mmd);
            }
            else if (localName.equals("many-to-many"))
            {
                // M-N field
                ClassMetaData cmd = (ClassMetaData)getStack();
                AbstractMemberMetaData mmd = newFieldObject(cmd, attrs);
                mmd.setTargetClassName(getAttr(attrs, "target-entity"));
                mmd.setOrdered();
                if (mmd.getMappedBy() == null && mmd.getJoinMetaData() == null)
                {
                    // M-N and no join specified (yet) so add one
                    mmd.setJoinMetaData(new JoinMetaData(mmd, null, null, null, null, null, null, null, null));
                }

                pushStack(mmd);
            }
            else if (localName.equals("map-key"))
            {
                // Key of a Map (field/property of the value class)
                AbstractMemberMetaData fmd = (AbstractMemberMetaData)getStack();
                String mappedByFieldName = getAttr(attrs, "name");
                if (StringUtils.isWhitespace(mappedByFieldName))
                {
                    mappedByFieldName = "#PK"; // Special value understood by MapMetaData.populate()
                }
                KeyMetaData keymd = new KeyMetaData(fmd, null, null, null, null, null, mappedByFieldName);
                fmd.setKeyMetaData(keymd);
            }
            else if (localName.equals("order-by"))
            {
                // Processed in endElement()
            }
            else if (localName.equals("cascade"))
            {
                // Do nothing
            }
            else if (localName.equals("cascade-type"))
            {
                // Handled in elements below
            }
            else if (localName.equals("cascade-all"))
            {
                AbstractMemberMetaData mmd = (AbstractMemberMetaData)getStack();
                mmd.setCascadePersist(true);
                mmd.setCascadeUpdate(true);
                mmd.setCascadeDelete(true);
                mmd.setCascadeRefresh(true);
            }
            else if (localName.equals("cascade-persist"))
            {
                MetaData md = getStack();
                if (md instanceof AbstractMemberMetaData)
                {
                    AbstractMemberMetaData mmd = (AbstractMemberMetaData)md;
                    mmd.setCascadePersist(true);
                }
                else if (md instanceof FileMetaData)
                {
                    // Specified at <persistence-unit-defaults>
                    defaultCascadePersist = true;
                }
            }
            else if (localName.equals("cascade-merge"))
            {
                AbstractMemberMetaData mmd = (AbstractMemberMetaData)getStack();
                mmd.setCascadeUpdate(true);
            }
            else if (localName.equals("cascade-remove"))
            {
                AbstractMemberMetaData mmd = (AbstractMemberMetaData)getStack();
                mmd.setCascadeDelete(true);
            }
            else if (localName.equals("cascade-refresh"))
            {
                AbstractMemberMetaData mmd = (AbstractMemberMetaData)getStack();
                mmd.setCascadeRefresh(true);
            }
            else if (localName.equals("version"))
            {
                if (getStack() instanceof ClassMetaData)
                {
                    // Version field
                    ClassMetaData cmd = (ClassMetaData)getStack();
                    AbstractMemberMetaData mmd = newFieldObject(cmd, attrs);

                    // Tag this field as the version field
                    VersionMetaData vermd = new VersionMetaData(VersionStrategy.VERSION_NUMBER.toString(), mmd.getName());
                    cmd.setVersionMetaData(vermd);

                    pushStack(mmd);
                }
            }
            else if (localName.equals("discriminator-value"))
            {
                // Processed in endElement()
            }
            else if (localName.equals("discriminator-column"))
            {
                ClassMetaData cmd = (ClassMetaData)getStack();
                InheritanceMetaData inhmd = cmd.getInheritanceMetaData();
                if (inhmd == null)
                {
                    // Add an empty inheritance specification
                    inhmd = new InheritanceMetaData(cmd, null);
                    cmd.setInheritanceMetaData(inhmd);
                }
                DiscriminatorMetaData discmd = inhmd.getDiscriminatorMetaData();
                if (discmd == null)
                {
                    // User hasnt specified discriminator value so use "provider-specific function" (JPA spec 9.1.3.1) - what a joke spec
                    discmd = new DiscriminatorMetaData(inhmd, null, null, DiscriminatorStrategy.CLASS_NAME.toString(), "true");
                    inhmd.setDiscriminatorMetaData(discmd);
                }
                String jdbcType = null;
                String discType = getAttr(attrs, "discriminator-type");
                if (discType != null)
                {
                    if (discType.equalsIgnoreCase("STRING"))
                    {
                        jdbcType = "VARCHAR";
                    }
                    else if (discType.equalsIgnoreCase("CHAR"))
                    {
                        jdbcType = "CHAR";
                    }
                    else if (discType.equalsIgnoreCase("INTEGER"))
                    {
                        jdbcType = "INTEGER";
                    }
                }
                ColumnMetaData colmd = new ColumnMetaData(discmd, getAttr(attrs, "name"), null, null, jdbcType, null, getAttr(attrs, "length"),
                    null, null, null, null, null, null, null);
                discmd.setColumnMetaData(colmd);
            }
            else if (localName.equals("generated-value"))
            {
                // generated value for this field
                AbstractMemberMetaData fmd = (AbstractMemberMetaData)getStack();
                IdentityStrategy idStrategy = IdentityStrategy.getIdentityStrategy(getAttr(attrs, "strategy"));
                fmd.setValueStrategy(idStrategy);
                fmd.setValueGeneratorName(getAttr(attrs, "generator"));
            }
            else if (localName.equals("join-table"))
            {
                // Join table for this field
                AbstractMemberMetaData fmd = (AbstractMemberMetaData)getStack();
                JoinMetaData joinmd = new JoinMetaData(fmd, null, null, null, null, null, null, null, null);
                String tableName = getAttr(attrs, "name");
                String schemaName = getAttr(attrs, "schema");
                String catalogName = getAttr(attrs, "catalog");

                fmd.setJoinMetaData(joinmd);
                if (!StringUtils.isWhitespace(tableName))
                {
                    fmd.setTable(tableName);
                }
                if (!StringUtils.isWhitespace(schemaName))
                {
                    fmd.setSchema(schemaName);
                }
                if (!StringUtils.isWhitespace(catalogName))
                {
                    fmd.setSchema(catalogName);
                }
                pushStack(joinmd);
            }
            else if (localName.equals("column"))
            {
                // Column for the current field
                AbstractMemberMetaData fmd = (AbstractMemberMetaData)getStack();
                ColumnMetaData colmd =
                    new ColumnMetaData(fmd,
                        getAttr(attrs, "name"),
                        null, // No "target" in JPA
                        null, // No "target-field" in JPA
                        null, // No "jdbc-type" in JPA (use Lob, Basic, Temporal to decide this)
                        null, // No "sql-type" in JPA
                        getAttr(attrs, "length"), // Should use precision if floating point type
                        getAttr(attrs, "scale"),
                        getAttr(attrs, "nullable"),
                        null, // No default-value in JPA
                        null, // No insert-value in JPA
                        getAttr(attrs, "insertable"),
                        getAttr(attrs, "updatable"),
                        getAttr(attrs, "unique"));
                fmd.addColumn(colmd);
                String table = getAttr(attrs, "table");
                if (!StringUtils.isWhitespace(table))
                {
                  // Using secondary table
                  fmd.setTable(table);
                }
            }
            else if (localName.equals("join-column"))
            {
              MetaData md = getStack();
              if (md instanceof JoinMetaData)
              {
                JoinMetaData joinmd = (JoinMetaData)md;
                    ColumnMetaData colmd =
                        new ColumnMetaData(joinmd,
                            getAttr(attrs, "name"),
                            getAttr(attrs, "referenced-column-name"),
                            null,
                            null, // Copy referenced column
                            null, // Copy referenced column
                            null, // Copy referenced column
                            null, // Copy referenced column
                            getAttr(attrs, "nullable"),
                            null, // No default-value in JPA
                            null, // No insert-value in JPA
                            getAttr(attrs, "insertable"),
                            getAttr(attrs, "updatable"),
                            getAttr(attrs, "unique"));
                joinmd.addColumn(colmd);
              }
              else if (md instanceof AbstractMemberMetaData)
              {
                // N-1, 1-1, 1-N (FK). Just set <column> for the field. Is this correct for 1-N FK ?
                AbstractMemberMetaData fmd = (AbstractMemberMetaData)md;
                ColumnMetaData colmd =
                        new ColumnMetaData(fmd,
                            getAttr(attrs, "name"),
                            getAttr(attrs, "referenced-column-name"),
                            null,
                            null, // Copy referenced column
                            null, // Copy referenced column
                            null, // Copy referenced column
                            null, // Copy referenced column
                            getAttr(attrs, "nullable"),
                            null, // No default-value in JPA
                            null, // No insert-value in JPA
                            getAttr(attrs, "insertable"),
                            getAttr(attrs, "updatable"),
                            getAttr(attrs, "unique"));
                fmd.addColumn(colmd);
              }
            }
            else if (localName.equals("inverse-join-column"))
            {
              MetaData md = getStack();
              if (md instanceof JoinMetaData)
              {
                // Join table column that is FK to the element table
                JoinMetaData joinmd = (JoinMetaData)md;
                ElementMetaData elemmd = null;
                AbstractMemberMetaData fmd = (AbstractMemberMetaData)joinmd.getParent();
                if (fmd.getElementMetaData() != null)
                {
                  elemmd = fmd.getElementMetaData();
                }
                else
                {
                  elemmd = new ElementMetaData(fmd, null, null, null, null, null, null);
                  fmd.setElementMetaData(elemmd);
                }
                ColumnMetaData colmd =
                        new ColumnMetaData(elemmd,
                            getAttr(attrs, "name"),
                            getAttr(attrs, "referenced-column-name"),
                            null,
                            null, // Copy referenced column
                            null, // Copy referenced column
                            null, // Copy referenced column
                            null, // Copy referenced column
                            getAttr(attrs, "nullable"),
                            null, // No default-value in JPA
                            null, // No insert-value in JPA
                            getAttr(attrs, "insertable"),
                            getAttr(attrs, "updatable"),
                            getAttr(attrs, "unique"));
                elemmd.addColumn(colmd);
              }
            }
            else if (localName.equals("unique-constraint"))
            {
                MetaData md = getStack();
                if (md instanceof AbstractClassMetaData)
                {
                    // Unique constraint on primary table
                    AbstractClassMetaData cmd = (AbstractClassMetaData)md;
                    UniqueMetaData unimd = new UniqueMetaData(null, cmd.getTable(), null); // Columns are in subelement
                    cmd.addUniqueConstraint(unimd);
                    pushStack(unimd);
                }
                else if (md instanceof JoinMetaData)
                {
                    // Unique constraint on secondary table or join table
                    JoinMetaData joinmd = (JoinMetaData)md;
                    UniqueMetaData unimd = new UniqueMetaData(null, null, null);
                    joinmd.setUniqueMetaData(unimd);
                    pushStack(unimd);
                }
            }
            else if (localName.equals("entity-listeners"))
            {
                // Nothing to add at this point
            }
            else if (localName.equals("entity-listener"))
            {
                MetaData md = getStack();
                EventListenerMetaData elmd = new EventListenerMetaData(getAttr(attrs, "class"));
                if (md instanceof AbstractClassMetaData)
                {
                    // Specified at <entity> or <mapped-superclass>
                    ((AbstractClassMetaData)md).addListener(elmd);
                }
                else if (md instanceof FileMetaData)
                {
                    // Specified at <persistence-unit-defaults>
                    ((FileMetaData)md).addListener(elmd);
                }

                pushStack(elmd);
            }
            else if (localName.equals("pre-persist"))
            {
                // Pre-create callback
                MetaData md = getStack();
                if (md instanceof AbstractClassMetaData)
                {
                    // Specified at <entity> or <mapped-superclass>
                    AbstractClassMetaData cmd = (AbstractClassMetaData)md;
                    EventListenerMetaData elmd = cmd.getListenerForClass(cmd.getFullClassName());
                    if (elmd == null)
                    {
                        elmd = new EventListenerMetaData(cmd.getFullClassName());
                        cmd.addListener(elmd);
                    }
                    elmd.addCallback("javax.persistence.PrePersist", getAttr(attrs, "method-name"));
                }
                else
                {
                    // Specified at <entity-listener>
                    EventListenerMetaData elmd = (EventListenerMetaData)md;
                    elmd.addCallback("javax.persistence.PrePersist", getAttr(attrs, "method-name"));
                }
            }
            else if (localName.equals("post-persist"))
            {
                // Post-create callback
                MetaData md = getStack();
                if (md instanceof AbstractClassMetaData)
                {
                    // Specified at <entity> or <mapped-superclass>
                    AbstractClassMetaData cmd = (AbstractClassMetaData)md;
                    EventListenerMetaData elmd = cmd.getListenerForClass(cmd.getFullClassName());
                    if (elmd == null)
                    {
                        elmd = new EventListenerMetaData(cmd.getFullClassName());
                        cmd.addListener(elmd);
                    }
                    elmd.addCallback("javax.persistence.PostPersist", getAttr(attrs, "method-name"));
                }
                else
                {
                    // Specified at <entity-listener>
                    EventListenerMetaData elmd = (EventListenerMetaData)md;
                    elmd.addCallback("javax.persistence.PostPersist", getAttr(attrs, "method-name"));
                }
            }
            else if (localName.equals("pre-remove"))
            {
                // Pre-delete callback
                MetaData md = getStack();
                if (md instanceof AbstractClassMetaData)
                {
                    // Specified at <entity> or <mapped-superclass>
                    AbstractClassMetaData cmd = (AbstractClassMetaData)md;
                    EventListenerMetaData elmd = cmd.getListenerForClass(cmd.getFullClassName());
                    if (elmd == null)
                    {
                        elmd = new EventListenerMetaData(cmd.getFullClassName());
                        cmd.addListener(elmd);
                    }
                    elmd.addCallback("javax.persistence.PreRemove", getAttr(attrs, "method-name"));
                }
                else
                {
                    // Specified at <entity-listener>
                    EventListenerMetaData elmd = (EventListenerMetaData)md;
                    elmd.addCallback("javax.persistence.PreRemove", getAttr(attrs, "method-name"));
                }
            }
            else if (localName.equals("post-remove"))
            {
                // Post-delete callback
                MetaData md = getStack();
                if (md instanceof AbstractClassMetaData)
                {
                    // Specified at <entity> or <mapped-superclass>
                    AbstractClassMetaData cmd = (AbstractClassMetaData)md;
                    EventListenerMetaData elmd = cmd.getListenerForClass(cmd.getFullClassName());
                    if (elmd == null)
                    {
                        elmd = new EventListenerMetaData(cmd.getFullClassName());
                        cmd.addListener(elmd);
                    }
                    elmd.addCallback("javax.persistence.PostRemove", getAttr(attrs, "method-name"));
                }
                else
                {
                    // Specified at <entity-listener>
                    EventListenerMetaData elmd = (EventListenerMetaData)md;
                    elmd.addCallback("javax.persistence.PostRemove", getAttr(attrs, "method-name"));
                }
            }
            else if (localName.equals("pre-update"))
            {
                // Pre-store callback
                MetaData md = getStack();
                if (md instanceof AbstractClassMetaData)
                {
                    // Specified at <entity> or <mapped-superclass>
                    AbstractClassMetaData cmd = (AbstractClassMetaData)md;
                    EventListenerMetaData elmd = cmd.getListenerForClass(cmd.getFullClassName());
                    if (elmd == null)
                    {
                        elmd = new EventListenerMetaData(cmd.getFullClassName());
                        cmd.addListener(elmd);
                    }
                    elmd.addCallback("javax.persistence.PreUpdate", getAttr(attrs, "method-name"));
                }
                else
                {
                    // Specified at <entity-listener>
                    EventListenerMetaData elmd = (EventListenerMetaData)md;
                    elmd.addCallback("javax.persistence.PreUpdate", getAttr(attrs, "method-name"));
                }
            }
            else if (localName.equals("post-update"))
            {
                // Post-store callback
                MetaData md = getStack();
                if (md instanceof AbstractClassMetaData)
                {
                    // Specified at <entity> or <mapped-superclass>
                    AbstractClassMetaData cmd = (AbstractClassMetaData)md;
                    EventListenerMetaData elmd = cmd.getListenerForClass(cmd.getFullClassName());
                    if (elmd == null)
                    {
                        elmd = new EventListenerMetaData(cmd.getFullClassName());
                        cmd.addListener(elmd);
                    }
                    elmd.addCallback("javax.persistence.PostUpdate", getAttr(attrs, "method-name"));
                }
                else
                {
                    // Specified at <entity-listener>
                    EventListenerMetaData elmd = (EventListenerMetaData)md;
                    elmd.addCallback("javax.persistence.PostUpdate", getAttr(attrs, "method-name"));
                }
            }
            else if (localName.equals("post-load"))
            {
                // Post-load callback
                MetaData md = getStack();
                if (md instanceof AbstractClassMetaData)
                {
                    // Specified at <entity> or <mapped-superclass>
                    AbstractClassMetaData cmd = (AbstractClassMetaData)md;
                    EventListenerMetaData elmd = cmd.getListenerForClass(cmd.getFullClassName());
                    if (elmd == null)
                    {
                        elmd = new EventListenerMetaData(cmd.getFullClassName());
                        cmd.addListener(elmd);
                    }
                    elmd.addCallback("javax.persistence.PostLoad", getAttr(attrs, "method-name"));
                }
                else
                {
                    // Specified at <entity-listener>
                    EventListenerMetaData elmd = (EventListenerMetaData)md;
                    elmd.addCallback("javax.persistence.PostLoad", getAttr(attrs, "method-name"));
                }
            }
            else if (localName.equals("attribute-override"))
            {
                // Override columns for a superclass field
                AbstractClassMetaData cmd = (AbstractClassMetaData)getStack();
                AbstractMemberMetaData fmd = newOverriddenFieldObject(cmd, attrs);
                cmd.addMember(fmd);
                pushStack(fmd);
            }
            else if (localName.equals("association-override"))
            {
                // Override columns for a superclass field
                AbstractClassMetaData cmd = (AbstractClassMetaData)getStack();
                AbstractMemberMetaData fmd = newOverriddenFieldObject(cmd, attrs);
                cmd.addMember(fmd);
                pushStack(fmd);
            }
            else if (localName.equals("exclude-default-listeners"))
            {
                AbstractClassMetaData cmd = (AbstractClassMetaData)getStack();
                cmd.excludeDefaultListeners();
            }
            else if (localName.equals("exclude-superclass-listeners"))
            {
                AbstractClassMetaData cmd = (AbstractClassMetaData)getStack();
                cmd.excludeSuperClassListeners();
            }
            else
            {
                String message = LOCALISER.msg("044037", qName);
                JPOXLogger.METADATA.error(message);
                throw new RuntimeException(message);
            }
        }
        catch(RuntimeException ex)
        {
            JPOXLogger.METADATA.error(LOCALISER.msg("044042", qName, getStack(), uri), ex);
            throw ex;
        }
    }

    /**
     * Handler method called at the end of an element.
     * @param uri URI of the tag
     * @param localName local name
     * @param qName Name of element just ending
     * @throws SAXException in parsing errors
     */
    public void endElement(String uri, String localName, String qName)
    throws SAXException
    {
        if (JPOXLogger.METADATA.isDebugEnabled())
        {
            JPOXLogger.METADATA.debug(LOCALISER.msg("044035", "<" + qName + ">", "" + stack.size()));
        }
        if (localName.length()<1)
        {
            localName = qName;
        }
        // Save the current string for elements that have a body value
        String currentString = getString().trim();
        if (currentString.length() > 0)
        {
            MetaData md = getStack();
            if (localName.equals("schema"))
            {
                if (md instanceof FileMetaData)
                {
                    // Specified at <entity-mappings> or <persistence-unit-defaults>
                    ((FileMetaData)md).setSchema(currentString);
                }
            }
            else if (localName.equals("catalog"))
            {
                if (md instanceof FileMetaData)
                {
                    // Specified at <entity-mappings> or <persistence-unit-defaults>
                    ((FileMetaData)md).setCatalog(currentString);
                }
            }
            else if (localName.equals("access"))
            {
                if (md instanceof FileMetaData)
                {
                    // Specified at <entity-mappings> or <persistence-unit-defaults>
                    if (currentString.equalsIgnoreCase("PROPERTY"))
                    {
                        // Use property access
                        propertyAccess = true;
                    }
                }
            }
            else if (localName.equals("package"))
            {
                if (md instanceof FileMetaData)
                {
                    // Add the default package
                    FileMetaData filemd = (FileMetaData)md;
                    filemd.addPackage(new PackageMetaData(filemd, currentString, null, null));
                    defaultPackageName = currentString;
                }
            }
            else if (localName.equals("discriminator-value"))
            {
                if (md instanceof ClassMetaData)
                {
                    // Add the discriminator value
                    ClassMetaData cmd = (ClassMetaData)md;
                    InheritanceMetaData inhmd = cmd.getInheritanceMetaData();
                    if (inhmd == null)
                    {
                        // Add an empty inheritance specification
                        inhmd = new InheritanceMetaData(cmd, null);
                        cmd.setInheritanceMetaData(inhmd);
                    }
                    String discrimValue = currentString;
                    DiscriminatorMetaData discmd = new DiscriminatorMetaData(inhmd, null, discrimValue,
                        DiscriminatorStrategy.VALUE_MAP.toString(), null);
                    inhmd.setDiscriminatorMetaData(discmd);
                }
            }
            else if (localName.equals("column-name"))
            {
                if (md instanceof UniqueMetaData)
                {
                    // Column for a unique constraint
                    ((UniqueMetaData)md).addColumn(new ColumnMetaData(md, currentString));
                }
            }
            else if (localName.equals("order-by"))
            {
                if (md instanceof AbstractMemberMetaData)
                {
                    // "Ordered List" so add its ordering constraint
                    AbstractMemberMetaData fmd = (AbstractMemberMetaData)md;
                    fmd.setOrderMetaData(new OrderMetaData(currentString));
                }
            }
            else if (localName.equals("query"))
            {
                if (md instanceof QueryMetaData)
                {
                    // Named query, so set the query string
                    ((QueryMetaData)md).setQuery(currentString);
                }
            }
            else if (localName.equals("enumerated"))
            {
                if (md instanceof AbstractMemberMetaData)
                {
                    AbstractMemberMetaData mmd = (AbstractMemberMetaData)md;
                    String enumerationType = currentString;
                    String jdbcType = "INTEGER";
                    if (enumerationType.equalsIgnoreCase("STRING"))
                    {
                        jdbcType = "VARCHAR";
                    }
                    if (mmd.getColumnMetaData() == null)
                    {
                        ColumnMetaData colmd = new ColumnMetaData(mmd, null, null, null, jdbcType,
                            null, null, null, null, null, null, null, null, null);
                        mmd.addColumn(colmd);
                    }
                    else
                    {
                        mmd.getColumnMetaData()[0].setJdbcType(jdbcType);
                    }
                }
            }
            else if (localName.equals("temporal"))
            {
                if (md instanceof AbstractMemberMetaData)
                {
                    AbstractMemberMetaData mmd = (AbstractMemberMetaData)md;
                    String enumerationType = currentString;
                    String jdbcType = null;
                    if (enumerationType.equalsIgnoreCase("DATE"))
                    {
                        jdbcType = "DATE";
                    }
                    else if (enumerationType.equalsIgnoreCase("TIME"))
                    {
                        jdbcType = "TIME";
                    }
                    else if (enumerationType.equalsIgnoreCase("TIMESTAMP"))
                    {
                        jdbcType = "TIMESTAMP";
                    }
                    if (mmd.getColumnMetaData() == null)
                    {
                        ColumnMetaData colmd = new ColumnMetaData(mmd, null, null, null, jdbcType,
                            null, null, null, null, null, null, null, null, null);
                        mmd.addColumn(colmd);
                    }
                    else
                    {
                        mmd.getColumnMetaData()[0].setJdbcType(jdbcType);
                    }
                }
            }
        }

        // Pop the tag
        // If startElement pushes an element onto the stack need a remove here for that type
        if (localName.equals("entity") ||
            localName.equals("mapped-superclass") ||
            localName.equals("entity-listener") ||
            localName.equals("attribute-override") ||
            localName.equals("association-override") ||
            localName.equals("id") ||
            localName.equals("embedded-id") ||
            localName.equals("basic") ||
            localName.equals("transient") ||
            localName.equals("one-to-one") ||
            localName.equals("one-to-many") ||
            localName.equals("many-to-one") ||
            localName.equals("many-to-many") ||
            localName.equals("version") ||
            localName.equals("secondary-table") ||
            localName.equals("join-table") ||
            localName.equals("unique-constraint") ||
            localName.equals("named-query") ||
            localName.equals("named-native-query") ||
            localName.equals("sql-result-set-mapping"))
        {
            popStack();
        }
    }
}
TOP

Related Classes of org.jpox.jpa.metadata.JPAMetaDataHandler

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.