All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.phloc.db.jpa.AbstractGlobalEntityManagerFactory Maven / Gradle / Ivy

The newest version!
/**
 * Copyright (C) 2006-2015 phloc systems
 * http://www.phloc.com
 * office[at]phloc[dot]com
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.phloc.db.jpa;

import java.util.HashMap;
import java.util.Map;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.OverridingMethodsMustInvokeSuper;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

import org.eclipse.persistence.config.PersistenceUnitProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.phloc.commons.annotations.Nonempty;
import com.phloc.commons.annotations.OverrideOnDemand;
import com.phloc.commons.annotations.ReturnsMutableCopy;
import com.phloc.commons.collections.ContainerHelper;
import com.phloc.commons.string.StringHelper;
import com.phloc.db.jpa.eclipselink.EclipseLinkLogger;
import com.phloc.db.jpa.eclipselink.EclipseLinkSessionCustomizer;
import com.phloc.db.jpa.utils.PersistenceXmlUtils;
import com.phloc.scopes.singleton.GlobalSingleton;

/**
 * Abstract global singleton to handle a single persistence unit.
 * 
 * @author Philip Helger
 */
public abstract class AbstractGlobalEntityManagerFactory extends GlobalSingleton
{
  private static final Logger s_aLogger = LoggerFactory.getLogger (AbstractGlobalEntityManagerFactory.class);

  static
  {
    // Check if all existing META-INF/persistence.xml files reference existing
    // classes
    PersistenceXmlUtils.checkPersistenceXMLValidity ();
  }

  private final String m_sPersistenceUnitName;
  private final Map  m_aFactoryProps;
  private EntityManagerFactory m_aFactory;

  /**
   * Constructor
   * 
   * @param sJdbcDriverClass
   *        Name of the JDBC driver class. Must be a class implementing
   *        java.sql.Driver.
   * @param sJdbcURL
   *        JDBC URL
   * @param sUserName
   *        User name to access the DB. May be null.
   * @param sPassword
   *        Password to access the DB. May be null.
   * @param sPlatformClass
   *        The EclipseLink platform name. May either be a fully qualified
   *        class-name of a recognized abbreviation.
   * @param sPersistenceUnitName
   *        The name of the persistence unit as stated in the persistence.xml
   * @param aAdditionalFactoryProperties
   *        An optional Map with properties for {@link EntityManagerFactory}.
   *        This can even be used to overwrite the settings specified as
   *        explicit parameters, so be careful. This map is applied after the
   *        special properties are set! May be null.
   */
  protected AbstractGlobalEntityManagerFactory (@Nonnull @Nonempty final String sJdbcDriverClass,
                                                @Nonnull @Nonempty final String sJdbcURL,
                                                @Nullable final String sUserName,
                                                @Nullable final String sPassword,
                                                @Nonnull @Nonempty final String sPlatformClass,
                                                @Nonnull @Nonempty final String sPersistenceUnitName,
                                                @Nullable final Map  aAdditionalFactoryProperties)
  {
    if (StringHelper.hasNoText (sJdbcDriverClass))
      throw new NullPointerException ("JdbcDriverClass");
    if (StringHelper.hasNoText (sJdbcURL))
      throw new IllegalArgumentException ("JdbcURL");
    if (StringHelper.hasNoText (sPlatformClass))
      throw new NullPointerException ("PlatformClass");
    if (StringHelper.hasNoText (sPersistenceUnitName))
      throw new IllegalArgumentException ("PersistenceUnitName");

    s_aLogger.info ("Using JDBC URL " +
                    sJdbcURL +
                    " with JDBC driver " +
                    sJdbcDriverClass +
                    " and user '" +
                    sUserName +
                    "'");

    final Map  aFactoryProps = new HashMap  ();
    aFactoryProps.put (PersistenceUnitProperties.JDBC_DRIVER, sJdbcDriverClass);
    aFactoryProps.put (PersistenceUnitProperties.JDBC_URL, sJdbcURL);
    aFactoryProps.put (PersistenceUnitProperties.JDBC_USER, sUserName);
    aFactoryProps.put (PersistenceUnitProperties.JDBC_PASSWORD, sPassword);

    aFactoryProps.put (PersistenceUnitProperties.LOGGING_LOGGER, EclipseLinkLogger.class.getName ());
    aFactoryProps.put (PersistenceUnitProperties.SESSION_CUSTOMIZER, EclipseLinkSessionCustomizer.class.getName ());
    aFactoryProps.put (PersistenceUnitProperties.TARGET_DATABASE, sPlatformClass);

    // Not desired to have default values for
    // PersistenceUnitProperties.DDL_GENERATION,
    // PersistenceUnitProperties.CREATE_JDBC_DDL_FILE and
    // PersistenceUnitProperties.DROP_JDBC_DDL_FILE, when multiple JPA
    // configurations are present

    // Add parameter properties
    if (aAdditionalFactoryProperties != null)
      aFactoryProps.putAll (aAdditionalFactoryProperties);

    // Consistency check if no explicit DDL generation mode is specified!
    if (aFactoryProps.containsKey (PersistenceUnitProperties.DDL_GENERATION) &&
        !aFactoryProps.containsKey (PersistenceUnitProperties.DDL_GENERATION_MODE))
    {
      final String sDDLGeneration = (String) aFactoryProps.get (PersistenceUnitProperties.DDL_GENERATION);
      if (!PersistenceUnitProperties.NONE.equals (sDDLGeneration))
      {
        s_aLogger.warn ("DDL generation is set to '" +
                        sDDLGeneration +
                        "' but no DDL generation mode is defined, which defaults to '" +
                        PersistenceUnitProperties.DDL_DATABASE_GENERATION +
                        "' - defaulting to '" +
                        PersistenceUnitProperties.DDL_SQL_SCRIPT_GENERATION +
                        "'!!!");
        aFactoryProps.put (PersistenceUnitProperties.DDL_GENERATION_MODE,
                           PersistenceUnitProperties.DDL_SQL_SCRIPT_GENERATION);
      }
    }

    m_sPersistenceUnitName = sPersistenceUnitName;
    m_aFactoryProps = aFactoryProps;
  }

  /**
   * This method allows you to customize the created
   * {@link EntityManagerFactory} in any way. By default it is returned as
   * created.
   * 
   * @param aEMF
   *        The original {@link EntityManagerFactory}. Never null.
   * @return The final {@link EntityManagerFactory} to use. May not be
   *         null.
   */
  @Nonnull
  @OverrideOnDemand
  protected EntityManagerFactory customizeEntityManagerFactory (@Nonnull final EntityManagerFactory aEMF)
  {
    return aEMF;
  }

  @Override
  @OverridingMethodsMustInvokeSuper
  protected void onAfterInstantiation ()
  {
    // Create entity manager factory
    final EntityManagerFactory aFactory = Persistence.createEntityManagerFactory (m_sPersistenceUnitName,
                                                                                  m_aFactoryProps);
    if (aFactory == null)
      throw new IllegalStateException ("Failed to create entity manager factory for persistence unit '" +
                                       m_sPersistenceUnitName +
                                       "' with properties " +
                                       m_aFactoryProps.toString () +
                                       "!");

    // Customize on demand
    m_aFactory = customizeEntityManagerFactory (aFactory);
    s_aLogger.info ("Created EntityManagerFactory for persistence unit '" + m_sPersistenceUnitName + "'");

    // Consistency check after creation!
    final Map  aRealProps = m_aFactory.getProperties ();
    if (aRealProps.containsKey (PersistenceUnitProperties.DDL_GENERATION) &&
        !aRealProps.containsKey (PersistenceUnitProperties.DDL_GENERATION_MODE))
    {
      final String sDDLGeneration = (String) aRealProps.get (PersistenceUnitProperties.DDL_GENERATION);
      if (!PersistenceUnitProperties.NONE.equals (sDDLGeneration))
      {
        throw new IllegalStateException ("DDL generation is set to '" +
                                         sDDLGeneration +
                                         "' but no DDL generation mode is defined, which defaults to '" +
                                         PersistenceUnitProperties.DDL_DATABASE_GENERATION +
                                         "' which can erase all your data. Please explicitly state a value for the property '" +
                                         PersistenceUnitProperties.DDL_GENERATION_MODE +
                                         "'!!!\nEffective properties are: " +
                                         aRealProps.toString ());
      }
    }
  }

  /**
   * Called when the global scope is destroyed (e.g. upon servlet context
   * shutdown)
   * 
   * @throws Exception
   *         if closing fails
   */
  @Override
  @OverridingMethodsMustInvokeSuper
  protected void onDestroy () throws Exception
  {
    // Destroy factory
    if (m_aFactory != null)
    {
      if (m_aFactory.isOpen ())
      {
        // Clear cache
        m_aFactory.getCache ().evictAll ();
        // Close
        m_aFactory.close ();
      }
      m_aFactory = null;
    }
    s_aLogger.info ("Closed EntityManagerFactory for persistence unit '" + m_sPersistenceUnitName + "'");
  }

  /**
   * @return The persistence unit name. Neither null nor empty.
   */
  @Nonnull
  @Nonempty
  public final String getPersistenceUnitName ()
  {
    return m_sPersistenceUnitName;
  }

  /**
   * @return The EntityManagerFactory creation properties. Never
   *         null.
   */
  @Nonnull
  @ReturnsMutableCopy
  public final Map  getAllFactoryProperties ()
  {
    return ContainerHelper.newMap (m_aFactoryProps);
  }

  /**
   * @return The underlying {@link EntityManagerFactory}. Never
   *         null.
   */
  @Nonnull
  public final EntityManagerFactory getEntityManagerFactory ()
  {
    if (m_aFactory == null)
      throw new IllegalStateException ("No EntityManagerFactory present!");
    return m_aFactory;
  }

  /**
   * Create a new {@link EntityManager} with the default properties - usually
   * this is suitable!
   * 
   * @return The created {@link EntityManager} and never null.
   */
  @Nonnull
  public final EntityManager createEntityManager ()
  {
    return createEntityManager (null);
  }

  /**
   * Create a new {@link EntityManager} with custom properties!
   * 
   * @param aMap
   *        The custom properties to use. May be null for no
   *        properties.
   * @return The created {@link EntityManager} and never null.
   */
  @Nonnull
  public EntityManager createEntityManager (@SuppressWarnings ("rawtypes") final Map aMap)
  {
    // Create entity manager (factory may be null - e.g. after close)
    final EntityManager aEntityManager = getEntityManagerFactory ().createEntityManager (aMap);
    if (aEntityManager == null)
      throw new IllegalStateException ("Failed to create EntityManager from factory " +
                                       m_aFactory +
                                       " with parameters " +
                                       aMap +
                                       "!");
    return aEntityManager;
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy