org.hibernate.cfg.Configuration.java Source code

Java tutorial

Introduction

Here is the source code for org.hibernate.cfg.Configuration.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;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import javax.persistence.AttributeConverter;
import javax.persistence.SharedCacheMode;

import org.hibernate.EmptyInterceptor;
import org.hibernate.HibernateException;
import org.hibernate.Interceptor;
import org.hibernate.MappingException;
import org.hibernate.SessionFactory;
import org.hibernate.SessionFactoryObserver;
import org.hibernate.boot.Metadata;
import org.hibernate.boot.MetadataBuilder;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.SessionFactoryBuilder;
import org.hibernate.boot.model.TypeContributor;
import org.hibernate.boot.model.naming.ImplicitNamingStrategy;
import org.hibernate.boot.model.naming.ImplicitNamingStrategyJpaCompliantImpl;
import org.hibernate.boot.model.naming.PhysicalNamingStrategy;
import org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl;
import org.hibernate.boot.model.relational.AuxiliaryDatabaseObject;
import org.hibernate.boot.registry.BootstrapServiceRegistry;
import org.hibernate.boot.registry.BootstrapServiceRegistryBuilder;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.annotations.NamedEntityGraphDefinition;
import org.hibernate.cfg.annotations.NamedProcedureCallDefinition;
import org.hibernate.context.spi.CurrentTenantIdentifierResolver;
import org.hibernate.dialect.function.SQLFunction;
import org.hibernate.engine.ResultSetMappingDefinition;
import org.hibernate.engine.spi.NamedQueryDefinition;
import org.hibernate.engine.spi.NamedSQLQueryDefinition;
import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.xml.XmlDocument;
import org.hibernate.proxy.EntityNotFoundDelegate;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.tuple.entity.EntityTuplizerFactory;
import org.hibernate.type.BasicType;
import org.hibernate.type.CompositeCustomType;
import org.hibernate.type.CustomType;
import org.hibernate.type.SerializationException;
import org.hibernate.usertype.CompositeUserType;
import org.hibernate.usertype.UserType;

/**
 * Represents one approach for bootstrapping Hibernate.  In fact, historically this was
 * <b>the</b> way to bootstrap Hibernate.
 * <p/>
 * The approach here is to define all configuration and mapping sources in one API
 * and to then build the {@link org.hibernate.SessionFactory} in one-shot.  The configuration
 * and mapping sources defined here are just held here until the SessionFactory is built.  This
 * is an important distinction from the legacy behavior of this class, where we would try to
 * incrementally build the mappings from sources as they were added.  The ramification of this
 * change in behavior is that users can add configuration and mapping sources here, but they can
 * no longer query the in-flight state of mappings ({@link org.hibernate.mapping.PersistentClass},
 * {@link org.hibernate.mapping.Collection}, etc) here.
 * <p/>
 * Note: Internally this class uses the new bootstrapping approach when asked to build the
 * SessionFactory.
 *
 * @author Gavin King
 * @author Steve Ebersole
 *
 * @see org.hibernate.SessionFactory
 */
@SuppressWarnings({ "UnusedDeclaration" })
public class Configuration {
    private static final CoreMessageLogger log = CoreLogging.messageLogger(Configuration.class);

    public static final String ARTEFACT_PROCESSING_ORDER = AvailableSettings.ARTIFACT_PROCESSING_ORDER;

    private final BootstrapServiceRegistry bootstrapServiceRegistry;
    private final MetadataSources metadataSources;

    // used during processing mappings
    private ImplicitNamingStrategy implicitNamingStrategy;
    private PhysicalNamingStrategy physicalNamingStrategy;
    private List<BasicType> basicTypes = new ArrayList<BasicType>();
    private List<TypeContributor> typeContributorRegistrations = new ArrayList<TypeContributor>();
    private Map<String, NamedQueryDefinition> namedQueries;
    private Map<String, NamedSQLQueryDefinition> namedSqlQueries;
    private Map<String, NamedProcedureCallDefinition> namedProcedureCallMap;
    private Map<String, ResultSetMappingDefinition> sqlResultSetMappings;
    private Map<String, NamedEntityGraphDefinition> namedEntityGraphMap;

    private Map<String, SQLFunction> sqlFunctions;
    private List<AuxiliaryDatabaseObject> auxiliaryDatabaseObjectList;
    private HashMap<Class, AttributeConverterDefinition> attributeConverterDefinitionsByClass;

    // used to build SF
    private StandardServiceRegistryBuilder standardServiceRegistryBuilder;
    private EntityNotFoundDelegate entityNotFoundDelegate;
    private EntityTuplizerFactory entityTuplizerFactory;
    private Interceptor interceptor;
    private SessionFactoryObserver sessionFactoryObserver;
    private CurrentTenantIdentifierResolver currentTenantIdentifierResolver;
    private Properties properties;
    private SharedCacheMode sharedCacheMode;

    public Configuration() {
        this(new BootstrapServiceRegistryBuilder().build());
    }

    public Configuration(BootstrapServiceRegistry serviceRegistry) {
        this.bootstrapServiceRegistry = serviceRegistry;
        this.metadataSources = new MetadataSources(serviceRegistry);
        reset();
    }

    public Configuration(MetadataSources metadataSources) {
        this.bootstrapServiceRegistry = getBootstrapRegistry(metadataSources.getServiceRegistry());
        this.metadataSources = metadataSources;
        reset();
    }

    private static BootstrapServiceRegistry getBootstrapRegistry(ServiceRegistry serviceRegistry) {
        if (BootstrapServiceRegistry.class.isInstance(serviceRegistry)) {
            return (BootstrapServiceRegistry) serviceRegistry;
        } else if (StandardServiceRegistry.class.isInstance(serviceRegistry)) {
            final StandardServiceRegistry ssr = (StandardServiceRegistry) serviceRegistry;
            return (BootstrapServiceRegistry) ssr.getParentServiceRegistry();
        }

        throw new HibernateException("No ServiceRegistry was passed to Configuration#buildSessionFactory "
                + "and could not determine how to locate BootstrapServiceRegistry "
                + "from Configuration instantiation");
    }

    protected void reset() {
        implicitNamingStrategy = ImplicitNamingStrategyJpaCompliantImpl.INSTANCE;
        physicalNamingStrategy = PhysicalNamingStrategyStandardImpl.INSTANCE;
        namedQueries = new HashMap<String, NamedQueryDefinition>();
        namedSqlQueries = new HashMap<String, NamedSQLQueryDefinition>();
        sqlResultSetMappings = new HashMap<String, ResultSetMappingDefinition>();
        namedEntityGraphMap = new HashMap<String, NamedEntityGraphDefinition>();
        namedProcedureCallMap = new HashMap<String, NamedProcedureCallDefinition>();

        standardServiceRegistryBuilder = new StandardServiceRegistryBuilder(bootstrapServiceRegistry);
        entityTuplizerFactory = new EntityTuplizerFactory();
        interceptor = EmptyInterceptor.INSTANCE;
        properties = new Properties();
        properties.putAll(standardServiceRegistryBuilder.getSettings());
    }

    // properties/settings ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    /**
     * Get all properties
     *
     * @return all properties
     */
    public Properties getProperties() {
        return properties;
    }

    /**
     * Specify a completely new set of properties
     *
     * @param properties The new set of properties
     *
     * @return this for method chaining
     */
    public Configuration setProperties(Properties properties) {
        this.properties = properties;
        return this;
    }

    /**
     * Get a property value by name
     *
     * @param propertyName The name of the property
     *
     * @return The value currently associated with that property name; may be null.
     */
    public String getProperty(String propertyName) {
        Object o = properties.get(propertyName);
        return o instanceof String ? (String) o : null;
    }

    /**
     * Set a property value by name
     *
     * @param propertyName The name of the property to set
     * @param value The new property value
     *
     * @return this for method chaining
     */
    public Configuration setProperty(String propertyName, String value) {
        properties.setProperty(propertyName, value);
        return this;
    }

    /**
     * Add the given properties to ours.
     *
     * @param properties The properties to add.
     *
     * @return this for method chaining
     */
    public Configuration addProperties(Properties properties) {
        this.properties.putAll(properties);
        return this;
    }

    public void setImplicitNamingStrategy(ImplicitNamingStrategy implicitNamingStrategy) {
        this.implicitNamingStrategy = implicitNamingStrategy;
    }

    public void setPhysicalNamingStrategy(PhysicalNamingStrategy physicalNamingStrategy) {
        this.physicalNamingStrategy = physicalNamingStrategy;
    }

    /**
     * Use the mappings and properties specified in an application resource named <tt>hibernate.cfg.xml</tt>.
     *
     * @return this for method chaining
     *
     * @throws HibernateException Generally indicates we cannot find <tt>hibernate.cfg.xml</tt>
     *
     * @see #configure(String)
     */
    public Configuration configure() throws HibernateException {
        return configure(StandardServiceRegistryBuilder.DEFAULT_CFG_RESOURCE_NAME);
    }

    /**
     * Use the mappings and properties specified in the given application resource. The format of the resource is
     * defined in <tt>hibernate-configuration-3.0.dtd</tt>.
     *
     * @param resource The resource to use
     *
     * @return this for method chaining
     *
     * @throws HibernateException Generally indicates we cannot find the named resource
     */
    public Configuration configure(String resource) throws HibernateException {
        standardServiceRegistryBuilder.configure(resource);
        // todo : still need to have StandardServiceRegistryBuilder handle the "other cfg.xml" elements.
        //      currently it just reads the config properties
        properties.putAll(standardServiceRegistryBuilder.getSettings());
        return this;
    }

    /**
     * Intended for internal testing use only!!!
     */
    public StandardServiceRegistryBuilder getStandardServiceRegistryBuilder() {
        return standardServiceRegistryBuilder;
    }

    /**
     * Use the mappings and properties specified in the given document. The format of the document is defined in
     * <tt>hibernate-configuration-3.0.dtd</tt>.
     *
     * @param url URL from which you wish to load the configuration
     *
     * @return this for method chaining
     *
     * @throws HibernateException Generally indicates a problem access the url
     */
    public Configuration configure(URL url) throws HibernateException {
        standardServiceRegistryBuilder.configure(url);
        properties.putAll(standardServiceRegistryBuilder.getSettings());
        return this;
    }

    /**
     * Use the mappings and properties specified in the given application file. The format of the file is defined in
     * <tt>hibernate-configuration-3.0.dtd</tt>.
     *
     * @param configFile File from which you wish to load the configuration
     *
     * @return this for method chaining
     *
     * @throws HibernateException Generally indicates a problem access the file
     */
    public Configuration configure(File configFile) throws HibernateException {
        standardServiceRegistryBuilder.configure(configFile);
        properties.putAll(standardServiceRegistryBuilder.getSettings());
        return this;
    }

    /**
     * @deprecated No longer supported.
     */
    @Deprecated
    public Configuration configure(org.w3c.dom.Document document) throws HibernateException {
        return this;
    }

    // MetadataSources ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    public Configuration registerTypeContributor(TypeContributor typeContributor) {
        typeContributorRegistrations.add(typeContributor);
        return this;
    }

    /**
     * Allows registration of a type into the type registry.  The phrase 'override' in the method name simply
     * reminds that registration *potentially* replaces a previously registered type .
     *
     * @param type The type to register.
     */
    public Configuration registerTypeOverride(BasicType type) {
        basicTypes.add(type);
        return this;
    }

    public Configuration registerTypeOverride(UserType type, String[] keys) {
        basicTypes.add(new CustomType(type, keys));
        return this;
    }

    public Configuration registerTypeOverride(CompositeUserType type, String[] keys) {
        basicTypes.add(new CompositeCustomType(type, keys));
        return this;
    }

    /**
     * Read mappings from a particular XML file
     *
     * @param xmlFile a path to a file
     * @return this (for method chaining purposes)
     * @throws org.hibernate.MappingException Indicates inability to locate or parse
     * the specified mapping file.
     * @see #addFile(java.io.File)
     */
    public Configuration addFile(String xmlFile) throws MappingException {
        metadataSources.addFile(xmlFile);
        return this;
    }

    /**
     * Read mappings from a particular XML file
     *
     * @param xmlFile a path to a file
     * @return this (for method chaining purposes)
     * @throws MappingException Indicates inability to locate the specified mapping file.
     */
    public Configuration addFile(File xmlFile) throws MappingException {
        metadataSources.addFile(xmlFile);
        return this;
    }

    /**
     * @deprecated No longer supported.
     */
    @Deprecated
    public void add(XmlDocument metadataXml) {
    }

    /**
     * Add a cached mapping file.  A cached file is a serialized representation
     * of the DOM structure of a particular mapping.  It is saved from a previous
     * call as a file with the name <tt>xmlFile + ".bin"</tt> where xmlFile is
     * the name of the original mapping file.
     * </p>
     * If a cached <tt>xmlFile + ".bin"</tt> exists and is newer than
     * <tt>xmlFile</tt> the <tt>".bin"</tt> file will be read directly. Otherwise
     * xmlFile is read and then serialized to <tt>xmlFile + ".bin"</tt> for use
     * the next time.
     *
     * @param xmlFile The cacheable mapping file to be added.
     * @return this (for method chaining purposes)
     * @throws MappingException Indicates problems reading the cached file or processing
     * the non-cached file.
     */
    public Configuration addCacheableFile(File xmlFile) throws MappingException {
        metadataSources.addCacheableFile(xmlFile);
        return this;
    }

    /**
     * <b>INTENDED FOR TESTSUITE USE ONLY!</b>
     * <p/>
     * Much like {@link #addCacheableFile(File)} except that here we will fail immediately if
     * the cache version cannot be found or used for whatever reason
     *
     * @param xmlFile The xml file, not the bin!
     *
     * @return The dom "deserialized" from the cached file.
     *
     * @throws SerializationException Indicates a problem deserializing the cached dom tree
     * @throws FileNotFoundException Indicates that the cached file was not found or was not usable.
     */
    public Configuration addCacheableFileStrictly(File xmlFile)
            throws SerializationException, FileNotFoundException {
        metadataSources.addCacheableFileStrictly(xmlFile);
        return this;
    }

    /**
     * Add a cacheable mapping file.
     *
     * @param xmlFile The name of the file to be added.  This must be in a form
     * useable to simply construct a {@link java.io.File} instance.
     * @return this (for method chaining purposes)
     * @throws MappingException Indicates problems reading the cached file or processing
     * the non-cached file.
     * @see #addCacheableFile(java.io.File)
     */
    public Configuration addCacheableFile(String xmlFile) throws MappingException {
        metadataSources.addCacheableFile(xmlFile);
        return this;
    }

    /**
     * @deprecated No longer supported
     */
    @Deprecated
    public Configuration addXML(String xml) throws MappingException {
        return this;
    }

    /**
     * Read mappings from a <tt>URL</tt>
     *
     * @param url The url for the mapping document to be read.
     * @return this (for method chaining purposes)
     * @throws MappingException Indicates problems reading the URL or processing
     * the mapping document.
     */
    public Configuration addURL(URL url) throws MappingException {
        metadataSources.addURL(url);
        return this;
    }

    /**
     * Read mappings from a DOM <tt>Document</tt>
     *
     * @param doc The DOM document
     * @return this (for method chaining purposes)
     * @throws MappingException Indicates problems reading the DOM or processing
     * the mapping document.
     *
     * @deprecated Use addURL, addResource, addFile, etc. instead
     */
    @Deprecated
    public Configuration addDocument(org.w3c.dom.Document doc) throws MappingException {
        metadataSources.addDocument(doc);
        return this;
    }

    /**
     * Read mappings from an {@link java.io.InputStream}.
     *
     * @param xmlInputStream The input stream containing a DOM.
     * @return this (for method chaining purposes)
     * @throws MappingException Indicates problems reading the stream, or
     * processing the contained mapping document.
     */
    public Configuration addInputStream(InputStream xmlInputStream) throws MappingException {
        metadataSources.addInputStream(xmlInputStream);
        return this;
    }

    /**
     * @deprecated This form (accepting a ClassLoader) is no longer supported.  Instead, add the ClassLoader
     * to the ClassLoaderService on the ServiceRegistry associated with this Configuration
     */
    @Deprecated
    public Configuration addResource(String resourceName, ClassLoader classLoader) throws MappingException {
        return addResource(resourceName);
    }

    /**
     * Read mappings as a application resourceName (i.e. classpath lookup)
     * trying different class loaders.
     *
     * @param resourceName The resource name
     * @return this (for method chaining purposes)
     * @throws MappingException Indicates problems locating the resource or
     * processing the contained mapping document.
     */
    public Configuration addResource(String resourceName) throws MappingException {
        metadataSources.addResource(resourceName);
        return this;
    }

    /**
     * Read a mapping as an application resource using the convention that a class
     * named <tt>foo.bar.Foo</tt> is mapped by a file <tt>foo/bar/Foo.hbm.xml</tt>
     * which can be resolved as a classpath resource.
     *
     * @param persistentClass The mapped class
     * @return this (for method chaining purposes)
     * @throws MappingException Indicates problems locating the resource or
     * processing the contained mapping document.
     */
    public Configuration addClass(Class persistentClass) throws MappingException {
        metadataSources.addClass(persistentClass);
        return this;
    }

    /**
     * Read metadata from the annotations associated with this class.
     *
     * @param annotatedClass The class containing annotations
     *
     * @return this (for method chaining)
     */
    @SuppressWarnings({ "unchecked" })
    public Configuration addAnnotatedClass(Class annotatedClass) {
        metadataSources.addAnnotatedClass(annotatedClass);
        return this;
    }

    /**
     * Read package-level metadata.
     *
     * @param packageName java package name
     *
     * @return this (for method chaining)
     *
     * @throws MappingException in case there is an error in the mapping data
     */
    public Configuration addPackage(String packageName) throws MappingException {
        metadataSources.addPackage(packageName);
        return this;
    }

    /**
     * Read all mappings from a jar file
     * <p/>
     * Assumes that any file named <tt>*.hbm.xml</tt> is a mapping document.
     *
     * @param jar a jar file
     * @return this (for method chaining purposes)
     * @throws MappingException Indicates problems reading the jar file or
     * processing the contained mapping documents.
     */
    public Configuration addJar(File jar) throws MappingException {
        metadataSources.addJar(jar);
        return this;
    }

    /**
     * Read all mapping documents from a directory tree.
     * <p/>
     * Assumes that any file named <tt>*.hbm.xml</tt> is a mapping document.
     *
     * @param dir The directory
     * @return this (for method chaining purposes)
     * @throws MappingException Indicates problems reading the jar file or
     * processing the contained mapping documents.
     */
    public Configuration addDirectory(File dir) throws MappingException {
        metadataSources.addDirectory(dir);
        return this;
    }

    // SessionFactory building ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    /**
     * Retrieve the configured {@link Interceptor}.
     *
     * @return The current {@link Interceptor}
     */
    public Interceptor getInterceptor() {
        return interceptor;
    }

    /**
     * Set the current {@link Interceptor}
     *
     * @param interceptor The {@link Interceptor} to use for the {@link #buildSessionFactory built}
     * {@link SessionFactory}.
     *
     * @return this for method chaining
     */
    public Configuration setInterceptor(Interceptor interceptor) {
        this.interceptor = interceptor;
        return this;
    }

    public EntityTuplizerFactory getEntityTuplizerFactory() {
        return entityTuplizerFactory;
    }

    /**
     * Retrieve the user-supplied delegate to handle non-existent entity
     * scenarios.  May be null.
     *
     * @return The user-supplied delegate
     */
    public EntityNotFoundDelegate getEntityNotFoundDelegate() {
        return entityNotFoundDelegate;
    }

    /**
     * Specify a user-supplied delegate to be used to handle scenarios where an entity could not be
     * located by specified id.  This is mainly intended for EJB3 implementations to be able to
     * control how proxy initialization errors should be handled...
     *
     * @param entityNotFoundDelegate The delegate to use
     */
    public void setEntityNotFoundDelegate(EntityNotFoundDelegate entityNotFoundDelegate) {
        this.entityNotFoundDelegate = entityNotFoundDelegate;
    }

    public SessionFactoryObserver getSessionFactoryObserver() {
        return sessionFactoryObserver;
    }

    public void setSessionFactoryObserver(SessionFactoryObserver sessionFactoryObserver) {
        this.sessionFactoryObserver = sessionFactoryObserver;
    }

    public CurrentTenantIdentifierResolver getCurrentTenantIdentifierResolver() {
        return currentTenantIdentifierResolver;
    }

    public void setCurrentTenantIdentifierResolver(
            CurrentTenantIdentifierResolver currentTenantIdentifierResolver) {
        this.currentTenantIdentifierResolver = currentTenantIdentifierResolver;
    }

    /**
     * Create a {@link SessionFactory} using the properties and mappings in this configuration. The
     * SessionFactory will be immutable, so changes made to this Configuration after building the
     * SessionFactory will not affect it.
     *
     * @param serviceRegistry The registry of services to be used in creating this session factory.
     *
     * @return The built {@link SessionFactory}
     *
     * @throws HibernateException usually indicates an invalid configuration or invalid mapping information
     */
    public SessionFactory buildSessionFactory(ServiceRegistry serviceRegistry) throws HibernateException {
        log.debug("Building session factory using provided StandardServiceRegistry");
        final MetadataBuilder metadataBuilder = metadataSources
                .getMetadataBuilder((StandardServiceRegistry) serviceRegistry);
        if (implicitNamingStrategy != null) {
            metadataBuilder.applyImplicitNamingStrategy(implicitNamingStrategy);
        }
        if (physicalNamingStrategy != null) {
            metadataBuilder.applyPhysicalNamingStrategy(physicalNamingStrategy);
        }
        if (sharedCacheMode != null) {
            metadataBuilder.applySharedCacheMode(sharedCacheMode);
        }
        if (!typeContributorRegistrations.isEmpty()) {
            for (TypeContributor typeContributor : typeContributorRegistrations) {
                metadataBuilder.applyTypes(typeContributor);
            }
        }
        if (!basicTypes.isEmpty()) {
            for (BasicType basicType : basicTypes) {
                metadataBuilder.applyBasicType(basicType);
            }
        }
        if (sqlFunctions != null) {
            for (Map.Entry<String, SQLFunction> entry : sqlFunctions.entrySet()) {
                metadataBuilder.applySqlFunction(entry.getKey(), entry.getValue());
            }
        }
        if (auxiliaryDatabaseObjectList != null) {
            for (AuxiliaryDatabaseObject auxiliaryDatabaseObject : auxiliaryDatabaseObjectList) {
                metadataBuilder.applyAuxiliaryDatabaseObject(auxiliaryDatabaseObject);
            }
        }
        if (attributeConverterDefinitionsByClass != null) {
            for (AttributeConverterDefinition attributeConverterDefinition : attributeConverterDefinitionsByClass
                    .values()) {
                metadataBuilder.applyAttributeConverter(attributeConverterDefinition);
            }
        }

        final Metadata metadata = metadataBuilder.build();

        final SessionFactoryBuilder sessionFactoryBuilder = metadata.getSessionFactoryBuilder();
        if (interceptor != null && interceptor != EmptyInterceptor.INSTANCE) {
            sessionFactoryBuilder.applyInterceptor(interceptor);
        }
        if (getSessionFactoryObserver() != null) {
            sessionFactoryBuilder.addSessionFactoryObservers(getSessionFactoryObserver());
        }
        if (getEntityNotFoundDelegate() != null) {
            sessionFactoryBuilder.applyEntityNotFoundDelegate(getEntityNotFoundDelegate());
        }
        if (getEntityTuplizerFactory() != null) {
            sessionFactoryBuilder.applyEntityTuplizerFactory(getEntityTuplizerFactory());
        }
        if (getCurrentTenantIdentifierResolver() != null) {
            sessionFactoryBuilder.applyCurrentTenantIdentifierResolver(getCurrentTenantIdentifierResolver());
        }

        return sessionFactoryBuilder.build();
    }

    /**
     * Create a {@link SessionFactory} using the properties and mappings in this configuration. The
     * {@link SessionFactory} will be immutable, so changes made to {@code this} {@link Configuration} after
     * building the {@link SessionFactory} will not affect it.
     *
     * @return The build {@link SessionFactory}
     *
     * @throws HibernateException usually indicates an invalid configuration or invalid mapping information
     */
    public SessionFactory buildSessionFactory() throws HibernateException {
        log.debug("Building session factory using internal StandardServiceRegistryBuilder");
        standardServiceRegistryBuilder.applySettings(properties);
        return buildSessionFactory(standardServiceRegistryBuilder.build());
    }

    public Map<String, SQLFunction> getSqlFunctions() {
        return sqlFunctions;
    }

    public void addSqlFunction(String functionName, SQLFunction function) {
        if (sqlFunctions == null) {
            sqlFunctions = new HashMap<String, SQLFunction>();
        }
        sqlFunctions.put(functionName, function);
    }

    public void addAuxiliaryDatabaseObject(AuxiliaryDatabaseObject object) {
        if (auxiliaryDatabaseObjectList == null) {
            auxiliaryDatabaseObjectList = new ArrayList<AuxiliaryDatabaseObject>();
        }
        auxiliaryDatabaseObjectList.add(object);
    }

    /**
     * Adds the AttributeConverter Class to this Configuration.
     *
     * @param attributeConverterClass The AttributeConverter class.
     * @param autoApply Should the AttributeConverter be auto applied to property types as specified
     * by its "entity attribute" parameterized type?
     */
    public void addAttributeConverter(Class<? extends AttributeConverter> attributeConverterClass,
            boolean autoApply) {
        addAttributeConverter(AttributeConverterDefinition.from(attributeConverterClass, autoApply));
    }

    /**
     * Adds the AttributeConverter Class to this Configuration.
     *
     * @param attributeConverterClass The AttributeConverter class.
     */
    public void addAttributeConverter(Class<? extends AttributeConverter> attributeConverterClass) {
        addAttributeConverter(AttributeConverterDefinition.from(attributeConverterClass));
    }

    /**
     * Adds the AttributeConverter instance to this Configuration.  This form is mainly intended for developers
     * to programmatically add their own AttributeConverter instance.  HEM, instead, uses the
     * {@link #addAttributeConverter(Class, boolean)} form
     *
     * @param attributeConverter The AttributeConverter instance.
     */
    public void addAttributeConverter(AttributeConverter attributeConverter) {
        addAttributeConverter(AttributeConverterDefinition.from(attributeConverter));
    }

    /**
     * Adds the AttributeConverter instance to this Configuration.  This form is mainly intended for developers
     * to programmatically add their own AttributeConverter instance.  HEM, instead, uses the
     * {@link #addAttributeConverter(Class, boolean)} form
     *
     * @param attributeConverter The AttributeConverter instance.
     * @param autoApply Should the AttributeConverter be auto applied to property types as specified
     * by its "entity attribute" parameterized type?
     */
    public void addAttributeConverter(AttributeConverter attributeConverter, boolean autoApply) {
        addAttributeConverter(AttributeConverterDefinition.from(attributeConverter, autoApply));
    }

    public void addAttributeConverter(AttributeConverterDefinition definition) {
        if (attributeConverterDefinitionsByClass == null) {
            attributeConverterDefinitionsByClass = new HashMap<Class, AttributeConverterDefinition>();
        }
        attributeConverterDefinitionsByClass.put(definition.getAttributeConverter().getClass(), definition);
    }

    /**
     * Sets the SharedCacheMode to use.
     *
     * Note that at the moment, only {@link javax.persistence.SharedCacheMode#ALL} has
     * any effect in terms of {@code hbm.xml} binding.
     *
     * @param sharedCacheMode The SharedCacheMode to use
     */
    public void setSharedCacheMode(SharedCacheMode sharedCacheMode) {
        this.sharedCacheMode = sharedCacheMode;
    }

    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    // todo : decide about these

    public Map getNamedSQLQueries() {
        return namedSqlQueries;
    }

    public Map getSqlResultSetMappings() {
        return sqlResultSetMappings;
    }

    public java.util.Collection<NamedEntityGraphDefinition> getNamedEntityGraphs() {
        return namedEntityGraphMap == null ? Collections.<NamedEntityGraphDefinition>emptyList()
                : namedEntityGraphMap.values();
    }

    public Map<String, NamedQueryDefinition> getNamedQueries() {
        return namedQueries;
    }

    public Map<String, NamedProcedureCallDefinition> getNamedProcedureCallMap() {
        return namedProcedureCallMap;
    }

    /**
     * @deprecated Does nothing
     */
    @Deprecated
    public void buildMappings() {
    }

    /**
     * Adds the incoming properties to the internal properties structure, as long as the internal structure does not
     * already contain an entry for the given key.
     *
     * @param properties The properties to merge
     *
     * @return this for method chaining
     */
    public Configuration mergeProperties(Properties properties) {
        for (Map.Entry entry : properties.entrySet()) {
            if (this.properties.containsKey(entry.getKey())) {
                continue;
            }
            this.properties.setProperty((String) entry.getKey(), (String) entry.getValue());
        }
        return this;
    }
}