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

org.opencastproject.util.persistencefn.PersistenceUtil Maven / Gradle / Ivy

There is a newer version: 16.7
Show newest version
/**
 * Licensed to The Apereo Foundation under one or more contributor license
 * agreements. See the NOTICE file distributed with this work for additional
 * information regarding copyright ownership.
 *
 *
 * The Apereo Foundation licenses this file to you under the Educational
 * Community 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://opensource.org/licenses/ecl2.txt
 *
 * 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.opencastproject.util.persistencefn;

import static com.entwinemedia.fn.Equality.eq;
import static com.entwinemedia.fn.Stream.$;
import static java.lang.String.format;

import org.opencastproject.util.data.Collections;

import com.entwinemedia.fn.Fn;
import com.entwinemedia.fn.ProductBuilder;
import com.entwinemedia.fn.data.Opt;
import com.entwinemedia.fn.fns.Products;
import com.mchange.v2.c3p0.ComboPooledDataSource;

import org.osgi.service.component.ComponentContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.beans.PropertyVetoException;
import java.net.URI;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.spi.PersistenceProvider;
import javax.sql.DataSource;

/**
 * Functions supporting persistence.
 */
public final class PersistenceUtil {
  private static final Logger logger = LoggerFactory.getLogger(PersistenceUtil.class);

  private PersistenceUtil() {
  }

  public static final Map NO_PERSISTENCE_PROPS = java.util.Collections.emptyMap();

  /**
   * Create a new entity manager factory with the persistence unit name emName. A
   * {@link javax.persistence.spi.PersistenceProvider} named persistence has to be registered as an OSGi
   * service. If you want to configure the factory please also register a map containing all properties under the name
   * persistenceProps. See
   * {@link javax.persistence.spi.PersistenceProvider#createEntityManagerFactory(String, java.util.Map)} for more
   * information about config maps.
   *
   * @param emName
   *         name of the persistence unit
   */
  public static EntityManagerFactory mkEntityManagerFactory(ComponentContext cc, String emName) {
    final PersistenceProvider persistenceProvider = (PersistenceProvider) cc.locateService("persistence");
    final Map pp = (Map) cc.locateService("persistenceProps");
    final Map persistenceProps = pp != null ? pp : NO_PERSISTENCE_PROPS;
    return persistenceProvider.createEntityManagerFactory(emName, persistenceProps);
  }

  /**
   * Create a new entity manager factory with the persistence unit name emName. A
   * {@link javax.persistence.spi.PersistenceProvider} named persistence has to be registered as an OSGi
   * service. See {@link javax.persistence.spi.PersistenceProvider#createEntityManagerFactory(String, java.util.Map)}
   * for more information about config maps.
   *
   * @param emName
   *         name of the persistence unit
   * @param persistenceProps
   *         config map for the creation of an EntityManagerFactory
   */
  public static EntityManagerFactory mkEntityManagerFactory(ComponentContext cc, String emName, Map persistenceProps) {
    final PersistenceProvider persistenceProvider = (PersistenceProvider) cc.locateService("persistence");
    return persistenceProvider.createEntityManagerFactory(emName, persistenceProps);
  }

  public static EntityManagerFactory mkEntityManagerFactory(
          String emName,
          String vendor,
          String driver,
          String url,
          String user,
          String pwd,
          Map persistenceProps,
          PersistenceProvider pp) {
    // Set up the database
    final ComboPooledDataSource pooledDataSource = new ComboPooledDataSource();
    try {
      pooledDataSource.setDriverClass(driver);
    } catch (PropertyVetoException e) {
      throw new RuntimeException(e);
    }
    pooledDataSource.setJdbcUrl(url);
    pooledDataSource.setUser(user);
    pooledDataSource.setPassword(pwd);

    // Set up the persistence properties
    final Map props = new HashMap<>(persistenceProps);
    props.put("javax.persistence.nonJtaDataSource", pooledDataSource);
    props.put("eclipselink.target-database", vendor);

    final EntityManagerFactory emf = pp.createEntityManagerFactory(emName, props);
    if (emf == null) {
      throw new Error("Cannot create entity manager factory for persistence unit " + emName
                              + ". Maybe you misspelled the name of the persistence unit?");
    }
    return emf;
  }

  /** Create a new entity manager or return none, if the factory has already been closed. */
  public static Opt mkEntityManager(EntityManagerFactory emf) {
    try {
      return Opt.some(emf.createEntityManager());
    } catch (IllegalStateException ex) {
      // factory is already closed
      return Opt.none();
    }
  }

  /* ------------------------------------------------------------------------------------------------------------------ */

  //
  // test entity manager
  //

  private static final ProductBuilder P = com.entwinemedia.fn.Products.E;
  private static final Map TEST_ENTITY_MANAGER_PROPS = $(
          P.p2("eclipselink.ddl-generation", "create-tables"),
          P.p2("eclipselink.ddl-generation.output-mode", "database"))
          .group(Products.p2_1(), Products.p2_2());
  private static final Map TEST_ENTITY_MANAGER_LOGGING_PROPS = $(
          P.p2("eclipselink.logging.level.sql", "FINE"),
          P.p2("eclipselink.logging.parameters", "true"))
          .group(Products.p2_1(), Products.p2_2());

  /**
   * Create a new entity manager factory backed by an in-memory H2 database for testing purposes.
   * If you want to turn on SQL logging see {@link #mkTestEntityManagerFactory(String)}
   *
   * @param emName
   *         name of the persistence unit (see META-INF/persistence.xml)
   */
  public static EntityManagerFactory mkTestEntityManagerFactory(String emName) {
    return mkTestEntityManagerFactory(emName, false);
  }

  /**
   * Create a new entity manager factory backed by an in-memory H2 database for testing purposes.
   *
   * @param emName
   *         name of the persistence unit (see META-INF/persistence.xml)
   * @param withSqlLogging
   *         turn on EclipseLink SQL logging
   */
  public static EntityManagerFactory mkTestEntityManagerFactory(String emName, boolean withSqlLogging) {
    return mkEntityManagerFactory(
            emName,
            "Auto",
            "org.h2.Driver",
            "jdbc:h2:./target/db" + System.currentTimeMillis(),
            "sa",
            "sa",
            withSqlLogging
                    ? Collections.merge(TEST_ENTITY_MANAGER_PROPS, TEST_ENTITY_MANAGER_LOGGING_PROPS)
                    : TEST_ENTITY_MANAGER_PROPS,
            mkTestPersistenceProvider());
  }

  /**
   * Create an entity manager for unit tests configured by the following system properties.
   * 
    *
  • -Dtest-database-url, JDBC URL, defaults to H2 in-memory database
  • *
  • -Dtest-database-user, defaults to 'matterhorn'
  • *
  • -Dtest-database-password, defaults to 'matterhorn'
  • *
  • -Dsql-logging=[true|false], defaults to 'false', turns on SQL logging to the console
  • *
  • -Dkeep-database=[true|false], defaults to 'false', keep an existing database or recreate at startup. Not used with H2.
  • *
* Currently only MySQL is recognized. * * @param emName * name of the persistence unit (see META-INF/persistence.xml) */ public static EntityManagerFactory mkTestEntityManagerFactoryFromSystemProperties(String emName) { final Opt dbUrl = Opt.nul(System.getProperty("test-database-url")); final boolean withSqlLogging = Boolean.getBoolean("sql-logging"); final boolean keepDatabase = Boolean.getBoolean("keep-database"); final String dbUser = Opt.nul(System.getProperty("test-database-user")).getOr("matterhorn"); final String dbPwd = Opt.nul(System.getProperty("test-database-password")).getOr("matterhorn"); for (String url : dbUrl) { try { final String dbType = new URI(new URI(url).getSchemeSpecificPart()).getScheme(); if (eq("mysql", dbType)) { logger.info(format("Use MySQL database\n" + " test-database-url=%s\n" + " test-database-user=%s\n" + " test-database-password=%s\n" + " sql-logging=%s\n" + " keep-database=%s", url, dbUser, dbPwd, withSqlLogging, keepDatabase)); return mkMySqlTestEntityManagerFactory(emName, url, dbUser, dbPwd, withSqlLogging, keepDatabase); } } catch (Exception ignore) { } } logger.info(format("Use H2 database\n sql-logging=%s", withSqlLogging)); return mkTestEntityManagerFactory(emName, withSqlLogging); } /** * Create a new entity manager factory using a MySQL database for testing purposes. * * @param emName * name of the persistence unit (see META-INF/persistence.xml) * @param jdbcUri * the JDBC URI of the database, e.g. jdbc:mysql://localhost/test_database * @param user * the database user * @param pwd * the user's password * @param withSqlLogging * turn on SQL logging * @param keepDatabase * recreate or keep the database at startup */ public static EntityManagerFactory mkMySqlTestEntityManagerFactory( String emName, String jdbcUri, String user, String pwd, boolean withSqlLogging, boolean keepDatabase) { final Map testEntityManagerProps = new HashMap<>(); testEntityManagerProps.put("eclipselink.ddl-generation", keepDatabase ? "none" : "drop-and-create-tables"); testEntityManagerProps.put("eclipselink.ddl-generation.output-mode", "database"); if (withSqlLogging) { testEntityManagerProps.putAll(PersistenceUtil.TEST_ENTITY_MANAGER_LOGGING_PROPS); } return PersistenceUtil.mkEntityManagerFactory( emName, "MySql", "com.mysql.jdbc.Driver", jdbcUri, user, pwd, testEntityManagerProps, PersistenceUtil.mkTestPersistenceProvider()); } // // // /** Create a new persistence provider for unit tests. */ public static PersistenceProvider mkTestPersistenceProvider() { return new org.eclipse.persistence.jpa.PersistenceProvider(); } public static void closeQuietly(Connection c) { if (c != null) { try { c.close(); } catch (SQLException ignore) { } } } /** * Test if a connection to the given data source can be established. * * @return none, if the connection could be established */ public static Opt testConnection(DataSource ds) { try (Connection tryConnect = ds.getConnection()) { return Opt.none(); } catch (SQLException e) { return Opt.some(e); } } /** * Try to get the database metadata from an entity manager. Return none, if the metadata * cannot be retrieved, e.g. because the entity manager does not expose them. */ public static Opt getDatabaseMetadata(EntityManager em) { try { final Connection c = em.unwrap(Connection.class); return Opt.some(c.getMetaData()); } catch (Exception e) { return Opt.none(); } } /** {@link #getDatabaseMetadata(EntityManager)} as a function. */ public static final Fn> getDatabaseMetadata = new Fn>() { @Override public Opt apply(EntityManager em) { return getDatabaseMetadata(em); } }; /** * Get the database vendor from some metadata. * * @return {@link DatabaseVendor#UNKNOWN} in case the database is not known or an arbitrary error occurs */ public static DatabaseVendor getVendor(DatabaseMetaData m) { try { switch (m.getDatabaseProductName()) { case "H2": return DatabaseVendor.H2; case "MySQL": return DatabaseVendor.MYSQL; case "Postgres": return DatabaseVendor.POSTGRES; default: return DatabaseVendor.UNKNOWN; } } catch (SQLException e) { return DatabaseVendor.UNKNOWN; } } public enum DatabaseVendor { H2, MYSQL, POSTGRES, UNKNOWN } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy