blob: f122d54fa3e632f6b8efad29d4c6de007bd43e29 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. The ASF licenses this file to You
* 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. For additional information regarding
* copyright in this work, please see the NOTICE file in the top level
* directory of this distribution.
*/
package org.apache.roller.weblogger.business.jpa;
import java.util.Collection;
import java.util.Enumeration;
import java.util.Properties;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.roller.weblogger.WebloggerException;
import org.apache.roller.weblogger.config.WebloggerConfig;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityManager;
import javax.persistence.FlushModeType;
import javax.persistence.Persistence;
import javax.persistence.PersistenceException;
import javax.persistence.Query;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.persistence.TypedQuery;
import org.apache.roller.weblogger.business.DatabaseProvider;
/**
* Responsible for the lowest-level interaction with the JPA API.
*/
@com.google.inject.Singleton
public class JPAPersistenceStrategy {
private static Log logger =
LogFactory.getFactory().getInstance(JPAPersistenceStrategy.class);
/**
* The thread local EntityManager.
*/
private final ThreadLocal<EntityManager> threadLocalEntityManager = new ThreadLocal<EntityManager>();
/**
* The EntityManagerFactory for this Roller instance.
*/
private EntityManagerFactory emf = null;
/**
* Construct by finding JPA EntityManagerFactory.
* @param dbProvider database configuration information for manual configuration.
* @throws org.apache.roller.weblogger.WebloggerException on any error
*/
@com.google.inject.Inject
protected JPAPersistenceStrategy(DatabaseProvider dbProvider) throws WebloggerException {
String jpaConfigurationType = WebloggerConfig.getProperty("jpa.configurationType");
if ("jndi".equals(jpaConfigurationType)) {
// Lookup EMF via JNDI: added for Geronimo
String emfJndiName = "java:comp/env/" + WebloggerConfig.getProperty("jpa.emf.jndi.name");
try {
emf = (EntityManagerFactory) new InitialContext().lookup(emfJndiName);
} catch (NamingException e) {
throw new WebloggerException("Could not look up EntityManagerFactory in jndi at " + emfJndiName, e);
}
} else {
// Add all JPA, OpenJPA, HibernateJPA, etc. properties found
Properties emfProps = new Properties();
Enumeration keys = WebloggerConfig.keys();
while (keys.hasMoreElements()) {
String key = (String) keys.nextElement();
if ( key.startsWith("javax.persistence.")
|| key.startsWith("openjpa.")
|| key.startsWith("eclipselink.")
|| key.startsWith("hibernate.")) {
String value = WebloggerConfig.getProperty(key);
logger.info(key + ": " + value);
emfProps.setProperty(key, value);
}
}
if (dbProvider.getType() == DatabaseProvider.ConfigurationType.JNDI_NAME) {
emfProps.setProperty("javax.persistence.nonJtaDataSource", dbProvider.getFullJndiName());
} else {
emfProps.setProperty("javax.persistence.jdbc.driver", dbProvider.getJdbcDriverClass());
emfProps.setProperty("javax.persistence.jdbc.url", dbProvider.getJdbcConnectionURL());
emfProps.setProperty("javax.persistence.jdbc.user", dbProvider.getJdbcUsername());
emfProps.setProperty("javax.persistence.jdbc.password", dbProvider.getJdbcPassword());
}
try {
this.emf = Persistence.createEntityManagerFactory("RollerPU", emfProps);
} catch (Exception pe) {
logger.error("ERROR: creating entity manager", pe);
throw new WebloggerException(pe);
}
}
}
/**
* Refresh changes to the current object.
*
* @throws org.apache.roller.weblogger.WebloggerException on any error
*/
public void refresh(Object clazz) throws WebloggerException {
if (clazz == null) {
return;
}
try {
EntityManager em = getEntityManager(true);
em.refresh(clazz);
} catch (Exception e) {
// ignored;
}
}
/**
* Flush changes to the datastore, commit transaction, release em.
* @throws org.apache.roller.weblogger.WebloggerException on any error
*/
public void flush() throws WebloggerException {
try {
EntityManager em = getEntityManager(true);
em.getTransaction().commit();
} catch (PersistenceException pe) {
throw new WebloggerException(pe);
}
}
/**
* Release database session, rolls back any uncommitted changes.
*/
public void release() {
try {
EntityManager em = getEntityManager(false);
if (isTransactionActive(em)) {
em.getTransaction().rollback();
}
em.close();
} catch (Exception e) {
logger.debug("error during releasing database session", e);
} finally {
threadLocalEntityManager.remove();
}
}
/**
* Store object using an existing transaction.
* @param obj the object to persist
* @return the object persisted
* @throws org.apache.roller.weblogger.WebloggerException on any error
*/
public Object store(Object obj) throws WebloggerException {
EntityManager em = getEntityManager(true);
if (!em.contains(obj)) {
// If entity is not managed we can assume it is new
em.persist(obj);
}
return obj;
}
/**
* Remove object from persistence storage.
* @param clazz the class of object to remove
* @param id the id of the object to remove
* @throws WebloggerException on any error deleting object
*/
public void remove(Class clazz, String id) throws WebloggerException {
EntityManager em = getEntityManager(true);
Object po = em.find(clazz, id);
em.remove(po);
}
/**
* Remove object from persistence storage.
* @param po the persistent object to remove
* @throws org.apache.roller.weblogger.WebloggerException on any error
*/
public void remove(Object po) throws WebloggerException {
EntityManager em = getEntityManager(true);
em.remove(po);
}
/**
* Remove object from persistence storage.
* @param pos the persistent objects to remove
* @throws org.apache.roller.weblogger.WebloggerException on any error
*/
public void removeAll(Collection pos) throws WebloggerException {
EntityManager em = getEntityManager(true);
for (Object obj : pos) {
em.remove(obj);
}
}
/**
* Retrieve object, no transaction needed.
* @param clazz the class of object to retrieve
* @param id the id of the object to retrieve
* @return the object retrieved
* @throws WebloggerException on any error retrieving object
*/
public Object load(Class clazz, String id)
throws WebloggerException {
EntityManager em = getEntityManager(false);
return em.find(clazz, id);
}
/**
* Return true if a transaction is active on the current EntityManager.
* @param em the persistence manager
* @return true if the persistence manager is not null and has an active
* transaction
*/
private boolean isTransactionActive(EntityManager em) {
return em != null && em.getTransaction().isActive();
}
/**
* Get the EntityManager associated with the current thread of control.
* @param isTransactionRequired true if a transaction is begun if not
* already active
* @return the EntityManager
*/
public EntityManager getEntityManager(boolean isTransactionRequired) {
EntityManager em = getThreadLocalEntityManager();
if (isTransactionRequired && !em.getTransaction().isActive()) {
em.getTransaction().begin();
}
return em;
}
/**
* Get the current ThreadLocal EntityManager
*/
private EntityManager getThreadLocalEntityManager() {
EntityManager em = threadLocalEntityManager.get();
if (em == null) {
em = emf.createEntityManager();
threadLocalEntityManager.set(em);
}
return em;
}
/**
* Get named query that won't commit changes to DB first (FlushModeType.COMMIT)
* @param queryName the name of the query
* @throws org.apache.roller.weblogger.WebloggerException on any error
*/
public Query getNamedQuery(String queryName)
throws WebloggerException {
EntityManager em = getEntityManager(false);
Query q = em.createNamedQuery(queryName);
// For performance, never flush/commit prior to running queries.
// Roller code assumes this behavior
q.setFlushMode(FlushModeType.COMMIT);
return q;
}
/**
* Get named TypedQuery that won't commit changes to DB first (FlushModeType.COMMIT)
* Preferred over getNamedQuery(String) due to it being typesafe.
* @param queryName the name of the query
* @param resultClass return type of query
* @throws org.apache.roller.weblogger.WebloggerException on any error
*/
public <T> TypedQuery<T> getNamedQuery(String queryName, Class<T> resultClass)
throws WebloggerException {
EntityManager em = getEntityManager(false);
TypedQuery<T> q = em.createNamedQuery(queryName, resultClass);
// For performance, never flush/commit prior to running queries.
// Roller code assumes this behavior
q.setFlushMode(FlushModeType.COMMIT);
return q;
}
/**
* Get named query with default flush mode (usually FlushModeType.AUTO)
* FlushModeType.AUTO commits changes to DB prior to running statement
*
* @param queryName the name of the query
* @param resultClass return type of query
* @throws org.apache.roller.weblogger.WebloggerException on any error
*/
public <T> TypedQuery<T> getNamedQueryCommitFirst(String queryName, Class<T> resultClass)
throws WebloggerException {
EntityManager em = getEntityManager(true);
return em.createNamedQuery(queryName, resultClass);
}
/**
* Create query from queryString that won't commit changes to DB first (FlushModeType.COMMIT)
* @param queryString the query
* @throws org.apache.roller.weblogger.WebloggerException on any error
*/
public Query getDynamicQuery(String queryString)
throws WebloggerException {
EntityManager em = getEntityManager(false);
Query q = em.createQuery(queryString);
// For performance, never flush/commit prior to running queries.
// Roller code assumes this behavior
q.setFlushMode(FlushModeType.COMMIT);
return q;
}
/**
* Create TypedQuery from queryString that won't commit changes to DB first (FlushModeType.COMMIT)
* Preferred over getDynamicQuery(String) due to it being typesafe.
* @param queryString the query
* @param resultClass return type of query
* @throws org.apache.roller.weblogger.WebloggerException on any error
*/
public <T> TypedQuery<T> getDynamicQuery(String queryString, Class<T> resultClass)
throws WebloggerException {
EntityManager em = getEntityManager(false);
TypedQuery<T> q = em.createQuery(queryString, resultClass);
// For performance, never flush/commit prior to running queries.
// Roller code assumes this behavior
q.setFlushMode(FlushModeType.COMMIT);
return q;
}
/**
* Get named update query with default flush mode (usually FlushModeType.AUTO)
* FlushModeType.AUTO commits changes to DB prior to running statement
* @param queryName the name of the query
* @throws org.apache.roller.weblogger.WebloggerException on any error
*/
public Query getNamedUpdate(String queryName)
throws WebloggerException {
EntityManager em = getEntityManager(true);
return em.createNamedQuery(queryName);
}
public void shutdown() {
if (emf != null) {
emf.close();
}
}
}