org.opencastproject.util.persistence.PersistenceUtil Maven / Gradle / Ivy
/**
* 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.persistence;
import static org.opencastproject.util.data.Monadics.mlist;
import static org.opencastproject.util.data.Option.none;
import static org.opencastproject.util.data.Option.option;
import static org.opencastproject.util.data.Option.some;
import org.opencastproject.util.data.Either;
import org.opencastproject.util.data.Function;
import org.opencastproject.util.data.Option;
import org.opencastproject.util.data.Tuple;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.eclipse.persistence.config.PersistenceUnitProperties;
import org.osgi.service.component.ComponentContext;
import java.beans.PropertyVetoException;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.NoResultException;
import javax.persistence.NonUniqueResultException;
import javax.persistence.Query;
import javax.persistence.TemporalType;
import javax.persistence.spi.PersistenceProvider;
import javax.sql.DataSource;
/** Functions supporting persistence. */
/**
* Functions supporting persistence.
*/
public final class PersistenceUtil {
private PersistenceUtil() {
}
public static final Map NO_PERSISTENCE_PROPS = Collections
.unmodifiableMap(new HashMap());
/**
* 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 newEntityManagerFactory(ComponentContext cc, String emName) {
PersistenceProvider persistenceProvider = (PersistenceProvider) cc.locateService("persistence");
final Map persistenceProps;
Map pp = (Map) cc.locateService("persistenceProps");
persistenceProps = pp != null ? pp : Collections.emptyMap();
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 newEntityManagerFactory(ComponentContext cc, String emName, Map persistenceProps) {
PersistenceProvider persistenceProvider = (PersistenceProvider) cc.locateService("persistence");
return persistenceProvider.createEntityManagerFactory(emName, persistenceProps);
}
/** Create a new persistence environment. This method is the preferred way of creating a persitence environment. */
public static PersistenceEnv newPersistenceEnvironment(PersistenceProvider persistenceProvider, String emName,
Map persistenceProps) {
return newPersistenceEnvironment(persistenceProvider.createEntityManagerFactory(emName, persistenceProps));
}
/**
* Shortcut for newPersistenceEnvironment(newEntityManagerFactory(cc, emName, persistenceProps))
.
*
* @see #newEntityManagerFactory(org.osgi.service.component.ComponentContext, String, java.util.Map)
*/
public static PersistenceEnv newPersistenceEnvironment(ComponentContext cc, String emName, Map persistenceProps) {
return newPersistenceEnvironment(newEntityManagerFactory(cc, emName, persistenceProps));
}
/**
* Shortcut for newPersistenceEnvironment(newEntityManagerFactory(cc, emName))
.
*
* @see #newEntityManagerFactory(org.osgi.service.component.ComponentContext, String)
*/
public static PersistenceEnv newPersistenceEnvironment(ComponentContext cc, String emName) {
return newPersistenceEnvironment(newEntityManagerFactory(cc, emName));
}
/** Create a new entity manager or return none, if the factory has already been closed. */
public static Option createEntityManager(EntityManagerFactory emf) {
try {
return some(emf.createEntityManager());
} catch (IllegalStateException ex) {
// factory is already closed
return none();
}
}
/**
* Equip a persistence environment with an exception handler.
*/
public static PersistenceEnv2 equip2(final PersistenceEnv penv, final Function exHandler) {
return new PersistenceEnv2() {
@Override
public Either tx(Function transactional) {
try {
return Either.right(penv.tx(transactional));
} catch (Exception e) {
return Either.left(exHandler.apply(e));
}
}
@Override
public void close() {
penv.close();
}
};
}
/**
* Create a new, concurrently usable persistence environment which uses JPA local transactions.
*
* Transaction propagation is supported on a per thread basis.
*
* @deprecated use {@link PersistenceEnvs#persistenceEnvironment(EntityManagerFactory)}
*/
@Deprecated
public static PersistenceEnv newPersistenceEnvironment(final EntityManagerFactory emf) {
return PersistenceEnvs.persistenceEnvironment(emf);
}
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 Option testConnection(DataSource ds) {
Connection connection = null;
try {
connection = ds.getConnection();
return none();
} catch (SQLException e) {
return some(e);
} finally {
closeQuietly(connection);
}
}
/**
* Create a named query with a list of parameters. Values of type {@link Date} are recognized and set as a timestamp (
* {@link TemporalType#TIMESTAMP}.
*
* @deprecated use {@link Queries#named} query(EntityManager, String, Class, Object[])
*/
@Deprecated
public static Query createNamedQuery(EntityManager em, String queryName, Tuple... params) {
final Query q = em.createNamedQuery(queryName);
for (Tuple p : params) {
final Object value = p.getB();
if (value instanceof Date) {
q.setParameter(p.getA(), (Date) p.getB(), TemporalType.TIMESTAMP);
} else {
q.setParameter(p.getA(), p.getB());
}
}
return q;
}
/**
* Run an update (UPDATE or DELETE) query and ensure that at least one row got affected.
*
* @deprecated use {@link Queries#named} #update(EntityManager, String, Object[])
*/
@Deprecated
public static boolean runUpdate(EntityManager em, String queryName, Tuple... params) {
return createNamedQuery(em, queryName, params).executeUpdate() > 0;
}
/**
* Run a query (SELECT) that should return a single result.
*
* @deprecated use {@link Queries#named} #findSingle(EntityManager, String, Object[])
*/
@Deprecated
public static Option runSingleResultQuery(EntityManager em, String queryName, Tuple... params) {
try {
return some((A) createNamedQuery(em, queryName, params).getSingleResult());
} catch (NoResultException e) {
return none();
} catch (NonUniqueResultException e) {
return none();
}
}
/**
* Run a query that should return the first result of it.
*
* @deprecated use {@link Queries#named} findFirst(EntityManager, String, Object[])
*/
@Deprecated
public static Option runFirstResultQuery(EntityManager em, String queryName, Tuple... params) {
try {
return some((A) createNamedQuery(em, queryName, params).setMaxResults(1).getSingleResult());
} catch (NoResultException e) {
return none();
} catch (NonUniqueResultException e) {
return none();
}
}
/**
* Execute a COUNT(x)
query.
*
* @deprecated use {@link Queries#named} count(EntityManager, String, Object[])
*/
@Deprecated
public static long runCountQuery(EntityManager em, String queryName, Tuple... params) {
return ((Number) createNamedQuery(em, queryName, params).getSingleResult()).longValue();
}
/** @deprecated use {@link Queries#find(Class, Object)} */
@Deprecated
public static Function> findById(final Class clazz, final Object primaryKey) {
return new Function>() {
@Override
public Option apply(EntityManager em) {
return option(em.find(clazz, primaryKey));
}
};
}
/**
* Find a single object.
*
* @param params
* the query parameters
* @param toA
* map to the desired result object
* @deprecated
*/
@Deprecated
public static Option find(EntityManager em, final Function toA, final String queryName,
final Tuple... params) {
return PersistenceUtil. runSingleResultQuery(em, queryName, params).map(toA);
}
/**
* Find multiple objects.
*
* @deprecated use {@link Queries#named} findAll(EntityManager, String, Object[])
*/
@Deprecated
public static List findAll(EntityManager em, final String queryName, final Tuple... params) {
return createNamedQuery(em, queryName, params).getResultList();
}
/**
* Find multiple objects with optional pagination.
*
* @deprecated use {@link Queries#named} findAll(EntityManager, String, Option, Option, Object[])
*/
@Deprecated
public static List findAll(EntityManager em, final String queryName, Option offset,
Option limit, final Tuple... params) {
final Query q = createNamedQuery(em, queryName, params);
for (Integer x : offset)
q.setFirstResult(x);
for (Integer x : limit)
q.setMaxResults(x);
return q.getResultList();
}
/**
* Find multiple objects.
*
* @param params
* the query parameters
* @param toA
* map to the desired result object
* @deprecated use {@link Queries#named} findAll(EntityManager, String, Object[]) instead
*/
@Deprecated
public static List findAll(EntityManager em, final Function toA, final String queryName,
final Tuple... params) {
return mlist((List) createNamedQuery(em, queryName, params).getResultList()).map(toA).value();
}
/**
* Find multiple objects with optional pagination.
*
* @param params
* the query parameters
* @param toA
* map to the desired result object
* @deprecated use {@link Queries#named} findAll(EntityManager, String, Option, Option, Object[]) instead
*/
@Deprecated
public static List findAll(EntityManager em, final Function toA, Option offset,
Option limit, final String queryName, final Tuple... params) {
final Query q = createNamedQuery(em, queryName, params);
for (Integer x : offset)
q.setFirstResult(x);
for (Integer x : limit)
q.setMaxResults(x);
return mlist((List) q.getResultList()).map(toA).value();
}
/**
* Create function to persist object a
using {@link EntityManager#persist(Object)}.
*
* @deprecated use {@link Queries#persist(Object)}
*/
@Deprecated
public static Function persist(final A a) {
return new Function() {
@Override
public A apply(EntityManager em) {
em.persist(a);
return a;
}
};
}
/**
* Create function to merge an object a
with the persisten context of the given entity manage.
*
* @deprecated use {@link Queries#merge(Object)}
*/
@Deprecated
public static Function merge(final A a) {
return new Function() {
@Override
public A apply(EntityManager em) {
em.merge(a);
return a;
}
};
}
public static EntityManagerFactory newEntityManagerFactory(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 factory backed by an in-memory H2 database for testing purposes.
*
* @param emName
* name of the persistence unit (see META-INF/persistence.xml)
*/
public static EntityManagerFactory newTestEntityManagerFactory(String emName) {
Map persistenceProperties = new HashMap<>();
persistenceProperties.put(PersistenceUnitProperties.DDL_GENERATION, PersistenceUnitProperties.DROP_AND_CREATE);
persistenceProperties.put(PersistenceUnitProperties.DDL_GENERATION_MODE, PersistenceUnitProperties.DDL_DATABASE_GENERATION);
return newEntityManagerFactory(emName, "Auto", "org.h2.Driver", "jdbc:h2:./target/db" + System.currentTimeMillis(),
"sa", "sa", persistenceProperties, testPersistenceProvider());
}
/** Create a new persistence provider for unit tests. */
public static PersistenceProvider testPersistenceProvider() {
return new org.eclipse.persistence.jpa.PersistenceProvider();
}
/**
* Create a new persistence environment based on an 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)
* @deprecated use {@link PersistenceEnvs#testPersistenceEnv(String)}
*/
@Deprecated
public static PersistenceEnv newTestPersistenceEnv(String emName) {
return newPersistenceEnvironment(newTestEntityManagerFactory(emName));
}
}