You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@roller.apache.org by sn...@apache.org on 2007/02/07 18:15:17 UTC

svn commit: r504622 [1/2] - in /incubator/roller/branches/roller_4.0: ./ apps/planet/ apps/planet/nbproject/ apps/planet/src/java/org/apache/roller/ apps/planet/src/java/org/apache/roller/planet/business/datamapper/ apps/planet/src/java/org/apache/roll...

Author: snoopdave
Date: Wed Feb  7 09:15:02 2007
New Revision: 504622

URL: http://svn.apache.org/viewvc?view=rev&rev=504622
Log:
Promoting JPA implementation from sandbox and into main src directories. Also, created components/core so that we don't have to duplicate core code in Roller and Roller-Planet source trees. Unit tests pass 100% for Hibernate and web UI passes my basic sanity tests. Unit tests not yet passing for JPA.

Added:
    incubator/roller/branches/roller_4.0/apps/planet/src/java/org/apache/roller/planet/business/datamapper/
    incubator/roller/branches/roller_4.0/apps/planet/src/java/org/apache/roller/planet/business/datamapper/DatamapperPlanetImpl.java
    incubator/roller/branches/roller_4.0/apps/planet/src/java/org/apache/roller/planet/business/datamapper/DatamapperPlanetManagerImpl.java
    incubator/roller/branches/roller_4.0/apps/planet/src/java/org/apache/roller/planet/business/jpa/
    incubator/roller/branches/roller_4.0/apps/planet/src/java/org/apache/roller/planet/business/jpa/JPAPlanetImpl.java
    incubator/roller/branches/roller_4.0/apps/planet/testdata/JPAEMF.properties
    incubator/roller/branches/roller_4.0/apps/planet/testdata/persistence.xml
    incubator/roller/branches/roller_4.0/components/
    incubator/roller/branches/roller_4.0/components/core/
    incubator/roller/branches/roller_4.0/components/core/build/
    incubator/roller/branches/roller_4.0/components/core/build.properties
    incubator/roller/branches/roller_4.0/components/core/build.xml
    incubator/roller/branches/roller_4.0/components/core/build/compile/
    incubator/roller/branches/roller_4.0/components/core/build/compile/business/
    incubator/roller/branches/roller_4.0/components/core/build/compile/business/org/
    incubator/roller/branches/roller_4.0/components/core/build/compile/business/org/apache/
    incubator/roller/branches/roller_4.0/components/core/build/compile/business/org/apache/roller/
    incubator/roller/branches/roller_4.0/components/core/build/compile/business/org/apache/roller/RollerException.class   (with props)
    incubator/roller/branches/roller_4.0/components/core/build/compile/business/org/apache/roller/business/
    incubator/roller/branches/roller_4.0/components/core/build/compile/business/org/apache/roller/business/datamapper/
    incubator/roller/branches/roller_4.0/components/core/build/compile/business/org/apache/roller/business/datamapper/DatamapperPersistenceStrategy.class   (with props)
    incubator/roller/branches/roller_4.0/components/core/build/compile/business/org/apache/roller/business/datamapper/DatamapperQuery.class   (with props)
    incubator/roller/branches/roller_4.0/components/core/build/compile/business/org/apache/roller/business/datamapper/DatamapperRemoveQuery.class   (with props)
    incubator/roller/branches/roller_4.0/components/core/build/compile/business/org/apache/roller/business/hibernate/
    incubator/roller/branches/roller_4.0/components/core/build/compile/business/org/apache/roller/business/hibernate/HibernatePersistenceStrategy$1.class   (with props)
    incubator/roller/branches/roller_4.0/components/core/build/compile/business/org/apache/roller/business/hibernate/HibernatePersistenceStrategy.class   (with props)
    incubator/roller/branches/roller_4.0/components/core/build/compile/business/org/apache/roller/business/hibernate/ThreadLocalSessionContextNoAutoClose$NoCleanupSynch.class   (with props)
    incubator/roller/branches/roller_4.0/components/core/build/compile/business/org/apache/roller/business/hibernate/ThreadLocalSessionContextNoAutoClose.class   (with props)
    incubator/roller/branches/roller_4.0/components/core/build/compile/business/org/apache/roller/business/jpa/
    incubator/roller/branches/roller_4.0/components/core/build/compile/business/org/apache/roller/business/jpa/JPADynamicQueryImpl.class   (with props)
    incubator/roller/branches/roller_4.0/components/core/build/compile/business/org/apache/roller/business/jpa/JPANamedQueryImpl.class   (with props)
    incubator/roller/branches/roller_4.0/components/core/build/compile/business/org/apache/roller/business/jpa/JPAPersistenceStrategy$1.class   (with props)
    incubator/roller/branches/roller_4.0/components/core/build/compile/business/org/apache/roller/business/jpa/JPAPersistenceStrategy.class   (with props)
    incubator/roller/branches/roller_4.0/components/core/build/compile/business/org/apache/roller/business/jpa/JPAQueryImpl.class   (with props)
    incubator/roller/branches/roller_4.0/components/core/build/compile/business/org/apache/roller/business/jpa/JPARemoveQueryImpl.class   (with props)
    incubator/roller/branches/roller_4.0/components/core/build/compile/business/org/apache/roller/business/jpa/JPAUpdateQuery.class   (with props)
    incubator/roller/branches/roller_4.0/components/core/build/lib/
    incubator/roller/branches/roller_4.0/components/core/src/
    incubator/roller/branches/roller_4.0/components/core/src/java/
    incubator/roller/branches/roller_4.0/components/core/src/java/org/
    incubator/roller/branches/roller_4.0/components/core/src/java/org/apache/
    incubator/roller/branches/roller_4.0/components/core/src/java/org/apache/roller/
    incubator/roller/branches/roller_4.0/components/core/src/java/org/apache/roller/RollerException.java
      - copied unchanged from r504168, incubator/roller/branches/roller_4.0/apps/planet/src/java/org/apache/roller/RollerException.java
    incubator/roller/branches/roller_4.0/components/core/src/java/org/apache/roller/business/
    incubator/roller/branches/roller_4.0/components/core/src/java/org/apache/roller/business/datamapper/
    incubator/roller/branches/roller_4.0/components/core/src/java/org/apache/roller/business/datamapper/DatamapperPersistenceStrategy.java
    incubator/roller/branches/roller_4.0/components/core/src/java/org/apache/roller/business/datamapper/DatamapperQuery.java
    incubator/roller/branches/roller_4.0/components/core/src/java/org/apache/roller/business/datamapper/DatamapperRemoveQuery.java
    incubator/roller/branches/roller_4.0/components/core/src/java/org/apache/roller/business/hibernate/
    incubator/roller/branches/roller_4.0/components/core/src/java/org/apache/roller/business/hibernate/HibernatePersistenceStrategy.java
    incubator/roller/branches/roller_4.0/components/core/src/java/org/apache/roller/business/hibernate/ThreadLocalSessionContextNoAutoClose.java
    incubator/roller/branches/roller_4.0/components/core/src/java/org/apache/roller/business/jpa/
    incubator/roller/branches/roller_4.0/components/core/src/java/org/apache/roller/business/jpa/JPADynamicQueryImpl.java
    incubator/roller/branches/roller_4.0/components/core/src/java/org/apache/roller/business/jpa/JPANamedQueryImpl.java
    incubator/roller/branches/roller_4.0/components/core/src/java/org/apache/roller/business/jpa/JPAPersistenceStrategy.java
    incubator/roller/branches/roller_4.0/components/core/src/java/org/apache/roller/business/jpa/JPAQueryImpl.java
    incubator/roller/branches/roller_4.0/components/core/src/java/org/apache/roller/business/jpa/JPARemoveQueryImpl.java
    incubator/roller/branches/roller_4.0/components/core/src/java/org/apache/roller/business/jpa/JPAUpdateQuery.java
    incubator/roller/branches/roller_4.0/src/org/apache/roller/business/datamapper/
      - copied from r504168, incubator/roller/branches/roller_4.0/sandbox/jdobackend/src/org/apache/roller/business/datamapper/
    incubator/roller/branches/roller_4.0/src/org/apache/roller/business/jpa/
      - copied from r504168, incubator/roller/branches/roller_4.0/sandbox/jdobackend/src/org/apache/roller/business/jpa/
    incubator/roller/branches/roller_4.0/tools/jpa/
    incubator/roller/branches/roller_4.0/tools/jpa/toplink-essentials.jar   (with props)
    incubator/roller/branches/roller_4.0/tools/roller-core/
    incubator/roller/branches/roller_4.0/tools/roller-core/roller-core.jar   (with props)
    incubator/roller/branches/roller_4.0/web/WEB-INF/classes/JPAEMF.properties
    incubator/roller/branches/roller_4.0/web/WEB-INF/classes/persistence.xml
Removed:
    incubator/roller/branches/roller_4.0/apps/planet/nbproject/
    incubator/roller/branches/roller_4.0/apps/planet/src/java/org/apache/roller/RollerException.java
    incubator/roller/branches/roller_4.0/apps/planet/src/java/org/apache/roller/planet/business/hibernate/HibernatePersistenceStrategy.java
    incubator/roller/branches/roller_4.0/apps/planet/src/java/org/apache/roller/planet/business/hibernate/ThreadLocalSessionContextNoAutoClose.java
    incubator/roller/branches/roller_4.0/sandbox/jdobackend/src/org/apache/roller/business/jpa/JPADynamicQueryImpl.java
    incubator/roller/branches/roller_4.0/sandbox/jdobackend/src/org/apache/roller/business/jpa/JPANamedQueryImpl.java
    incubator/roller/branches/roller_4.0/sandbox/jdobackend/src/org/apache/roller/business/jpa/JPAQueryImpl.java
    incubator/roller/branches/roller_4.0/sandbox/jdobackend/src/org/apache/roller/business/jpa/JPARemoveQueryImpl.java
    incubator/roller/branches/roller_4.0/sandbox/jdobackend/src/org/apache/roller/business/jpa/JPAUpdateQuery.java
    incubator/roller/branches/roller_4.0/src/org/apache/roller/RollerException.java
    incubator/roller/branches/roller_4.0/src/org/apache/roller/business/datamapper/DatamapperPersistenceStrategy.java
    incubator/roller/branches/roller_4.0/src/org/apache/roller/business/datamapper/DatamapperPlanetImpl.java
    incubator/roller/branches/roller_4.0/src/org/apache/roller/business/datamapper/DatamapperPlanetManagerImpl.java
    incubator/roller/branches/roller_4.0/src/org/apache/roller/business/datamapper/DatamapperQuery.java
    incubator/roller/branches/roller_4.0/src/org/apache/roller/business/datamapper/DatamapperRemoveQuery.java
    incubator/roller/branches/roller_4.0/src/org/apache/roller/business/hibernate/HibernatePersistenceStrategy.java
    incubator/roller/branches/roller_4.0/src/org/apache/roller/business/jpa/JPADynamicQueryImpl.java
    incubator/roller/branches/roller_4.0/src/org/apache/roller/business/jpa/JPANamedQueryImpl.java
    incubator/roller/branches/roller_4.0/src/org/apache/roller/business/jpa/JPAPersistenceStrategy.java
    incubator/roller/branches/roller_4.0/src/org/apache/roller/business/jpa/JPAPlanetImpl.java
    incubator/roller/branches/roller_4.0/src/org/apache/roller/business/jpa/JPAQueryImpl.java
    incubator/roller/branches/roller_4.0/src/org/apache/roller/business/jpa/JPARemoveQueryImpl.java
    incubator/roller/branches/roller_4.0/src/org/apache/roller/business/jpa/JPAUpdateQuery.java
    incubator/roller/branches/roller_4.0/tools/roller-planet/roller-planet-business.jar
Modified:
    incubator/roller/branches/roller_4.0/ant.properties
    incubator/roller/branches/roller_4.0/apps/planet/build.xml
    incubator/roller/branches/roller_4.0/apps/planet/src/java/org/apache/roller/planet/business/hibernate/HibernatePlanetImpl.java
    incubator/roller/branches/roller_4.0/apps/planet/src/java/org/apache/roller/planet/business/hibernate/HibernatePlanetManagerImpl.java
    incubator/roller/branches/roller_4.0/apps/planet/testdata/planet.properties
    incubator/roller/branches/roller_4.0/build.xml
    incubator/roller/branches/roller_4.0/metadata/database/3xx-to-400-migration.vm
    incubator/roller/branches/roller_4.0/metadata/database/createdb.vm
    incubator/roller/branches/roller_4.0/nbproject/project.xml
    incubator/roller/branches/roller_4.0/properties.xmlf
    incubator/roller/branches/roller_4.0/sandbox/jdobackend/src/org/apache/roller/business/datamapper/DatamapperPlanetImpl.java
    incubator/roller/branches/roller_4.0/sandbox/jdobackend/src/org/apache/roller/business/datamapper/DatamapperPlanetManagerImpl.java
    incubator/roller/branches/roller_4.0/sandbox/jdobackend/src/org/apache/roller/business/datamapper/DatamapperRollerPlanetManagerImpl.java
    incubator/roller/branches/roller_4.0/sandbox/jdobackend/src/org/apache/roller/business/jpa/JPAPlanetImpl.java
    incubator/roller/branches/roller_4.0/src/org/apache/roller/business/datamapper/DatamapperAutoPingManagerImpl.java
    incubator/roller/branches/roller_4.0/src/org/apache/roller/business/datamapper/DatamapperBookmarkManagerImpl.java
    incubator/roller/branches/roller_4.0/src/org/apache/roller/business/datamapper/DatamapperPingQueueManagerImpl.java
    incubator/roller/branches/roller_4.0/src/org/apache/roller/business/datamapper/DatamapperPropertiesManagerImpl.java
    incubator/roller/branches/roller_4.0/src/org/apache/roller/business/datamapper/DatamapperRollerPlanetManagerImpl.java
    incubator/roller/branches/roller_4.0/src/org/apache/roller/business/datamapper/DatamapperWeblogManagerImpl.java
    incubator/roller/branches/roller_4.0/src/org/apache/roller/business/jpa/JPARollerImpl.java
    incubator/roller/branches/roller_4.0/src/org/apache/roller/planet/business/hibernate/HibernateRollerPlanetImpl.java
    incubator/roller/branches/roller_4.0/src/org/apache/roller/planet/business/hibernate/HibernateRollerPlanetManagerImpl.java

Modified: incubator/roller/branches/roller_4.0/ant.properties
URL: http://svn.apache.org/viewvc/incubator/roller/branches/roller_4.0/ant.properties?view=diff&rev=504622&r1=504621&r2=504622
==============================================================================
--- incubator/roller/branches/roller_4.0/ant.properties (original)
+++ incubator/roller/branches/roller_4.0/ant.properties Wed Feb  7 09:15:02 2007
@@ -3,7 +3,7 @@
 basedir=.
 
 # what version is this?
-ro.version=3.2-dev
+ro.version=4.0-dev
 
 # compile time settings
 build.debug=true

Modified: incubator/roller/branches/roller_4.0/apps/planet/build.xml
URL: http://svn.apache.org/viewvc/incubator/roller/branches/roller_4.0/apps/planet/build.xml?view=diff&rev=504622&r1=504621&r2=504622
==============================================================================
--- incubator/roller/branches/roller_4.0/apps/planet/build.xml (original)
+++ incubator/roller/branches/roller_4.0/apps/planet/build.xml Wed Feb  7 09:15:02 2007
@@ -41,6 +41,9 @@
     
     
     <fileset id="roller-jars" dir="${tools}">
+        
+        <include name="roller-core/roller-core.jar"/>
+
         <!-- General dependencies -->
         <include name="lib/commons-codec-1.3.jar"/>
         <include name="lib/log4j-1.2.11.jar"/>
@@ -65,6 +68,9 @@
         <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="jpa/toplink-essentials.jar"/>
                 
         <!-- needed for ROME -->
         <include name="lib/rome-0.9.jar"/>

Added: incubator/roller/branches/roller_4.0/apps/planet/src/java/org/apache/roller/planet/business/datamapper/DatamapperPlanetImpl.java
URL: http://svn.apache.org/viewvc/incubator/roller/branches/roller_4.0/apps/planet/src/java/org/apache/roller/planet/business/datamapper/DatamapperPlanetImpl.java?view=auto&rev=504622
==============================================================================
--- incubator/roller/branches/roller_4.0/apps/planet/src/java/org/apache/roller/planet/business/datamapper/DatamapperPlanetImpl.java (added)
+++ incubator/roller/branches/roller_4.0/apps/planet/src/java/org/apache/roller/planet/business/datamapper/DatamapperPlanetImpl.java Wed Feb  7 09:15:02 2007
@@ -0,0 +1,84 @@
+
+/*
+ * 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.planet.business.datamapper;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.roller.RollerException;
+import org.apache.roller.planet.business.Planet;
+import org.apache.roller.planet.business.PlanetManager;
+import org.apache.roller.business.datamapper.DatamapperPersistenceStrategy;
+
+/**
+ * A Datamapper specific implementation of the Roller business layer.
+ */
+public abstract class DatamapperPlanetImpl implements Planet {
+
+    protected static Log logger = LogFactory.getLog(DatamapperPlanetImpl.class);
+
+    // our singleton instance
+    private static DatamapperPlanetImpl me = null;
+
+    // a persistence utility class
+    protected DatamapperPersistenceStrategy strategy = null;
+
+    // references to the managers we maintain
+    private PlanetManager planetManager = null;
+
+    
+    protected DatamapperPlanetImpl() throws RollerException {
+    }
+
+    
+    public void flush() throws RollerException {
+        this.strategy.flush();
+    }
+
+    
+    public void release() {
+
+        // release our own stuff first
+        //if (planetManager != null) planetManager.release();
+
+        // tell Datamapper to close down
+        this.strategy.release();
+    }
+
+    
+    public void shutdown() {
+
+        // do our own shutdown first
+        this.release();
+    }
+    
+    /**
+     * @see org.apache.roller.business.Roller#getBookmarkManager()
+     */
+    public PlanetManager getPlanetManager() {
+        if ( planetManager == null ) {
+            planetManager = createDatamapperPlanetManager(strategy);
+        }
+        return planetManager;
+    }
+
+    protected PlanetManager createDatamapperPlanetManager(
+            DatamapperPersistenceStrategy strategy) {
+        return new DatamapperPlanetManagerImpl(strategy);
+    }    
+}

Added: incubator/roller/branches/roller_4.0/apps/planet/src/java/org/apache/roller/planet/business/datamapper/DatamapperPlanetManagerImpl.java
URL: http://svn.apache.org/viewvc/incubator/roller/branches/roller_4.0/apps/planet/src/java/org/apache/roller/planet/business/datamapper/DatamapperPlanetManagerImpl.java?view=auto&rev=504622
==============================================================================
--- incubator/roller/branches/roller_4.0/apps/planet/src/java/org/apache/roller/planet/business/datamapper/DatamapperPlanetManagerImpl.java (added)
+++ incubator/roller/branches/roller_4.0/apps/planet/src/java/org/apache/roller/planet/business/datamapper/DatamapperPlanetManagerImpl.java Wed Feb  7 09:15:02 2007
@@ -0,0 +1,498 @@
+package org.apache.roller.planet.business.datamapper;
+/*
+ * 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.
+ */
+
+import com.sun.syndication.feed.synd.SyndEntry;
+import com.sun.syndication.feed.synd.SyndFeed;
+import com.sun.syndication.fetcher.FeedFetcher;
+import com.sun.syndication.fetcher.impl.FeedFetcherCache;
+import com.sun.syndication.fetcher.impl.HttpURLFeedFetcher;
+import com.sun.syndication.fetcher.impl.SyndFeedInfo;
+
+import java.io.File;
+import java.net.URL;
+import java.sql.Timestamp;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.apache.roller.RollerException;
+
+import org.apache.roller.planet.business.PlanetManager;
+import org.apache.roller.planet.pojos.PlanetConfigData;
+import org.apache.roller.planet.pojos.PlanetEntryData;
+import org.apache.roller.planet.pojos.PlanetGroupData;
+import org.apache.roller.planet.pojos.PlanetSubscriptionData;
+import org.apache.roller.planet.util.rome.DiskFeedInfoCache;
+import org.apache.roller.business.datamapper.DatamapperQuery;
+
+import org.apache.roller.business.datamapper.DatamapperPersistenceStrategy;
+
+
+/**
+ * Manages Planet Roller objects and entry aggregations in a database.
+ * 
+ * @author Dave Johnson
+ */
+public class DatamapperPlanetManagerImpl implements PlanetManager {
+
+    private static Log log = LogFactory.getLog(
+        DatamapperPlanetManagerImpl.class);
+
+    /** The strategy for this manager. */
+    private DatamapperPersistenceStrategy strategy;
+
+    protected Map lastUpdatedByGroup = new HashMap();
+    protected static final String NO_GROUP = "zzz_nogroup_zzz";
+
+    public DatamapperPlanetManagerImpl 
+            (DatamapperPersistenceStrategy strategy) {
+        log.debug("Instantiating Datamapper Planet Manager");
+
+        this.strategy = strategy;
+    }
+
+    public void saveConfiguration(PlanetConfigData config)
+            throws RollerException {
+        strategy.store(config);
+    }
+
+    public void saveGroup(PlanetGroupData group) throws RollerException {
+        strategy.store(group);
+    }
+
+    public void saveEntry(PlanetEntryData entry) throws RollerException {
+        strategy.store(entry);
+    }
+
+    public void saveSubscription(PlanetSubscriptionData sub)
+            throws RollerException {
+        PlanetSubscriptionData existing = getSubscription(sub.getFeedURL());
+        if (existing == null || (existing.getId().equals(sub.getId()))) {
+            strategy.store(sub);
+        }
+        else {
+            throw new RollerException("ERROR: duplicate feed URLs not allowed");
+        }
+    }
+
+    public void deleteEntry(PlanetEntryData entry) throws RollerException {
+        strategy.remove(entry);
+    }
+
+    public void deleteGroup(PlanetGroupData group) throws RollerException {
+        strategy.remove(group);
+    }
+
+    public void deleteSubscription(PlanetSubscriptionData sub)
+            throws RollerException {
+        strategy.remove(sub);
+    }
+
+    public PlanetConfigData getConfiguration() throws RollerException {
+        List results = (List) strategy.newQuery(PlanetConfigData.class, 
+                "PlanetConfigData.getAll"); 
+        PlanetConfigData config = results.size()!=0 ? 
+            (PlanetConfigData)results.get(0) : null;
+            
+        // We inject the cache dir into the config object here to maintain
+        // compatibility with the standaline version of the aggregator.
+//        if (config != null) {
+//            config.setCacheDir(
+//                PlanetConfig.getProperty("planet.aggregator.cache.dir"));
+//        }
+        return config;
+    }
+
+    public PlanetSubscriptionData getSubscription(String feedUrl)
+            throws RollerException {
+        List results = (List) strategy.newQuery(PlanetSubscriptionData.class, 
+                "PlanetSubscriptionData.getByFeedURL"); 
+        return results.size()!=0 ? 
+            (PlanetSubscriptionData)results.get(0) : null;
+    }
+
+    public PlanetSubscriptionData getSubscriptionById(String id)
+            throws RollerException {
+        return (PlanetSubscriptionData) strategy.load(
+                PlanetSubscriptionData.class, id);
+    }
+
+    public Iterator getAllSubscriptions() {
+        try {
+            return ((List)strategy.newQuery(PlanetSubscriptionData.class, 
+                    "PlanetSubscriptionData.getAll")).iterator(); 
+        } catch (Throwable e) {
+            throw new RuntimeException(
+                    "ERROR fetching subscription collection", e);
+        }
+    }
+
+    public int getSubscriptionCount() throws RollerException {
+        return ((List)strategy.newQuery(PlanetSubscriptionData.class, 
+                "PlanetSubscriptionData.getAll")).size(); 
+    }
+
+    public List getTopSubscriptions(int offset, int length) 
+            throws RollerException {
+        return getTopSubscriptions(null, offset, length);
+    }
+    
+    /**
+     * Get top X subscriptions, restricted by group.
+     */
+    public List getTopSubscriptions(
+            String groupHandle, int offset, int len) throws RollerException {
+        List result = null;
+        if (groupHandle != null) {
+            result = (List) strategy.newQuery(PlanetSubscriptionData.class,
+                "PlanetSubscriptionData.getByGroupHandleOrderByInboundBlogsDesc")
+            .execute(groupHandle);
+        } else {
+            result = (List) strategy.newQuery(PlanetSubscriptionData.class,
+                "PlanetSubscriptionData.getAllOrderByInboundBlogsDesc")
+                .execute();
+        }
+        // TODO handle offset and length
+        return result;
+    }
+    
+    public PlanetGroupData getGroup(String handle) throws RollerException {
+        List results = (List) strategy.newQuery(PlanetGroupData.class, 
+                "PlanetGroupData.getByHandle").execute(handle); 
+        // TODO handle max result == 1
+        PlanetGroupData group = results.size()!=0 ? 
+            (PlanetGroupData)results.get(0) : null;
+        return group;
+    }
+
+    public PlanetGroupData getGroupById(String id) throws RollerException {
+        return (PlanetGroupData) strategy.load(PlanetGroupData.class, id);
+    }
+
+    public List getGroups() throws RollerException {
+        return (List) strategy.newQuery(PlanetGroupData.class, 
+                "PlanetGroupData.getAll").execute(); 
+    }
+
+    public List getGroupHandles() throws RollerException {
+        List handles = new ArrayList();
+        Iterator list = getGroups().iterator();
+        while (list.hasNext()) {
+            PlanetGroupData group = (PlanetGroupData) list.next();
+            handles.add(group.getHandle());
+        }
+        return handles;
+    }
+
+    /**
+     * Get entries in a single feed as list of PlanetEntryData objects.
+     */
+    public List getFeedEntries(
+            String feedUrl, int offset, int len) throws RollerException {      
+        List result = (List) strategy.newQuery(PlanetEntryData.class, 
+                "PlanetEntryData.getByFeedURL").execute(feedUrl); 
+        // TODO handle offset and length
+        return result;
+    }
+
+    public List getAggregation(
+            int offset, int len) throws RollerException {
+        return getAggregation(null, null, null, offset, len);
+    }
+    
+    /**
+     * Get agggration from cache, enries in reverse chonological order.
+     * @param offset    Offset into results (for paging)
+     * @param len       Maximum number of results to return (for paging)
+     */
+    public List getAggregation(Date startDate, Date endDate,
+            int offset, int len) throws RollerException {
+        return getAggregation(null, startDate, endDate, offset, len);
+    }
+    
+    public List getAggregation(
+            PlanetGroupData group, int offset, int len) 
+            throws RollerException {
+        return getAggregation(group, null, null, offset, len);
+    }
+    
+    /**
+     * Get agggration for group from cache, enries in reverse chonological order.
+     * Respects category constraints of group.
+     * @param group Restrict to entries from one subscription group.
+     * @param offset    Offset into results (for paging)
+     * @param length    Maximum number of results to return (for paging)
+     */
+    public List getAggregation(
+            PlanetGroupData group, Date startDate, Date endDate,
+            int offset, int length) throws RollerException {
+        List result = null;
+        if (endDate == null) endDate = new Date();
+        try {
+            String groupHandle = (group == null) ? NO_GROUP : group.getHandle();
+            long startTime = System.currentTimeMillis();
+            DatamapperQuery query;
+            Object[] params;
+            if (group != null) {
+                if (startDate != null) {
+                    params = new Object[] {groupHandle, endDate, startDate};
+                    query = strategy.newQuery(PlanetEntryData.class,
+                            "PlanetEntryData.getByGroup&EndDate&StartDateOrderByPubTimeDesc");
+                } else {
+                    params = new Object[] {groupHandle, endDate};
+                    query = strategy.newQuery(PlanetEntryData.class,
+                            "PlanetEntryData.getByGroup&EndDateOrderByPubTimeDesc");
+                }
+                // TODO handle offset and length
+            } else {
+                if (startDate != null) {
+                    params = new Object[] {endDate, startDate};
+                    query = strategy.newQuery(PlanetEntryData.class,
+                            "PlanetEntryData.getByExternalOrInternalGroup&EndDate&StartDateOrderByPubTimeDesc");
+                } else {
+                    params = new Object[] {endDate};
+                    query = strategy.newQuery(PlanetEntryData.class,
+                            "PlanetEntryData.getByExternalOrInternalGroup&EndDateOrderByPubTimeDesc");
+                }
+                // TODO handle offset and length
+            }
+            result = (List) query.execute(params);
+            Date retLastUpdated;
+            if (result.size() > 0) {
+                PlanetEntryData entry = (PlanetEntryData)result.get(0);
+                retLastUpdated = entry.getPubTime();
+            } else {
+                retLastUpdated = new Date();
+            }
+            lastUpdatedByGroup.put(groupHandle, retLastUpdated);
+            
+            long endTime = System.currentTimeMillis();
+            log.debug("Generated aggregation in "
+                    + ((endTime-startTime)/1000.0) + " seconds");
+            
+        } catch (Throwable e) {
+            log.error("ERROR: building aggregation for: " + group, e);
+            throw new RollerException(e);
+        }
+        return result;
+    }
+    
+    public synchronized void clearCachedAggregations() {
+        lastUpdatedByGroup.clear();
+    }
+                                                                                        
+    public Date getLastUpdated() {
+        return (Date) lastUpdatedByGroup.get(NO_GROUP);
+    }
+
+    public Date getLastUpdated(PlanetGroupData group) {
+        return (Date) lastUpdatedByGroup.get(group);
+    }
+
+    public void refreshEntries(String cacheDirPath) throws RollerException {
+        
+        Date now = new Date();
+        long startTime = System.currentTimeMillis();
+        PlanetConfigData config = getConfiguration();
+        
+        // can't continue without cache dir
+        if (cacheDirPath == null) {
+            log.warn("Planet cache directory not set, aborting refresh");
+            return;
+        }
+        
+        // allow ${user.home} in cache dir property
+        String cacheDirName = cacheDirPath.replaceFirst(
+                "\\$\\{user.home}",System.getProperty("user.home"));
+        
+        // allow ${catalina.home} in cache dir property
+        if (System.getProperty("catalina.home") != null) {
+            cacheDirName = cacheDirName.replaceFirst(
+                "\\$\\{catalina.home}",System.getProperty("catalina.home"));
+        }
+        
+        // create cache  dir if it does not exist
+        File cacheDir = null;
+        try {
+            cacheDir = new File(cacheDirName);
+            if (!cacheDir.exists()) cacheDir.mkdirs();
+        } catch (Exception e) {
+            log.error("Unable to create planet cache directory");
+            return;
+        }
+        
+        // abort if cache dir is not writable
+        if (!cacheDir.canWrite()) {
+            log.error("Planet cache directory is not writable");
+            return;
+        }
+        
+        FeedFetcherCache feedInfoCache =
+                new DiskFeedInfoCache(cacheDirName);
+        
+        if (config.getProxyHost()!=null && config.getProxyPort() > 0) {
+            System.setProperty("proxySet", "true");
+            System.setProperty("http.proxyHost", config.getProxyHost());
+            System.setProperty("http.proxyPort",
+                    Integer.toString(config.getProxyPort()));
+        }
+        /** a hack to set 15 sec timeouts for java.net.HttpURLConnection */
+        System.setProperty("sun.net.client.defaultConnectTimeout", "15000");
+        System.setProperty("sun.net.client.defaultReadTimeout", "15000");
+        
+        FeedFetcher feedFetcher = new HttpURLFeedFetcher(feedInfoCache);
+        //FeedFetcher feedFetcher = new HttpClientFeedFetcher(feedInfoCache);
+        feedFetcher.setUsingDeltaEncoding(false);
+        feedFetcher.setUserAgent("RollerPlanetAggregator");
+        
+        // Loop through all subscriptions in the system
+        Iterator subs = getAllSubscriptions();
+        while (subs.hasNext()) {
+            
+            long subStartTime = System.currentTimeMillis();
+            
+            PlanetSubscriptionData sub = (PlanetSubscriptionData)subs.next();
+            
+            // reattach sub.  sub gets detached as we iterate
+            sub = this.getSubscriptionById(sub.getId());
+            
+            Set newEntries = this.getNewEntries(sub, feedFetcher, feedInfoCache);
+            int count = newEntries.size();
+            
+            log.debug("   Entry count: " + count);
+            if (count > 0) {
+                sub.purgeEntries();
+                sub.addEntries(newEntries);
+                this.saveSubscription(sub);
+                this.strategy.flush();
+            }
+            long subEndTime = System.currentTimeMillis();
+            log.info("   " + count + " - "
+                    + ((subEndTime-subStartTime)/1000.0)
+                    + " seconds to process (" + count + ") entries of "
+                    + sub.getFeedURL());
+        }
+        // Clear the aggregation cache
+        clearCachedAggregations();
+        
+        long endTime = System.currentTimeMillis();
+        log.info("--- DONE --- Refreshed entries in "
+                + ((endTime-startTime)/1000.0) + " seconds");
+    }
+        
+    protected Set getNewEntries(PlanetSubscriptionData sub,
+                                FeedFetcher feedFetcher,
+                                FeedFetcherCache feedInfoCache)
+            throws RollerException {
+
+        Set newEntries = new TreeSet();
+        SyndFeed feed = null;
+        URL feedURL = null;
+        Date lastUpdated = new Date();
+        try {
+            feedURL = new URL(sub.getFeedURL());
+            log.debug("Get feed from cache "+sub.getFeedURL());
+            feed = feedFetcher.retrieveFeed(feedURL);
+            SyndFeedInfo feedInfo = feedInfoCache.getFeedInfo(feedURL);
+            if (feedInfo.getLastModified() != null) {
+                long lastUpdatedLong =
+                        ((Long)feedInfo.getLastModified()).longValue();
+                if (lastUpdatedLong != 0) {
+                    lastUpdated = new Date(lastUpdatedLong);
+                }
+            }
+            Thread.sleep(100); // be nice
+        } catch (Exception e) {
+            log.warn("ERROR parsing " + sub.getFeedURL()
+            + " : " + e.getClass().getName() + " : " + e.getMessage());
+            log.debug(e);
+            return newEntries; // bail out
+        }
+        if (lastUpdated!=null && sub.getLastUpdated()!=null) {
+            Calendar feedCal = Calendar.getInstance();
+            feedCal.setTime(lastUpdated);
+
+            Calendar subCal = Calendar.getInstance();
+            subCal.setTime(sub.getLastUpdated());
+
+            if (!feedCal.after(subCal)) {
+                if (log.isDebugEnabled()) {
+                    String msg = MessageFormat.format(
+                            "   Skipping ({0} / {1})",
+                            new Object[] {
+                        lastUpdated, sub.getLastUpdated()});
+                    log.debug(msg);
+                }
+                return newEntries; // bail out
+            }
+        }
+        if (feed.getPublishedDate() != null) {
+            sub.setLastUpdated(feed.getPublishedDate());
+            // saving sub here causes detachment issues, so we save it later
+        }
+
+        // Horrible kludge for Feeds without entry dates: most recent entry is
+        // given feed's last publish date (or yesterday if none exists) and
+        // earler entries are placed at once day intervals before that.
+        Calendar cal = Calendar.getInstance();
+        if (sub.getLastUpdated() != null) {
+            cal.setTime(sub.getLastUpdated());
+        } else {
+            cal.setTime(new Date());
+            cal.add(Calendar.DATE, -1);
+        }
+
+        // Populate subscription object with new entries
+        Iterator entries = feed.getEntries().iterator();
+        while (entries.hasNext()) {
+            try {
+                SyndEntry romeEntry = (SyndEntry) entries.next();
+                PlanetEntryData entry =
+                        new PlanetEntryData(feed, romeEntry, sub);
+                log.debug("Entry title=" + entry.getTitle() + " content size=" + entry.getContent().length());
+                if (entry.getPubTime() == null) {
+                    log.debug("No published date, assigning fake date for "+feedURL);
+                    entry.setPubTime(new Timestamp(cal.getTimeInMillis()));
+                }
+                if (entry.getPermalink() == null) {
+                    log.warn("No permalink, rejecting entry from "+feedURL);
+                } else {
+                    newEntries.add(entry);
+                }
+                cal.add(Calendar.DATE, -1);
+            } catch (Exception e) {
+                log.error("ERROR processing subscription entry", e);
+            }
+        }
+        return newEntries;
+    }
+
+    public void release() {}
+}
+

Modified: incubator/roller/branches/roller_4.0/apps/planet/src/java/org/apache/roller/planet/business/hibernate/HibernatePlanetImpl.java
URL: http://svn.apache.org/viewvc/incubator/roller/branches/roller_4.0/apps/planet/src/java/org/apache/roller/planet/business/hibernate/HibernatePlanetImpl.java?view=diff&rev=504622&r1=504621&r2=504622
==============================================================================
--- incubator/roller/branches/roller_4.0/apps/planet/src/java/org/apache/roller/planet/business/hibernate/HibernatePlanetImpl.java (original)
+++ incubator/roller/branches/roller_4.0/apps/planet/src/java/org/apache/roller/planet/business/hibernate/HibernatePlanetImpl.java Wed Feb  7 09:15:02 2007
@@ -25,7 +25,7 @@
 import org.apache.roller.planet.config.PlanetConfig;
 import org.apache.roller.planet.business.Planet;
 import org.apache.roller.planet.business.PlanetManager;
-import org.apache.roller.planet.business.hibernate.HibernatePersistenceStrategy;
+import org.apache.roller.business.hibernate.HibernatePersistenceStrategy;
 
 
 /**

Modified: incubator/roller/branches/roller_4.0/apps/planet/src/java/org/apache/roller/planet/business/hibernate/HibernatePlanetManagerImpl.java
URL: http://svn.apache.org/viewvc/incubator/roller/branches/roller_4.0/apps/planet/src/java/org/apache/roller/planet/business/hibernate/HibernatePlanetManagerImpl.java?view=diff&rev=504622&r1=504621&r2=504622
==============================================================================
--- incubator/roller/branches/roller_4.0/apps/planet/src/java/org/apache/roller/planet/business/hibernate/HibernatePlanetManagerImpl.java (original)
+++ incubator/roller/branches/roller_4.0/apps/planet/src/java/org/apache/roller/planet/business/hibernate/HibernatePlanetManagerImpl.java Wed Feb  7 09:15:02 2007
@@ -44,6 +44,7 @@
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.roller.RollerException;
+import org.apache.roller.business.hibernate.HibernatePersistenceStrategy;
 import org.apache.roller.planet.business.PlanetManager;
 import org.apache.roller.planet.pojos.PlanetConfigData;
 import org.apache.roller.planet.pojos.PlanetEntryData;

Added: incubator/roller/branches/roller_4.0/apps/planet/src/java/org/apache/roller/planet/business/jpa/JPAPlanetImpl.java
URL: http://svn.apache.org/viewvc/incubator/roller/branches/roller_4.0/apps/planet/src/java/org/apache/roller/planet/business/jpa/JPAPlanetImpl.java?view=auto&rev=504622
==============================================================================
--- incubator/roller/branches/roller_4.0/apps/planet/src/java/org/apache/roller/planet/business/jpa/JPAPlanetImpl.java (added)
+++ incubator/roller/branches/roller_4.0/apps/planet/src/java/org/apache/roller/planet/business/jpa/JPAPlanetImpl.java Wed Feb  7 09:15:02 2007
@@ -0,0 +1,71 @@
+/*
+* 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.planet.business.jpa;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.roller.RollerException;
+import org.apache.roller.planet.business.datamapper.DatamapperPlanetImpl;
+import org.apache.roller.planet.business.datamapper.DatamapperPlanetManagerImpl;
+import org.apache.roller.planet.business.Planet;
+import org.apache.roller.planet.business.PlanetManager;
+import org.apache.roller.business.jpa.JPAPersistenceStrategy;
+
+
+/**
+ * Implements Planet, the entry point interface for the Roller-Planet business 
+ * tier APIs using the Java Persistence API (JPA).
+ */
+public class JPAPlanetImpl extends DatamapperPlanetImpl {   
+    
+    private static Log log = LogFactory.getLog(JPAPlanetImpl.class);
+    
+    // our singleton instance
+    private static JPAPlanetImpl me = null;
+        
+    // references to the managers we maintain
+    protected PlanetManager planetManager = null;
+    
+        
+    protected JPAPlanetImpl() throws RollerException {
+        // set strategy used by Datamapper
+        strategy = new JPAPersistenceStrategy("PlanetPU");
+    }
+    
+    
+    /**
+     * Instantiates and returns an instance of JPAPlanetImpl.
+     */
+    public static Planet instantiate() throws RollerException {
+        if (me == null) {
+            log.debug("Instantiating JPAPlanetImpl");
+            me = new JPAPlanetImpl();
+        }
+        
+        return me;
+    }
+    
+    
+    public PlanetManager getPlanetManager() {
+        if ( planetManager == null ) {
+            planetManager = new DatamapperPlanetManagerImpl(strategy);  
+        }
+        return planetManager;
+    }           
+}

Added: incubator/roller/branches/roller_4.0/apps/planet/testdata/JPAEMF.properties
URL: http://svn.apache.org/viewvc/incubator/roller/branches/roller_4.0/apps/planet/testdata/JPAEMF.properties?view=auto&rev=504622
==============================================================================
--- incubator/roller/branches/roller_4.0/apps/planet/testdata/JPAEMF.properties (added)
+++ incubator/roller/branches/roller_4.0/apps/planet/testdata/JPAEMF.properties Wed Feb  7 09:15:02 2007
@@ -0,0 +1,7 @@
+toplink.jdbc.driver=org.apache.derby.jdbc.ClientDriver
+toplink.jdbc.url=jdbc:derby://localhost:3219/roller
+#toplink.jdbc.url=jdbc:derby://localhost:1527/roller-jpa
+toplink.jdbc.user=APP
+toplink.jdbc.password=APP
+toplink.logging.level=FINE
+

Added: incubator/roller/branches/roller_4.0/apps/planet/testdata/persistence.xml
URL: http://svn.apache.org/viewvc/incubator/roller/branches/roller_4.0/apps/planet/testdata/persistence.xml?view=auto&rev=504622
==============================================================================
--- incubator/roller/branches/roller_4.0/apps/planet/testdata/persistence.xml (added)
+++ incubator/roller/branches/roller_4.0/apps/planet/testdata/persistence.xml Wed Feb  7 09:15:02 2007
@@ -0,0 +1,13 @@
+<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="1.0">
+    
+    <persistence-unit name ="PlanetPU" transaction-type = "RESOURCE_LOCAL">
+        <provider>oracle.toplink.essentials.ejb.cmp3.EntityManagerFactoryProvider</provider>
+
+	<mapping-file>org/apache/roller/pojos/PlanetConfigData.orm.xml               </mapping-file>
+	<mapping-file>org/apache/roller/pojos/PlanetEntryData.orm.xml		         </mapping-file>
+	<mapping-file>org/apache/roller/pojos/PlanetGroupData.orm.xml		         </mapping-file>
+	<mapping-file>org/apache/roller/pojos/PlanetSubscriptionData.orm.xml	     </mapping-file>
+
+    </persistence-unit>
+    
+</persistence>

Modified: incubator/roller/branches/roller_4.0/apps/planet/testdata/planet.properties
URL: http://svn.apache.org/viewvc/incubator/roller/branches/roller_4.0/apps/planet/testdata/planet.properties?view=diff&rev=504622&r1=504621&r2=504622
==============================================================================
--- incubator/roller/branches/roller_4.0/apps/planet/testdata/planet.properties (original)
+++ incubator/roller/branches/roller_4.0/apps/planet/testdata/planet.properties Wed Feb  7 09:15:02 2007
@@ -41,8 +41,8 @@
 #    PlanetConfig.getProperty("propname");
 
 # Business layer implementation to be used
-persistence.planet.classname=\
-org.apache.roller.planet.business.hibernate.HibernatePlanetImpl
+persistence.planet.classname=org.apache.roller.planet.business.hibernate.HibernatePlanetImpl
+#persistence.planet.classname=org.apache.roller.planet.business.jpa.JPAPlanetImpl
 
 # You MUST override and set these three properties correctly:
 planet.aggregator.cache.dir=/var/planet/cache

Modified: incubator/roller/branches/roller_4.0/build.xml
URL: http://svn.apache.org/viewvc/incubator/roller/branches/roller_4.0/build.xml?view=diff&rev=504622&r1=504621&r2=504622
==============================================================================
--- incubator/roller/branches/roller_4.0/build.xml (original)
+++ incubator/roller/branches/roller_4.0/build.xml Wed Feb  7 09:15:02 2007
@@ -413,6 +413,7 @@
         <fileset refid="spring.jars" /> 
         <fileset refid="jstl.jars" />
         
+        <fileset refid="roller-core.jars" />
         <fileset refid="roller-planet.jars" />
         
         <!-- include custom jars -->
@@ -1145,9 +1146,36 @@
        <classpath refid="jsp.compile.path"/>
     </javac>
 </target>
+
+
+<!-- ********************************************************************* -->
+<!-- Gen JPA mappings  -->
+<!-- ********************************************************************* -->
+
+<target name="gen-jpa-mapping" description="Generate JPA mapping files from hiberatem mappings">
+	<xslt basedir="${build.compile.business}/org/apache/roller/pojos" includes="*.hbm.xml" 
+		destdir="${build.compile.business}/org/apache/roller/pojos/jpa" style="sandbox/jdobackend/HibernateToJPA.xsl">
+  		<xmlcatalog>
+			<dtd publicId="-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+			    location="sandbox/jdobackend/hibernate-mapping-3.0.dtd"/>
+		</xmlcatalog>
+		<mapper type="glob" from="*.hbm.xml" to="*.orm.xml"/>
+	</xslt>
+	
+	<xslt basedir="${build.compile.business}/org/apache/roller/planet/pojos/" includes="*.hbm.xml" 
+		destdir="${build.compile.business}/org/apache/roller/planet/pojos/jpa" style="sandbox/jdobackend/HibernateToJPA.xsl">
+  		<xmlcatalog>
+			<dtd publicId="-//Hibernate/Hibernate Mapping DTD 3.0//EN"
+			    location="sandbox/jdobackend/hibernate-mapping-3.0.dtd"/>
+		</xmlcatalog>
+		<mapper type="glob" from="*.hbm.xml" to="*.orm.xml"/>
+	</xslt>
+	
+</target>
+
 	    
 <!-- ********************************************************************* -->
-<!-- HSQLDB start, init and stop targets -->
+<!-- Derby start, init and stop targets -->
 <!-- ********************************************************************* -->
 
 <target name="init-db" description=

Added: incubator/roller/branches/roller_4.0/components/core/build.properties
URL: http://svn.apache.org/viewvc/incubator/roller/branches/roller_4.0/components/core/build.properties?view=auto&rev=504622
==============================================================================
--- incubator/roller/branches/roller_4.0/components/core/build.properties (added)
+++ incubator/roller/branches/roller_4.0/components/core/build.properties Wed Feb  7 09:15:02 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: incubator/roller/branches/roller_4.0/components/core/build.xml
URL: http://svn.apache.org/viewvc/incubator/roller/branches/roller_4.0/components/core/build.xml?view=auto&rev=504622
==============================================================================
--- incubator/roller/branches/roller_4.0/components/core/build.xml (added)
+++ incubator/roller/branches/roller_4.0/components/core/build.xml Wed Feb  7 09:15:02 2007
@@ -0,0 +1,128 @@
+<?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="buildtime/activation.jar"/>
+        <include name="buildtime/mail.jar"/>
+        <include name="struts-1.2.4/lib/antlr.jar"/>
+        <include name="struts-1.2.4/lib/commons-lang-2.0.jar"/>
+        <include name="struts-1.2.4/lib/commons-logging.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"/>
+        
+        <!-- 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="jpa/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: incubator/roller/branches/roller_4.0/components/core/build/compile/business/org/apache/roller/RollerException.class
URL: http://svn.apache.org/viewvc/incubator/roller/branches/roller_4.0/components/core/build/compile/business/org/apache/roller/RollerException.class?view=auto&rev=504622
==============================================================================
Binary file - no diff available.

Propchange: incubator/roller/branches/roller_4.0/components/core/build/compile/business/org/apache/roller/RollerException.class
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: incubator/roller/branches/roller_4.0/components/core/build/compile/business/org/apache/roller/business/datamapper/DatamapperPersistenceStrategy.class
URL: http://svn.apache.org/viewvc/incubator/roller/branches/roller_4.0/components/core/build/compile/business/org/apache/roller/business/datamapper/DatamapperPersistenceStrategy.class?view=auto&rev=504622
==============================================================================
Binary file - no diff available.

Propchange: incubator/roller/branches/roller_4.0/components/core/build/compile/business/org/apache/roller/business/datamapper/DatamapperPersistenceStrategy.class
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: incubator/roller/branches/roller_4.0/components/core/build/compile/business/org/apache/roller/business/datamapper/DatamapperQuery.class
URL: http://svn.apache.org/viewvc/incubator/roller/branches/roller_4.0/components/core/build/compile/business/org/apache/roller/business/datamapper/DatamapperQuery.class?view=auto&rev=504622
==============================================================================
Binary file - no diff available.

Propchange: incubator/roller/branches/roller_4.0/components/core/build/compile/business/org/apache/roller/business/datamapper/DatamapperQuery.class
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: incubator/roller/branches/roller_4.0/components/core/build/compile/business/org/apache/roller/business/datamapper/DatamapperRemoveQuery.class
URL: http://svn.apache.org/viewvc/incubator/roller/branches/roller_4.0/components/core/build/compile/business/org/apache/roller/business/datamapper/DatamapperRemoveQuery.class?view=auto&rev=504622
==============================================================================
Binary file - no diff available.

Propchange: incubator/roller/branches/roller_4.0/components/core/build/compile/business/org/apache/roller/business/datamapper/DatamapperRemoveQuery.class
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: incubator/roller/branches/roller_4.0/components/core/build/compile/business/org/apache/roller/business/hibernate/HibernatePersistenceStrategy$1.class
URL: http://svn.apache.org/viewvc/incubator/roller/branches/roller_4.0/components/core/build/compile/business/org/apache/roller/business/hibernate/HibernatePersistenceStrategy%241.class?view=auto&rev=504622
==============================================================================
Binary file - no diff available.

Propchange: incubator/roller/branches/roller_4.0/components/core/build/compile/business/org/apache/roller/business/hibernate/HibernatePersistenceStrategy$1.class
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: incubator/roller/branches/roller_4.0/components/core/build/compile/business/org/apache/roller/business/hibernate/HibernatePersistenceStrategy.class
URL: http://svn.apache.org/viewvc/incubator/roller/branches/roller_4.0/components/core/build/compile/business/org/apache/roller/business/hibernate/HibernatePersistenceStrategy.class?view=auto&rev=504622
==============================================================================
Binary file - no diff available.

Propchange: incubator/roller/branches/roller_4.0/components/core/build/compile/business/org/apache/roller/business/hibernate/HibernatePersistenceStrategy.class
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: incubator/roller/branches/roller_4.0/components/core/build/compile/business/org/apache/roller/business/hibernate/ThreadLocalSessionContextNoAutoClose$NoCleanupSynch.class
URL: http://svn.apache.org/viewvc/incubator/roller/branches/roller_4.0/components/core/build/compile/business/org/apache/roller/business/hibernate/ThreadLocalSessionContextNoAutoClose%24NoCleanupSynch.class?view=auto&rev=504622
==============================================================================
Binary file - no diff available.

Propchange: incubator/roller/branches/roller_4.0/components/core/build/compile/business/org/apache/roller/business/hibernate/ThreadLocalSessionContextNoAutoClose$NoCleanupSynch.class
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: incubator/roller/branches/roller_4.0/components/core/build/compile/business/org/apache/roller/business/hibernate/ThreadLocalSessionContextNoAutoClose.class
URL: http://svn.apache.org/viewvc/incubator/roller/branches/roller_4.0/components/core/build/compile/business/org/apache/roller/business/hibernate/ThreadLocalSessionContextNoAutoClose.class?view=auto&rev=504622
==============================================================================
Binary file - no diff available.

Propchange: incubator/roller/branches/roller_4.0/components/core/build/compile/business/org/apache/roller/business/hibernate/ThreadLocalSessionContextNoAutoClose.class
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: incubator/roller/branches/roller_4.0/components/core/build/compile/business/org/apache/roller/business/jpa/JPADynamicQueryImpl.class
URL: http://svn.apache.org/viewvc/incubator/roller/branches/roller_4.0/components/core/build/compile/business/org/apache/roller/business/jpa/JPADynamicQueryImpl.class?view=auto&rev=504622
==============================================================================
Binary file - no diff available.

Propchange: incubator/roller/branches/roller_4.0/components/core/build/compile/business/org/apache/roller/business/jpa/JPADynamicQueryImpl.class
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: incubator/roller/branches/roller_4.0/components/core/build/compile/business/org/apache/roller/business/jpa/JPANamedQueryImpl.class
URL: http://svn.apache.org/viewvc/incubator/roller/branches/roller_4.0/components/core/build/compile/business/org/apache/roller/business/jpa/JPANamedQueryImpl.class?view=auto&rev=504622
==============================================================================
Binary file - no diff available.

Propchange: incubator/roller/branches/roller_4.0/components/core/build/compile/business/org/apache/roller/business/jpa/JPANamedQueryImpl.class
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: incubator/roller/branches/roller_4.0/components/core/build/compile/business/org/apache/roller/business/jpa/JPAPersistenceStrategy$1.class
URL: http://svn.apache.org/viewvc/incubator/roller/branches/roller_4.0/components/core/build/compile/business/org/apache/roller/business/jpa/JPAPersistenceStrategy%241.class?view=auto&rev=504622
==============================================================================
Binary file - no diff available.

Propchange: incubator/roller/branches/roller_4.0/components/core/build/compile/business/org/apache/roller/business/jpa/JPAPersistenceStrategy$1.class
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: incubator/roller/branches/roller_4.0/components/core/build/compile/business/org/apache/roller/business/jpa/JPAPersistenceStrategy.class
URL: http://svn.apache.org/viewvc/incubator/roller/branches/roller_4.0/components/core/build/compile/business/org/apache/roller/business/jpa/JPAPersistenceStrategy.class?view=auto&rev=504622
==============================================================================
Binary file - no diff available.

Propchange: incubator/roller/branches/roller_4.0/components/core/build/compile/business/org/apache/roller/business/jpa/JPAPersistenceStrategy.class
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: incubator/roller/branches/roller_4.0/components/core/build/compile/business/org/apache/roller/business/jpa/JPAQueryImpl.class
URL: http://svn.apache.org/viewvc/incubator/roller/branches/roller_4.0/components/core/build/compile/business/org/apache/roller/business/jpa/JPAQueryImpl.class?view=auto&rev=504622
==============================================================================
Binary file - no diff available.

Propchange: incubator/roller/branches/roller_4.0/components/core/build/compile/business/org/apache/roller/business/jpa/JPAQueryImpl.class
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: incubator/roller/branches/roller_4.0/components/core/build/compile/business/org/apache/roller/business/jpa/JPARemoveQueryImpl.class
URL: http://svn.apache.org/viewvc/incubator/roller/branches/roller_4.0/components/core/build/compile/business/org/apache/roller/business/jpa/JPARemoveQueryImpl.class?view=auto&rev=504622
==============================================================================
Binary file - no diff available.

Propchange: incubator/roller/branches/roller_4.0/components/core/build/compile/business/org/apache/roller/business/jpa/JPARemoveQueryImpl.class
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: incubator/roller/branches/roller_4.0/components/core/build/compile/business/org/apache/roller/business/jpa/JPAUpdateQuery.class
URL: http://svn.apache.org/viewvc/incubator/roller/branches/roller_4.0/components/core/build/compile/business/org/apache/roller/business/jpa/JPAUpdateQuery.class?view=auto&rev=504622
==============================================================================
Binary file - no diff available.

Propchange: incubator/roller/branches/roller_4.0/components/core/build/compile/business/org/apache/roller/business/jpa/JPAUpdateQuery.class
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: incubator/roller/branches/roller_4.0/components/core/src/java/org/apache/roller/business/datamapper/DatamapperPersistenceStrategy.java
URL: http://svn.apache.org/viewvc/incubator/roller/branches/roller_4.0/components/core/src/java/org/apache/roller/business/datamapper/DatamapperPersistenceStrategy.java?view=auto&rev=504622
==============================================================================
--- incubator/roller/branches/roller_4.0/components/core/src/java/org/apache/roller/business/datamapper/DatamapperPersistenceStrategy.java (added)
+++ incubator/roller/branches/roller_4.0/components/core/src/java/org/apache/roller/business/datamapper/DatamapperPersistenceStrategy.java Wed Feb  7 09:15:02 2007
@@ -0,0 +1,117 @@
+/*
+ * 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.datamapper;
+
+import java.util.Collection;
+
+import org.apache.roller.RollerException;
+
+
+/**
+ *
+ */
+public interface DatamapperPersistenceStrategy {
+
+    /**
+     * Flush changes to the datastore, commit transaction, release pm.
+     * @throws org.apache.roller.RollerException on any error
+     */
+    void flush() 
+            throws RollerException;
+    
+    /**
+     * Release database session, rolls back any uncommitted changes.
+     */
+    void release();
+
+    /**
+     * Store object in the database. Start a transaction if no
+     * transaction in progress.
+     * @param obj the object to persist
+     * @return the object persisted
+     * @throws org.apache.roller.RollerException on any error
+     */
+    Object store(Object obj) 
+            throws RollerException;
+
+    /**
+     * Remove object from persistence storage. Start a transaction if no
+     * transaction in progress.
+     * @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;
+
+    /**
+     * Remove object from persistence storage. Start a transaction if no
+     * transaction in progress.
+     * @param po the persistent object to remove
+     * @throws org.apache.roller.RollerException on any error
+     */
+    public void remove(Object po)
+            throws RollerException;
+
+    /**
+     * Remove objects from persistence storage. Start a transaction if no
+     * transaction in progress.
+     * @param pos the persistent objects to remove
+     * @throws org.apache.roller.RollerException on any error
+     */
+    public void removeAll(Collection pos) 
+            throws RollerException;
+
+    /**
+     * Remove objects from persistence storage. Start a transaction if no
+     * transaction in progress.
+     * @param clazz the persistent from which to remove all objects 
+     * @throws org.apache.roller.RollerException on any error
+     */
+    public void removeAll(Class clazz) 
+            throws RollerException;
+
+    /**
+     * 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;
+
+    /**
+     * Create query.
+     * @param clazz the class of instances to find
+     * @param queryName the name of the query
+     * @throws org.apache.roller.RollerException on any error
+     */
+    public DatamapperQuery newQuery(Class clazz, String queryName)
+            throws RollerException;
+
+    /**
+     * Create query used for bulk remove operations.
+     * @param clazz the class of instances to remove
+     * @param queryName the name of the query
+     * @throws org.apache.roller.RollerException on any error
+     */
+    public DatamapperRemoveQuery newRemoveQuery(Class clazz, String queryName)
+            throws RollerException;
+
+}

Added: incubator/roller/branches/roller_4.0/components/core/src/java/org/apache/roller/business/datamapper/DatamapperQuery.java
URL: http://svn.apache.org/viewvc/incubator/roller/branches/roller_4.0/components/core/src/java/org/apache/roller/business/datamapper/DatamapperQuery.java?view=auto&rev=504622
==============================================================================
--- incubator/roller/branches/roller_4.0/components/core/src/java/org/apache/roller/business/datamapper/DatamapperQuery.java (added)
+++ incubator/roller/branches/roller_4.0/components/core/src/java/org/apache/roller/business/datamapper/DatamapperQuery.java Wed Feb  7 09:15:02 2007
@@ -0,0 +1,55 @@
+
+/*
+ * 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.datamapper;
+
+/**
+ *
+ */
+public interface DatamapperQuery {
+
+    /** Execute the query with no parameters.
+     * @return the results of the query
+     */
+    Object execute();
+
+    /** Execute the query with one parameter.
+     * @param param the parameter
+     * @return the results of the query
+     */
+    Object execute(Object param);
+
+    /** Execute the query with parameters.
+     * @param params the parameters
+     * @return the results of the query
+     */
+    Object execute(Object[] params);
+
+    /** Set the result to be a single instance (not a List).
+     * @return the instance on which this method is called
+     */
+    DatamapperQuery setUnique();
+
+    /** Set the range of results for this query.
+     * @param fromIncl the beginning row number
+     * @param toExcl the ending row number
+     * @return the instance on which this method is called
+     */
+    DatamapperQuery setRange(long fromIncl, long toExcl);
+
+}

Added: incubator/roller/branches/roller_4.0/components/core/src/java/org/apache/roller/business/datamapper/DatamapperRemoveQuery.java
URL: http://svn.apache.org/viewvc/incubator/roller/branches/roller_4.0/components/core/src/java/org/apache/roller/business/datamapper/DatamapperRemoveQuery.java?view=auto&rev=504622
==============================================================================
--- incubator/roller/branches/roller_4.0/components/core/src/java/org/apache/roller/business/datamapper/DatamapperRemoveQuery.java (added)
+++ incubator/roller/branches/roller_4.0/components/core/src/java/org/apache/roller/business/datamapper/DatamapperRemoveQuery.java Wed Feb  7 09:15:02 2007
@@ -0,0 +1,41 @@
+
+/*
+ * 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.datamapper;
+
+/**
+ *
+ */
+public interface DatamapperRemoveQuery {
+
+    /**
+     * Remove instances selected by the query with no parameters.
+     */
+    void removeAll();
+
+    /** Remove instances selected by the query with one parameter.
+     * @param param the parameter
+     */
+    void removeAll(Object param);
+
+    /** Remove instances selected by the query with parameters.
+     * @param params the parameters
+     */
+    void removeAll(Object[] params);
+
+}

Added: incubator/roller/branches/roller_4.0/components/core/src/java/org/apache/roller/business/hibernate/HibernatePersistenceStrategy.java
URL: http://svn.apache.org/viewvc/incubator/roller/branches/roller_4.0/components/core/src/java/org/apache/roller/business/hibernate/HibernatePersistenceStrategy.java?view=auto&rev=504622
==============================================================================
--- incubator/roller/branches/roller_4.0/components/core/src/java/org/apache/roller/business/hibernate/HibernatePersistenceStrategy.java (added)
+++ incubator/roller/branches/roller_4.0/components/core/src/java/org/apache/roller/business/hibernate/HibernatePersistenceStrategy.java Wed Feb  7 09:15:02 2007
@@ -0,0 +1,319 @@
+/*
+ * 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.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+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.jdom.Attribute;
+import org.jdom.Document;
+import org.jdom.Element;
+import org.jdom.input.SAXBuilder;
+import org.jdom.output.DOMOutputter;
+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 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(""));
+        }
+    };
+    
+    
+    public HibernatePersistenceStrategy() {
+    }   
+
+    /** 
+     * Construct self using Hibernate config resource and optional dialect.
+     * @param configResouce Classpath-based path to Hibernate config file (e.g. "/hibernate.cgf.xml")
+     * @parma dialect Classname of Hibernate dialect to be used (overriding any specified in the configResource)
+     */
+    public HibernatePersistenceStrategy(
+            String configResource,
+            String dialect) throws Exception {
+
+        log.info("configResource: " + configResource);
+        log.info("dialect:        " + dialect);
+        
+        // read configResource into DOM form
+        SAXBuilder builder = new SAXBuilder();
+        builder.setEntityResolver(noOpEntityResolver); 
+        Document configDoc = builder.build(
+            getClass().getResourceAsStream(configResource));
+        Element root = configDoc.getRootElement();
+        Element sessionFactoryElem = root.getChild("session-factory");
+        
+        // remove any existing connection.datasource and dialect properties
+        List propertyElems = sessionFactoryElem.getChildren("property");
+        List removeList = new ArrayList();
+        for (Iterator it = propertyElems.iterator(); it.hasNext();) {
+            Element elem = (Element) it.next();
+            if (elem.getAttribute("name") != null 
+                && elem.getAttribute("name").getValue().equals("dialect")) {
+                removeList.add(elem);           
+            }
+        }
+        for (Iterator it = removeList.iterator(); it.hasNext();) {
+            Element elem = (Element) it.next();
+            sessionFactoryElem.removeContent(elem); 
+        }
+        
+        // add Roller dialect property      
+        Element prop = new Element("property").setAttribute(
+            new Attribute("name","dialect"));
+        prop.addContent(dialect);
+        sessionFactoryElem.addContent(prop);
+        
+        Configuration config = new Configuration();
+        DOMOutputter outputter = new DOMOutputter();
+        config.configure(outputter.output(configDoc));
+        this.sessionFactory = config.buildSessionFactory(); 
+    }
+    
+    /** 
+     * Construct self using Hibernate config resource and optional dialect.
+     * @param configResouce Classpath-based path to Hibernate config file (e.g. "/hibernate.cgf.xml")
+     * @parma dialect Classname of Hibernate dialect to be used (or null to use one specified in configResource)
+     */
+    public HibernatePersistenceStrategy(
+            String configResource,
+            String dialect,
+            String driverClass,
+            String connectionURL,
+            String username,
+            String password) throws Exception {
+        
+        log.info("configResource: " + configResource);
+        log.info("dialect:        " + dialect);
+        log.info("driverClass:    " + driverClass);
+        log.info("connectionURL:  " + connectionURL);
+        log.info("username:       " + username);
+
+        // read configResource into DOM form
+        SAXBuilder builder = new SAXBuilder();
+        builder.setEntityResolver(noOpEntityResolver); 
+        Document configDoc = builder.build(
+            getClass().getResourceAsStream(configResource));
+        Element root = configDoc.getRootElement();
+        Element sessionFactoryElem = root.getChild("session-factory");
+        
+        // remove any existing connection.datasource and dialect properties
+        List propertyElems = sessionFactoryElem.getChildren("property");
+        List removeList = new ArrayList();
+        for (Iterator it = propertyElems.iterator(); it.hasNext();) {
+            Element elem = (Element) it.next();
+            if (elem.getAttribute("name") != null 
+                && elem.getAttribute("name").getValue().equals("connection.datasource")) {
+                removeList.add(elem);
+            }
+            if (elem.getAttribute("name") != null 
+                && elem.getAttribute("name").getValue().equals("dialect")) {
+                removeList.add(elem);
+            }
+        }
+        for (Iterator it = removeList.iterator(); it.hasNext();) {
+            Element elem = (Element) it.next();
+            sessionFactoryElem.removeContent(elem); 
+        }
+                                       
+        // add JDBC connection params instead
+        Element prop = new Element("property").setAttribute(
+            new Attribute("name","hibernate.connection.driver_class"));
+        prop.addContent(driverClass);
+        sessionFactoryElem.addContent(prop);
+
+        prop = new Element("property").setAttribute(
+            new Attribute("name","hibernate.connection.url"));
+        prop.addContent(connectionURL);
+        sessionFactoryElem.addContent(prop);
+        
+        prop = new Element("property").setAttribute(
+            new Attribute("name","hibernate.connection.username"));
+        prop.addContent(username);
+        sessionFactoryElem.addContent(prop);
+        
+        prop = new Element("property").setAttribute(
+            new Attribute("name","hibernate.connection.password"));
+        prop.addContent(password);
+        sessionFactoryElem.addContent(prop);
+        
+        prop = new Element("property").setAttribute(
+            new Attribute("name","dialect"));
+        prop.addContent(dialect);
+        sessionFactoryElem.addContent(prop);
+        
+        Configuration config = new Configuration();
+        DOMOutputter outputter = new DOMOutputter();
+        config.configure(outputter.output(configDoc));
+        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);
+    }
+    
+}