org.hibernate.cfg.annotations.reflection.XMLContext.java Source code

Java tutorial

Introduction

Here is the source code for org.hibernate.cfg.annotations.reflection.XMLContext.java

Source

/*
 * Hibernate, Relational Persistence for Idiomatic Java
 *
 * License: GNU Lesser General Public License (LGPL), version 2.1 or later.
 * See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
 */
package org.hibernate.cfg.annotations.reflection;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.persistence.AccessType;
import javax.persistence.AttributeConverter;

import org.hibernate.AnnotationException;
import org.hibernate.cfg.AttributeConverterDefinition;
import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.ReflectHelper;
import org.hibernate.internal.util.StringHelper;

import org.dom4j.Document;
import org.dom4j.Element;

/**
 * A helper for consuming orm.xml mappings.
 *
 * @author Emmanuel Bernard
 * @author Brett Meyer
 */
public class XMLContext implements Serializable {
    private static final CoreMessageLogger LOG = CoreLogging.messageLogger(XMLContext.class);

    private Default globalDefaults;
    private Map<String, Element> classOverriding = new HashMap<String, Element>();
    private Map<String, Default> defaultsOverriding = new HashMap<String, Default>();
    private List<Element> defaultElements = new ArrayList<Element>();
    private List<String> defaultEntityListeners = new ArrayList<String>();
    private boolean hasContext = false;

    /**
     * @param doc The xml document to add
     * @return Add a xml document to this context and return the list of added class names.
     */
    @SuppressWarnings("unchecked")
    public List<String> addDocument(Document doc) {
        hasContext = true;
        List<String> addedClasses = new ArrayList<String>();
        Element root = doc.getRootElement();
        //global defaults
        Element metadata = root.element("persistence-unit-metadata");
        if (metadata != null) {
            if (globalDefaults == null) {
                globalDefaults = new Default();
                globalDefaults.setMetadataComplete(
                        metadata.element("xml-mapping-metadata-complete") != null ? Boolean.TRUE : null);
                Element defaultElement = metadata.element("persistence-unit-defaults");
                if (defaultElement != null) {
                    Element unitElement = defaultElement.element("schema");
                    globalDefaults.setSchema(unitElement != null ? unitElement.getTextTrim() : null);
                    unitElement = defaultElement.element("catalog");
                    globalDefaults.setCatalog(unitElement != null ? unitElement.getTextTrim() : null);
                    unitElement = defaultElement.element("access");
                    setAccess(unitElement, globalDefaults);
                    unitElement = defaultElement.element("cascade-persist");
                    globalDefaults.setCascadePersist(unitElement != null ? Boolean.TRUE : null);
                    unitElement = defaultElement.element("delimited-identifiers");
                    globalDefaults.setDelimitedIdentifiers(unitElement != null ? Boolean.TRUE : null);
                    defaultEntityListeners.addAll(addEntityListenerClasses(defaultElement, null, addedClasses));
                }
            } else {
                LOG.duplicateMetadata();
            }
        }

        //entity mapping default
        Default entityMappingDefault = new Default();
        Element unitElement = root.element("package");
        String packageName = unitElement != null ? unitElement.getTextTrim() : null;
        entityMappingDefault.setPackageName(packageName);
        unitElement = root.element("schema");
        entityMappingDefault.setSchema(unitElement != null ? unitElement.getTextTrim() : null);
        unitElement = root.element("catalog");
        entityMappingDefault.setCatalog(unitElement != null ? unitElement.getTextTrim() : null);
        unitElement = root.element("access");
        setAccess(unitElement, entityMappingDefault);
        defaultElements.add(root);

        setLocalAttributeConverterDefinitions(root.elements("converter"));

        List<Element> entities = root.elements("entity");
        addClass(entities, packageName, entityMappingDefault, addedClasses);

        entities = root.elements("mapped-superclass");
        addClass(entities, packageName, entityMappingDefault, addedClasses);

        entities = root.elements("embeddable");
        addClass(entities, packageName, entityMappingDefault, addedClasses);
        return addedClasses;
    }

    private void setAccess(Element unitElement, Default defaultType) {
        if (unitElement != null) {
            String access = unitElement.getTextTrim();
            setAccess(access, defaultType);
        }
    }

    private void setAccess(String access, Default defaultType) {
        AccessType type;
        if (access != null) {
            try {
                type = AccessType.valueOf(access);
            } catch (IllegalArgumentException e) {
                throw new AnnotationException("Invalid access type " + access + " (check your xml configuration)");
            }
            defaultType.setAccess(type);
        }
    }

    private void addClass(List<Element> entities, String packageName, Default defaults, List<String> addedClasses) {
        for (Element element : entities) {
            String className = buildSafeClassName(element.attributeValue("class"), packageName);
            if (classOverriding.containsKey(className)) {
                //maybe switch it to warn?
                throw new IllegalStateException("Duplicate XML entry for " + className);
            }
            addedClasses.add(className);
            classOverriding.put(className, element);
            Default localDefault = new Default();
            localDefault.override(defaults);
            String metadataCompleteString = element.attributeValue("metadata-complete");
            if (metadataCompleteString != null) {
                localDefault.setMetadataComplete(Boolean.parseBoolean(metadataCompleteString));
            }
            String access = element.attributeValue("access");
            setAccess(access, localDefault);
            defaultsOverriding.put(className, localDefault);

            LOG.debugf("Adding XML overriding information for %s", className);
            addEntityListenerClasses(element, packageName, addedClasses);
        }
    }

    private List<String> addEntityListenerClasses(Element element, String packageName, List<String> addedClasses) {
        List<String> localAddedClasses = new ArrayList<String>();
        Element listeners = element.element("entity-listeners");
        if (listeners != null) {
            @SuppressWarnings("unchecked")
            List<Element> elements = listeners.elements("entity-listener");
            for (Element listener : elements) {
                String listenerClassName = buildSafeClassName(listener.attributeValue("class"), packageName);
                if (classOverriding.containsKey(listenerClassName)) {
                    //maybe switch it to warn?
                    if ("entity-listener".equals(classOverriding.get(listenerClassName).getName())) {
                        LOG.duplicateListener(listenerClassName);
                        continue;
                    }
                    throw new IllegalStateException("Duplicate XML entry for " + listenerClassName);
                }
                localAddedClasses.add(listenerClassName);
                classOverriding.put(listenerClassName, listener);
            }
        }
        LOG.debugf("Adding XML overriding information for listeners: %s", localAddedClasses);
        addedClasses.addAll(localAddedClasses);
        return localAddedClasses;
    }

    @SuppressWarnings("unchecked")
    private void setLocalAttributeConverterDefinitions(List<Element> converterElements) {
        for (Element converterElement : converterElements) {
            final String className = converterElement.attributeValue("class");
            final String autoApplyAttribute = converterElement.attributeValue("auto-apply");
            final boolean autoApply = autoApplyAttribute != null && Boolean.parseBoolean(autoApplyAttribute);

            try {
                final Class<? extends AttributeConverter> attributeConverterClass = ReflectHelper
                        .classForName(className);
                attributeConverterDefinitions
                        .add(new AttributeConverterDefinition(attributeConverterClass.newInstance(), autoApply));
            } catch (ClassNotFoundException e) {
                throw new AnnotationException(
                        "Unable to locate specified AttributeConverter implementation class : " + className, e);
            } catch (Exception e) {
                throw new AnnotationException(
                        "Unable to instantiate specified AttributeConverter implementation class : " + className,
                        e);
            }
        }
    }

    public static String buildSafeClassName(String className, String defaultPackageName) {
        if (className.indexOf('.') < 0 && StringHelper.isNotEmpty(defaultPackageName)) {
            className = StringHelper.qualify(defaultPackageName, className);
        }
        return className;
    }

    public static String buildSafeClassName(String className, XMLContext.Default defaults) {
        return buildSafeClassName(className, defaults.getPackageName());
    }

    public Default getDefault(String className) {
        Default xmlDefault = new Default();
        xmlDefault.override(globalDefaults);
        if (className != null) {
            Default entityMappingOverriding = defaultsOverriding.get(className);
            xmlDefault.override(entityMappingOverriding);
        }
        return xmlDefault;
    }

    public Element getXMLTree(String className) {
        return classOverriding.get(className);
    }

    public List<Element> getAllDocuments() {
        return defaultElements;
    }

    public boolean hasContext() {
        return hasContext;
    }

    private List<AttributeConverterDefinition> attributeConverterDefinitions = new ArrayList<AttributeConverterDefinition>();

    public void applyDiscoveredAttributeConverters(AttributeConverterDefinitionCollector collector) {
        for (AttributeConverterDefinition definition : attributeConverterDefinitions) {
            collector.addAttributeConverter(definition);
        }
        attributeConverterDefinitions.clear();
    }

    public static class Default implements Serializable {
        private AccessType access;
        private String packageName;
        private String schema;
        private String catalog;
        private Boolean metadataComplete;
        private Boolean cascadePersist;
        private Boolean delimitedIdentifier;

        public AccessType getAccess() {
            return access;
        }

        protected void setAccess(AccessType access) {
            this.access = access;
        }

        public String getCatalog() {
            return catalog;
        }

        protected void setCatalog(String catalog) {
            this.catalog = catalog;
        }

        public String getPackageName() {
            return packageName;
        }

        protected void setPackageName(String packageName) {
            this.packageName = packageName;
        }

        public String getSchema() {
            return schema;
        }

        protected void setSchema(String schema) {
            this.schema = schema;
        }

        public Boolean getMetadataComplete() {
            return metadataComplete;
        }

        public boolean canUseJavaAnnotations() {
            return metadataComplete == null || !metadataComplete;
        }

        protected void setMetadataComplete(Boolean metadataComplete) {
            this.metadataComplete = metadataComplete;
        }

        public Boolean getCascadePersist() {
            return cascadePersist;
        }

        void setCascadePersist(Boolean cascadePersist) {
            this.cascadePersist = cascadePersist;
        }

        public void override(Default globalDefault) {
            if (globalDefault != null) {
                if (globalDefault.getAccess() != null)
                    access = globalDefault.getAccess();
                if (globalDefault.getPackageName() != null)
                    packageName = globalDefault.getPackageName();
                if (globalDefault.getSchema() != null)
                    schema = globalDefault.getSchema();
                if (globalDefault.getCatalog() != null)
                    catalog = globalDefault.getCatalog();
                if (globalDefault.getDelimitedIdentifier() != null)
                    delimitedIdentifier = globalDefault.getDelimitedIdentifier();
                if (globalDefault.getMetadataComplete() != null) {
                    metadataComplete = globalDefault.getMetadataComplete();
                }
                //TODO fix that in stone if cascade-persist is set already?
                if (globalDefault.getCascadePersist() != null)
                    cascadePersist = globalDefault.getCascadePersist();
            }
        }

        public void setDelimitedIdentifiers(Boolean delimitedIdentifier) {
            this.delimitedIdentifier = delimitedIdentifier;
        }

        public Boolean getDelimitedIdentifier() {
            return delimitedIdentifier;
        }
    }

    public List<String> getDefaultEntityListeners() {
        return defaultEntityListeners;
    }
}