Author: snoopdave Date: Thu May 24 15:14:14 2007 New Revision: 541450 URL: http://svn.apache.org/viewvc?view=rev&rev=541450 Log: New JPA backend merge: new "core" component with shared DB code
Added: roller/trunk/components/ roller/trunk/components/core/ roller/trunk/components/core/build/ roller/trunk/components/core/build.properties roller/trunk/components/core/build.xml roller/trunk/components/core/build/compile/ roller/trunk/components/core/build/compile/business/ roller/trunk/components/core/build/compile/business/org/ roller/trunk/components/core/build/compile/business/org/apache/ roller/trunk/components/core/build/compile/business/org/apache/roller/ roller/trunk/components/core/build/compile/business/org/apache/roller/business/ roller/trunk/components/core/build/compile/business/org/apache/roller/business/hibernate/ roller/trunk/components/core/build/compile/business/org/apache/roller/business/jpa/ roller/trunk/components/core/build/compile/business/org/apache/roller/util/ roller/trunk/components/core/build/lib/ roller/trunk/components/core/dist/ roller/trunk/components/core/src/ roller/trunk/components/core/src/java/ roller/trunk/components/core/src/java/org/ roller/trunk/components/core/src/java/org/apache/ roller/trunk/components/core/src/java/org/apache/roller/ roller/trunk/components/core/src/java/org/apache/roller/RollerException.java roller/trunk/components/core/src/java/org/apache/roller/business/ roller/trunk/components/core/src/java/org/apache/roller/business/hibernate/ roller/trunk/components/core/src/java/org/apache/roller/business/hibernate/HibernatePersistenceStrategy.java roller/trunk/components/core/src/java/org/apache/roller/business/hibernate/ThreadLocalSessionContextNoAutoClose.java roller/trunk/components/core/src/java/org/apache/roller/business/jpa/ roller/trunk/components/core/src/java/org/apache/roller/business/jpa/JPAPersistenceStrategy.java roller/trunk/components/core/src/java/org/apache/roller/util/ roller/trunk/components/core/src/java/org/apache/roller/util/UUIDGenerator.java Added: roller/trunk/components/core/build.properties URL: http://svn.apache.org/viewvc/roller/trunk/components/core/build.properties?view=auto&rev=541450 ============================================================================== --- roller/trunk/components/core/build.properties (added) +++ roller/trunk/components/core/build.properties Thu May 24 15:14:14 2007 @@ -0,0 +1,9 @@ + +# compile properties +build.debug=true +build.sourcelevel=1.4 +build.deprecation=false + +# unit test properties +junit.fork=true +junit.haltonerror=false Added: roller/trunk/components/core/build.xml URL: http://svn.apache.org/viewvc/roller/trunk/components/core/build.xml?view=auto&rev=541450 ============================================================================== --- roller/trunk/components/core/build.xml (added) +++ roller/trunk/components/core/build.xml Thu May 24 15:14:14 2007 @@ -0,0 +1,129 @@ +<?xml version="1.0"?> +<!-- + 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. +--> +<project name="Roller Core" default="build" basedir="."> + + <description>Build core Roller utils.</description> + + <property file="build.properties" /> + + <!-- core properties --> + <property name="build" value="${basedir}/build" /> + <property name="dist" value="${basedir}/dist" /> + <property name="src" value="${basedir}/src/java" /> + <property name="tools" value="${basedir}/../../tools" /> + + <!-- build properties --> + <property name="build.compile" value="${build}/compile"/> + <property name="build.compile.business" value="${build.compile}/business"/> + <property name="build.compile.test" value="${build.compile}/test"/> + <property name="build.lib" value="${build}/lib"/> + + <fileset id="core-jars" dir="${tools}"> + <!-- General dependencies --> + <include name="lib/jdom.jar"/> + <include name="lib/commons-codec-1.3.jar"/> + <include name="lib/log4j-1.2.11.jar"/> + <include name="lib/jaxen-full.jar"/> + <include name="lib/saxpath.jar"/> + <include name="lib/commons-lang-2.1.jar"/> + <include name="lib/commons-logging-1.0.4.jar"/> + <include name="struts-2.0.5/lib/antlr-2.7.2.jar"/> + <include name="struts-1.2.4/lib/commons-fileupload.jar"/> + <include name="struts-1.2.4/lib/commons-validator.jar"/> + <include name="struts-1.2.4/lib/commons-collections.jar"/> + <include name="lib/commons-id-0.1-SNAPSHOT.jar"/> + <include name="buildtime/activation.jar"/> + <include name="buildtime/mail.jar"/> + + <!-- needed for Hibernate --> + <include name="hibernate-3.1/hibernate3.jar"/> + <include name="hibernate-3.1/lib/antlr.jar"/> + <include name="hibernate-3.1/lib/asm.jar"/> + <include name="hibernate-3.1/lib/asm-attrs.jar"/> + <include name="hibernate-3.1/lib/cglib-2.1.3.jar"/> + <include name="hibernate-3.1/lib/ehcache-1.1.jar"/> + <include name="hibernate-3.1/lib/dom4j-1.6.1.jar"/> + <include name="hibernate-3.1/lib/jta.jar"/> + <include name="hibernate-3.1/lib/jdbc2_0-stdext.jar"/> + + <!-- needed for JPA --> + <include name="toplink-essentials-9.1/toplink-essentials.jar"/> + + </fileset> + + <path id="core.path"> + <fileset refid="core-jars" /> + </path> + + <!-- ============================================== --> + <!-- clean out any contents from last build --> + <target name="clean" description="Clean (i.e. remove) build and dist dirs"> + <delete dir="${build}" /> + <delete dir="${dist}" /> + </target> + + + <!-- ============================================== --> + <!-- build all code --> + <target name="build" depends="build-business" > + </target> + + <!-- build the business layer code and jar it up --> + <target name="build-business"> + + <!-- compile planet classes --> + <mkdir dir="${build.compile.business}"/> + <javac destdir="${build.compile.business}" + debug="${build.debug}" + source="${build.sourcelevel}" + deprecation="${build.deprecation}"> + + <src path="${src}" /> + + <classpath> + <path refid="core.path"/> + </classpath> + </javac> + + <!-- Copy resources --> + <copy todir="${build.compile.business}"> + <fileset dir="${src}" excludes="**/*.java, **/*.html, **/*.png" /> + </copy> + + <!-- Jar up the business layer --> + <mkdir dir="${build.lib}"/> + <jar basedir="${build.compile.business}" + jarfile="${build.lib}/roller-core.jar"/> + + </target> + + + <!-- ============================================== --> + <!-- create distributable components --> + <target name="dist" depends="build-business" description="Create Roller core distributables"> + + <!-- distributable libraries --> + <mkdir dir="${dist}/lib" /> + <copy todir="${dist}/lib" > + <fileset dir="${build.lib}" /> + </copy> + + </target> + +</project> Added: roller/trunk/components/core/src/java/org/apache/roller/RollerException.java URL: http://svn.apache.org/viewvc/roller/trunk/components/core/src/java/org/apache/roller/RollerException.java?view=auto&rev=541450 ============================================================================== --- roller/trunk/components/core/src/java/org/apache/roller/RollerException.java (added) +++ roller/trunk/components/core/src/java/org/apache/roller/RollerException.java Thu May 24 15:14:14 2007 @@ -0,0 +1,135 @@ +/* + * 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; + +import java.io.PrintStream; +import java.io.PrintWriter; + + +/** + * Base Roller exception class. + */ +public class RollerException extends Exception { + + private Throwable mRootCause = null; + + + /** + * Construct emtpy exception object. + */ + public RollerException() { + super(); + } + + + /** + * Construct RollerException with message string. + * @param s Error message string. + */ + public RollerException(String s) { + super(s); + } + + + /** + * Construct RollerException, wrapping existing throwable. + * @param s Error message + * @param t Existing connection to wrap. + */ + public RollerException(String s, Throwable t) { + super(s); + mRootCause = t; + } + + + /** + * Construct RollerException, wrapping existing throwable. + * @param t Existing exception to be wrapped. + */ + public RollerException(Throwable t) { + mRootCause = t; + } + + + /** + * Get root cause object, or null if none. + * @return Root cause or null if none. + */ + public Throwable getRootCause() { + return mRootCause; + } + + + /** + * Get root cause message. + * @return Root cause message. + */ + public String getRootCauseMessage() { + String rcmessage = null; + if (getRootCause()!=null) { + if (getRootCause().getCause()!=null) { + rcmessage = getRootCause().getCause().getMessage(); + } + rcmessage = (rcmessage == null) ? getRootCause().getMessage() : rcmessage; + rcmessage = (rcmessage == null) ? super.getMessage() : rcmessage; + rcmessage = (rcmessage == null) ? "NONE" : rcmessage; + } + return rcmessage; + } + + + /** + * Print stack trace for exception and for root cause exception if htere is one. + * @see java.lang.Throwable#printStackTrace() + */ + public void printStackTrace() { + super.printStackTrace(); + if (mRootCause != null) { + System.out.println("--- ROOT CAUSE ---"); + mRootCause.printStackTrace(); + } + } + + + /** + * Print stack trace for exception and for root cause exception if htere is one. + * @param s Stream to print to. + */ + public void printStackTrace(PrintStream s) { + super.printStackTrace(s); + if (mRootCause != null) { + s.println("--- ROOT CAUSE ---"); + mRootCause.printStackTrace(s); + } + } + + + /** + * Print stack trace for exception and for root cause exception if htere is one. + * @param s Writer to write to. + */ + public void printStackTrace(PrintWriter s) { + super.printStackTrace(s); + if (null != mRootCause) { + s.println("--- ROOT CAUSE ---"); + mRootCause.printStackTrace(s); + } + } + +} Added: roller/trunk/components/core/src/java/org/apache/roller/business/hibernate/HibernatePersistenceStrategy.java URL: http://svn.apache.org/viewvc/roller/trunk/components/core/src/java/org/apache/roller/business/hibernate/HibernatePersistenceStrategy.java?view=auto&rev=541450 ============================================================================== --- roller/trunk/components/core/src/java/org/apache/roller/business/hibernate/HibernatePersistenceStrategy.java (added) +++ roller/trunk/components/core/src/java/org/apache/roller/business/hibernate/HibernatePersistenceStrategy.java Thu May 24 15:14:14 2007 @@ -0,0 +1,204 @@ +/* + * 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.business.hibernate; + +import java.io.StringBufferInputStream; +import java.util.Properties; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.hibernate.HibernateException; +import org.hibernate.Session; +import org.hibernate.SessionFactory; +import org.hibernate.Transaction; +import org.hibernate.cfg.Configuration; +import org.apache.roller.RollerException; +import org.hibernate.cfg.Environment; +import org.xml.sax.EntityResolver; +import org.xml.sax.InputSource; + + +/** + * Base class for Hibernate persistence implementation. + * + * This class serves as a helper/util class for all of the Hibernate + * manager implementations by providing a set of basic persistence methods + * that can be easily reused. + */ +public class HibernatePersistenceStrategy { + + static final long serialVersionUID = 2561090040518169098L; + + protected static SessionFactory sessionFactory = null; + + private static Log log = LogFactory.getLog(HibernatePersistenceStrategy.class); + + /** No-op so XML parser doesn't hit the network looking for Hibernate DTDs */ + private EntityResolver noOpEntityResolver = new EntityResolver() { + public InputSource resolveEntity(String publicId, String systemId) { + return new InputSource(new StringBufferInputStream("")); + } + }; + + /** + * Persistence strategy configures itself by using Roller properties: + * 'hibernate.configResource' - the resource name of Roller's Hibernate XML configuration file, + * 'hibernate.dialect' - the classname of the Hibernate dialect to be used, + * 'hibernate.connectionProvider - the classname of Roller's connnection provider impl. + */ + public HibernatePersistenceStrategy(String configResource, String dialect, String connectionProvider) { + + // Read Hibernate config file specified by Roller config + Configuration config = new Configuration(); + config.configure(configResource); + + // Add dialect specified by Roller config and our connection provider + Properties props = new Properties(); + props.put(Environment.DIALECT, dialect); + props.put(Environment.CONNECTION_PROVIDER, connectionProvider); + config.mergeProperties(props); + + this.sessionFactory = config.buildSessionFactory(); + } + + + /** + * Get persistence session on current thread. + * + * This will open a new Session if one is not already open, otherwise + * it will return the already open Session. + */ + public Session getSession() { + + log.debug("Obtaining Hibernate Session"); + + // get Hibernate Session and make sure we are in a transaction + // this will join existing Session/Transaction if they exist + Session session = sessionFactory.getCurrentSession(); + session.beginTransaction(); + + return session; + } + + + public void flush() throws RollerException { + + Session session = getSession(); + try { + // first lets flush the current state to the db + log.debug("Flushing Hibernate Session"); + session.flush(); + + // then commit the current transaction to finish it + log.debug("Committing Hibernate Transaction"); + session.getTransaction().commit(); + + } catch(Throwable t) { + // uh oh ... failed persisting, gotta release + release(); + + // wrap and rethrow so caller knows something bad happened + throw new RollerException(t); + } + } + + + /** + * Release database session, rollback any uncommitted changes. + * + * IMPORTANT: we don't want to open a transaction and force the use of a + * jdbc connection just to close the session and do a rollback, so this + * method must be sensitive about how the release is triggered. + * + * In particular we don't want to use our custom getSession() method which + * automatically begins a transaction. Instead we get a Session and check + * if there is already an active transaction that needs to be rolled back. + * If not then we can close the Session without ever getting a jdbc + * connection, which is important for scalability. + */ + public void release() { + + try { + Session session = sessionFactory.getCurrentSession(); + + if(session != null && session.isOpen()) { + + log.debug("Closing Hibernate Session"); + + try { + Transaction tx = session.getTransaction(); + + if(tx != null && tx.isActive()) { + log.debug("Forcing rollback on active transaction"); + tx.rollback(); + } + } catch(Throwable t) { + log.error("ERROR doing Hibernate rollback", t); + } finally { + if(session.isOpen()) { + session.close(); + } + } + } + } catch(Throwable t) { + log.error("ERROR closing Hibernate Session", t); + } + } + + + /** + * Retrieve object. We return null if the object is not found. + */ + public Object load(String id, Class clazz) throws RollerException { + + if(id == null || clazz == null) { + throw new RollerException("Cannot load objects when value is null"); + } + + return (Object) getSession().get(clazz, id); + } + + + /** + * Store object. + */ + public void store(Object obj) throws HibernateException { + + if(obj == null) { + throw new HibernateException("Cannot save null object"); + } + + Session session = getSession(); + + session.saveOrUpdate(obj); + } + + + /** + * Remove object. + */ + public void remove(Object obj) throws HibernateException { + + if(obj == null) { + throw new HibernateException("Cannot remove null object"); + } + + getSession().delete(obj); + } + +} Added: roller/trunk/components/core/src/java/org/apache/roller/business/hibernate/ThreadLocalSessionContextNoAutoClose.java URL: http://svn.apache.org/viewvc/roller/trunk/components/core/src/java/org/apache/roller/business/hibernate/ThreadLocalSessionContextNoAutoClose.java?view=auto&rev=541450 ============================================================================== --- roller/trunk/components/core/src/java/org/apache/roller/business/hibernate/ThreadLocalSessionContextNoAutoClose.java (added) +++ roller/trunk/components/core/src/java/org/apache/roller/business/hibernate/ThreadLocalSessionContextNoAutoClose.java Thu May 24 15:14:14 2007 @@ -0,0 +1,130 @@ +/* + * 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.business.hibernate; + +import org.hibernate.FlushMode; +import org.hibernate.SessionFactory; +import org.hibernate.classic.Session; +import org.hibernate.context.ThreadLocalSessionContext; +import org.hibernate.engine.SessionFactoryImplementor; + + +/** + * This is a special Hibernate SessionContext which was taken from the Hibernate forums so that we can use it + * to provide a way to commit our transactions while keeping the Session open for further use. Details here ... + * + * http://forum.hibernate.org/viewtopic.php?t=958752 + * + * ... which was found from a reference here ... + * + * http://forum.hibernate.org/viewtopic.php?t=957056 + * + * Extends [EMAIL PROTECTED] ThreadLocalSessionContext} to allow for long conversations. It achieves this by setting every + * <code>Session</code> it produces to <code>FlushMode.NEVER</code> so that it won't flush unless explicitly asked + * to, and by preventing the session from auto-closing or unbinding from the thread after a <code>Transaction</code> + * commit. Note that this means the application code must do these functions manually as needed! + */ +public class ThreadLocalSessionContextNoAutoClose extends ThreadLocalSessionContext { + + /** + * Create a new instance. + * + * @param factory The <code>SessionFactoryImplementor</code> required by the super constructor. + */ + public ThreadLocalSessionContextNoAutoClose(SessionFactoryImplementor factory) { + super(factory); + } + + + /** + * Returns <code>false</code> to prevent auto closing. + * + * @return <code>false</code> to prevent auto closing. + */ + protected boolean isAutoCloseEnabled() { + return false; + } + + + /** + * Returns <code>false</code> to prevent auto flushing. + * + * @return <code>false</code> to prevent auto flushing. + */ + protected boolean isAutoFlushEnabled() { + return false; + } + + + /** + * Uses <code>super.buildOrObtainSession()</code>, then sets the resulting <code>Session</code>'s flush mode + * to <code>FlushMode.NEVER</code> to prevent auto-flushing. + * + * @return A session configured with <code>FlushMode.NEVER</code>. + */ + protected Session buildOrObtainSession() { + Session s = super.buildOrObtainSession(); + s.setFlushMode(FlushMode.NEVER); + return s; + } + + + /** + * Returns an instance of <code>CleanupSynch</code> which prevents auto closing and unbinding. + * + * @return A <code>CleanupSynch</code> which prevents auto closing and unbinding. + */ + protected CleanupSynch buildCleanupSynch() { + return new NoCleanupSynch(factory); + } + + + /** + * A simple extension of <code>CleanupSynch</code> that prevents any cleanup from happening. No session closing or + * unbinding. + */ + private static class NoCleanupSynch extends ThreadLocalSessionContext.CleanupSynch { + + /** + * Creates a new instance based on the given factory. + * + * @param factory The required <code>SessionFactory</code> that is passed to the super constructor. + */ + public NoCleanupSynch(SessionFactory factory) { + super(factory); + } + + /** + * Does nothing, thus helping to prevent session closing and/or unbinding. + */ + public void beforeCompletion() { + // do nothing + } + + /** + * Does nothing, thus helping to prevent session closing and/or unbinding. + * + * @param i + */ + public void afterCompletion(int i) { + // do nothing + } + } + +} Added: roller/trunk/components/core/src/java/org/apache/roller/business/jpa/JPAPersistenceStrategy.java URL: http://svn.apache.org/viewvc/roller/trunk/components/core/src/java/org/apache/roller/business/jpa/JPAPersistenceStrategy.java?view=auto&rev=541450 ============================================================================== --- roller/trunk/components/core/src/java/org/apache/roller/business/jpa/JPAPersistenceStrategy.java (added) +++ roller/trunk/components/core/src/java/org/apache/roller/business/jpa/JPAPersistenceStrategy.java Thu May 24 15:14:14 2007 @@ -0,0 +1,375 @@ + +/* + * 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.business.jpa; + +import java.util.Collection; +import java.util.Properties; +import java.util.Iterator; +import java.util.Enumeration; +import java.util.Properties; +import java.io.InputStream; +import java.io.IOException; +import java.security.AccessController; +import java.security.PrivilegedAction; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.roller.RollerException; +import javax.persistence.EntityManagerFactory; +import javax.persistence.EntityManager; +import javax.persistence.FlushModeType; +import javax.persistence.Persistence; +import javax.persistence.PersistenceException; +import javax.persistence.Query; + +/** + * JPAPersistenceStrategy is responsible for the lowest-level interaction with + * the JPA API. + */ +// TODO handle PersistenceExceptions! +public class JPAPersistenceStrategy { + + /** + * The thread local EntityManager. + */ + private final ThreadLocal threadLocalEntityManager = new ThreadLocal(); + + /** + * The EntityManagerFactory for this Roller instance. + */ + private EntityManagerFactory emf = null; + + /** + * The logger instance for this class. + */ + private static Log logger = LogFactory.getFactory().getInstance( + JPAPersistenceStrategy.class); + + /** + * Construct by finding JPA EntityManagerFactory. + * @throws org.apache.roller.RollerException on any error + */ + public JPAPersistenceStrategy( + String puName, + String jndiName, + Properties properties) throws RollerException { + + // set strategy used by Datamapper + // You can configure JPA completely via the JPAEMF.properties file + Properties emfProps = loadPropertiesFromResourceName( + "JPAEMF.properties", getContextClassLoader()); + + // Add additional properties passed in + Enumeration keys = properties.keys(); + while (keys.hasMoreElements()) { + String key = (String)keys.nextElement(); + String value = properties.getProperty(key); + logger.info(key + ": " + value); + emfProps.setProperty(key, value); + } + + emfProps.setProperty("openjpa.ConnectionFactoryName", jndiName); + + try { + this.emf = Persistence.createEntityManagerFactory(puName, emfProps); + } catch (PersistenceException pe) { + logger.error("ERROR: creating entity manager", pe); + throw new RollerException(pe); + } + } + + /** + * Construct by finding JPA EntityManagerFactory. + * @throws org.apache.roller.RollerException on any error + */ + public JPAPersistenceStrategy( + String puName, + String driverClass, + String connectonUrl, + String username, + String password, + Properties properties) throws RollerException { + + logger.info("driverClass: " + driverClass); + logger.info("connectionURL: " + connectonUrl); + logger.info("username: " + username); + + // set strategy used by Datamapper + // You can configure JPA completely via the JPAEMF.properties file + Properties emfProps = loadPropertiesFromResourceName( + "JPAEMF.properties", getContextClassLoader()); + + // Add additional properties passed in + Enumeration keys = properties.keys(); + while (keys.hasMoreElements()) { + String key = (String)keys.nextElement(); + String value = properties.getProperty(key); + logger.info(key + ": " + value); + emfProps.setProperty(key, value); + } + + // Try to please all the players + emfProps.setProperty("openjpa.ConnectionDriverName", driverClass); + emfProps.setProperty("openjpa.ConnectionURL", connectonUrl); + emfProps.setProperty("openjpa.ConnectionUserName", username); + emfProps.setProperty("openjpa.ConnectionPassword", password); + + emfProps.setProperty("toplink.jdbc.driver", driverClass); + emfProps.setProperty("toplink.jdbc.url", connectonUrl); + emfProps.setProperty("toplink.jdbc.user", username); + emfProps.setProperty("toplink.jdbc.password", password); + + emfProps.setProperty("hibernate.connection.driver_class",driverClass); + emfProps.setProperty("hibernate.connection.url", connectonUrl); + emfProps.setProperty("hibernate.connection.username", username); + emfProps.setProperty("hibernate.connection.password", password); + + try { + this.emf = Persistence.createEntityManagerFactory(puName, emfProps); + } catch (PersistenceException pe) { + logger.error("ERROR: creating entity manager", pe); + throw new RollerException(pe); + } + } + + /** + * Flush changes to the datastore, commit transaction, release em. + * @throws org.apache.roller.RollerException on any error + */ + public void flush() throws RollerException { + try { + EntityManager em = getEntityManager(true); + em.getTransaction().commit(); + } catch (PersistenceException pe) { + throw new RollerException(pe); + } + } + + /** + * Release database session, rolls back any uncommitted changes. + */ + public void release() { + EntityManager em = getEntityManager(false); + if (isTransactionActive(em)) { + em.getTransaction().rollback(); + } + em.close(); + setThreadLocalEntityManager(null); + } + + /** + * Store object using an existing transaction. + * @param obj the object to persist + * @return the object persisted + * @throws org.apache.roller.RollerException on any error + */ + public Object store(Object obj) throws RollerException { + 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 RollerException on any error deleting object + */ + public void remove(Class clazz, String id) throws RollerException { + 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.RollerException on any error + */ + public void remove(Object po) throws RollerException { + EntityManager em = getEntityManager(true); + em.remove(po); + } + + /** + * Remove object from persistence storage. + * @param pos the persistent objects to remove + * @throws org.apache.roller.RollerException on any error + */ + public void removeAll(Collection pos) throws RollerException { + EntityManager em = getEntityManager(true); + for (Iterator iterator = pos.iterator(); iterator.hasNext();) { + Object obj = iterator.next(); + 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 RollerException on any error retrieving object + */ + public Object load(Class clazz, String id) + throws RollerException { + 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) { + if (em == null) { + return false; + } + return 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 + */ + private 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 = (EntityManager) threadLocalEntityManager.get(); + if (em == null) { + em = emf.createEntityManager(); + threadLocalEntityManager.set(em); + } + return em; + } + + /** + * Set the current ThreadLocal EntityManager + */ + private void setThreadLocalEntityManager(Object em) { + threadLocalEntityManager.set(em); + } + + /** + * Get named query with FlushModeType.COMMIT + * @param clazz the class of instances to find + * @param queryName the name of the query + * @throws org.apache.roller.RollerException on any error + */ + public Query getNamedQuery(String queryName) + throws RollerException { + EntityManager em = getEntityManager(false); + Query q = em.createNamedQuery(queryName); + // Never flush for queries. Roller code assumes this behavior + q.setFlushMode(FlushModeType.COMMIT); + return q; + } + + /** + * Create query from queryString with FlushModeType.COMMIT + * @param queryString the quuery + * @throws org.apache.roller.RollerException on any error + */ + public Query getDynamicQuery(String queryString) + throws RollerException { + EntityManager em = getEntityManager(false); + Query q = em.createQuery(queryString); + // Never flush for queries. Roller code assumes this behavior + q.setFlushMode(FlushModeType.COMMIT); + return q; + } + + /** + * Get named update query with default flush mode + * @param clazz the class of instances to find + * @param queryName the name of the query + * @throws org.apache.roller.RollerException on any error + */ + public Query getNamedUpdate(String queryName) + throws RollerException { + EntityManager em = getEntityManager(true); + Query q = em.createNamedQuery(queryName); + return q; + } + + /** + * Loads properties from given resourceName using given class loader + * @param resourceName The name of the resource containing properties + * @param cl Classloeder to be used to locate the resouce + * @return A properties object + * @throws RollerException + */ + private static Properties loadPropertiesFromResourceName( + String resourceName, ClassLoader cl) throws RollerException { + Properties props = new Properties(); + InputStream in = null; + in = cl.getResourceAsStream(resourceName); + if (in == null) { + //TODO: Check how i18n is done in roller + throw new RollerException( + "Could not locate properties to load " + resourceName); + } + try { + props.load(in); + } catch (IOException ioe) { + throw new RollerException( + "Could not load properties from " + resourceName); + } finally { + if (in != null) { + try { + in.close(); + } catch (IOException ioe) { + } + } + } + + return props; + } + + /** + * Get the context class loader associated with the current thread. This is + * done in a doPrivileged block because it is a secure method. + * @return the current thread's context class loader. + */ + private static ClassLoader getContextClassLoader() { + return (ClassLoader) AccessController.doPrivileged( + new PrivilegedAction() { + public Object run() { + return Thread.currentThread().getContextClassLoader(); + } + }); + } +} + Added: roller/trunk/components/core/src/java/org/apache/roller/util/UUIDGenerator.java URL: http://svn.apache.org/viewvc/roller/trunk/components/core/src/java/org/apache/roller/util/UUIDGenerator.java?view=auto&rev=541450 ============================================================================== --- roller/trunk/components/core/src/java/org/apache/roller/util/UUIDGenerator.java (added) +++ roller/trunk/components/core/src/java/org/apache/roller/util/UUIDGenerator.java Thu May 24 15:14:14 2007 @@ -0,0 +1,43 @@ +/* + * 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.util; + +import org.apache.commons.id.uuid.VersionFourGenerator; + + +/** + * Generates UUID values. + */ +public class UUIDGenerator { + + private static final VersionFourGenerator uuidGenerator = new VersionFourGenerator(); + + + // non-instantiable + private UUIDGenerator() {} + + + /** + * Generate a new UUID. + */ + public static String generateUUID() { + return uuidGenerator.nextIdentifier().toString(); + } + +}