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();
+    }
+    
+}


Reply via email to