Package org.apache.openjpa.persistence

Source Code of org.apache.openjpa.persistence.XMLPersistenceMetaDataParser

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you 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.openjpa.persistence;

import java.lang.reflect.Field;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.security.AccessController;
import java.security.PrivilegedActionException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.Stack;
import javax.persistence.CascadeType;
import javax.persistence.GenerationType;
import static javax.persistence.CascadeType.*;

import org.apache.commons.lang.StringUtils;
import org.xml.sax.Attributes;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.apache.openjpa.conf.OpenJPAConfiguration;
import org.apache.openjpa.enhance.PersistenceCapable;
import org.apache.openjpa.event.BeanLifecycleCallbacks;
import org.apache.openjpa.event.LifecycleCallbacks;
import org.apache.openjpa.event.LifecycleEvent;
import org.apache.openjpa.event.MethodLifecycleCallbacks;
import org.apache.openjpa.kernel.QueryLanguages;
import org.apache.openjpa.kernel.jpql.JPQLParser;
import org.apache.openjpa.lib.conf.Configurations;
import org.apache.openjpa.lib.log.Log;
import org.apache.openjpa.lib.meta.CFMetaDataParser;
import org.apache.openjpa.lib.util.J2DoPrivHelper;
import org.apache.openjpa.lib.util.Localizer;
import org.apache.openjpa.meta.ClassMetaData;
import org.apache.openjpa.meta.DelegatingMetaDataFactory;
import org.apache.openjpa.meta.FieldMetaData;
import org.apache.openjpa.meta.JavaTypes;
import org.apache.openjpa.meta.LifecycleMetaData;
import org.apache.openjpa.meta.MetaDataDefaults;
import org.apache.openjpa.meta.MetaDataFactory;
import static org.apache.openjpa.meta.MetaDataModes.*;
import org.apache.openjpa.meta.MetaDataRepository;
import org.apache.openjpa.meta.Order;
import org.apache.openjpa.meta.QueryMetaData;
import org.apache.openjpa.meta.SequenceMetaData;
import org.apache.openjpa.meta.ValueMetaData;
import static org.apache.openjpa.persistence.MetaDataTag.*;
import static org.apache.openjpa.persistence.PersistenceStrategy.*;
import org.apache.openjpa.util.ImplHelper;

import serp.util.Numbers;

/**
* Custom SAX parser used by the system to quickly parse persistence i
* metadata files.
*
* @author Steve Kim
* @nojavadoc
*/
public class XMLPersistenceMetaDataParser
    extends CFMetaDataParser
    implements PersistenceMetaDataFactory.Parser {

    // parse constants
    protected static final String ELEM_PKG = "package";
    protected static final String ELEM_ACCESS = "access";
    protected static final String ELEM_ATTRS = "attributes";
    protected static final String ELEM_LISTENER = "entity-listener";
    protected static final String ELEM_CASCADE = "cascade";
    protected static final String ELEM_CASCADE_ALL = "cascade-all";
    protected static final String ELEM_CASCADE_PER = "cascade-persist";
    protected static final String ELEM_CASCADE_MER = "cascade-merge";
    protected static final String ELEM_CASCADE_REM = "cascade-remove";
    protected static final String ELEM_CASCADE_REF = "cascade-refresh";
    protected static final String ELEM_PU_META = "persistence-unit-metadata";
    protected static final String ELEM_PU_DEF = "persistence-unit-defaults";
    protected static final String ELEM_XML_MAP_META_COMPLETE =
        "xml-mapping-metadata-complete";

    private static final Map<String, Object> _elems =
        new HashMap<String, Object>();

    static {
        _elems.put(ELEM_PKG, ELEM_PKG);
        _elems.put(ELEM_ACCESS, ELEM_ACCESS);
        _elems.put(ELEM_ATTRS, ELEM_ATTRS);
        _elems.put(ELEM_LISTENER, ELEM_LISTENER);
        _elems.put(ELEM_CASCADE, ELEM_CASCADE);
        _elems.put(ELEM_CASCADE_ALL, ELEM_CASCADE_ALL);
        _elems.put(ELEM_CASCADE_PER, ELEM_CASCADE_PER);
        _elems.put(ELEM_CASCADE_REM, ELEM_CASCADE_REM);
        _elems.put(ELEM_CASCADE_MER, ELEM_CASCADE_MER);
        _elems.put(ELEM_CASCADE_REF, ELEM_CASCADE_REF);
        _elems.put(ELEM_PU_META, ELEM_PU_META);
        _elems.put(ELEM_PU_DEF, ELEM_PU_DEF);
        _elems.put(ELEM_XML_MAP_META_COMPLETE, ELEM_XML_MAP_META_COMPLETE);

        _elems.put("entity-listeners", ENTITY_LISTENERS);
        _elems.put("pre-persist", PRE_PERSIST);
        _elems.put("post-persist", POST_PERSIST);
        _elems.put("pre-remove", PRE_REMOVE);
        _elems.put("post-remove", POST_REMOVE);
        _elems.put("pre-update", PRE_UPDATE);
        _elems.put("post-update", POST_UPDATE);
        _elems.put("post-load", POST_LOAD);
        _elems.put("exclude-default-listeners", EXCLUDE_DEFAULT_LISTENERS);
        _elems.put("exclude-superclass-listeners",
            EXCLUDE_SUPERCLASS_LISTENERS);

        _elems.put("named-query", QUERY);
        _elems.put("named-native-query", NATIVE_QUERY);
        _elems.put("query-hint", QUERY_HINT);
        _elems.put("query", QUERY_STRING);

        _elems.put("flush-mode", FLUSH_MODE);
        _elems.put("sequence-generator", SEQ_GENERATOR);

        _elems.put("id", ID);
        _elems.put("id-class", ID_CLASS);
        _elems.put("embedded-id", EMBEDDED_ID);
        _elems.put("version", VERSION);
        _elems.put("generated-value", GENERATED_VALUE);
        _elems.put("map-key", MAP_KEY);
        _elems.put("order-by", ORDER_BY);
        _elems.put("lob", LOB);

        _elems.put("basic", BASIC);
        _elems.put("many-to-one", MANY_ONE);
        _elems.put("one-to-one", ONE_ONE);
        _elems.put("embedded", EMBEDDED);
        _elems.put("one-to-many", ONE_MANY);
        _elems.put("many-to-many", MANY_MANY);
        _elems.put("transient", TRANSIENT);
    }

    private static final Localizer _loc = Localizer.forPackage
        (XMLPersistenceMetaDataParser.class);

    private final OpenJPAConfiguration _conf;
    private MetaDataRepository _repos = null;
    private AnnotationPersistenceMetaDataParser _parser = null;
    private ClassLoader _envLoader = null;
    private int _mode = MODE_NONE;
    private boolean _override = false;

    private final Stack _elements = new Stack();
    private final Stack _parents = new Stack();

    private Class _cls = null;
    private int _fieldPos = 0;
    private int _clsPos = 0;
    private int _access = ClassMetaData.ACCESS_UNKNOWN;
    private PersistenceStrategy _strategy = null;
    private Set<CascadeType> _cascades = null;
    private Set<CascadeType> _pkgCascades = null;

    private Class _listener = null;
    private Collection<LifecycleCallbacks>[] _callbacks = null;
    private int[] _highs = null;

    /**
     * Constructor; supply configuration.
     */
    public XMLPersistenceMetaDataParser(OpenJPAConfiguration conf) {
        _conf = conf;
        setValidating(true);
        setLog(conf.getLog(OpenJPAConfiguration.LOG_METADATA));
        setParseComments(true);
        setMode(MODE_META | MODE_MAPPING | MODE_QUERY);
        setParseText(true);
    }

    /**
     * Configuration supplied on construction.
     */
    public OpenJPAConfiguration getConfiguration() {
        return _conf;
    }

    /**
     * The annotation parser. When class is discovered in an XML file,
     * we first parse any annotations present, then override with the XML.
     */
    public AnnotationPersistenceMetaDataParser getAnnotationParser() {
        return _parser;
    }

    /**
     * The annotation parser. When class is discovered in an XML file,
     * we first parse any annotations present, then override with the XML.
     */
    public void setAnnotationParser(AnnotationPersistenceMetaDataParser parser){
        _parser = parser;
    }

    /**
     * Returns the repository for this parser. If none has been set, creates
     * a new repository and sets it.
     */
    public MetaDataRepository getRepository() {
        if (_repos == null) {
            MetaDataRepository repos = _conf.newMetaDataRepositoryInstance();
            MetaDataFactory mdf = repos.getMetaDataFactory();
            if (mdf instanceof DelegatingMetaDataFactory)
                mdf = ((DelegatingMetaDataFactory) mdf).getInnermostDelegate();
            if (mdf instanceof PersistenceMetaDataFactory)
                ((PersistenceMetaDataFactory) mdf).setXMLParser(this);
            _repos = repos;
        }
        return _repos;
    }

    /**
     * Set the metadata repository for this parser.
     */
    public void setRepository(MetaDataRepository repos) {
        _repos = repos;
        if (repos != null
            && (repos.getValidate() & repos.VALIDATE_RUNTIME) != 0)
            setParseComments(false);
    }

    /**
     * Return the environmental class loader to pass on to parsed
     * metadata instances.
     */
    public ClassLoader getEnvClassLoader() {
        return _envLoader;
    }

    /**
     * Set the environmental class loader to pass on to parsed
     * metadata instances.
     */
    public void setEnvClassLoader(ClassLoader loader) {
        _envLoader = loader;
    }

    /**
     * Whether to allow later parses of mapping information to override
     * earlier information for the same class. Defaults to false. Useful
     * when a tool is mapping a class, so that .jdo file partial mapping
     * information can be used even when mappings are stored in .orm files
     * or other locations.
     */
    public boolean getMappingOverride() {
        return _override;
    }

    /**
     * Whether to allow later parses of mapping information to override
     * earlier information for the same class. Defaults to false. Useful
     * when a tool is mapping a class, so that .jdo file partial mapping
     * information can be used even when mappings are stored in .orm files
     * or other locations.
     */
    public void setMappingOverride(boolean override) {
        _override = override;
    }

    /**
     * The parse mode according to the expected document type. The
     * mode constants act as bit flags, and therefore can be combined.
     */
    public int getMode() {
        return _mode;
    }

    /**
     * The parse mode according to the expected document type.
     */
    public void setMode(int mode, boolean on) {
        if (mode == MODE_NONE)
            setMode(MODE_NONE);
        else if (on)
            setMode(_mode | mode);
        else
            setMode(_mode & ~mode);
    }

    /**
     * The parse mode according to the expected document type.
     */
    public void setMode(int mode) {
        _mode = mode;
        if (_parser != null)
            _parser.setMode(mode);
    }

    /**
     * Convenience method for interpreting {@link #getMode}.
     */
    protected boolean isMetaDataMode() {
        return (_mode & MODE_META) != 0;
    }

    /**
     * Convenience method for interpreting {@link #getMode}.
     */
    protected boolean isQueryMode() {
        return (_mode & MODE_QUERY) != 0;
    }

    /**
     * Convenience method for interpreting {@link #getMode}.
     */
    protected boolean isMappingMode() {
        return (_mode & MODE_MAPPING) != 0;
    }

    /**
     * Returns true if we're in mapping mode or in metadata mode with
     * mapping override enabled.
     */
    protected boolean isMappingOverrideMode() {
        return isMappingMode() || (_override && isMetaDataMode());
    }

    ///////////////
    // XML parsing
    ///////////////

    /**
     * Push a parse element onto the stack.
     */
    protected void pushElement(Object elem) {
        _elements.push(elem);
    }

    /**
     * Pop a parse element from the stack.
     */
    protected Object popElement() {
        return _elements.pop();
    }

    /**
     * Return the current element being parsed. May be a class metadata,
     * field metadata, query metadata, etc.
     */
    protected Object currentElement() {
        if (_elements.isEmpty())
            return null;
        return _elements.peek();
    }

    /**
     * Return the current {@link PersistenceStrategy} if any.
     */
    protected PersistenceStrategy currentStrategy() {
        return _strategy;
    }

    /**
     * Return the tag of the current parent element.
     */
    protected Object currentParent() {
        if (_parents.isEmpty())
            return null;
        return _parents.peek();
    }

    /**
     * Return whether we're running the parser at runtime.
     */
    protected boolean isRuntime() {
        return (getRepository().getValidate()
            & MetaDataRepository.VALIDATE_RUNTIME) != 0;
    }

    @Override
    protected Object getSchemaSource() {
        return XMLPersistenceMetaDataParser.class.getResourceAsStream
            ("orm-xsd.rsrc");
    }

    @Override
    protected String getPackageAttributeName() {
        return null;
    }

    @Override
    protected String getClassAttributeName() {
        return "class";
    }

    @Override
    protected int getClassElementDepth() {
        return 1;
    }

    @Override
    protected boolean isClassElementName(String name) {
        return "entity".equals(name)
            || "embeddable".equals(name)
            || "mapped-superclass".equals(name);
    }

    @Override
    protected void reset() {
        super.reset();
        _elements.clear();
        _parents.clear();
        _cls = null;
        _fieldPos = 0;
        _clsPos = 0;

        _access = ClassMetaData.ACCESS_UNKNOWN;
        _strategy = null;
        _listener = null;
        _callbacks = null;
        _highs = null;
        _cascades = null;
        _pkgCascades = null;
    }

    @Override
    protected boolean startSystemElement(String name, Attributes attrs)
        throws SAXException {
        Object tag = (Object) _elems.get(name);
        boolean ret = false;
        if (tag == null) {
            if (isMappingOverrideMode())
                tag = startSystemMappingElement(name, attrs);
            ret = tag != null;
        } else if (tag instanceof MetaDataTag) {
            switch ((MetaDataTag) tag) {
                case QUERY:
                    ret = startNamedQuery(attrs);
                    break;
                case QUERY_HINT:
                    ret = startQueryHint(attrs);
                    break;
                case NATIVE_QUERY:
                    ret = startNamedNativeQuery(attrs);
                    break;
                case QUERY_STRING:
                    ret = startQueryString(attrs);
                    break;
                case SEQ_GENERATOR:
                    ret = startSequenceGenerator(attrs);
                    break;
                case FLUSH_MODE:
                    ret = startFlushMode(attrs);
                    break;
                case ENTITY_LISTENERS:
                    ret = startEntityListeners(attrs);
                    break;
                case PRE_PERSIST:
                case POST_PERSIST:
                case PRE_REMOVE:
                case POST_REMOVE:
                case PRE_UPDATE:
                case POST_UPDATE:
                case POST_LOAD:
                    ret = startCallback((MetaDataTag) tag, attrs);
                    break;
                default:
                    warnUnsupportedTag(name);
            }
        } else if (tag == ELEM_PU_META || tag == ELEM_PU_DEF)
            ret = isMetaDataMode();
        else if (tag == ELEM_XML_MAP_META_COMPLETE)
            setAnnotationParser(null);
        else if (tag == ELEM_ACCESS)
            ret = _mode != MODE_QUERY;
        else if (tag == ELEM_LISTENER)
            ret = startEntityListener(attrs);
        else if (tag == ELEM_CASCADE)
            ret = isMetaDataMode();
        else if (tag == ELEM_CASCADE_ALL || tag == ELEM_CASCADE_PER
            || tag == ELEM_CASCADE_MER || tag == ELEM_CASCADE_REM
            || tag == ELEM_CASCADE_REF)
            ret = startCascade(tag, attrs);

        if (ret)
            _parents.push(tag);
        return ret;
    }

    @Override
    protected void endSystemElement(String name)
        throws SAXException {
        Object tag = _elems.get(name);
        if (tag == null && isMappingOverrideMode())
            endSystemMappingElement(name);
        else if (tag instanceof MetaDataTag) {
            switch ((MetaDataTag) tag) {
                case QUERY:
                    endNamedQuery();
                    break;
                case QUERY_HINT:
                    endQueryHint();
                    break;
                case NATIVE_QUERY:
                    endNamedNativeQuery();
                    break;
                case QUERY_STRING:
                    endQueryString();
                    break;
                case SEQ_GENERATOR:
                    endSequenceGenerator();
                    break;
            }
        } else if (tag == ELEM_ACCESS)
            endAccess();
        else if (tag == ELEM_LISTENER)
            endEntityListener();

        _parents.pop();
    }

    /**
     * Implement to parse a mapping element outside of any class.
     *
     * @return the tag for the given element, or null to skip the element
     */
    protected Object startSystemMappingElement(String name, Attributes attrs)
        throws SAXException {
        return null;
    }

    /**
     * Implement to parse a mapping element outside of any class.
     */
    protected void endSystemMappingElement(String name)
        throws SAXException {
    }

    @Override
    protected boolean startClassElement(String name, Attributes attrs)
        throws SAXException {
        Object tag = (Object) _elems.get(name);
        boolean ret = false;
        if (tag == null) {
            if (isMappingOverrideMode())
                tag = startClassMappingElement(name, attrs);
            ret = tag != null;
        } else if (tag instanceof MetaDataTag) {
            switch ((MetaDataTag) tag) {
                case GENERATED_VALUE:
                    ret = startGeneratedValue(attrs);
                    break;
                case ID:
                    ret = startId(attrs);
                    break;
                case EMBEDDED_ID:
                    ret = startEmbeddedId(attrs);
                    break;
                case ID_CLASS:
                    ret = startIdClass(attrs);
                    break;
                case LOB:
                    ret = startLob(attrs);
                    break;
                case QUERY:
                    ret = startNamedQuery(attrs);
                    break;
                case QUERY_HINT:
                    ret = startQueryHint(attrs);
                    break;
                case NATIVE_QUERY:
                    ret = startNamedNativeQuery(attrs);
                    break;
                case QUERY_STRING:
                    ret = startQueryString(attrs);
                    break;
                case SEQ_GENERATOR:
                    ret = startSequenceGenerator(attrs);
                    break;
                case VERSION:
                    ret = startVersion(attrs);
                    break;
                case MAP_KEY:
                    ret = startMapKey(attrs);
                    break;
                case FLUSH_MODE:
                    ret = startFlushMode(attrs);
                    break;
                case ORDER_BY:
                case ENTITY_LISTENERS:
                    ret = isMetaDataMode();
                    break;
                case EXCLUDE_DEFAULT_LISTENERS:
                    ret = startExcludeDefaultListeners(attrs);
                    break;
                case EXCLUDE_SUPERCLASS_LISTENERS:
                    ret = startExcludeSuperclassListeners(attrs);
                    break;
                case PRE_PERSIST:
                case POST_PERSIST:
                case PRE_REMOVE:
                case POST_REMOVE:
                case PRE_UPDATE:
                case POST_UPDATE:
                case POST_LOAD:
                    ret = startCallback((MetaDataTag) tag, attrs);
                    break;
                default:
                    warnUnsupportedTag(name);
            }
        } else if (tag instanceof PersistenceStrategy) {
            PersistenceStrategy ps = (PersistenceStrategy) tag;
            ret = startStrategy(ps, attrs);
            if (ret)
                _strategy = ps;
        } else if (tag == ELEM_LISTENER)
            ret = startEntityListener(attrs);
        else if (tag == ELEM_ATTRS)
            ret = _mode != MODE_QUERY;
        else if (tag == ELEM_CASCADE)
            ret = isMetaDataMode();
        else if (tag == ELEM_CASCADE_ALL || tag == ELEM_CASCADE_PER
            || tag == ELEM_CASCADE_MER || tag == ELEM_CASCADE_REM
            || tag == ELEM_CASCADE_REF)
            ret = startCascade(tag, attrs);

        if (ret)
            _parents.push(tag);
        return ret;
    }

    @Override
    protected void endClassElement(String name)
        throws SAXException {
        Object tag = _elems.get(name);
        if (tag == null && isMappingOverrideMode())
            endClassMappingElement(name);
        else if (tag instanceof MetaDataTag) {
            switch ((MetaDataTag) tag) {
                case GENERATED_VALUE:
                    endGeneratedValue();
                    break;
                case ID:
                    endId();
                    break;
                case EMBEDDED_ID:
                    endEmbeddedId();
                    break;
                case ID_CLASS:
                    endIdClass();
                    break;
                case LOB:
                    endLob();
                    break;
                case QUERY:
                    endNamedQuery();
                    break;
                case QUERY_HINT:
                    endQueryHint();
                    break;
                case NATIVE_QUERY:
                    endNamedNativeQuery();
                    break;
                case QUERY_STRING:
                    endQueryString();
                    break;
                case SEQ_GENERATOR:
                    endSequenceGenerator();
                    break;
                case VERSION:
                    endVersion();
                    break;
                case ORDER_BY:
                    endOrderBy();
                    break;
            }
        } else if (tag instanceof PersistenceStrategy)
            endStrategy((PersistenceStrategy) tag);
        else if (tag == ELEM_ACCESS)
            endAccess();
        else if (tag == ELEM_LISTENER)
            endEntityListener();

        _parents.pop();
    }

    /**
     * Log warning about an unsupported tag.
     */
    private void warnUnsupportedTag(String name) {
        Log log = getLog();
        if (log.isInfoEnabled())
            log.trace(_loc.get("unsupported-tag", name));
    }

    /**
     * Implement to parse a mapping element within a class.
     *
     * @return the tag for the given element, or null to skip element
     */
    protected Object startClassMappingElement(String name, Attributes attrs)
        throws SAXException {
        return null;
    }

    /**
     * Implement to parse a mapping element within a class.
     */
    protected void endClassMappingElement(String name)
        throws SAXException {
    }

    @Override
    protected boolean startClass(String elem, Attributes attrs)
        throws SAXException {
        super.startClass(elem, attrs);

        // query mode only?
        _cls = classForName(currentClassName());
        if (_mode == MODE_QUERY) {
            if (_parser != null &&
                !"true".equals(attrs.getValue("metadata-complete")))
                _parser.parse(_cls);
            return true;
        }

        Log log = getLog();
        if (log.isTraceEnabled())
            log.trace(_loc.get("parse-class", _cls.getName()));

        MetaDataRepository repos = getRepository();
        ClassMetaData meta = repos.getCachedMetaData(_cls);
        if (meta != null
            && ((isMetaDataMode() && (meta.getSourceMode() & MODE_META) != 0)
            || (isMappingMode() && (meta.getSourceMode() & MODE_MAPPING) != 0)))
        {
            if (log.isWarnEnabled())
                log.warn(_loc.get("dup-metadata", _cls, getSourceName()));
            _cls = null;
            return false;
        }

        // if we don't know the access type, check to see if a superclass
        // has already defined the access type
        int defaultAccess = _access;
        if (defaultAccess == ClassMetaData.ACCESS_UNKNOWN) {
            ClassMetaData sup = repos.getCachedMetaData(_cls.getSuperclass());
            if (sup != null)
                defaultAccess = sup.getAccessType();
        }

        if (meta == null) {
            // add metadata for this type
            int access = toAccessType(attrs.getValue("access"), defaultAccess);
            meta = repos.addMetaData(_cls, access);
            meta.setEnvClassLoader(_envLoader);
            meta.setSourceMode(MODE_NONE);

            // parse annotations first so XML overrides them
            if (_parser != null &&
                !"true".equals(attrs.getValue("metadata-complete")))
                _parser.parse(_cls);
        }

        boolean mappedSuper = "mapped-superclass".equals(elem);
        if (isMetaDataMode()) {
            meta.setSource(getSourceFile(), meta.SRC_XML);
            meta.setSourceMode(MODE_META, true);
            Locator locator = getLocation().getLocator();
            if (locator != null) {
                meta.setLineNumber(Numbers.valueOf(locator.getLineNumber()));
                meta.setColNumber(Numbers.valueOf(locator.getColumnNumber()));
            }
            meta.setListingIndex(_clsPos);
            String name = attrs.getValue("name");
            if (!StringUtils.isEmpty(name))
                meta.setTypeAlias(name);
            meta.setAbstract(mappedSuper);
            meta.setEmbeddedOnly(mappedSuper || "embeddable".equals(elem));
            if (mappedSuper)
                meta.setIdentityType(meta.ID_UNKNOWN);
        }
        if (isMappingMode())
            meta.setSourceMode(MODE_MAPPING, true);
        if (isMappingOverrideMode())
            startClassMapping(meta, mappedSuper, attrs);
        if (isQueryMode())
            meta.setSourceMode(MODE_QUERY, true);

        _clsPos++;
        _fieldPos = 0;
        addComments(meta);
        pushElement(meta);
        return true;
    }

    @Override
    protected void endClass(String elem)
        throws SAXException {
        if (_mode != MODE_QUERY) {
            ClassMetaData meta = (ClassMetaData) popElement();
            storeCallbacks(meta);
            if (isMappingOverrideMode())
                endClassMapping(meta);
        }
        _cls = null;
        super.endClass(elem);
    }

    /**
     * Implement to add mapping attributes to class.
     */
    protected void startClassMapping(ClassMetaData mapping,
        boolean mappedSuper, Attributes attrs)
        throws SAXException {
    }

    /**
     * Implement to finalize class mapping.
     */
    protected void endClassMapping(ClassMetaData mapping)
        throws SAXException {
    }

    /**
     * Default access element.
     */
    private void endAccess() {
        _access = toAccessType(currentText(), ClassMetaData.ACCESS_UNKNOWN);
    }

    /**
     * Parse the given string as an entity access type, defaulting to given
     * default if string is empty.
     */
    private int toAccessType(String str, int def) {
        if (StringUtils.isEmpty(str))
            return def;
        if ("PROPERTY".equals(str))
            return ClassMetaData.ACCESS_PROPERTY;
        return ClassMetaData.ACCESS_FIELD;
    }

    /**
     * Parse flush-mode element.
     */
    private boolean startFlushMode(Attributes attrs)
        throws SAXException {
        Log log = getLog();
        if (log.isWarnEnabled())
            log.warn(_loc.get("unsupported", "flush-mode", getSourceName()));
        return false;
    }

    /**
     * Parse sequence-generator.
     */
    protected boolean startSequenceGenerator(Attributes attrs) {
        if (!isMappingOverrideMode())
            return false;

        String name = attrs.getValue("name");
        Log log = getLog();
        if (log.isTraceEnabled())
            log.trace(_loc.get("parse-sequence", name));

        SequenceMetaData meta = getRepository().getCachedSequenceMetaData(name);
        if (meta != null && log.isWarnEnabled())
            log.warn(_loc.get("override-sequence", name));

        meta = getRepository().addSequenceMetaData(name);
        String seq = attrs.getValue("sequence-name");
        String val = attrs.getValue("initial-value");
        int initial = val == null ? 1 : Integer.parseInt(val);
        val = attrs.getValue("allocation-size");
        int allocate = val == null ? 50 : Integer.parseInt(val);

        String clsName, props;
        if (seq == null || seq.indexOf('(') == -1) {
            clsName = SequenceMetaData.IMPL_NATIVE;
            props = null;
        } else { // plugin
            clsName = Configurations.getClassName(seq);
            props = Configurations.getProperties(seq);
            seq = null;
        }

        meta.setSequencePlugin(Configurations.getPlugin(clsName, props));
        meta.setSequence(seq);
        meta.setInitialValue(initial);
        meta.setAllocate(allocate);

        Object cur = currentElement();
        Object scope = (cur instanceof ClassMetaData)
            ? ((ClassMetaData) cur).getDescribedType() : null;
        meta.setSource(getSourceFile(), scope, meta.SRC_XML);
        Locator locator = getLocation().getLocator();
        if (locator != null) {
            meta.setLineNumber(Numbers.valueOf(locator.getLineNumber()));
            meta.setColNumber(Numbers.valueOf(locator.getColumnNumber()));
        }
        return true;
    }

    protected void endSequenceGenerator() {
    }

    /**
     * Parse id.
     */
    protected boolean startId(Attributes attrs)
        throws SAXException {
        FieldMetaData fmd = parseField(attrs);
        fmd.setExplicit(true);
        fmd.setPrimaryKey(true);
        return true;
    }

    protected void endId()
        throws SAXException {
        finishField();
    }

    /**
     * Parse embedded-id.
     */
    protected boolean startEmbeddedId(Attributes attrs)
        throws SAXException {
        FieldMetaData fmd = parseField(attrs);
        fmd.setExplicit(true);
        fmd.setPrimaryKey(true);
        fmd.setEmbedded(true);
        if (fmd.getEmbeddedMetaData() == null)
            fmd.addEmbeddedMetaData();
        return true;
    }

    protected void endEmbeddedId()
        throws SAXException {
        finishField();
    }

    /**
     * Parse id-class.
     */
    protected boolean startIdClass(Attributes attrs)
        throws SAXException {
        if (!isMetaDataMode())
            return false;

        ClassMetaData meta = (ClassMetaData) currentElement();
        String cls = attrs.getValue("class");
        Class idCls = null;
        try {
            idCls = classForName(cls);
        } catch (Throwable t) {
            throw getException(_loc.get("invalid-id-class", meta, cls), t);
        }
        meta.setObjectIdType(idCls, true);
        return true;
    }

    protected void endIdClass()
        throws SAXException {
    }

    /**
     * Parse lob.
     */
    protected boolean startLob(Attributes attrs)
        throws SAXException {
        FieldMetaData fmd = (FieldMetaData) currentElement();
        if (fmd.getDeclaredTypeCode() != JavaTypes.STRING
            && fmd.getDeclaredType() != char[].class
            && fmd.getDeclaredType() != Character[].class
            && fmd.getDeclaredType() != byte[].class
            && fmd.getDeclaredType() != Byte[].class)
            fmd.setSerialized(true);
        return true;
    }

    protected void endLob()
        throws SAXException {
    }

    /**
     * Parse generated-value.
     */
    protected boolean startGeneratedValue(Attributes attrs)
        throws SAXException {
        if (!isMappingOverrideMode())
            return false;

        String strategy = attrs.getValue("strategy");
        String generator = attrs.getValue("generator");
        GenerationType type = StringUtils.isEmpty(strategy)
            ? GenerationType.AUTO : GenerationType.valueOf(strategy);

        FieldMetaData fmd = (FieldMetaData) currentElement();
        AnnotationPersistenceMetaDataParser.parseGeneratedValue(fmd, type,
            generator);
        return true;
    }

    protected void endGeneratedValue()
        throws SAXException {
    }

    /**
     * Lazily parse cascades.
     */
    protected boolean startCascade(Object tag, Attributes attrs)
        throws SAXException {
        if (!isMetaDataMode())
            return false;

        Set<CascadeType> cascades = null;
        if (currentElement() instanceof FieldMetaData) {
            if (_cascades == null)
                _cascades = EnumSet.noneOf(CascadeType.class);
            cascades = _cascades;
        } else {
            if (_pkgCascades == null)
                _pkgCascades = EnumSet.noneOf(CascadeType.class);
            cascades = _pkgCascades;
        }
        boolean all = ELEM_CASCADE_ALL == tag;
        if (all || ELEM_CASCADE_PER == tag)
            cascades.add(PERSIST);
        if (all || ELEM_CASCADE_REM == tag)
            cascades.add(REMOVE);
        if (all || ELEM_CASCADE_MER == tag)
            cascades.add(MERGE);
        if (all || ELEM_CASCADE_REF == tag)
            cascades.add(REFRESH);
        return true;
    }

    /**
     * Set the cached cascades into the field.
     */
    protected void setCascades(FieldMetaData fmd) {
        Set<CascadeType> cascades = _cascades;
        if (_cascades == null)
            cascades = _pkgCascades;
        if (cascades == null)
            return;

        ValueMetaData vmd = fmd;
        switch (_strategy) {
            case ONE_MANY:
            case MANY_MANY:
                vmd = fmd.getElement();
        }
        for (CascadeType cascade : cascades) {
            switch (cascade) {
                case PERSIST:
                    vmd.setCascadePersist(ValueMetaData.CASCADE_IMMEDIATE);
                    break;
                case MERGE:
                    vmd.setCascadeAttach(ValueMetaData.CASCADE_IMMEDIATE);
                    break;
                case REMOVE:
                    vmd.setCascadeDelete(ValueMetaData.CASCADE_IMMEDIATE);
                    break;
                case REFRESH:
                    vmd.setCascadeRefresh(ValueMetaData.CASCADE_IMMEDIATE);
                    break;
            }
        }
        _cascades = null;
    }

    /**
     * Parse common field attributes.
     */
    private FieldMetaData parseField(Attributes attrs)
        throws SAXException {
        ClassMetaData meta = (ClassMetaData) currentElement();
        String name = attrs.getValue("name");
        FieldMetaData field = meta.getDeclaredField(name);
        if ((field == null || field.getDeclaredType() == Object.class)
            && meta.getDescribedType() != Object.class) {
            Member member = null;
            Class type = null;
            int def = _repos.getMetaDataFactory().getDefaults().
                getDefaultAccessType();
            try {
                if (meta.getAccessType() == ClassMetaData.ACCESS_PROPERTY
                    || (meta.getAccessType() == ClassMetaData.ACCESS_UNKNOWN
                    && def == ClassMetaData.ACCESS_PROPERTY)) {
                    String cap = StringUtils.capitalize(name);
                    type = meta.getDescribedType();
                    try {
                        member = (Method) AccessController.doPrivileged(
                            J2DoPrivHelper.getDeclaredMethodAction(
                                type, "get" + cap,
                                (Class[]) null));// varargs disambiguate
                    } catch (Exception excep) {
                        try {
                            member = (Method) AccessController.doPrivileged(
                                J2DoPrivHelper.getDeclaredMethodAction(
                                    type, "is" + cap, (Class[]) null));
                        } catch (Exception excep2) {
                            throw excep;
                        }
                    }
                    type = ((Method) member).getReturnType();
                } else {
                    member = (Field) AccessController.doPrivileged(
                        J2DoPrivHelper.getDeclaredFieldAction(
                            meta.getDescribedType(), name));
                    type = ((Field) member).getType();
                }
            } catch (Exception e) {
                if (e instanceof PrivilegedActionException)
                    e = ((PrivilegedActionException) e).getException();
                throw getException(_loc.get("invalid-attr", name, meta), e);
            }

            if (field == null) {
                field = meta.addDeclaredField(name, type);
                PersistenceMetaDataDefaults.setCascadeNone(field);
                PersistenceMetaDataDefaults.setCascadeNone(field.getKey());
                PersistenceMetaDataDefaults.setCascadeNone(field.getElement());
            }
            field.backingMember(member);
        } else if (field == null) {
            field = meta.addDeclaredField(name, Object.class);
            PersistenceMetaDataDefaults.setCascadeNone(field);
            PersistenceMetaDataDefaults.setCascadeNone(field.getKey());
            PersistenceMetaDataDefaults.setCascadeNone(field.getElement());
        }

        if (isMetaDataMode())
            field.setListingIndex(_fieldPos);

        _fieldPos++;
        pushElement(field);
        addComments(field);

        if (isMappingOverrideMode())
            startFieldMapping(field, attrs);
        return field;
    }

    /**
     * Pops field element.
     */
    private void finishField()
        throws SAXException {
        FieldMetaData field = (FieldMetaData) popElement();
        setCascades(field);
        if (isMappingOverrideMode())
            endFieldMapping(field);
        _strategy = null;
    }

    /**
     * Implement to add field mapping data. Does nothing by default.
     */
    protected void startFieldMapping(FieldMetaData field, Attributes attrs)
        throws SAXException {
    }

    /**
     * Implement to finalize field mapping. Does nothing by default.
     */
    protected void endFieldMapping(FieldMetaData field)
        throws SAXException {
    }

    /**
     * Parse version.
     */
    protected boolean startVersion(Attributes attrs)
        throws SAXException {
        FieldMetaData fmd = parseField(attrs);
        fmd.setExplicit(true);
        fmd.setVersion(true);
        return true;
    }

    protected void endVersion()
        throws SAXException {
        finishField();
    }

    /**
     * Parse strategy element.
     */
    private boolean startStrategy(PersistenceStrategy strategy,
        Attributes attrs)
        throws SAXException {
        FieldMetaData fmd = parseField(attrs);
        fmd.setExplicit(true);
        fmd.setManagement(FieldMetaData.MANAGE_PERSISTENT);

        String val = attrs.getValue("fetch");
        if (val != null)
            fmd.setInDefaultFetchGroup("EAGER".equals(val));
        val = attrs.getValue("optional");
        if ("false".equals(val))
            fmd.setNullValue(FieldMetaData.NULL_EXCEPTION);
        else if ("true".equals(val)
                && fmd.getNullValue() == FieldMetaData.NULL_EXCEPTION) {
            // Reset value if the field was annotated with optional=false.
            // Otherwise leave it alone.
            fmd.setNullValue(FieldMetaData.NULL_UNSET);
        }
        if (isMappingOverrideMode()) {
            val = attrs.getValue("mapped-by");
            if (val != null)
                fmd.setMappedBy(val);
        }
        parseStrategy(fmd, strategy, attrs);
        return true;
    }

    private void endStrategy(PersistenceStrategy strategy)
        throws SAXException {
        finishField();
    }

    /**
     * Parse strategy specific attributes.
     */
    private void parseStrategy(FieldMetaData fmd,
        PersistenceStrategy strategy, Attributes attrs)
        throws SAXException {
        switch (strategy) {
            case BASIC:
                parseBasic(fmd, attrs);
                break;
            case EMBEDDED:
                parseEmbedded(fmd, attrs);
                break;
            case ONE_ONE:
                parseOneToOne(fmd, attrs);
                break;
            case MANY_ONE:
                parseManyToOne(fmd, attrs);
                break;
            case MANY_MANY:
                parseManyToMany(fmd, attrs);
                break;
            case ONE_MANY:
                parseOneToMany(fmd, attrs);
                break;
            case TRANSIENT:
                fmd.setManagement(FieldMetaData.MANAGE_NONE);
                break;
        }
    }

    /**
     * Parse basic.
     */
    protected void parseBasic(FieldMetaData fmd, Attributes attrs)
        throws SAXException {
    }

    /**
     * Parse embedded.
     */
    protected void parseEmbedded(FieldMetaData fmd, Attributes attrs)
        throws SAXException {
        assertPC(fmd, "Embedded");
        fmd.setEmbedded(true);
        fmd.setSerialized(false); // override any Lob annotation
        if (fmd.getEmbeddedMetaData() == null)
            fmd.addEmbeddedMetaData();
    }

    /**
     * Throw proper exception if given value is not possibly persistence
     * capable.
     */
    private void assertPC(FieldMetaData fmd, String attr)
        throws SAXException {
        if (!JavaTypes.maybePC(fmd))
            throw getException(_loc.get("bad-meta-anno", fmd, attr));
    }

    /**
     * Parse one-to-one.
     */
    protected void parseOneToOne(FieldMetaData fmd, Attributes attrs)
        throws SAXException {
        String val = attrs.getValue("target-entity");
        if (val != null)
            fmd.setTypeOverride(classForName(val));
        assertPC(fmd, "OneToOne");
        fmd.setSerialized(false); // override any Lob annotation
        if (!fmd.isDefaultFetchGroupExplicit())
            fmd.setInDefaultFetchGroup(true);
    }

    /**
     * Parse many-to-one.
     */
    protected void parseManyToOne(FieldMetaData fmd, Attributes attrs)
        throws SAXException {
        String val = attrs.getValue("target-entity");
        if (val != null)
            fmd.setTypeOverride(classForName(val));
        assertPC(fmd, "ManyToOne");
        fmd.setSerialized(false); // override any Lob annotation
        if (!fmd.isDefaultFetchGroupExplicit())
            fmd.setInDefaultFetchGroup(true);
    }

    /**
     * Parse many-to-many.
     */
    protected void parseManyToMany(FieldMetaData fmd, Attributes attrs)
        throws SAXException {
        String val = attrs.getValue("target-entity");
        if (val != null)
            fmd.getElement().setDeclaredType(classForName(val));
        assertPCCollection(fmd, "ManyToMany");
        fmd.setSerialized(false); // override Lob in annotation
    }

    /**
     * Throw exception if given field not a collection of possible persistence
     * capables.
     */
    private void assertPCCollection(FieldMetaData fmd, String attr)
        throws SAXException {
        switch (fmd.getDeclaredTypeCode()) {
            case JavaTypes.ARRAY:
            case JavaTypes.COLLECTION:
            case JavaTypes.MAP:
                if (JavaTypes.maybePC(fmd.getElement()))
                    break;
                // no break
            default:
                throw getException(_loc.get("bad-meta-anno", fmd, attr));
        }
    }

    /**
     * Parse one-to-many.
     */
    protected void parseOneToMany(FieldMetaData fmd, Attributes attrs)
        throws SAXException {
        String val = attrs.getValue("target-entity");
        if (val != null)
            fmd.getElement().setDeclaredType(classForName(val));
        assertPCCollection(fmd, "OneToMany");
        fmd.setSerialized(false); // override any Lob annotation
    }

    /**
     * Parse map-key.
     */
    private boolean startMapKey(Attributes attrs)
        throws SAXException {
        if (!isMappingOverrideMode())
            return false;

        FieldMetaData fmd = (FieldMetaData) currentElement();
        String mapKey = attrs.getValue("name");
        if (mapKey == null)
            fmd.getKey().setValueMappedBy(ValueMetaData.MAPPED_BY_PK);
        else
            fmd.getKey().setValueMappedBy(mapKey);
        return true;
    }

    /**
     * Parse order-by.
     */
    private void endOrderBy()
        throws SAXException {
        FieldMetaData fmd = (FieldMetaData) currentElement();
        String dec = currentText();
        if (StringUtils.isEmpty(dec))
            dec = Order.ELEMENT + " asc";
        fmd.setOrderDeclaration(dec);
    }

    /**
     * Parse named-query.
     */
    protected boolean startNamedQuery(Attributes attrs)
        throws SAXException {
        if (!isQueryMode())
            return false;

        String name = attrs.getValue("name");
        Log log = getLog();
        if (log.isTraceEnabled())
            log.trace(_loc.get("parse-query", name));

        QueryMetaData meta = getRepository().getCachedQueryMetaData(null, name);
        if (meta != null && log.isWarnEnabled())
            log.warn(_loc.get("override-query", name, currentLocation()));

        meta = getRepository().addQueryMetaData(null, name);
        meta.setDefiningType(_cls);
        meta.setQueryString(attrs.getValue("query"));
        meta.setLanguage(JPQLParser.LANG_JPQL);
        Locator locator = getLocation().getLocator();
        if (locator != null) {
            meta.setLineNumber(Numbers.valueOf(locator.getLineNumber()));
            meta.setColNumber(Numbers.valueOf(locator.getColumnNumber()));
        }
        Object cur = currentElement();
        Object scope = (cur instanceof ClassMetaData)
            ? ((ClassMetaData) cur).getDescribedType() : null;
        meta.setSource(getSourceFile(), scope, meta.SRC_XML);
        if (isMetaDataMode())
            meta.setSourceMode(MODE_META);
        else if (isMappingMode())
            meta.setSourceMode(MODE_MAPPING);
        else
            meta.setSourceMode(MODE_QUERY);
        pushElement(meta);
        return true;
    }

    protected void endNamedQuery()
        throws SAXException {
        popElement();
    }

    protected boolean startQueryString(Attributes attrs)
        throws SAXException {
        return true;
    }

    protected void endQueryString()
        throws SAXException {
        QueryMetaData meta = (QueryMetaData) currentElement();
        meta.setQueryString(currentText());
    }

    /**
     * Parse query-hint.
     */
    protected boolean startQueryHint(Attributes attrs)
        throws SAXException {
        QueryMetaData meta = (QueryMetaData) currentElement();
        meta.addHint(attrs.getValue("name"), attrs.getValue("value"));
        return true;
    }

    protected void endQueryHint()
        throws SAXException {
    }

    /**
     * Parse native-named-query.
     */
    protected boolean startNamedNativeQuery(Attributes attrs)
        throws SAXException {
        if (!isQueryMode())
            return false;

        String name = attrs.getValue("name");
        Log log = getLog();
        if (log.isTraceEnabled())
            log.trace(_loc.get("parse-native-query", name));

        QueryMetaData meta = getRepository().getCachedQueryMetaData(null, name);
        if (meta != null && log.isWarnEnabled())
            log.warn(_loc.get("override-query", name, currentLocation()));

        meta = getRepository().addQueryMetaData(null, name);
        meta.setDefiningType(_cls);
        meta.setQueryString(attrs.getValue("query"));
        meta.setLanguage(QueryLanguages.LANG_SQL);
        String val = attrs.getValue("result-class");
        if (val != null) {
            Class type = classForName(val);
            if (ImplHelper.isManagedType(getConfiguration(), type))
                meta.setCandidateType(type);
            else
                meta.setResultType(type);
        }

        val = attrs.getValue("result-set-mapping");
        if (val != null)
            meta.setResultSetMappingName(val);

        Object cur = currentElement();
        Object scope = (cur instanceof ClassMetaData)
            ? ((ClassMetaData) cur).getDescribedType() : null;
        meta.setSource(getSourceFile(), scope, meta.SRC_XML);
        Locator locator = getLocation().getLocator();
        if (locator != null) {
            meta.setLineNumber(Numbers.valueOf(locator.getLineNumber()));
            meta.setColNumber(Numbers.valueOf(locator.getColumnNumber()));
        }
        if (isMetaDataMode())
            meta.setSourceMode(MODE_META);
        else if (isMappingMode())
            meta.setSourceMode(MODE_MAPPING);
        else
            meta.setSourceMode(MODE_QUERY);
        pushElement(meta);
        return true;
    }

    protected void endNamedNativeQuery()
        throws SAXException {
        popElement();
    }

    /**
     * Start entity-listeners
     */
    private boolean startEntityListeners(Attributes attrs)
        throws SAXException {
        if (!isMetaDataMode())
            return false;
        if (currentElement() == null)
            return true;

        // reset listeners declared in annotations.
        LifecycleMetaData meta = ((ClassMetaData) currentElement()).
            getLifecycleMetaData();
        for (int i = 0; i < LifecycleEvent.ALL_EVENTS.length; i++)
            meta.setDeclaredCallbacks(i, null, 0);
        return true;
    }

    /**
     * Parse exclude-default-listeners.
     */
    private boolean startExcludeDefaultListeners(Attributes attrs)
        throws SAXException {
        if (!isMetaDataMode())
            return false;
        ClassMetaData meta = (ClassMetaData) currentElement();
        meta.getLifecycleMetaData().setIgnoreSystemListeners(true);
        return true;
    }

    /**
     * Parse exclude-superclass-listeners.
     */
    private boolean startExcludeSuperclassListeners(Attributes attrs)
        throws SAXException {
        if (!isMetaDataMode())
            return false;
        ClassMetaData meta = (ClassMetaData) currentElement();
        meta.getLifecycleMetaData().setIgnoreSuperclassCallbacks
            (LifecycleMetaData.IGNORE_HIGH);
        return true;
    }

    /**
     * Parse entity-listener.
     */
    private boolean startEntityListener(Attributes attrs)
        throws SAXException {
        _listener = classForName(attrs.getValue("class"));
        boolean system = currentElement() == null;
        Collection<LifecycleCallbacks>[] parsed =
            AnnotationPersistenceMetaDataParser.parseCallbackMethods(_listener,
                null, true, true, _repos);
        if (parsed == null)
            return true;

        if (_callbacks == null) {
            _callbacks = (Collection<LifecycleCallbacks>[])
                new Collection[LifecycleEvent.ALL_EVENTS.length];
            if (!system)
                _highs = new int[LifecycleEvent.ALL_EVENTS.length];
        }
        for (int i = 0; i < parsed.length; i++) {
            if (parsed[i] == null)
                continue;
            if (_callbacks[i] == null)
                _callbacks[i] = parsed[i];
            else
                _callbacks[i].addAll(parsed[i]);
            if (!system)
                _highs[i] += parsed[i].size();
        }
        return true;
    }

    private void endEntityListener()
        throws SAXException {
        // should be in endEntityListeners I think to merge callbacks
        // into a single listener.  But then the user cannot remove.
        if (currentElement() == null && _callbacks != null) {
            _repos.addSystemListener(new PersistenceListenerAdapter
                (_callbacks));
            _callbacks = null;
        }
        _listener = null;
    }

    private boolean startCallback(MetaDataTag callback, Attributes attrs)
        throws SAXException {
        if (!isMetaDataMode())
            return false;
        int[] events = MetaDataParsers.getEventTypes(callback);
        if (events == null)
            return false;

        boolean system = currentElement() == null;
        Class type = currentElement() == null ? null :
            ((ClassMetaData) currentElement()).getDescribedType();
        if (type == null)
            type = Object.class;

        if (_callbacks == null) {
            _callbacks = (Collection<LifecycleCallbacks>[])
                new Collection[LifecycleEvent.ALL_EVENTS.length];
            if (!system)
                _highs = new int[LifecycleEvent.ALL_EVENTS.length];
        }

        MetaDataDefaults def = _repos.getMetaDataFactory().getDefaults();
        LifecycleCallbacks adapter;
        if (_listener != null)
            adapter = new BeanLifecycleCallbacks(_listener,
                attrs.getValue("method-name"), false, type);
        else
            adapter = new MethodLifecycleCallbacks(_cls,
                attrs.getValue("method-name"), false);

        for (int i = 0; i < events.length; i++) {
            int event = events[i];
            if (_listener != null) {
                MetaDataParsers.validateMethodsForSameCallback(_listener,
                    _callbacks[event], ((BeanLifecycleCallbacks) adapter).
                    getCallbackMethod(), callback, def, getLog());
            } else {
                MetaDataParsers.validateMethodsForSameCallback(_cls,
                    _callbacks[event], ((MethodLifecycleCallbacks) adapter).
                    getCallbackMethod(), callback, def, getLog());

            }
            if (_callbacks[event] == null)
                _callbacks[event] = new ArrayList<LifecycleCallbacks>(3);
            _callbacks[event].add(adapter);
            if (!system && _listener != null)
                _highs[event]++;
        }
        return true;
    }

    /**
     * Store lifecycle metadata.
     */
    private void storeCallbacks(ClassMetaData cls) {
        LifecycleMetaData meta = cls.getLifecycleMetaData();
        Class supCls = cls.getDescribedType().getSuperclass();
        Collection<LifecycleCallbacks>[] supCalls = null;
        if (!Object.class.equals(supCls)) {
            supCalls = AnnotationPersistenceMetaDataParser.parseCallbackMethods
                (supCls, null, true, false, _repos);
        }
        if (supCalls != null) {
            for (int event : LifecycleEvent.ALL_EVENTS) {
                if (supCalls[event] == null)
                    continue;
                meta.setNonPCSuperclassCallbacks(event, supCalls[event].toArray
                    (new LifecycleCallbacks[supCalls[event].size()]), 0);
            }
        }
        if (_callbacks == null)
            return;

        for (int event : LifecycleEvent.ALL_EVENTS) {
            if (_callbacks[event] == null)
                continue;
            meta.setDeclaredCallbacks(event, (LifecycleCallbacks[])
                _callbacks[event].toArray
                    (new LifecycleCallbacks[_callbacks[event].size()]),
                _highs[event]);
        }
        _callbacks = null;
        _highs = null;
    }

    /**
     * Instantiate the given class, taking into account the default package.
   */
  protected Class classForName(String name)
    throws SAXException {
    if ("Entity".equals(name))
      return PersistenceCapable.class;
    return super.classForName(name, isRuntime());
  }
}
TOP

Related Classes of org.apache.openjpa.persistence.XMLPersistenceMetaDataParser

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.