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/06/16 15:52:11 UTC

svn commit: r547924 [1/2] - in /roller/trunk/apps/weblogger: ./ nbproject/ src/java/org/apache/roller/weblogger/business/ src/java/org/apache/roller/weblogger/business/utils/ src/java/org/apache/roller/weblogger/config/ src/java/org/apache/roller/weblo...

Author: snoopdave
Date: Sat Jun 16 06:52:09 2007
New Revision: 547924

URL: http://svn.apache.org/viewvc?view=rev&rev=547924
Log:
Roller EZ install implementation, still does routing logic in a filter -- next I'll move that to a Struts action and establish some page flow.

Added:
    roller/trunk/apps/weblogger/scratch.txt
    roller/trunk/apps/weblogger/src/java/org/apache/roller/weblogger/business/utils/DatabaseCreator.java
    roller/trunk/apps/weblogger/src/java/org/apache/roller/weblogger/business/utils/DatabaseScriptProvider.java
    roller/trunk/apps/weblogger/src/java/org/apache/roller/weblogger/business/utils/DatabaseUpgrader.java
      - copied, changed from r545007, roller/trunk/apps/weblogger/src/java/org/apache/roller/weblogger/business/utils/UpgradeDatabase.java
    roller/trunk/apps/weblogger/src/java/org/apache/roller/weblogger/business/utils/SQLScriptRunner.java
    roller/trunk/apps/weblogger/src/java/org/apache/roller/weblogger/ui/core/filters/BootstrapFilter.java
    roller/trunk/apps/weblogger/src/java/org/apache/roller/weblogger/ui/struts2/core/CreateDatabase.java
    roller/trunk/apps/weblogger/src/java/org/apache/roller/weblogger/ui/struts2/core/DatabaseError.java
    roller/trunk/apps/weblogger/src/java/org/apache/roller/weblogger/ui/struts2/core/UpgradeDatabase.java
    roller/trunk/apps/weblogger/src/sql/320-to-400-migration.vm
      - copied unchanged from r546202, roller/trunk/apps/weblogger/src/sql/3xx-to-400-migration.vm
    roller/trunk/apps/weblogger/test/java/org/apache/roller/weblogger/business/SQLScriptRunnerTest.java
    roller/trunk/apps/weblogger/testdata/WEB-INF/dbscripts/
    roller/trunk/apps/weblogger/testdata/WEB-INF/dbscripts/dummydb/
    roller/trunk/apps/weblogger/testdata/WEB-INF/dbscripts/dummydb/createdb-derby.sql
    roller/trunk/apps/weblogger/testdata/WEB-INF/dbscripts/dummydb/createdb-mysql.sql
    roller/trunk/apps/weblogger/testdata/WEB-INF/dbscripts/dummydb/droptables.sql
    roller/trunk/apps/weblogger/web/WEB-INF/jsps/core/CreateDatabase.jsp
    roller/trunk/apps/weblogger/web/WEB-INF/jsps/core/DatabaseError.jsp
    roller/trunk/apps/weblogger/web/WEB-INF/jsps/core/UpgradeDatabase.jsp
    roller/trunk/apps/weblogger/web/WEB-INF/jsps/tiles/bannerInstallation.jsp
Removed:
    roller/trunk/apps/weblogger/src/sql/3xx-to-400-migration.vm
Modified:
    roller/trunk/apps/weblogger/build.xml
    roller/trunk/apps/weblogger/nbproject/project.xml
    roller/trunk/apps/weblogger/src/java/org/apache/roller/weblogger/business/DatabaseProvider.java
    roller/trunk/apps/weblogger/src/java/org/apache/roller/weblogger/config/roller.properties
    roller/trunk/apps/weblogger/src/java/org/apache/roller/weblogger/ui/core/RollerContext.java
    roller/trunk/apps/weblogger/src/sql/dbscripts.properties
    roller/trunk/apps/weblogger/web/WEB-INF/classes/ApplicationResources.properties
    roller/trunk/apps/weblogger/web/WEB-INF/classes/struts.xml
    roller/trunk/apps/weblogger/web/WEB-INF/jsps/tiles/tiles-errorpage.jsp
    roller/trunk/apps/weblogger/web/WEB-INF/tiles.xml
    roller/trunk/apps/weblogger/web/WEB-INF/web.xml

Modified: roller/trunk/apps/weblogger/build.xml
URL: http://svn.apache.org/viewvc/roller/trunk/apps/weblogger/build.xml?view=diff&rev=547924&r1=547923&r2=547924
==============================================================================
--- roller/trunk/apps/weblogger/build.xml (original)
+++ roller/trunk/apps/weblogger/build.xml Sat Jun 16 06:52:09 2007
@@ -221,6 +221,7 @@
         <copy todir="${build.compile.web}">
             <fileset dir="${ro.src}">
                 <exclude name="**/META-INF/**"/> <!-- don't copy persistence.xml -->
+                <exclude name="**/pojos/**"/> <!-- don't copy any POJO ORM mapping files -->
                 <exclude name="**/*.java"/>
                 <exclude name="**/*.html"/>
                 <exclude name="**/*.png"/>
@@ -717,14 +718,13 @@
         
         <!-- Copy test resources -->
         <copy todir="${build.compile.tests}">
-            <fileset dir="${ro.tests}" 
-                     excludes="**/*.java, **/*.html, **/*.png" />
+            <fileset dir="${ro.tests}" excludes="**/*.java, **/*.html, **/*.png" />
         </copy>
         
         <!-- 
-    Copy web config files to ${build.tests} to make them available for testing.
-    This includes the WEB-INF directory, minus jsps
-    -->
+        Copy web config files to ${build.tests} to make them available for testing.
+        This includes the WEB-INF directory, minus jsps
+        -->
         <mkdir dir="${build.tests}/WEB-INF" />
         <copy todir="${build.tests}/WEB-INF">
             <fileset dir="${basedir}/web/WEB-INF">
@@ -737,10 +737,11 @@
         </copy>
         
         <!-- 
-    Copy custom testing files which will overwrite some config files 
-    -->
+        Copy custom testing files which will overwrite some config files 
+        -->
         <copy todir="${build.tests}" overwrite="true">
             <fileset dir="${basedir}/testdata" />
+            <fileset dir="${build.webapp}" includes="**/dbscripts/**" />
         </copy>
         
         <!-- allow for custom build work -->

Modified: roller/trunk/apps/weblogger/nbproject/project.xml
URL: http://svn.apache.org/viewvc/roller/trunk/apps/weblogger/nbproject/project.xml?view=diff&rev=547924&r1=547923&r2=547924
==============================================================================
--- roller/trunk/apps/weblogger/nbproject/project.xml (original)
+++ roller/trunk/apps/weblogger/nbproject/project.xml Sat Jun 16 06:52:09 2007
@@ -4,7 +4,7 @@
     <configuration>
         <general-data xmlns="http://www.netbeans.org/ns/freeform-project/1">
             <!-- Do not use Project Properties customizer when editing this file manually. -->
-            <name>roller_weblogger_trunk</name>
+            <name>roller_weblogger_newinstaller</name>
             <properties>
                 <property name="ant.script">build.xml</property>
             </properties>
@@ -103,7 +103,7 @@
             <compilation-unit>
                 <package-root>src/java</package-root>
                 <package-root>test/java</package-root>
-                <classpath mode="compile">../../tools/lib/commons-betwixt-1.0-beta-1.jar:../../tools/lib/commons-codec-1.3.jar:../../tools/lib/commons-collections-3.2.jar:../../tools/lib/commons-httpclient-2.0.2.jar:../../tools/lib/commons-id-0.1-SNAPSHOT.jar:../../tools/lib/commons-lang-2.1.jar:../../tools/lib/commons-logging-1.0.4.jar:../../tools/lib/jaxen-full.jar:../../tools/lib/jdom.jar:../../tools/lib/log4j-1.2.11.jar:../../tools/lib/lucene-1.4.3.jar:../../tools/lib/rome-0.9.jar:../../tools/lib/rome-fetcher-0.9.jar:../../tools/lib/saxpath.jar:../../tools/lib/velocity-1.5.jar:../../tools/lib/taglibs-string.jar:../../tools/struts-1.2.4/lib/antlr.jar:../../tools/struts-1.2.4/lib/commons-beanutils.jar:../../tools/struts-1.2.4/lib/commons-digester.jar:../../tools/struts-1.2.4/lib/commons-validator.jar:../../tools/struts-1.2.4/lib/jakarta-oro.jar:../../tools/struts-1.2.4/lib/struts-el.jar:../../tools/struts-1.2.4/lib/struts.jar:../../tools/struts-2.0.6/lib/antlr-2.7.2.jar:..
 /../tools/struts-2.0.6/lib/commons-beanutils-1.6.jar:../../tools/struts-2.0.6/lib/commons-chain-1.1.jar:../../tools/struts-2.0.6/lib/commons-fileupload-1.2.jar:../../tools/struts-2.0.6/lib/commons-io-1.3.1.jar:../../tools/struts-2.0.6/lib/commons-validator-1.3.0.jar:../../tools/struts-2.0.6/lib/freemarker-2.3.8.jar:../../tools/struts-2.0.6/lib/ognl-2.6.11.jar:../../tools/struts-2.0.6/lib/oro-2.0.8.jar:../../tools/struts-2.0.6/lib/struts2-core-2.0.6.jar:../../tools/struts-2.0.6/lib/struts2-spring-plugin-2.0.6.jar:../../tools/struts-2.0.6/lib/struts2-tiles-plugin-2.0.6.jar:../../tools/struts-2.0.6/lib/tiles-api-2.0-20070207.130156-4.jar:../../tools/struts-2.0.6/lib/tiles-core-2.0-20070207.130156-4.jar:../../tools/struts-2.0.6/lib/xwork-2.0.1.jar:../../tools/buildtime/tomcat-5.0.28/jsp-api.jar:../../tools/buildtime/tomcat-5.0.28/servlet-api.jar:../../tools/buildtime/activation.jar:../../tools/buildtime/mail.jar:../../tools/jakarta-taglibs-standard-1.1.2/lib/jstl.jar:../../tools
 /jakarta-taglibs-standard-1.1.2/lib/serializer.jar:../../tools/jakarta-taglibs-standard-1.1.2/lib/standard.jar:../../tools/jakarta-taglibs-standard-1.1.2/lib/xalan.jar:../../tools/hibernate-3.1/hibernate3.jar:../../tools/hibernate-3.1/lib/asm-attrs.jar:../../tools/hibernate-3.1/lib/asm.jar:../../tools/hibernate-3.1/lib/cglib-2.1.3.jar:../../tools/hibernate-3.1/lib/dom4j-1.6.1.jar:../../tools/hibernate-3.1/lib/ehcache-1.1.jar:../../tools/hibernate-3.1/lib/jdbc2_0-stdext.jar:../../tools/hibernate-3.1/lib/jta.jar:../../tools/openjpa-0.9.7/geronimo-j2ee-connector_1.5_spec-1.0.1.jar:../../tools/openjpa-0.9.7/geronimo-jpa_3.0_spec-1.0.jar:../../tools/openjpa-0.9.7/geronimo-jta_1.0.1B_spec-1.0.1.jar:../../tools/openjpa-0.9.7/openjpa-0.9.7-incubating.jar:../../tools/openjpa-0.9.7/serp-1.11.0.jar:../../tools/spring-1.2/acegi-security-1.0.3.jar:../../tools/spring-1.2/spring.jar:../../tools/roller-core/roller-core.jar:../../tools/roller-planet/roller-planet-business.jar:../../tools/xml
 rpc-3.0/lib/ws-commons-util-1.0.1.jar:../../tools/xmlrpc-3.0/lib/xmlrpc-client-3.0.jar:../../tools/xmlrpc-3.0/lib/xmlrpc-common-3.0.jar:../../tools/xmlrpc-3.0/lib/xmlrpc-server-3.0.jar</classpath>
+                <classpath mode="compile">../../tools/lib/commons-betwixt-1.0-beta-1.jar:../../tools/lib/commons-codec-1.3.jar:../../tools/lib/commons-collections-3.2.jar:../../tools/lib/commons-httpclient-2.0.2.jar:../../tools/lib/commons-id-0.1-SNAPSHOT.jar:../../tools/lib/commons-lang-2.1.jar:../../tools/lib/commons-logging-1.0.4.jar:../../tools/lib/jaxen-full.jar:../../tools/lib/jdom.jar:../../tools/lib/log4j-1.2.11.jar:../../tools/lib/lucene-1.4.3.jar:../../tools/lib/rome-0.9.jar:../../tools/lib/rome-fetcher-0.9.jar:../../tools/lib/saxpath.jar:../../tools/lib/velocity-1.5.jar:../../tools/lib/taglibs-string.jar:../../tools/struts-1.2.4/lib/antlr.jar:../../tools/struts-1.2.4/lib/commons-beanutils.jar:../../tools/struts-1.2.4/lib/commons-digester.jar:../../tools/struts-1.2.4/lib/commons-validator.jar:../../tools/struts-1.2.4/lib/jakarta-oro.jar:../../tools/struts-1.2.4/lib/struts-el.jar:../../tools/struts-1.2.4/lib/struts.jar:../../tools/struts-2.0.6/lib/antlr-2.7.2.jar:..
 /../tools/struts-2.0.6/lib/commons-beanutils-1.6.jar:../../tools/struts-2.0.6/lib/commons-chain-1.1.jar:../../tools/struts-2.0.6/lib/commons-fileupload-1.2.jar:../../tools/struts-2.0.6/lib/commons-io-1.3.1.jar:../../tools/struts-2.0.6/lib/commons-validator-1.3.0.jar:../../tools/struts-2.0.6/lib/freemarker-2.3.8.jar:../../tools/struts-2.0.6/lib/ognl-2.6.11.jar:../../tools/struts-2.0.6/lib/oro-2.0.8.jar:../../tools/struts-2.0.6/lib/struts2-core-2.0.6.jar:../../tools/struts-2.0.6/lib/struts2-spring-plugin-2.0.6.jar:../../tools/struts-2.0.6/lib/struts2-tiles-plugin-2.0.6.jar:../../tools/struts-2.0.6/lib/tiles-api-2.0-20070207.130156-4.jar:../../tools/struts-2.0.6/lib/tiles-core-2.0-20070207.130156-4.jar:../../tools/struts-2.0.6/lib/xwork-2.0.1.jar:../../tools/buildtime/tomcat-5.0.28/jsp-api.jar:../../tools/buildtime/tomcat-5.0.28/servlet-api.jar:../../tools/buildtime/activation.jar:../../tools/buildtime/mail.jar:../../tools/jakarta-taglibs-standard-1.1.2/lib/jstl.jar:../../tools
 /jakarta-taglibs-standard-1.1.2/lib/serializer.jar:../../tools/jakarta-taglibs-standard-1.1.2/lib/standard.jar:../../tools/jakarta-taglibs-standard-1.1.2/lib/xalan.jar:../../tools/hibernate-3.1/hibernate3.jar:../../tools/hibernate-3.1/lib/asm-attrs.jar:../../tools/hibernate-3.1/lib/asm.jar:../../tools/hibernate-3.1/lib/cglib-2.1.3.jar:../../tools/hibernate-3.1/lib/dom4j-1.6.1.jar:../../tools/hibernate-3.1/lib/ehcache-1.1.jar:../../tools/hibernate-3.1/lib/jdbc2_0-stdext.jar:../../tools/hibernate-3.1/lib/jta.jar:../../tools/openjpa-0.9.7/geronimo-j2ee-connector_1.5_spec-1.0.1.jar:../../tools/openjpa-0.9.7/geronimo-jpa_3.0_spec-1.0.jar:../../tools/openjpa-0.9.7/geronimo-jta_1.0.1B_spec-1.0.1.jar:../../tools/openjpa-0.9.7/openjpa-0.9.7-incubating.jar:../../tools/openjpa-0.9.7/serp-1.11.0.jar:../../tools/spring-1.2/acegi-security-1.0.3.jar:../../tools/spring-1.2/spring.jar:../../tools/roller-core/roller-core.jar:../../tools/roller-planet/roller-planet-business.jar:../../tools/xml
 rpc-3.0/lib/ws-commons-util-1.0.1.jar:../../tools/xmlrpc-3.0/lib/xmlrpc-client-3.0.jar:../../tools/xmlrpc-3.0/lib/xmlrpc-common-3.0.jar:../../tools/xmlrpc-3.0/lib/xmlrpc-server-3.0.jar:../../tools/buildtime/junit-4.1.jar</classpath>
                 <source-level>1.5</source-level>
             </compilation-unit>
         </java-data>

Added: roller/trunk/apps/weblogger/scratch.txt
URL: http://svn.apache.org/viewvc/roller/trunk/apps/weblogger/scratch.txt?view=auto&rev=547924
==============================================================================
--- roller/trunk/apps/weblogger/scratch.txt (added)
+++ roller/trunk/apps/weblogger/scratch.txt Sat Jun 16 06:52:09 2007
@@ -0,0 +1,6 @@
+
+run '/Users/dave/src/roller_apache/roller_newinstaller/apps/weblogger/build/webapp/WEB-INF/dbscripts/droptables.sql';
+
+run '/Users/dave/src/roller_apache/old_releases/roller-2.0.2/WEB-INF/dbscripts/derby/createdb.sql';
+insert into roller_properties values ('roller.database.version','200');
+

Modified: roller/trunk/apps/weblogger/src/java/org/apache/roller/weblogger/business/DatabaseProvider.java
URL: http://svn.apache.org/viewvc/roller/trunk/apps/weblogger/src/java/org/apache/roller/weblogger/business/DatabaseProvider.java?view=diff&rev=547924&r1=547923&r2=547924
==============================================================================
--- roller/trunk/apps/weblogger/src/java/org/apache/roller/weblogger/business/DatabaseProvider.java (original)
+++ roller/trunk/apps/weblogger/src/java/org/apache/roller/weblogger/business/DatabaseProvider.java Sat Jun 16 06:52:09 2007
@@ -3,6 +3,8 @@
 import java.sql.Connection;
 import java.sql.DriverManager;
 import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Properties;
 import javax.naming.InitialContext;
 import javax.naming.NamingException;
@@ -15,6 +17,13 @@
 /**
  * Encapsulates Roller database configuration via JDBC properties or JNDI.
  *
+ * <p>To keep the logs from filling up with DB connection errors, will only 
+ * attempt to connect once.</p>
+ * 
+ * <p>Keeps startup exception and log so we can present useful debugging
+ * information to whoever is installing Roller.</p>
+ *
+ *
  * <p>Reads configuration properties from RollerConfig:</p>
  * <pre>
  * # Specify database configuration type of 'jndi' or 'jdbc'
@@ -32,14 +41,15 @@
  */
 public class DatabaseProvider  {
     private static Log log = LogFactory.getLog(DatabaseProvider.class);
+
     public enum ConfigurationType {JNDI_NAME, JDBC_PROPERTIES;}
+    private ConfigurationType type = ConfigurationType.JNDI_NAME; 
     
     private static DatabaseProvider singletonInstance = null;
+    private static WebloggerException startupException = null;
+    private static List<String> startupLog = new ArrayList<String>();
     
-    private DataSource dataSource = null;
-    
-    private ConfigurationType type = ConfigurationType.JNDI_NAME; 
-    
+    private DataSource dataSource = null;    
     private String jndiName = null; 
     
     private String jdbcDriverClass = null;
@@ -47,12 +57,14 @@
     private String jdbcPassword = null;
     private String jdbcUsername = null;
     private Properties props = null;
-   
+    
+    
     /**
      * Reads configuraiton, loads driver or locates data-source and attempts
      * to get test connecton so that we can fail early.
      */ 
     private DatabaseProvider() throws WebloggerException {
+        
         String connectionTypeString = 
                 RollerConfig.getProperty("database.configurationType"); 
         if ("jdbc".equals(connectionTypeString)) {
@@ -64,43 +76,82 @@
         jdbcUsername =      RollerConfig.getProperty("database.jdbc.username");
         jdbcPassword =      RollerConfig.getProperty("database.jdbc.password");
         
-        // init now so we fail early
+        successMessage("SUCCESS: Got parameters. Using configuration type " + type);
+
+        // If we're doing JDBC then attempt to load JDBC driver class
         if (getType() == ConfigurationType.JDBC_PROPERTIES) {
-            log.info("Using 'jdbc' properties based configuration");
+            successMessage("-- Using JDBC driver class: "   + jdbcDriverClass);
+            successMessage("-- Using JDBC connection URL: " + jdbcConnectionURL);
+            successMessage("-- Using JDBC username: "       + jdbcUsername);
+            successMessage("-- Using JDBC password: [hidden]");
             try {
                 Class.forName(getJdbcDriverClass());
             } catch (ClassNotFoundException ex) {
-                throw new WebloggerException(
-                   "Cannot load specified JDBC driver class [" +getJdbcDriverClass()+ "]", ex);
+                String errorMsg = 
+                     "ERROR: cannot load JDBC driver class [" + getJdbcDriverClass()+ "]. "
+                    +"Likely problem: JDBC driver jar missing from server classpath.";
+                errorMessage(errorMsg);
+                startupException = new WebloggerException(errorMsg, ex);
+                throw startupException;
             }
+            successMessage("SUCCESS: loaded JDBC driver class [" +getJdbcDriverClass()+ "]");
+            
             if (getJdbcUsername() != null || getJdbcPassword() != null) {
                 props = new Properties();
                 if (getJdbcUsername() != null) props.put("user", getJdbcUsername());
                 if (getJdbcPassword() != null) props.put("password", getJdbcPassword());
             }
-        } else {
-            log.info("Using 'jndi' based configuration");
+            
+        // Else attempt to locate JNDI datasource
+        } else { 
             String name = "java:comp/env/" + getJndiName();
+            successMessage("-- Using JNDI datasource name: " + name);
             try {
                 InitialContext ic = new InitialContext();
                 dataSource = (DataSource)ic.lookup(name);
             } catch (NamingException ex) {
-                throw new WebloggerException(
-                    "ERROR looking up data-source with JNDI name: " + name, ex);
+                String errorMsg = 
+                    "ERROR: cannot locate JNDI DataSource [" +name+ "]. "
+                   +"Likely problem: no DataSource or datasource is misconfigured.";
+                errorMessage(errorMsg);
+                startupException =  new WebloggerException(errorMsg, ex);
+                throw startupException;
             }            
+            successMessage("SUCCESS: located JNDI DataSource [" +name+ "]");
         }
+        
+        // So far so good. Now, can we get a connection?
         try { 
             Connection testcon = getConnection();
             testcon.close();
         } catch (Throwable t) {
-            throw new WebloggerException("ERROR unable to obtain connection", t);
+            String errorMsg = 
+                "ERROR: unable to obtain database connection. "
+               +"Likely problem: bad connection parameters or database unavailable.";
+            errorMessage(errorMsg);
+            startupException =  new WebloggerException(errorMsg, t);
+            throw startupException;
         }
     }
     
+    private void successMessage(String msg) {
+        startupLog.add(msg);
+        log.info(msg);
+    }
+    
+    private void errorMessage(String msg) {
+        startupLog.add(msg);
+        log.error(msg);
+    }
+    
     /**
      * Get global database provider singlton, instantiating if necessary.
      */
     public static DatabaseProvider getDatabaseProvider() throws WebloggerException {
+        // No need to jam log with database connection attempts
+        if (startupException != null) {
+            throw startupException;
+        }
         if (singletonInstance == null) {
             singletonInstance = new DatabaseProvider();
         }
@@ -108,6 +159,20 @@
     }
     
     /**
+     * Exception that occured during startup, or null if none occured.
+     */
+    public static WebloggerException getStartupException() {
+        return startupException;
+    }
+
+    /** 
+     * List of success and error messages when class was first instantiated.
+     **/
+    public static List<String> getStartupLog() {
+        return startupLog;
+    }
+
+    /**
      * Get database connection from data-source or driver manager, depending 
      * on which is configured.
      */
@@ -142,4 +207,5 @@
     public String getJdbcUsername() {
         return jdbcUsername;
     }
+
 }

Added: roller/trunk/apps/weblogger/src/java/org/apache/roller/weblogger/business/utils/DatabaseCreator.java
URL: http://svn.apache.org/viewvc/roller/trunk/apps/weblogger/src/java/org/apache/roller/weblogger/business/utils/DatabaseCreator.java?view=auto&rev=547924
==============================================================================
--- roller/trunk/apps/weblogger/src/java/org/apache/roller/weblogger/business/utils/DatabaseCreator.java (added)
+++ roller/trunk/apps/weblogger/src/java/org/apache/roller/weblogger/business/utils/DatabaseCreator.java Sat Jun 16 06:52:09 2007
@@ -0,0 +1,152 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  The ASF licenses this file to You
+ * under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.  For additional information regarding
+ * copyright in this work, please see the NOTICE file in the top level
+ * directory of this distribution.
+ */
+
+package org.apache.roller.weblogger.business.utils;
+
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.roller.weblogger.WebloggerException;
+import org.apache.roller.weblogger.business.DatabaseProvider;
+import org.apache.roller.weblogger.business.RollerFactory;
+
+/**
+ * Creates Roller database.
+ */
+public class DatabaseCreator {    
+    private static Log log = LogFactory.getLog(DatabaseCreator.class); 
+    private DatabaseScriptProvider scripts = null;
+    private List<String>           messages = new ArrayList<String>();
+    
+    
+    public DatabaseCreator(DatabaseScriptProvider scriptProvider) {
+        this.scripts = scriptProvider;
+    }
+    
+    
+    /** 
+     * Determine if database schema needs to be upgraded.
+     */
+    public static boolean isCreationRequired() throws WebloggerException {
+        Connection con = null;
+        try {            
+            con = DatabaseProvider.getDatabaseProvider().getConnection();
+            
+            // just check for a couple key Roller tables
+            if (tableExists(con, "rolleruser") && tableExists(con, "userrole")) return false;
+            
+        } catch (SQLException e) {
+            throw new WebloggerException("ERROR obtaining connection");            
+        } finally {
+            try { if (con != null) con.close(); } catch (Exception ignored) {}
+        }
+        return true;
+    }
+    
+    
+    /**
+     * Create datatabase tables.
+     */
+    public void createDatabase() throws Exception {
+        Connection con = null;
+        SQLScriptRunner create = null;
+        try {
+            con = DatabaseProvider.getDatabaseProvider().getConnection();
+            String handle = getDatabaseHandle(con);
+            create = new SQLScriptRunner(scripts.getDatabaseScript(handle + "/createdb.sql"));
+            create.runScript(con, true);
+            messages.addAll(create.getMessages());
+            
+            DatabaseUpgrader.setDatabaseVersion(con, RollerFactory.getRoller().getVersion());
+            
+        } catch (SQLException sqle) {
+            errorMessage("ERROR running SQL in database creation script");
+            throw sqle;           
+        } catch (Exception ioe) {
+            if (create != null) messages.addAll(create.getMessages());
+            errorMessage("ERROR reading/parsing database creation script");
+            throw ioe;           
+        } finally {
+            try { if (con != null) con.close(); } catch (Exception ignored) {}
+        }
+    }
+    
+    
+    /** Return messages from last run of script, empty if no previous run */
+    public List<String> getMessages() {
+        return messages;
+    }
+    
+    
+    private void errorMessage(String msg) {
+        messages.add(msg);
+        log.error(msg);
+    }    
+    
+    
+    private void successMessage(String msg) {
+        messages.add(msg);
+        log.trace(msg);
+    }
+    
+    
+    /**
+     * Use database product name to get the database script directory name.
+     */
+    public static String getDatabaseHandle(Connection con) throws SQLException {
+        String productName = con.getMetaData().getDatabaseProductName(); 
+        String handle = "mysql";
+        if (       productName.toLowerCase().indexOf("mysql") != -1) {
+            handle =  "mysql";
+        } else if (productName.toLowerCase().indexOf("derby") != -1) {
+            handle =  "derby";
+        } else if (productName.toLowerCase().indexOf("hsql") != -1) {
+            handle =  "hsqldb";
+        } else if (productName.toLowerCase().indexOf("postgres") != -1) {
+            handle =  "postgresql";
+        } else if (productName.toLowerCase().indexOf("oracle") != -1) {
+            handle =  "oracle";
+        } else if (productName.toLowerCase().indexOf("microsoft") != -1) {
+            handle =  "mssql";
+        } else if (productName.toLowerCase().indexOf("db2") != -1) {   
+            handle =  "db2";
+        }
+        return handle;
+    }
+
+    
+    /**
+     * Return true if named table exists in database.
+     */
+    private static boolean tableExists(Connection con, String tableName) throws SQLException {
+        String[] types = {"TABLE"};
+        ResultSet rs = con.getMetaData().getTables(null, null, "%", null);
+        while (rs.next()) {
+            if (tableName.toLowerCase().equals(rs.getString("TABLE_NAME").toLowerCase())) {
+                return true;
+            }
+        }
+        return false;
+    }  
+
+}
+

Added: roller/trunk/apps/weblogger/src/java/org/apache/roller/weblogger/business/utils/DatabaseScriptProvider.java
URL: http://svn.apache.org/viewvc/roller/trunk/apps/weblogger/src/java/org/apache/roller/weblogger/business/utils/DatabaseScriptProvider.java?view=auto&rev=547924
==============================================================================
--- roller/trunk/apps/weblogger/src/java/org/apache/roller/weblogger/business/utils/DatabaseScriptProvider.java (added)
+++ roller/trunk/apps/weblogger/src/java/org/apache/roller/weblogger/business/utils/DatabaseScriptProvider.java Sat Jun 16 06:52:09 2007
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  The ASF licenses this file to You
+ * under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.  For additional information regarding
+ * copyright in this work, please see the NOTICE file in the top level
+ * directory of this distribution.
+ */
+package org.apache.roller.weblogger.business.utils;
+
+import java.io.InputStream;
+
+/**
+ * Interface for retrieving database script.
+ */
+public interface DatabaseScriptProvider {
+    
+    /** Get database script, path is relative to dbscripts dir */
+    public InputStream getDatabaseScript(String path) throws Exception;
+}

Copied: roller/trunk/apps/weblogger/src/java/org/apache/roller/weblogger/business/utils/DatabaseUpgrader.java (from r545007, roller/trunk/apps/weblogger/src/java/org/apache/roller/weblogger/business/utils/UpgradeDatabase.java)
URL: http://svn.apache.org/viewvc/roller/trunk/apps/weblogger/src/java/org/apache/roller/weblogger/business/utils/DatabaseUpgrader.java?view=diff&rev=547924&p1=roller/trunk/apps/weblogger/src/java/org/apache/roller/weblogger/business/utils/UpgradeDatabase.java&r1=545007&p2=roller/trunk/apps/weblogger/src/java/org/apache/roller/weblogger/business/utils/DatabaseUpgrader.java&r2=547924
==============================================================================
--- roller/trunk/apps/weblogger/src/java/org/apache/roller/weblogger/business/utils/UpgradeDatabase.java (original)
+++ roller/trunk/apps/weblogger/src/java/org/apache/roller/weblogger/business/utils/DatabaseUpgrader.java Sat Jun 16 06:52:09 2007
@@ -23,134 +23,158 @@
 import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.sql.Statement;
+import java.util.ArrayList;
 import java.util.Date;
+import java.util.List;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.roller.weblogger.WebloggerException;
+import org.apache.roller.weblogger.business.DatabaseProvider;
+import org.apache.roller.weblogger.business.RollerFactory;
 import org.apache.roller.weblogger.pojos.WeblogPermission;
 
 
 /**
- * Upgrade Roller Database.
+ * Upgrades Roller database.
  */
-public class UpgradeDatabase {
-    
-    private static Log mLogger = LogFactory.getLog(UpgradeDatabase.class);
+public class DatabaseUpgrader {    
+    private static Log log = LogFactory.getLog(DatabaseUpgrader.class);
+    private DatabaseScriptProvider scripts = null;
+    private List<String>           messages = new ArrayList<String>();
     
     // the name of the property which holds the dbversion value
     private static final String DBVERSION_PROP = "roller.database.version";
     
     
+    public DatabaseUpgrader(DatabaseScriptProvider scriptProvider) {
+        this.scripts = scriptProvider;
+    }    
+    
+    
+    /** 
+     * Determine if database schema needs to be upgraded.
+     */
+    public static boolean isUpgradeRequired() throws WebloggerException {        
+        int desiredVersion = parseVersionString(RollerFactory.getRoller().getVersion());
+        int databaseVersion = getDatabaseVersion();
+        return databaseVersion < desiredVersion;
+    }
+
+
+    public void successMessage(String msg) {
+        messages.add(msg);
+        log.info(msg);
+    }
+    
+
+    public void errorMessage(String msg) {
+        messages.add(msg);
+        log.error(msg);
+    }
+    
+
+    public void errorMessage(String msg, Throwable t) {
+        messages.add(msg);
+        log.error(msg, t);
+    }
+    
+
+    public List<String> getMessages() {
+        return messages;
+    }
+
+    
     /**
      * Upgrade database if dbVersion is older than desiredVersion.
      */
-    public static void upgradeDatabase(Connection con, String desiredVersion)
-            throws WebloggerException {
-        
-        int myVersion = 0;
-        int dbversion = -1;
-        
-        // NOTE: this assumes a maximum of 3 digits for the version number
-        //       so if we get to 10.0 then we'll need to upgrade this
-        
-        // strip out non-digits
-        desiredVersion = desiredVersion.replaceAll("\\Q.\\E", "");
-        desiredVersion = desiredVersion.replaceAll("\\D", "");
-        if(desiredVersion.length() > 3)
-            desiredVersion = desiredVersion.substring(0, 3);
-        
-        // parse to an int
-        try {
-            int parsed = Integer.parseInt(desiredVersion);
-            
-            if(parsed < 100)
-                myVersion = parsed * 10;
-            else
-                myVersion = parsed;
-        } catch(Exception e) {}
+    public void upgradeDatabase(boolean runScripts) throws WebloggerException {
         
+        int myVersion = parseVersionString(RollerFactory.getRoller().getVersion());
+        int dbversion = getDatabaseVersion();
         
-        // get the current db version
+        log.debug("Database version = "+dbversion);
+        log.debug("Desired version = "+myVersion);
+       
+        Connection con = null;
         try {
-            Statement stmt = con.createStatement();
-            
-            // just check in the roller_properties table
-            ResultSet rs = stmt.executeQuery(
-                    "select value from roller_properties where name = '"+DBVERSION_PROP+"'");
-            
-            if(rs.next()) {
-                dbversion = Integer.parseInt(rs.getString(1));
-                
-            } else {
-                // tough to know if this is an upgrade with no db version :/
-                // however, if roller_properties is not empty then we at least
-                // we have someone upgrading from 1.2.x
-                rs = stmt.executeQuery("select count(*) from roller_properties");
-                if(rs.next()) {
-                    if(rs.getInt(1) > 0)
-                        dbversion = 120;
-                }
+            con = DatabaseProvider.getDatabaseProvider().getConnection();
+            if(dbversion < 0) {
+                String msg = "Cannot upgrade database tables, Roller database version cannot be determined";
+                errorMessage(msg);
+                throw new WebloggerException(msg);
+            } else if(dbversion >= myVersion) {
+                log.info("Database is current, no upgrade needed");
+                return;
             }
-            
-        } catch(Exception e) {
-            // that's strange ... hopefully we didn't need to upgrade
-            mLogger.error("Couldn't lookup current database version", e);
-            return;
-        }
-        
-        mLogger.debug("Database version = "+dbversion);
-        mLogger.debug("Desired version = "+myVersion);
-        
-        if(dbversion < 0) {
-            mLogger.info("New installation found, setting db version to "+myVersion);
-            UpgradeDatabase.setDatabaseVersion(con, myVersion);
-            return;
-        } else if(dbversion >= myVersion) {
-            mLogger.info("Database is current, no upgrade needed");
-            return;
-        }
-        
-        mLogger.info("Database is old, beginning upgrade to version "+myVersion);
+
+            log.info("Database is old, beginning upgrade to version "+myVersion);
+
+            // iterate through each upgrade as needed
+            // to add to the upgrade sequence simply add a new "if" statement
+            // for whatever version needed and then define a new method upgradeXXX()
+            if(dbversion < 130) {
+                upgradeTo130(con, runScripts);
+                dbversion = 130;
+            }
+            if (dbversion < 200) {
+                upgradeTo200(con, runScripts);
+                dbversion = 200;
+            }
+            if(dbversion < 210) {
+                upgradeTo210(con, runScripts);
+                dbversion = 210;
+            }
+            if(dbversion < 230) {
+                upgradeTo230(con, runScripts);
+                dbversion = 230;
+            }
+            if(dbversion < 240) {
+                upgradeTo240(con, runScripts);
+                dbversion = 240;
+            }
+            if(dbversion < 300) {
+                upgradeTo300(con, runScripts);
+                dbversion = 300;
+            }
+            if(dbversion < 310) {
+                upgradeTo310(con, runScripts);
+                dbversion = 310;
+            }
+            if(dbversion < 320) {
+                upgradeTo320(con, runScripts);
+                dbversion = 320;
+            }
+            if(dbversion < 400) {
+                upgradeTo400(con, runScripts);
+                dbversion = 400;
+            }
+
+            // make sure the database version is the exact version
+            // we are upgrading too.
+            DatabaseUpgrader.updateDatabaseVersion(con, myVersion);
         
-        // iterate through each upgrade as needed
-        // to add to the upgrade sequence simply add a new "if" statement
-        // for whatever version needed and then define a new method upgradeXXX()
-        if(dbversion < 130) {
-            UpgradeDatabase.upgradeTo130(con);
-            dbversion = 130;
-        }
-        if (dbversion < 200) {
-            UpgradeDatabase.upgradeTo200(con);
-            dbversion = 200;
-        }
-        if(dbversion < 210) {
-            UpgradeDatabase.upgradeTo210(con);
-            dbversion = 210;
-        }
-        if(dbversion < 300) {
-            UpgradeDatabase.upgradeTo300(con);
-            dbversion = 300;
-        }
-        if(dbversion < 320) {
-            UpgradeDatabase.upgradeTo320(con);
-            dbversion = 320;
-        }
-        if(dbversion < 400) {
-            UpgradeDatabase.upgradeTo400(con);
-            dbversion = 400;
+        } catch (SQLException e) {
+            throw new WebloggerException("ERROR obtaining connection");
+        } finally {
+            try { if (con != null) con.close(); } catch (Exception ignored) {}
         }
-        
-        // make sure the database version is the exact version
-        // we are upgrading too.
-        UpgradeDatabase.updateDatabaseVersion(con, myVersion);
     }
     
     
     /**
      * Upgrade database for Roller 1.3.0
      */
-    private static void upgradeTo130(Connection con) throws WebloggerException {
+    private void upgradeTo130(Connection con, boolean runScripts) throws WebloggerException {
         try {
+            if (runScripts) {
+                String handle = DatabaseCreator.getDatabaseHandle(con);
+                String scriptPath = handle + "/120-to-130-migration.sql";
+                successMessage("Running database upgrade script: "+scriptPath);                
+                SQLScriptRunner runner = new SQLScriptRunner(scripts.getDatabaseScript(scriptPath));
+                runner.runScript(con, true);
+                messages.addAll(runner.getMessages());
+            }
+            
             /*
              * The new theme management code is going into place and it uses
              * the old website.themeEditor attribute to store a users theme.
@@ -164,8 +188,8 @@
              * in effect because they are using a shared theme instead.
              */
             
-            mLogger.info("Doing upgrade to 130 ...");
-            mLogger.info("Ensuring that all website themes are set to custom");
+            successMessage("Doing upgrade to 130 ...");
+            successMessage("Ensuring that all website themes are set to custom");
             
             PreparedStatement setCustomThemeStmt = con.prepareStatement(
                     "update website set editortheme = ?");
@@ -175,25 +199,32 @@
             
             if (!con.getAutoCommit()) con.commit();
             
-            mLogger.info("Upgrade to 130 complete.");
+            successMessage("Upgrade to 130 complete.");
             
-        } catch (SQLException e) {
-            mLogger.error("Problem upgrading database to version 130", e);
+        } catch (Exception e) {
+            errorMessage("Problem upgrading database to version 130", e);  
             throw new WebloggerException("Problem upgrading database to version 130", e);
         }
         
-        // If someone is upgrading to 1.3.x then we are setting the db version
-        // for the first time.  Normally we would just updateDatabaseVersion()
-        UpgradeDatabase.setDatabaseVersion(con, 130);
+        DatabaseUpgrader.updateDatabaseVersion(con, 130);
     }
     
     /**
      * Upgrade database for Roller 2.0.0
      */
-    private static void upgradeTo200(Connection con) throws WebloggerException {
+    private void upgradeTo200(Connection con, boolean runScripts) throws WebloggerException {
         try {
-            mLogger.info("Doing upgrade to 200 ...");
-            mLogger.info("Populating roller_user_permissions table");
+            if (runScripts) {
+                String handle = DatabaseCreator.getDatabaseHandle(con);
+                String scriptPath = handle + "/130-to-200-migration.sql";
+                successMessage("Running database upgrade script: "+scriptPath);                
+                SQLScriptRunner runner = new SQLScriptRunner(scripts.getDatabaseScript(scriptPath));
+                runner.runScript(con, true);
+                messages.addAll(runner.getMessages());
+            }
+            
+            successMessage("Doing upgrade to 200 ...");
+            successMessage("Populating roller_user_permissions table");
             
             PreparedStatement websitesQuery = con.prepareStatement(
                     "select w.id as wid, u.id as uid, u.username as uname from "
@@ -215,7 +246,7 @@
                 String websiteid = websiteSet.getString("wid");
                 String userid = websiteSet.getString("uid");
                 String handle = websiteSet.getString("uname");
-                mLogger.info("Processing website: " + handle);
+                successMessage("Processing website: " + handle);
                 
                 // use website user's username as website handle
                 websiteUpdate.clearParameters();
@@ -251,22 +282,31 @@
             
             if (!con.getAutoCommit()) con.commit();
             
-            mLogger.info("Upgrade to 200 complete.");
+            successMessage("Upgrade to 200 complete.");
             
-        } catch (SQLException e) {
-            mLogger.error("Problem upgrading database to version 200", e);
+        } catch (Exception e) {
+            errorMessage("Problem upgrading database to version 200", e);
             throw new WebloggerException("Problem upgrading database to version 200", e);
         }
         
-        UpgradeDatabase.updateDatabaseVersion(con, 200);
+        DatabaseUpgrader.updateDatabaseVersion(con, 200);
     }
     
     
     /**
      * Upgrade database for Roller 2.1.0
      */
-    private static void upgradeTo210(Connection con) throws WebloggerException {
+    private void upgradeTo210(Connection con, boolean runScripts) throws WebloggerException {
         try {
+            if (runScripts) {
+                String handle = DatabaseCreator.getDatabaseHandle(con);
+                String scriptPath = handle + "/200-to-210-migration.sql";
+                successMessage("Running database upgrade script: "+scriptPath);                
+                SQLScriptRunner runner = new SQLScriptRunner(scripts.getDatabaseScript(scriptPath));
+                runner.runScript(con, true);
+                messages.addAll(runner.getMessages());
+            }
+            
             /*
              * For Roller 2.1.0 we are going to standardize some of the
              * weblog templates and make them less editable.  To do this
@@ -276,8 +316,8 @@
              * the required "Weblog" template as their default template.
              */
             
-            mLogger.info("Doing upgrade to 210 ...");
-            mLogger.info("Ensuring that all weblogs use the 'Weblog' template as their default page");
+            successMessage("Doing upgrade to 210 ...");
+            successMessage("Ensuring that all weblogs use the 'Weblog' template as their default page");
             
             // this query will give us all websites that have modified their
             // default page to link to something other than "Weblog"
@@ -311,7 +351,7 @@
                 String websiteid = websiteSet.getString(1);
                 String template = websiteSet.getString(2);
                 String handle = websiteSet.getString(3);
-                mLogger.info("Processing website: " + handle);
+                successMessage("Processing website: " + handle);
                 
                 String defaultpageid = null;
                 
@@ -357,22 +397,75 @@
             
             if (!con.getAutoCommit()) con.commit();
             
-            mLogger.info("Upgrade to 210 complete.");
+            successMessage("Upgrade to 210 complete.");
             
-        } catch (SQLException e) {
-            mLogger.error("Problem upgrading database to version 210", e);
+        } catch (Exception e) {
+            log.error("Problem upgrading database to version 210", e);
             throw new WebloggerException("Problem upgrading database to version 210", e);
         }
         
-        UpgradeDatabase.updateDatabaseVersion(con, 210);
+        DatabaseUpgrader.updateDatabaseVersion(con, 210);
+    }
+    
+    
+    /**
+     * Upgrade database for Roller 2.3.0
+     */
+    private void upgradeTo230(Connection con, boolean runScripts) throws WebloggerException {
+        try {
+            if (runScripts) {
+                String handle = DatabaseCreator.getDatabaseHandle(con);
+                String scriptPath = handle + "/210-to-230-migration.sql";
+                successMessage("Running database upgrade script: "+scriptPath);                
+                SQLScriptRunner runner = new SQLScriptRunner(scripts.getDatabaseScript(scriptPath));
+                runner.runScript(con, true);
+                messages.addAll(runner.getMessages());
+            }
+        } catch (Exception e) {
+            errorMessage("Problem upgrading database to version 230", e);
+            throw new WebloggerException("Problem upgrading database to version 230", e);
+        }
+        
+        DatabaseUpgrader.updateDatabaseVersion(con, 230);
+    }
+    
+    
+    /**
+     * Upgrade database for Roller 2.4.0
+     */
+    private void upgradeTo240(Connection con, boolean runScripts) throws WebloggerException {
+        try {
+            if (runScripts) {
+                String handle = DatabaseCreator.getDatabaseHandle(con);
+                String scriptPath = handle + "/230-to-240-migration.sql";
+                successMessage("Running database upgrade script: "+scriptPath);                
+                SQLScriptRunner runner = new SQLScriptRunner(scripts.getDatabaseScript(scriptPath));
+                runner.runScript(con, true);
+                messages.addAll(runner.getMessages());
+            }
+        } catch (Exception e) {
+            errorMessage("Problem upgrading database to version 240", e);
+            throw new WebloggerException("Problem upgrading database to version 240", e);
+        }
+        
+        DatabaseUpgrader.updateDatabaseVersion(con, 240);
     }
     
     
     /**
      * Upgrade database for Roller 3.0.0
      */
-    private static void upgradeTo300(Connection con) throws WebloggerException {
+    private void upgradeTo300(Connection con, boolean runScripts) throws WebloggerException {
         try {
+            if (runScripts) {
+                String handle = DatabaseCreator.getDatabaseHandle(con);
+                String scriptPath = handle + "/240-to-300-migration.sql";
+                successMessage("Running database upgrade script: "+scriptPath);                
+                SQLScriptRunner runner = new SQLScriptRunner(scripts.getDatabaseScript(scriptPath));
+                runner.runScript(con, true);
+                messages.addAll(runner.getMessages());
+            }
+            
             /*
              * For Roller 3.0.0 we are allowing each weblogentry to track a
              * locale now so that we can support multi-lingual blogs.  As part
@@ -382,12 +475,12 @@
              * 2. set the locale on all entries to the locale for the weblog
              */
             
-            mLogger.info("Doing upgrade to 300 ...");
+            successMessage("Doing upgrade to 300 ...");
             
             // get system default language
             String locale = java.util.Locale.getDefault().getLanguage();
             
-            mLogger.info("Setting website locale to "+locale+" for websites with no locale");
+            successMessage("Setting website locale to "+locale+" for websites with no locale");
             
             // update all weblogs where locale is "null"
             PreparedStatement updateNullWeblogLocale = con.prepareStatement(
@@ -401,7 +494,7 @@
             updateEmptyWeblogLocale.executeUpdate();
 
             
-            mLogger.info("Setting weblogentry locales to website locale");
+            successMessage("Setting weblogentry locales to website locale");
             
             // get all entries and the locale of its website
             PreparedStatement selectWeblogsLocale = con.prepareStatement(
@@ -428,26 +521,57 @@
             
             if (!con.getAutoCommit()) con.commit();
             
-            mLogger.info("Upgrade to 300 complete.");
+            successMessage("Upgrade to 300 complete.");
             
-        } catch (SQLException e) {
-            mLogger.error("Problem upgrading database to version 300", e);
+        } catch (Exception e) {
+            errorMessage("Problem upgrading database to version 300", e);
             throw new WebloggerException("Problem upgrading database to version 300", e);
         }
         
-        UpgradeDatabase.updateDatabaseVersion(con, 300);
+        DatabaseUpgrader.updateDatabaseVersion(con, 300);
     }
     
     
     /**
+     * Upgrade database for Roller 3.1.0
+     */
+    private void upgradeTo310(Connection con, boolean runScripts) throws WebloggerException {
+        try {
+            if (runScripts) {
+                String handle = DatabaseCreator.getDatabaseHandle(con);
+                String scriptPath = handle + "/300-to-310-migration.sql";
+                successMessage("Running database upgrade script: "+scriptPath);                
+                SQLScriptRunner runner = new SQLScriptRunner(scripts.getDatabaseScript(scriptPath));
+                runner.runScript(con, true);
+                messages.addAll(runner.getMessages());
+            }
+        } catch (Exception e) {
+            errorMessage("Problem upgrading database to version 310", e);
+            throw new WebloggerException("Problem upgrading database to version 310", e);
+        }
+        
+        DatabaseUpgrader.updateDatabaseVersion(con, 310);
+    }
+
+    
+    /**
      * Upgrade database for Roller 3.2.0
      */
-    private static void upgradeTo320(Connection con) throws WebloggerException {
+    private void upgradeTo320(Connection con, boolean runScripts) throws WebloggerException {
         
-        mLogger.info("Doing upgrade to 320 ...");
+        successMessage("Doing upgrade to 320 ...");
         
         try {    
-            mLogger.info("Populating parentid columns for weblogcategory and folder tables");
+            if (runScripts) {
+                String handle = DatabaseCreator.getDatabaseHandle(con);
+                String scriptPath = handle + "/310-to-320-migration.sql";
+                successMessage("Running database upgrade script: "+scriptPath);                
+                SQLScriptRunner runner = new SQLScriptRunner(scripts.getDatabaseScript(scriptPath));
+                runner.runScript(con, true);
+                messages.addAll(runner.getMessages());
+            }
+            
+            successMessage("Populating parentid columns for weblogcategory and folder tables");
             
             // Populate parentid in weblogcategory and folder tables.
             //
@@ -496,16 +620,16 @@
             
             if (!con.getAutoCommit()) con.commit();
            
-            mLogger.info("Done populating parentid columns.");
+            successMessage("Done populating parentid columns.");
             
-        } catch (SQLException e) {
-            mLogger.error("Problem upgrading database to version 320", e);
+        } catch (Exception e) {
+            errorMessage("Problem upgrading database to version 320", e);
             throw new WebloggerException("Problem upgrading database to version 320", e);
         }
         
         
         try {
-            mLogger.info("Populating path columns for weblogcategory and folder tables.");
+            successMessage("Populating path columns for weblogcategory and folder tables.");
                         
             // Populate path in weblogcategory and folder tables.
             //
@@ -556,7 +680,7 @@
             // we use the do/while construct to ensure it's run at least once
             int catNumCounted = 0;
             do {
-                mLogger.debug("Doing pass over Lx children for categories");
+                log.debug("Doing pass over Lx children for categories");
                 
                 // reset count for each iteration of outer loop
                 catNumCounted = 0;
@@ -575,7 +699,7 @@
                     catNumCounted++;
                 }
                 
-                mLogger.debug("Updated "+catNumCounted+" Lx category paths");
+                log.debug("Updated "+catNumCounted+" Lx category paths");
             } while(catNumCounted > 0);
             
             
@@ -621,7 +745,7 @@
             // we use the do/while construct to ensure it's run at least once
             int folderNumUpdated = 0;
             do {
-                mLogger.debug("Doing pass over Lx children for folders");
+                log.debug("Doing pass over Lx children for folders");
                 
                 // reset count for each iteration of outer loop
                 folderNumUpdated = 0;
@@ -640,32 +764,41 @@
                     folderNumUpdated++;
                 }
                 
-                mLogger.debug("Updated "+folderNumUpdated+" Lx folder paths");
+                log.debug("Updated "+folderNumUpdated+" Lx folder paths");
             } while(folderNumUpdated > 0);
             
             if (!con.getAutoCommit()) con.commit();
            
-            mLogger.info("Done populating path columns.");
+            successMessage("Done populating path columns.");
             
         } catch (SQLException e) {
-            mLogger.error("Problem upgrading database to version 320", e);
+            log.error("Problem upgrading database to version 320", e);
             throw new WebloggerException("Problem upgrading database to version 320", e);
         }
         
         // finally, upgrade db version string to 320
-        UpgradeDatabase.updateDatabaseVersion(con, 320);
+        DatabaseUpgrader.updateDatabaseVersion(con, 320);
     }
     
     
     /**
      * Upgrade database for Roller 4.0.0
      */
-    private static void upgradeTo400(Connection con) throws WebloggerException {
+    private void upgradeTo400(Connection con, boolean runScripts) throws WebloggerException {
         
-        mLogger.info("Doing upgrade to 400 ...");
+        successMessage("Doing upgrade to 400 ...");
         
         try {    
-            mLogger.info("Merging planet groups 'all' and 'external'");
+            if (runScripts) {
+                String handle = DatabaseCreator.getDatabaseHandle(con);
+                String scriptPath = handle + "/320-to-400-migration.sql";
+                successMessage("Running database upgrade script: "+scriptPath);                
+                SQLScriptRunner runner = new SQLScriptRunner(scripts.getDatabaseScript(scriptPath));
+                runner.runScript(con, true);
+                messages.addAll(runner.getMessages());
+            }
+            
+            successMessage("Merging planet groups 'all' and 'external'");
             
             // Move all subscriptions in the planet group 'external' to group 'all'
             
@@ -710,24 +843,92 @@
             
             if (!con.getAutoCommit()) con.commit();
            
-            mLogger.info("Planet group 'external' merged into group 'all'.");
+            successMessage("Planet group 'external' merged into group 'all'.");
             
-        } catch (SQLException e) {
-            mLogger.error("Problem upgrading database to version 400", e);
+        } catch (Exception e) {
+            errorMessage("Problem upgrading database to version 400", e);
             throw new WebloggerException("Problem upgrading database to version 400", e);
         }
         
         // finally, upgrade db version string to 400
-        UpgradeDatabase.updateDatabaseVersion(con, 400);
+        DatabaseUpgrader.updateDatabaseVersion(con, 400);
     }
     
     
+    private static int getDatabaseVersion() throws WebloggerException {
+        int dbversion = -1;
+        
+        // get the current db version
+        Connection con = null;
+        try {
+            con = DatabaseProvider.getDatabaseProvider().getConnection();
+            Statement stmt = con.createStatement();
+            
+            // just check in the roller_properties table
+            ResultSet rs = stmt.executeQuery(
+                    "select value from roller_properties where name = '"+DBVERSION_PROP+"'");
+            
+            if(rs.next()) {
+                dbversion = Integer.parseInt(rs.getString(1));
+                
+            } else {
+                // tough to know if this is an upgrade with no db version :/
+                // however, if roller_properties is not empty then we at least
+                // we have someone upgrading from 1.2.x
+                rs = stmt.executeQuery("select count(*) from roller_properties");
+                if(rs.next()) {
+                    if(rs.getInt(1) > 0)
+                        dbversion = 120;
+                }
+            }
+            
+        } catch(Exception e) {
+            // that's strange ... hopefully we didn't need to upgrade
+            log.error("Couldn't lookup current database version", e);           
+        } finally {
+            try { if (con != null) con.close(); } catch (Exception ignored) {}
+        }       
+        return dbversion;
+    }
+    
+    
+    private static int parseVersionString(String vstring) {        
+        int myversion = 0;
+        
+        // NOTE: this assumes a maximum of 3 digits for the version number
+        // so if we get to 10.0 then we'll need to upgrade this
+        
+        // strip out non-digits
+        vstring = vstring.replaceAll("\\Q.\\E", "");
+        vstring = vstring.replaceAll("\\D", "");
+        if(vstring.length() > 3)
+            vstring = vstring.substring(0, 3);
+        
+        // parse to an int
+        try {
+            int parsed = Integer.parseInt(vstring);            
+            if(parsed < 100) myversion = parsed * 10;
+            else myversion = parsed;
+        } catch(Exception e) {}  
+        
+        return myversion;
+    }
+    
+
     /**
      * Insert a new database.version property.
-     *
      * This should only be called once for new installations
      */
-    private static void setDatabaseVersion(Connection con, int version)
+    public static void setDatabaseVersion(Connection con, String version) 
+            throws WebloggerException {
+        setDatabaseVersion(con, parseVersionString(version));
+    }
+
+    /**
+     * Insert a new database.version property.
+     * This should only be called once for new installations
+     */
+    public static void setDatabaseVersion(Connection con, int version)
             throws WebloggerException {
         
         try {
@@ -735,7 +936,7 @@
             stmt.executeUpdate("insert into roller_properties "+
                     "values('"+DBVERSION_PROP+"', '"+version+"')");
             
-            mLogger.debug("Set database verstion to "+version);
+            log.debug("Set database verstion to "+version);
         } catch(SQLException se) {
             throw new WebloggerException("Error setting database version.", se);
         }
@@ -754,10 +955,10 @@
                     "set value = '"+version+"'"+
                     "where name = '"+DBVERSION_PROP+"'");
             
-            mLogger.debug("Updated database verstion to "+version);
+            log.debug("Updated database verstion to "+version);
         } catch(SQLException se) {
             throw new WebloggerException("Error setting database version.", se);
-        }
-    }
+        } 
+    } 
 }
 

Added: roller/trunk/apps/weblogger/src/java/org/apache/roller/weblogger/business/utils/SQLScriptRunner.java
URL: http://svn.apache.org/viewvc/roller/trunk/apps/weblogger/src/java/org/apache/roller/weblogger/business/utils/SQLScriptRunner.java?view=auto&rev=547924
==============================================================================
--- roller/trunk/apps/weblogger/src/java/org/apache/roller/weblogger/business/utils/SQLScriptRunner.java (added)
+++ roller/trunk/apps/weblogger/src/java/org/apache/roller/weblogger/business/utils/SQLScriptRunner.java Sat Jun 16 06:52:09 2007
@@ -0,0 +1,156 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  The ASF licenses this file to You
+ * under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.  For additional information regarding
+ * copyright in this work, please see the NOTICE file in the top level
+ * directory of this distribution.
+ */
+
+package org.apache.roller.weblogger.business.utils;
+
+import java.io.BufferedReader;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * SQL script runner, parses script and allows you to run it. 
+ * You can run the script multiple times if necessary.
+ * Assumes that anything on an input line after "--" or ";" can be ignored.
+ */
+public class SQLScriptRunner {
+    private static Log   log = LogFactory.getLog(SQLScriptRunner.class);
+    
+    private String       scriptPath = null;
+    private List<String> commands = new ArrayList<String>();
+    private List<String> messages = new ArrayList<String>();
+    private boolean      failed = false;
+    private boolean      errors = false;
+        
+    
+    /** Creates a new instance of SQLScriptRunner */
+    public SQLScriptRunner(InputStream is) throws IOException {
+        this.scriptPath = scriptPath;
+        BufferedReader in = new BufferedReader(new InputStreamReader(is));
+        String command = ""; 
+        String line;
+        while ((line = in.readLine()) != null) {
+            line = line.trim();
+            
+            if (!line.startsWith("--")) { // ignore lines starting with "--"    
+                
+                if (line.indexOf("--") > 0) {
+                    // trim comment off end of line
+                    line = line.substring(0, line.indexOf("--")).trim();
+                }
+                
+                // add line to current command
+                command += line.trim();
+                if (command.endsWith(";")) { 
+                    // ";" is end of command, so add completed command to list
+                    commands.add(command.substring(0, command.length() - 1));   
+                    command = "";
+                } else {
+                    command += " "; // still more command coming so add space
+                }
+            } 
+        }
+        in.close();    
+    }
+    
+    
+    /** Creates a new instance of SQLScriptRunner */
+    public SQLScriptRunner(String scriptPath) throws IOException {
+        this(new FileInputStream(scriptPath));
+    }
+    
+    
+    /** Number of SQL commands in script */
+    public int getCommandCount() {
+        return commands.size();
+    }
+    
+    
+    /** Return messages from last run of script, empty if no previous run */
+    public List<String> getMessages() {
+        return messages;
+    }
+    
+    
+    /** Returns true if last call to runScript() threw an exception */
+    public boolean getFailed() {
+        return failed;
+    }
+    
+    
+    /** Returns true if last run had any errors */
+    public boolean getErrors() {
+        return errors;
+    }
+    
+    
+    /** Run script, logs messages, and optionally throws exception on error */
+    public void runScript(
+            Connection con, boolean stopOnError) throws SQLException {
+        failed = false;
+        errors = false;
+        for (String command : commands) {
+            
+            // run each command
+            try {
+                Statement stmt = con.createStatement();
+                stmt.executeUpdate(command);
+                if (!con.getAutoCommit()) con.commit();
+                
+                // on success, echo command to messages
+                successMessage(command);
+                
+            } catch (SQLException ex) {
+                // add error message with text of SQL command to messages
+                errorMessage("ERROR: SQLException executing SQL [" + command 
+                        + "] : " + ex.getLocalizedMessage());
+                // add stack trace to messages
+                StringWriter sw = new StringWriter();
+                ex.printStackTrace(new PrintWriter(sw));
+                errorMessage(sw.toString());
+                if (stopOnError) {
+                    failed = true;
+                    throw ex;
+                }
+            }
+        }
+    }
+    
+    
+    private void errorMessage(String msg) {
+        messages.add(msg);
+        log.error(msg);
+    }    
+    
+    
+    private void successMessage(String msg) {
+        messages.add(msg);
+        log.error(msg);
+    }
+}
+

Modified: roller/trunk/apps/weblogger/src/java/org/apache/roller/weblogger/config/roller.properties
URL: http://svn.apache.org/viewvc/roller/trunk/apps/weblogger/src/java/org/apache/roller/weblogger/config/roller.properties?view=diff&rev=547924&r1=547923&r2=547924
==============================================================================
--- roller/trunk/apps/weblogger/src/java/org/apache/roller/weblogger/config/roller.properties (original)
+++ roller/trunk/apps/weblogger/src/java/org/apache/roller/weblogger/config/roller.properties Sat Jun 16 06:52:09 2007
@@ -40,6 +40,12 @@
 # properties in this file are accessed like this ...
 #    RollerConfig.getProperty("propname");
 
+# Installation type 'auto' or 'manual'
+# - Set to 'auto' if you'd like tables to be auto-created if they are not found
+#   on startup and auto-upgraded if they need it.
+# - Set to 'manual' if you'd want to run the SQL scripts by hand. 
+installation.type=manual
+
 #---------------------------------
 # Database configuration settings
 

Modified: roller/trunk/apps/weblogger/src/java/org/apache/roller/weblogger/ui/core/RollerContext.java
URL: http://svn.apache.org/viewvc/roller/trunk/apps/weblogger/src/java/org/apache/roller/weblogger/ui/core/RollerContext.java?view=diff&rev=547924&r1=547923&r2=547924
==============================================================================
--- roller/trunk/apps/weblogger/src/java/org/apache/roller/weblogger/ui/core/RollerContext.java (original)
+++ roller/trunk/apps/weblogger/src/java/org/apache/roller/weblogger/ui/core/RollerContext.java Sat Jun 16 06:52:09 2007
@@ -39,7 +39,8 @@
 import org.apache.roller.weblogger.WebloggerException;
 import org.apache.roller.weblogger.business.DatabaseProvider;
 import org.apache.roller.weblogger.business.runnable.RollerTask;
-import org.apache.roller.weblogger.business.utils.UpgradeDatabase;
+import org.apache.roller.weblogger.business.utils.DatabaseScriptProvider;
+import org.apache.roller.weblogger.business.utils.DatabaseUpgrader;
 import org.apache.roller.weblogger.config.PingConfig;
 import org.apache.roller.weblogger.config.RollerConfig;
 import org.apache.roller.weblogger.business.Roller;
@@ -62,8 +63,8 @@
 /**
  * Initialize the Roller web application/context.
  */
-public class RollerContext extends ContextLoaderListener 
-        implements ServletContextListener {
+public class RollerContext extends ContextLoaderListener  
+        implements ServletContextListener, DatabaseScriptProvider { 
     
     private static Log log = LogFactory.getLog(RollerContext.class);
     
@@ -81,64 +82,78 @@
     public void contextInitialized(ServletContextEvent sce) {
         
         log.info("Apache Roller Weblogger Initializing ...");
-                
-        // Keep a reverence to ServletContext object
-        this.servletContext = sce.getServletContext();
-        
-        // Call Spring's context ContextLoaderListener to initialize all the 
-        // context files specified in web.xml. This is necessary because 
-        // listeners don't initialize in the order specified in 2.3 containers
-        super.contextInitialized(sce);
-            
-        // get the *real* path to <context>/resources
-        String ctxPath = servletContext.getRealPath("/");
-        if(!ctxPath.endsWith(File.separator))
-            ctxPath += File.separator + "resources";
-        else
-            ctxPath += "resources";
-        
-        // try setting the uploads path to <context>/resources
-        // NOTE: this should go away at some point
-        // we leave it here for now to allow users to keep writing
-        // uploads into their webapp context, but this is a bad idea
-        //
-        // also, the RollerConfig.setUploadsDir() method is smart
-        // enough to disregard this call unless the uploads.path
-        // is set to ${webapp.context}
-        RollerConfig.setUploadsDir(ctxPath);
-        
-        // try setting the themes path to <context>/themes
-        // NOTE: this should go away at some point
-        // we leave it here for now to allow users to keep using
-        // themes in their webapp context, but this is a bad idea
-        //
-        // also, the RollerConfig.setThemesDir() method is smart
-        // enough to disregard this call unless the themes.dir
-        // is set to ${webapp.context}
-        RollerConfig.setThemesDir(servletContext.getRealPath("/")+File.separator+"themes");
-        
-        try {
-            // Parts of database upgrade are not included in migration scripts
-            upgradeDatabaseIfNeeded();
-            
-            // trigger bootstrapping process
-            RollerFactory.bootstrap();
             
-            // flush any changes made during bootstrapping
-            RollerFactory.getRoller().flush();
+        try {
             
+            // First, initialize everything that requires no database 
+
+            // Keep a reverence to ServletContext object
+            this.servletContext = sce.getServletContext();
+
+            // Save self to context as DatabaseScriptProvider
+            this.servletContext.setAttribute("DatabaseScriptProvider", this);
+
+            // Call Spring's context ContextLoaderListener to initialize all the 
+            // context files specified in web.xml. This is necessary because 
+            // listeners don't initialize in the order specified in 2.3 containers
+            super.contextInitialized(sce);
+
+            // get the *real* path to <context>/resources
+            String ctxPath = servletContext.getRealPath("/");
+            if(!ctxPath.endsWith(File.separator))
+                ctxPath += File.separator + "resources";
+            else
+                ctxPath += "resources";
+
+            // try setting the uploads path to <context>/resources
+            // NOTE: this should go away at some point
+            // we leave it here for now to allow users to keep writing
+            // uploads into their webapp context, but this is a bad idea
+            //
+            // also, the RollerConfig.setUploadsDir() method is smart
+            // enough to disregard this call unless the uploads.path
+            // is set to ${webapp.context}
+            RollerConfig.setUploadsDir(ctxPath);
+
+            // try setting the themes path to <context>/themes
+            // NOTE: this should go away at some point
+            // we leave it here for now to allow users to keep using
+            // themes in their webapp context, but this is a bad idea
+            //
+            // also, the RollerConfig.setThemesDir() method is smart
+            // enough to disregard this call unless the themes.dir
+            // is set to ${webapp.context}
+            RollerConfig.setThemesDir(servletContext.getRealPath("/")+File.separator+"themes");
+        
             // Initialize Acegi based on Roller configuration
             initializeSecurityFeatures(servletContext);
             
             // Setup Velocity template engine
             setupVelocity();
+           
+
+            // Now, the database dependent part...
+
+            // If installation type is manual, then don't run migraton scripts
+            if ("manual".equals(RollerConfig.getProperty("installation.type"))) {
+                if (DatabaseUpgrader.isUpgradeRequired()) {
+                    DatabaseUpgrader upgrader = new DatabaseUpgrader(this); 
+                    upgrader.upgradeDatabase(false);
+                }
+            }
+            
+            // trigger bootstrapping process
+            RollerFactory.bootstrap();
+            
+            // flush any changes made during bootstrapping
+            RollerFactory.getRoller().flush();
             
         } catch (Throwable t) {
             log.fatal("Roller Weblogger initialization failed", t);
         }
         
         // Initialize Planet if necessary
-        if(RollerConfig.getBooleanProperty("planet.aggregator.enabled")) {
+        if (RollerConfig.getBooleanProperty("planet.aggregator.enabled")) {
             try {
                 Planet planet = PlanetFactory.getPlanet();                
                 PlanetFactory.getPlanet().getPropertiesManager();                
@@ -165,16 +180,6 @@
     
     
     /**
-     * Trigger any database upgrade work that needs to be done.
-     */
-    private void upgradeDatabaseIfNeeded() throws Exception {        
-        Connection con = DatabaseProvider.getDatabaseProvider().getConnection();
-        UpgradeDatabase.upgradeDatabase(con, RollerFactory.getRoller().getVersion());
-        con.close();
-    }
-    
-    
-    /**
      * Initialize the Velocity rendering engine.
      */
     private void setupVelocity() throws Exception {        
@@ -294,7 +299,15 @@
         return servletContext;
     }
     
-    
+
+    /**
+     * Get database script as stream, path is relative to dbscripts directory.
+     */
+    public InputStream getDatabaseScript(String path) throws Exception {
+        return getServletContext().getResourceAsStream("/WEB-INF/dbscripts/" + path);
+    }
+
+
     /**
      * Get an instance of AutoProvision, if available in roller.properties
      * @return AutoProvision
@@ -342,5 +355,4 @@
     public static UIPluginManager getUIPluginManager() {
         return UIPluginManagerImpl.getInstance();
     }
-
 }

Added: roller/trunk/apps/weblogger/src/java/org/apache/roller/weblogger/ui/core/filters/BootstrapFilter.java
URL: http://svn.apache.org/viewvc/roller/trunk/apps/weblogger/src/java/org/apache/roller/weblogger/ui/core/filters/BootstrapFilter.java?view=auto&rev=547924
==============================================================================
--- roller/trunk/apps/weblogger/src/java/org/apache/roller/weblogger/ui/core/filters/BootstrapFilter.java (added)
+++ roller/trunk/apps/weblogger/src/java/org/apache/roller/weblogger/ui/core/filters/BootstrapFilter.java Sat Jun 16 06:52:09 2007
@@ -0,0 +1,121 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  The ASF licenses this file to You
+ * under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.  For additional information regarding
+ * copyright in this work, please see the NOTICE file in the top level
+ * directory of this distribution.
+ */
+
+package org.apache.roller.weblogger.ui.core.filters;
+
+import java.io.IOException;
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.roller.RollerException;
+import org.apache.roller.weblogger.business.DatabaseProvider;
+import org.apache.roller.weblogger.config.RollerConfig;
+import org.apache.roller.weblogger.business.utils.DatabaseCreator;
+import org.apache.roller.weblogger.business.utils.DatabaseUpgrader;
+
+
+/**
+ * Checks database setup, forwards to appropriate error or setup page.
+ */
+public class BootstrapFilter implements Filter {
+    private ServletContext context = null;
+    private static Log log = LogFactory.getLog(BootstrapFilter.class);
+    
+    
+    /**
+     * Release Roller persistence session at end of request processing.
+     */
+    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
+            throws IOException, ServletException {
+        
+        HttpServletRequest request = (HttpServletRequest) req;
+        HttpServletResponse response = (HttpServletResponse) res;
+        
+        log.debug("Entered "+request.getRequestURI());
+        
+        if ("auto".equals(RollerConfig.getProperty("installation.type"))) {
+            
+            // an auto-install is in progress, do some checks and if necessary
+            // redirect to error, db create or db upgrade page
+
+            // only do this if Roller is configured for auto-install and 
+            // only if request is NOT for install page or a style/script file
+            
+            String requestURI = request.getRequestURI();
+            if (     requestURI != null 
+                 && !requestURI.startsWith("/roller/roller-ui/install") 
+                 && !requestURI.endsWith(".js")
+                 && !requestURI.endsWith(".css")) {
+                        
+                // if cannot connect to database
+                try {
+                    DatabaseProvider dp = DatabaseProvider.getDatabaseProvider();             
+                } catch (RollerException e) {
+                    // we doing an install, so forward to informative database error page
+                    RequestDispatcher rd = 
+                        context.getRequestDispatcher("/roller-ui/install/databaseError.rol");
+                    rd.forward(req, res);
+                    return;
+                }   
+
+                // if installation type 'auto' then check if upgrade required
+                try {               
+                    if (DatabaseCreator.isCreationRequired()) {
+                        // forward to database create page
+                        RequestDispatcher rd = context.getRequestDispatcher(
+                            "/roller-ui/install/createDatabase.rol");
+                        rd.forward(req, res);   
+                        return;
+                    } 
+                    if (DatabaseUpgrader.isUpgradeRequired()) {
+                        // forward to database upgrade page
+                        RequestDispatcher rd = context.getRequestDispatcher(
+                            "/roller-ui/install/upgradeDatabase.rol");
+                        rd.forward(req, res);
+                        return;
+                    }
+                } catch (Throwable t) {
+                    // Exception at this point indicates something is 
+                    // horribly wrong and there is no way to recover.
+                    throw new RuntimeException("FATAL error checking database status", t);
+                }
+            }
+        }
+                  
+        chain.doFilter(request, response);                    
+        log.debug("Exiting "+request.getRequestURI());
+    }
+    
+    
+    public void init(FilterConfig filterConfig) throws ServletException {
+        context = filterConfig.getServletContext();
+    }
+    
+    public void destroy() {}
+    
+}
+

Added: roller/trunk/apps/weblogger/src/java/org/apache/roller/weblogger/ui/struts2/core/CreateDatabase.java
URL: http://svn.apache.org/viewvc/roller/trunk/apps/weblogger/src/java/org/apache/roller/weblogger/ui/struts2/core/CreateDatabase.java?view=auto&rev=547924
==============================================================================
--- roller/trunk/apps/weblogger/src/java/org/apache/roller/weblogger/ui/struts2/core/CreateDatabase.java (added)
+++ roller/trunk/apps/weblogger/src/java/org/apache/roller/weblogger/ui/struts2/core/CreateDatabase.java Sat Jun 16 06:52:09 2007
@@ -0,0 +1,102 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  The ASF licenses this file to You
+ * under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.  For additional information regarding
+ * copyright in this work, please see the NOTICE file in the top level
+ * directory of this distribution.
+ */
+
+package org.apache.roller.weblogger.ui.struts2.core;
+
+import com.opensymphony.xwork2.ActionSupport;
+import java.sql.Connection;
+import java.util.List;
+import java.util.Map;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.roller.weblogger.WebloggerException;
+import org.apache.roller.weblogger.business.DatabaseProvider;
+import org.apache.roller.weblogger.business.utils.DatabaseCreator;
+import org.apache.roller.weblogger.business.utils.DatabaseScriptProvider;
+import org.apache.roller.weblogger.config.RollerConfig;
+import org.apache.struts2.interceptor.ApplicationAware;
+
+/**
+ * Walk user through database auto-creation process.
+ */
+public class CreateDatabase extends ActionSupport implements ApplicationAware { 
+    private static Log log = LogFactory.getLog(CreateDatabase.class);
+    
+    private DatabaseScriptProvider scripts = null;    
+    private boolean error = false;
+    private List<String> messages = null;
+    
+    
+    public String execute() {
+        return SUCCESS;
+    }
+    
+    /**
+     * Looks for DatabaseScriptProvider via key 'DatabaseScriptProvider'
+     */
+    public void setApplication(Map map) {
+        if (map.get("DatabaseScriptProvider") != null) {
+            scripts = (DatabaseScriptProvider)map.get("DatabaseScriptProvider");
+        }
+    }
+
+    public String create() {
+        DatabaseCreator creator = new DatabaseCreator(scripts);
+        try {
+            creator.createDatabase();
+        } catch (Exception ex) {
+            log.error("ERROR running database creation script", ex);
+            error = true;
+        }
+        messages = creator.getMessages();
+        return SUCCESS;
+    }
+
+    public boolean isCreationRequired() {
+        try {
+            return DatabaseCreator.isCreationRequired();
+        } catch (WebloggerException ex) {
+            log.error("ERROR determining if database creation required", ex);
+        }
+        return false;
+    }
+
+    public List<String> getMessages() {
+        return messages;
+    }
+    
+    public boolean getError() {
+        return error;
+    }
+    
+    public String getProp(String key) {
+        // Static config only, we don't have database yet
+        String value = RollerConfig.getProperty(key);
+        return (value == null) ? key : value;
+    }
+    
+    public String getDatabaseProductName() {
+        String name = "error";
+        try {
+            Connection con = DatabaseProvider.getDatabaseProvider().getConnection();
+            name = con.getMetaData().getDatabaseProductName();
+        } catch (Exception intentionallyIgnored) {}
+        return name;
+    }
+}
+

Added: roller/trunk/apps/weblogger/src/java/org/apache/roller/weblogger/ui/struts2/core/DatabaseError.java
URL: http://svn.apache.org/viewvc/roller/trunk/apps/weblogger/src/java/org/apache/roller/weblogger/ui/struts2/core/DatabaseError.java?view=auto&rev=547924
==============================================================================
--- roller/trunk/apps/weblogger/src/java/org/apache/roller/weblogger/ui/struts2/core/DatabaseError.java (added)
+++ roller/trunk/apps/weblogger/src/java/org/apache/roller/weblogger/ui/struts2/core/DatabaseError.java Sat Jun 16 06:52:09 2007
@@ -0,0 +1,62 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  The ASF licenses this file to You
+ * under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.  For additional information regarding
+ * copyright in this work, please see the NOTICE file in the top level
+ * directory of this distribution.
+ */
+
+package org.apache.roller.weblogger.ui.struts2.core;
+
+import com.opensymphony.xwork2.ActionSupport;
+import java.io.StringWriter;
+import java.util.List;
+import org.apache.roller.RollerException;
+import org.apache.roller.weblogger.business.DatabaseProvider;
+import org.apache.roller.weblogger.config.RollerConfig;
+
+/**
+ * Display error message about database.
+ */
+public class DatabaseError extends ActionSupport { 
+    
+    public String execute() {
+        return SUCCESS;
+    }
+    
+    public String getProp(String key) {
+        // Static config only, we don't have database yet
+        String value = RollerConfig.getProperty(key);
+        return (value == null) ? key : value;
+    }    
+    
+    public List<String> getStartupLog() {
+        return DatabaseProvider.getStartupLog();
+    }
+    
+    public Throwable getRootCauseException() {
+        RollerException re = DatabaseProvider.getStartupException();
+        if (re.getRootCause() != null) {
+            return re.getRootCause();
+        } else {
+            return re;
+        }
+    }
+    
+    public String getRootCauseStackTrace() {
+        StringWriter sw = new java.io.StringWriter();
+        Throwable e = getRootCauseException();
+        e.printStackTrace(new java.io.PrintWriter(sw));
+        return sw.toString().trim();
+    }
+}