jackrabbit-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ste...@apache.org
Subject svn commit: r328071 - in /incubator/jackrabbit/trunk: ./ applications/test/ applications/test/workspaces/default/ applications/test/workspaces/test/ contrib/db-persistence/ contrib/examples/ src/conf/ src/java/org/apache/jackrabbit/core/state/db/ xdocs/
Date Mon, 24 Oct 2005 13:55:40 GMT
Author: stefan
Date: Mon Oct 24 06:55:26 2005
New Revision: 328071

URL: http://svn.apache.org/viewcvs?rev=328071&view=rev
Log:
- moved db-persistence code from contrib to core
- changed default configuration to use DerbyPersistenceManager
  instead of filesystem-based ObjectPersistenceManager
- removed CQFileSystem from project.xml and default configuration

as discussed in the following thread:
http://thread.gmane.org/gmane.comp.apache.jackrabbit.devel/4026

Added:
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/db/
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/db/DerbyPersistenceManager.java   (with props)
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/db/SimpleDbPersistenceManager.java   (with props)
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/db/daffodil.ddl
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/db/default.ddl
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/db/derby.ddl
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/db/mssql.ddl
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/db/mysql.ddl
    incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/db/package.html   (with props)
Removed:
    incubator/jackrabbit/trunk/contrib/db-persistence/
Modified:
    incubator/jackrabbit/trunk/applications/test/repository.xml
    incubator/jackrabbit/trunk/applications/test/workspaces/default/workspace.xml
    incubator/jackrabbit/trunk/applications/test/workspaces/test/workspace.xml
    incubator/jackrabbit/trunk/contrib/examples/project.xml
    incubator/jackrabbit/trunk/maven.xml
    incubator/jackrabbit/trunk/project.xml
    incubator/jackrabbit/trunk/src/conf/repository.xml
    incubator/jackrabbit/trunk/xdocs/firststeps.xml

Modified: incubator/jackrabbit/trunk/applications/test/repository.xml
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/applications/test/repository.xml?rev=328071&r1=328070&r2=328071&view=diff
==============================================================================
--- incubator/jackrabbit/trunk/applications/test/repository.xml (original)
+++ incubator/jackrabbit/trunk/applications/test/repository.xml Mon Oct 24 06:55:26 2005
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="ISO-8859-1"?>
+<?xml version="1.0"?>
 <!DOCTYPE Repository [
     <!--
         the Repository element configures a repository instance;
@@ -75,7 +75,7 @@
     <!ATTLIST LoginModule
       class CDATA #REQUIRED>
 
-    <!--
+   <!--
         the Workspaces element specifies the workspaces root directory
         (rootPath attribute) and the name of the default workspace
         (defaultWorkspace attribute).
@@ -165,32 +165,17 @@
             virtual file system of the workspace:
             class: FQN of class implementing the FileSystem interface
         -->
-        <FileSystem class="com.day.jackrabbit.fs.cq.CQFileSystem">
-            <param name="path" value="${wsp.home}/wspStore.dat"/>
-            <param name="autoRepair" value="false"/>
-            <param name="blockSize" value="128"/>
-            <param name="autoSync" value="false"/>
-        </FileSystem>
-        <!--
         <FileSystem class="org.apache.jackrabbit.core.fs.local.LocalFileSystem">
             <param name="path" value="${wsp.home}"/>
         </FileSystem>
-        -->
         <!--
             persistence manager of the workspace:
             class: FQN of class implementing the PersistenceManager interface
         -->
-        <!--
-        <PersistenceManager class="org.apache.jackrabbit.core.state.xml.XMLPersistenceManager"/>
-        -->
-        <!--
-        <PersistenceManager class="org.apache.jackrabbit.core.state.mem.InMemPersistenceManager">
-            <param name="initialCapacity" value="100000"/>
-            <param name="loadFactor" value="0.3"/>
-            <param name="persistent" value="true"/>
+        <PersistenceManager class="org.apache.jackrabbit.core.state.db.DerbyPersistenceManager">
+          <param name="url" value="jdbc:derby:${wsp.home}/db;create=true"/>
+          <param name="schemaObjectPrefix" value="${wsp.name}_"/>
         </PersistenceManager>
-        -->
-        <PersistenceManager class="org.apache.jackrabbit.core.state.obj.ObjectPersistenceManager"/>
         <!--
             Search index and the file system it uses.
             class: FQN of class implementing the QueryHandler interface
@@ -208,26 +193,20 @@
             Configures the filesystem to use for versioning for the respective
             persistence manager
         -->
-        <FileSystem class="com.day.jackrabbit.fs.cq.CQFileSystem">
-            <param name="path" value="${rep.home}/version/version.dat"/>
-            <param name="autoRepair" value="false"/>
-            <param name="blockSize" value="128"/>
-            <param name="autoSync" value="false"/>
+        <FileSystem class="org.apache.jackrabbit.core.fs.local.LocalFileSystem">
+            <param name="path" value="${rep.home}/version" />
         </FileSystem>
-    
-        <!--
-            <FileSystem class="org.apache.jackrabbit.core.fs.local.LocalFileSystem">
-                <param name="path" value="${rep.home}/version"/>
-            </FileSystem>
-        -->
         
         <!--
-            Configures the perisistence manager to be used for persisting version state.
+            Configures the persistence manager to be used for persisting version state.
             Please note that the current versioning implementation is based on
             a 'normal' persistence manager, but this could change in future
             implementations.
         -->
-        <PersistenceManager class="org.apache.jackrabbit.core.state.obj.ObjectPersistenceManager"/>
+        <PersistenceManager class="org.apache.jackrabbit.core.state.db.DerbyPersistenceManager">
+          <param name="url" value="jdbc:derby:${rep.home}/version/db;create=true"/>
+          <param name="schemaObjectPrefix" value="version_"/>
+        </PersistenceManager>
 
     </Versioning>
 </Repository>

Modified: incubator/jackrabbit/trunk/applications/test/workspaces/default/workspace.xml
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/applications/test/workspaces/default/workspace.xml?rev=328071&r1=328070&r2=328071&view=diff
==============================================================================
--- incubator/jackrabbit/trunk/applications/test/workspaces/default/workspace.xml (original)
+++ incubator/jackrabbit/trunk/applications/test/workspaces/default/workspace.xml Mon Oct 24 06:55:26 2005
@@ -1,20 +1,20 @@
-<?xml version="1.0" encoding="UTF-8"?>
+<?xml version="1.0"?>
 <Workspace name="default">
   <!--
       virtual file system of the workspace:
       class: FQN of class implementing FileSystem interface
   -->
-  <FileSystem class="com.day.jackrabbit.fs.cq.CQFileSystem">
-    <param name="path" value="${wsp.home}/data/wspStore.dat"/>
-    <param name="autoRepair" value="false"/>
-    <param name="blockSize" value="128"/>
-    <param name="autoSync" value="false"/>
+  <FileSystem class="org.apache.jackrabbit.core.fs.local.LocalFileSystem">
+    <param name="path" value="${wsp.home}" />
   </FileSystem>
   <!--
       persistence of the workspace:
       class: FQN of class implementing PersistenceManager interface
   -->
-  <PersistenceManager class="org.apache.jackrabbit.core.state.obj.ObjectPersistenceManager"/>
+  <PersistenceManager class="org.apache.jackrabbit.core.state.db.DerbyPersistenceManager">
+     <param name="url" value="jdbc:derby:${wsp.home}/db;create=true"/>
+     <param name="schemaObjectPrefix" value="${wsp.name}_"/>
+  </PersistenceManager>
   <!--
       Search index and the file system it uses.
   -->

Modified: incubator/jackrabbit/trunk/applications/test/workspaces/test/workspace.xml
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/applications/test/workspaces/test/workspace.xml?rev=328071&r1=328070&r2=328071&view=diff
==============================================================================
--- incubator/jackrabbit/trunk/applications/test/workspaces/test/workspace.xml (original)
+++ incubator/jackrabbit/trunk/applications/test/workspaces/test/workspace.xml Mon Oct 24 06:55:26 2005
@@ -1,20 +1,20 @@
-<?xml version="1.0" encoding="UTF-8"?>
+<?xml version="1.0"?>
 <Workspace name="test">
   <!--
       virtual file system of the workspace:
       class: FQN of class implementing FileSystem interface
   -->
-  <FileSystem class="com.day.jackrabbit.fs.cq.CQFileSystem">
-    <param name="path" value="${wsp.home}/data/wspStore.dat"/>
-    <param name="autoRepair" value="false"/>
-    <param name="blockSize" value="128"/>
-    <param name="autoSync" value="false"/>
+  <FileSystem class="org.apache.jackrabbit.core.fs.local.LocalFileSystem">
+    <param name="path" value="${wsp.home}" />
   </FileSystem>
   <!--
       persistence of the workspace:
       class: FQN of class implementing PersistenceManager interface
   -->
-  <PersistenceManager class="org.apache.jackrabbit.core.state.obj.ObjectPersistenceManager"/>
+  <PersistenceManager class="org.apache.jackrabbit.core.state.db.DerbyPersistenceManager">
+     <param name="url" value="jdbc:derby:${wsp.home}/db;create=true"/>
+     <param name="schemaObjectPrefix" value="${wsp.name}_"/>
+  </PersistenceManager>
   <!--
       Search index and the file system it uses.
   -->

Modified: incubator/jackrabbit/trunk/contrib/examples/project.xml
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/contrib/examples/project.xml?rev=328071&r1=328070&r2=328071&view=diff
==============================================================================
--- incubator/jackrabbit/trunk/contrib/examples/project.xml (original)
+++ incubator/jackrabbit/trunk/contrib/examples/project.xml Mon Oct 24 06:55:26 2005
@@ -63,7 +63,7 @@
       <version>1.0-SNAPSHOT</version>
     </dependency>
 
-    <!--d Runtime dependencies needed by Jackrabbit -->
+    <!-- Runtime dependencies needed by Jackrabbit -->
     <dependency>
       <groupId>concurrent</groupId>
       <artifactId>concurrent</artifactId>
@@ -98,28 +98,6 @@
       <groupId>xerces</groupId>
       <artifactId>xmlParserAPIs</artifactId>
       <version>2.0.2</version>
-    </dependency>
-    <!--
-      cqfs-jackrabbit and cqfs are optional runtime dependencies 
-      (an alternative FileSystem implementation); 
-      commons-logging is a dependency of cqfs
-    -->
-    <dependency>
-      <groupId>cqfs</groupId>
-      <artifactId>cqfs-jackrabbit</artifactId>
-      <version>3.5.6-SNAPSHOT</version>
-      <url>http://www.day.com/maven/cqfs/jars/cqfs-jackrabbit-3.5.6-SNAPSHOT.jar</url>
-    </dependency>
-    <dependency>
-      <groupId>cqfs</groupId>
-      <artifactId>cqfs</artifactId>
-      <version>3.5.6-SNAPSHOT</version>
-      <url>http://www.day.com/maven/cqfs/jars/cqfs-3.5.6-SNAPSHOT.jar</url>
-    </dependency>
-    <dependency>
-      <groupId>commons-logging</groupId>
-      <artifactId>commons-logging</artifactId>
-      <version>1.0</version>
     </dependency>
   </dependencies>
 

Modified: incubator/jackrabbit/trunk/maven.xml
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/maven.xml?rev=328071&r1=328070&r2=328071&view=diff
==============================================================================
--- incubator/jackrabbit/trunk/maven.xml (original)
+++ incubator/jackrabbit/trunk/maven.xml Mon Oct 24 06:55:26 2005
@@ -175,10 +175,9 @@
 
     <!--
         Copies all dependencies to ./target/lib
-        (except the optional runtime dependencies cqfs and cqfs-jackrabbit)
     -->
     <goal name="copy-deps">
-        <deploy:copy-deps todir="./target/lib" excludes="cqfs,cqfs-jackrabbit"/>
+        <deploy:copy-deps todir="./target/lib"/>
     </goal>
 
     <!--

Modified: incubator/jackrabbit/trunk/project.xml
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/project.xml?rev=328071&r1=328070&r2=328071&view=diff
==============================================================================
--- incubator/jackrabbit/trunk/project.xml (original)
+++ incubator/jackrabbit/trunk/project.xml Mon Oct 24 06:55:26 2005
@@ -356,36 +356,10 @@
             <artifactId>xmlParserAPIs</artifactId>
             <version>2.0.2</version>
         </dependency>
-        <!--
-          cqfs-jackrabbit and cqfs are optional runtime dependencies 
-          (an alternative FileSystem implementation); 
-          commons-logging is a dependency of cqfs
-        -->
         <dependency>
-            <groupId>cqfs</groupId>
-            <artifactId>cqfs-jackrabbit</artifactId>
-            <version>3.5.6-SNAPSHOT</version>
-            <url>http://www.day.com/maven/cqfs/jars/cqfs-jackrabbit-3.5.6-SNAPSHOT.jar</url>
-            <properties>
-                <scope>runtime</scope>
-            </properties>
-        </dependency>
-        <dependency>
-            <groupId>cqfs</groupId>
-            <artifactId>cqfs</artifactId>
-            <version>3.5.6-SNAPSHOT</version>
-            <url>http://www.day.com/maven/cqfs/jars/cqfs-3.5.6-SNAPSHOT.jar</url>
-            <properties>
-                <scope>runtime</scope>
-            </properties>
-        </dependency>
-        <dependency>
-            <groupId>commons-logging</groupId>
-            <artifactId>commons-logging</artifactId>
-            <version>1.0</version>
-            <properties>
-                <scope>runtime</scope>
-            </properties>
+            <groupId>org.apache.derby</groupId>
+            <artifactId>derby</artifactId>
+            <version>10.1.1.0</version>
         </dependency>
     </dependencies>
 
@@ -428,6 +402,7 @@
                 <includes>
                     <include>**/*.xml</include>
                     <include>**/*.properties</include>
+                    <include>**/*.ddl</include>
                     <include>META-INF/services/*</include>
                 </includes>
             </resource>

Modified: incubator/jackrabbit/trunk/src/conf/repository.xml
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/conf/repository.xml?rev=328071&r1=328070&r2=328071&view=diff
==============================================================================
--- incubator/jackrabbit/trunk/src/conf/repository.xml (original)
+++ incubator/jackrabbit/trunk/src/conf/repository.xml Mon Oct 24 06:55:26 2005
@@ -165,32 +165,17 @@
             virtual file system of the workspace:
             class: FQN of class implementing the FileSystem interface
         -->
-        <FileSystem class="com.day.jackrabbit.fs.cq.CQFileSystem">
-            <param name="path" value="${wsp.home}/wspStore.dat"/>
-            <param name="autoRepair" value="false"/>
-            <param name="blockSize" value="128"/>
-            <param name="autoSync" value="false"/>
-        </FileSystem>
-        <!--
         <FileSystem class="org.apache.jackrabbit.core.fs.local.LocalFileSystem">
             <param name="path" value="${wsp.home}"/>
         </FileSystem>
-        -->
         <!--
             persistence manager of the workspace:
             class: FQN of class implementing the PersistenceManager interface
         -->
-        <!--
-        <PersistenceManager class="org.apache.jackrabbit.core.state.xml.XMLPersistenceManager"/>
-        -->
-        <!--
-        <PersistenceManager class="org.apache.jackrabbit.core.state.mem.InMemPersistenceManager">
-            <param name="initialCapacity" value="100000"/>
-            <param name="loadFactor" value="0.3"/>
-            <param name="persistent" value="true"/>
+        <PersistenceManager class="org.apache.jackrabbit.core.state.db.DerbyPersistenceManager">
+            <param name="url" value="jdbc:derby:${wsp.home}/db;create=true"/>
+            <param name="schemaObjectPrefix" value="${wsp.name}_"/>
         </PersistenceManager>
-        -->
-        <PersistenceManager class="org.apache.jackrabbit.core.state.obj.ObjectPersistenceManager"/>
         <!--
             Search index and the file system it uses.
             class: FQN of class implementing the QueryHandler interface
@@ -241,18 +226,9 @@
             Configures the filesystem to use for versioning for the respective
             persistence manager
         -->
-        <FileSystem class="com.day.jackrabbit.fs.cq.CQFileSystem">
-            <param name="path" value="${rep.home}/version/version.dat"/>
-            <param name="autoRepair" value="false"/>
-            <param name="blockSize" value="128"/>
-            <param name="autoSync" value="false"/>
+        <FileSystem class="org.apache.jackrabbit.core.fs.local.LocalFileSystem">
+            <param name="path" value="${rep.home}/version"/>
         </FileSystem>
-    
-        <!--
-            <FileSystem class="org.apache.jackrabbit.core.fs.local.LocalFileSystem">
-                <param name="path" value="${rep.home}/version"/>
-            </FileSystem>
-        -->
         
         <!--
             Configures the perisistence manager to be used for persisting version state.
@@ -260,7 +236,10 @@
             a 'normal' persistence manager, but this could change in future
             implementations.
         -->
-        <PersistenceManager class="org.apache.jackrabbit.core.state.obj.ObjectPersistenceManager"/>
+        <PersistenceManager class="org.apache.jackrabbit.core.state.db.DerbyPersistenceManager">
+            <param name="url" value="jdbc:derby:${rep.home}/version/db;create=true"/>
+            <param name="schemaObjectPrefix" value="version_"/>
+        </PersistenceManager>
 
     </Versioning>
 </Repository>

Added: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/db/DerbyPersistenceManager.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/db/DerbyPersistenceManager.java?rev=328071&view=auto
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/db/DerbyPersistenceManager.java (added)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/db/DerbyPersistenceManager.java Mon Oct 24 06:55:26 2005
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2004-2005 The Apache Software Foundation or its licensors,
+ *                     as applicable.
+ *
+ * Licensed 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.
+ */
+package org.apache.jackrabbit.core.state.db;
+
+import org.apache.log4j.Logger;
+
+import java.sql.DriverManager;
+import java.sql.SQLException;
+
+/**
+ * <code>DerbyPersistenceManager</code> is a JDBC-based
+ * <code>PersistenceManager</code> for Jackrabbit that persists
+ * <code>ItemState</code> and <code>NodeReferences</code> objects in an
+ * embedded Derby database using a simple custom serialization format and a
+ * very basic non-normalized database schema (in essence tables with one 'key'
+ * and one 'data' column).
+ * <p/>
+ * It is configured through the following properties:
+ * <ul>
+ * <li><code>url</code>: the database url of the form
+ * <code>"jdbc:derby:[db];[attributes]"</code></li>
+ * <li><code>schemaObjectPrefix</code>: prefix to be prepended to schema objects</li>
+ * <li><code>driver</code>: the FQN name of the JDBC driver class
+ * (default: <code>"org.apache.derby.jdbc.EmbeddedDriver"</code>)</li>
+ * <li><code>schema</code>: type of schema to be used
+ * (default: <code>"derby"</code>)</li>
+ * <li><code>user</code>: the database user (default: <code>""</code>)</li>
+ * <li><code>password</code>: the user's password (default: <code>""</code>)</li>
+ * </ul>
+ * See also {@link SimpleDbPersistenceManager}.
+ * <p/>
+ * The following is a fragment from a sample configuration:
+ * <pre>
+ *   &lt;PersistenceManager class="org.apache.jackrabbit.core.state.db.DerbyPersistenceManager"&gt;
+ *       &lt;param name="url" value="jdbc:derby:${wsp.home}/db;create=true"/&gt;
+ *       &lt;param name="schemaObjectPrefix" value="${wsp.name}_"/&gt;
+ *  &lt;/PersistenceManager&gt;
+ * </pre>
+ */
+public class DerbyPersistenceManager extends SimpleDbPersistenceManager {
+
+    /**
+     * Logger instance
+     */
+    private static Logger log = Logger.getLogger(DerbyPersistenceManager.class);
+
+    /**
+     * Creates a new <code>SimpleDbPersistenceManager</code> instance.
+     */
+    public DerbyPersistenceManager() {
+        // preset some attributes to reasonable defaults
+        schema = "derby";
+        driver = "org.apache.derby.jdbc.EmbeddedDriver";
+        schemaObjectPrefix = "";
+        user = "";
+        password = "";
+        initialized = false;
+    }
+
+    //---------------------------------< SimpleDbPersistenceManager overrides >
+    /**
+     * {@inheritDoc}
+     * <p/>
+     * Overridden in order to properly shutdown the embedded Derby database.
+     */
+    public synchronized void close() throws Exception {
+        if (!initialized) {
+            throw new IllegalStateException("not initialized");
+        }
+
+        // prepare connection url for issuing shutdown command
+        String url = con.getMetaData().getURL();
+        int pos = url.lastIndexOf(';');
+        if (pos != -1) {
+            // strip amy attributes from connection url
+            url = url.substring(0, pos);
+        }
+        url += ";shutdown=true";
+
+        // we have to reset the connection to 'autoCommit=true' before closing it;
+        // otherwise Derby would mysteriously complain about some pending uncommitted
+        // changes which can't possibly be true.
+        // @todo further investigate
+        con.setAutoCommit(true);
+
+        // call base class implementation
+        super.close();
+
+        // now it's safe to shutdown the embedded Derby database
+        try {
+            DriverManager.getConnection(url);
+        } catch (SQLException e) {
+            // a shutdown command always raises a SQLException
+            log.info(e.getMessage());
+        }
+    }
+}

Propchange: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/db/DerbyPersistenceManager.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/db/DerbyPersistenceManager.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url

Added: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/db/SimpleDbPersistenceManager.java
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/db/SimpleDbPersistenceManager.java?rev=328071&view=auto
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/db/SimpleDbPersistenceManager.java (added)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/db/SimpleDbPersistenceManager.java Mon Oct 24 06:55:26 2005
@@ -0,0 +1,930 @@
+/*
+ * Copyright 2004-2005 The Apache Software Foundation or its licensors,
+ *                     as applicable.
+ *
+ * Licensed 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.
+ */
+package org.apache.jackrabbit.core.state.db;
+
+import org.apache.jackrabbit.core.NodeId;
+import org.apache.jackrabbit.core.PropertyId;
+import org.apache.jackrabbit.core.fs.FileSystem;
+import org.apache.jackrabbit.core.fs.FileSystemPathUtil;
+import org.apache.jackrabbit.core.fs.FileSystemResource;
+import org.apache.jackrabbit.core.fs.local.LocalFileSystem;
+import org.apache.jackrabbit.core.state.AbstractPersistenceManager;
+import org.apache.jackrabbit.core.state.ChangeLog;
+import org.apache.jackrabbit.core.state.ItemState;
+import org.apache.jackrabbit.core.state.ItemStateException;
+import org.apache.jackrabbit.core.state.NoSuchItemStateException;
+import org.apache.jackrabbit.core.state.NodeReferences;
+import org.apache.jackrabbit.core.state.NodeReferencesId;
+import org.apache.jackrabbit.core.state.NodeState;
+import org.apache.jackrabbit.core.state.PMContext;
+import org.apache.jackrabbit.core.state.PropertyState;
+import org.apache.jackrabbit.core.state.obj.BLOBStore;
+import org.apache.jackrabbit.core.state.obj.ObjectPersistenceManager;
+import org.apache.jackrabbit.core.value.BLOBFileValue;
+import org.apache.jackrabbit.core.value.InternalValue;
+import org.apache.jackrabbit.name.QName;
+import org.apache.jackrabbit.util.Text;
+import org.apache.log4j.Logger;
+
+import javax.jcr.PropertyType;
+import javax.jcr.RepositoryException;
+import java.io.BufferedOutputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.InputStreamReader;
+import java.io.BufferedReader;
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+
+/**
+ * <code>SimpleDbPersistenceManager</code> is a generic JDBC-based
+ * <code>PersistenceManager</code> for Jackrabbit that persists
+ * <code>ItemState</code> and <code>NodeReferences</code> objects using a
+ * simple custom serialization format and a very basic non-normalized database
+ * schema (in essence tables with one 'key' and one 'data' column).
+ * <p/>
+ * It is configured through the following properties:
+ * <ul>
+ * <li><code>driver</code>: the FQN name of the JDBC driver class</li>
+ * <li><code>url</code>: the database url of the form <code>jdbc:subprotocol:subname</code></li>
+ * <li><code>user</code>: the database user</li>
+ * <li><code>password</code>: the user's password</li>
+ * <li><code>schema</code>: type of schema to be used
+ * (e.g. <code>mysql</code>, <code>mssql</code>, etc.); </li>
+ * <li><code>schemaObjectPrefix</code>: prefix to be prepended to schema objects</li>
+ * </ul>
+ * The required schema objects are automatically created by executing the DDL
+ * statements read from the [schema].ddl file. The .ddl file is read from the
+ * resources by calling <code>getClass().getResourceAsStream(schema + ".ddl")</code>.
+ * Every line in the specified .ddl file is executed separatly by calling
+ * <code>java.sql.Statement.execute(String)</code> where every occurence of the
+ * the string <code>"${schemaObjectPrefix}"</code> has been replaced with the
+ * value of the property <code>schemaObjectPrefix</code>.
+ * <p/>
+ * The following is a fragment from a sample configuration using MySQL:
+ * <pre>
+ *   &lt;PersistenceManager class="org.apache.jackrabbit.core.state.db.SimpleDbPersistenceManager"&gt;
+ *       &lt;param name="driver" value="com.mysql.jdbc.Driver"/&gt;
+ *       &lt;param name="url" value="jdbc:mysql:///test"/&gt;
+ *       &lt;param name="schema" value="mysql"/&gt;
+ *       &lt;param name="schemaObjectPrefix" value="${wsp.name}_"/&gt;
+ *  &lt;/PersistenceManager&gt;
+ * </pre>
+ * The following is a fragment from a sample configuration using Daffodil One$DB Embedded:
+ * <pre>
+ *   &lt;PersistenceManager class="org.apache.jackrabbit.core.state.db.SimpleDbPersistenceManager"&gt;
+ *       &lt;param name="driver" value="in.co.daffodil.db.jdbc.DaffodilDBDriver"/&gt;
+ *       &lt;param name="url" value="jdbc:daffodilDB_embedded:${wsp.name};path=${wsp.home}/../../databases;create=true"/&gt;
+ *       &lt;param name="user" value="daffodil"/&gt;
+ *       &lt;param name="password" value="daffodil"/&gt;
+ *       &lt;param name="schema" value="daffodil"/&gt;
+ *       &lt;param name="schemaObjectPrefix" value="${wsp.name}_"/&gt;
+ *  &lt;/PersistenceManager&gt;
+ * </pre>
+ */
+public class SimpleDbPersistenceManager extends AbstractPersistenceManager
+        implements BLOBStore {
+
+    /** Logger instance */
+    private static Logger log = Logger.getLogger(SimpleDbPersistenceManager.class);
+
+    protected static final String SCHEMA_OBJECT_PREFIX_VARIABLE =
+            "${schemaObjectPrefix}";
+
+    protected boolean initialized;
+
+    protected String driver;
+    protected String url;
+    protected String user;
+    protected String password;
+    protected String schema;
+    protected String schemaObjectPrefix;
+
+    // initial size of buffer used to serialize objects
+    protected static final int INITIAL_BUFFER_SIZE = 1024;
+
+    // jdbc connection
+    protected Connection con;
+
+    // shared prepared statements for NodeState management
+    protected PreparedStatement nodeStateInsert;
+    protected PreparedStatement nodeStateUpdate;
+    protected PreparedStatement nodeStateSelect;
+    protected PreparedStatement nodeStateDelete;
+
+    // shared prepared statements for PropertyState management
+    protected PreparedStatement propertyStateInsert;
+    protected PreparedStatement propertyStateUpdate;
+    protected PreparedStatement propertyStateSelect;
+    protected PreparedStatement propertyStateDelete;
+
+    // shared prepared statements for NodeReference management
+    protected PreparedStatement nodeReferenceInsert;
+    protected PreparedStatement nodeReferenceUpdate;
+    protected PreparedStatement nodeReferenceSelect;
+    protected PreparedStatement nodeReferenceDelete;
+
+    /** file system where BLOB data is stored */
+    protected FileSystem blobFS;
+
+    /**
+     * Creates a new <code>SimpleDbPersistenceManager</code> instance.
+     */
+    public SimpleDbPersistenceManager() {
+        schema = "default";
+        schemaObjectPrefix = "";
+        initialized = false;
+    }
+
+    //----------------------------------------------------< setters & getters >
+    public String getUrl() {
+        return url;
+    }
+
+    public void setUrl(String url) {
+        this.url = url;
+    }
+
+    public String getUser() {
+        return user;
+    }
+
+    public void setUser(String user) {
+        this.user = user;
+    }
+
+    public String getPassword() {
+        return password;
+    }
+
+    public void setPassword(String password) {
+        this.password = password;
+    }
+
+    public String getDriver() {
+        return driver;
+    }
+
+    public void setDriver(String driver) {
+        this.driver = driver;
+    }
+
+    public String getSchemaObjectPrefix() {
+        return schemaObjectPrefix;
+    }
+
+    public void setSchemaObjectPrefix(String schemaObjectPrefix) {
+        // make sure prefix is all uppercase
+        this.schemaObjectPrefix = schemaObjectPrefix.toUpperCase();
+    }
+
+    public String getSchema() {
+        return schema;
+    }
+
+    public void setSchema(String schema) {
+        this.schema = schema;
+    }
+
+    //------------------------------------------------------------< BLOBStore >
+    /**
+     * {@inheritDoc}
+     */
+    public FileSystemResource get(String blobId) throws Exception {
+        return new FileSystemResource(blobFS, blobId);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public String put(PropertyId id, int index, InputStream in, long size)
+            throws Exception {
+        String path = buildBlobFilePath(id.getParentUUID(), id.getName(), index);
+        OutputStream out = null;
+        FileSystemResource internalBlobFile = new FileSystemResource(blobFS, path);
+        internalBlobFile.makeParentDirs();
+        try {
+            out = new BufferedOutputStream(internalBlobFile.getOutputStream());
+            byte[] buffer = new byte[8192];
+            int read;
+            while ((read = in.read(buffer)) > 0) {
+                out.write(buffer, 0, read);
+            }
+        } finally {
+            out.close();
+        }
+        return path;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean remove(String blobId) throws Exception {
+        FileSystemResource res = new FileSystemResource(blobFS, blobId);
+        if (!res.exists()) {
+            return false;
+        }
+        // delete resource and prune empty parent folders
+        res.delete(true);
+        return true;
+    }
+
+    //---------------------------------------------------< PersistenceManager >
+    /**
+     * {@inheritDoc}
+     */
+    public void init(PMContext context) throws Exception {
+        if (initialized) {
+            throw new IllegalStateException("already initialized");
+        }
+
+        // setup jdbc connection
+        Class.forName(driver);
+        con = DriverManager.getConnection(url, user, password);
+        con.setAutoCommit(false);
+
+        // check if schema objects exist and create them if necessary
+        checkSchema();
+
+        /**
+         * store blob's in local file system in a sub directory
+         * of the workspace home directory
+         */
+        LocalFileSystem blobFS = new LocalFileSystem();
+        blobFS.setRoot(new File(context.getHomeDir(), "blobs"));
+        blobFS.init();
+        this.blobFS = blobFS;
+
+        // prepare statements
+        nodeStateInsert =
+                con.prepareStatement("insert into "
+                + schemaObjectPrefix + "NODE (NODE_DATA, NODE_ID) values (?, ?)");
+        nodeStateUpdate =
+                con.prepareStatement("update "
+                + schemaObjectPrefix + "NODE set NODE_DATA = ? where NODE_ID = ?");
+        nodeStateSelect =
+                con.prepareStatement("select NODE_DATA from "
+                + schemaObjectPrefix + "NODE where NODE_ID = ?");
+        nodeStateDelete =
+                con.prepareStatement("delete from "
+                + schemaObjectPrefix + "NODE where NODE_ID = ?");
+
+        propertyStateInsert =
+                con.prepareStatement("insert into "
+                + schemaObjectPrefix + "PROP (PROP_DATA, PROP_ID) values (?, ?)");
+        propertyStateUpdate =
+                con.prepareStatement("update "
+                + schemaObjectPrefix + "PROP set PROP_DATA = ? where PROP_ID = ?");
+        propertyStateSelect =
+                con.prepareStatement("select PROP_DATA from "
+                + schemaObjectPrefix + "PROP where PROP_ID = ?");
+        propertyStateDelete =
+                con.prepareStatement("delete from "
+                + schemaObjectPrefix + "PROP where PROP_ID = ?");
+
+        nodeReferenceInsert =
+                con.prepareStatement("insert into "
+                + schemaObjectPrefix + "REFS (REFS_DATA, NODE_ID) values (?, ?)");
+        nodeReferenceUpdate =
+                con.prepareStatement("update "
+                + schemaObjectPrefix + "REFS set REFS_DATA = ? where NODE_ID = ?");
+        nodeReferenceSelect =
+                con.prepareStatement("select REFS_DATA from "
+                + schemaObjectPrefix + "REFS where NODE_ID = ?");
+        nodeReferenceDelete =
+                con.prepareStatement("delete from "
+                + schemaObjectPrefix + "REFS where NODE_ID = ?");
+
+        initialized = true;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public synchronized void close() throws Exception {
+        if (!initialized) {
+            throw new IllegalStateException("not initialized");
+        }
+
+        try {
+            // close shared prepared statements
+            closeStatement(nodeStateInsert);
+            closeStatement(nodeStateUpdate);
+            closeStatement(nodeStateSelect);
+            closeStatement(nodeStateDelete);
+
+            closeStatement(propertyStateInsert);
+            closeStatement(propertyStateUpdate);
+            closeStatement(propertyStateSelect);
+            closeStatement(propertyStateDelete);
+
+            closeStatement(nodeReferenceInsert);
+            closeStatement(nodeReferenceUpdate);
+            closeStatement(nodeReferenceSelect);
+            closeStatement(nodeReferenceDelete);
+
+            // close jdbc connection
+            con.close();
+            // close blob store
+            blobFS.close();
+            blobFS = null;
+        } finally {
+            initialized = false;
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public synchronized void store(ChangeLog changeLog)
+            throws ItemStateException {
+        ItemStateException ise = null;
+        try {
+            super.store(changeLog);
+        } catch (ItemStateException e) {
+            ise = e;
+        } finally {
+            if (ise == null) {
+                // storing the changes succeeded, now commit the changes
+                try {
+                    con.commit();
+                } catch (SQLException e) {
+                    String msg = "committing change log failed";
+                    log.error(msg, e);
+                    throw new ItemStateException(msg, e);
+                }
+            } else {
+                // storing the changes failed, rollback changes
+                try {
+                    con.rollback();
+                } catch (SQLException e) {
+                    String msg = "rollback of change log failed";
+                    log.error(msg, e);
+                    // re-throw original exception
+                    throw ise;
+                }
+            }
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public synchronized NodeState load(NodeId id)
+            throws NoSuchItemStateException, ItemStateException {
+        if (!initialized) {
+            throw new IllegalStateException("not initialized");
+        }
+
+        PreparedStatement stmt = nodeStateSelect;
+        ResultSet rs = null;
+        InputStream in = null;
+        try {
+            stmt.setString(1, id.toString());
+            stmt.execute();
+            rs = stmt.getResultSet();
+            if (!rs.next()) {
+                throw new NoSuchItemStateException(id.toString());
+            }
+
+            in = rs.getBinaryStream(1);
+            NodeState state = createNew(id);
+            ObjectPersistenceManager.deserialize(state, in);
+
+            return state;
+        } catch (Exception e) {
+            if (e instanceof NoSuchItemStateException) {
+                throw (NoSuchItemStateException) e;
+            }
+            String msg = "failed to read node state: " + id;
+            log.error(msg, e);
+            throw new ItemStateException(msg, e);
+        } finally {
+            closeStream(in);
+            closeResultSet(rs);
+            resetStatement(stmt);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public synchronized PropertyState load(PropertyId id)
+            throws NoSuchItemStateException, ItemStateException {
+        if (!initialized) {
+            throw new IllegalStateException("not initialized");
+        }
+
+        PreparedStatement stmt = propertyStateSelect;
+        ResultSet rs = null;
+        InputStream in = null;
+        try {
+            stmt.setString(1, id.toString());
+            stmt.execute();
+            rs = stmt.getResultSet();
+            if (!rs.next()) {
+                throw new NoSuchItemStateException(id.toString());
+            }
+
+            in = rs.getBinaryStream(1);
+            PropertyState state = createNew(id);
+            ObjectPersistenceManager.deserialize(state, in, this);
+
+            return state;
+        } catch (Exception e) {
+            if (e instanceof NoSuchItemStateException) {
+                throw (NoSuchItemStateException) e;
+            }
+            String msg = "failed to read property state: " + id;
+            log.error(msg, e);
+            throw new ItemStateException(msg, e);
+        } finally {
+            closeStream(in);
+            closeResultSet(rs);
+            resetStatement(stmt);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     * <p/>
+     * This method uses shared <code>PreparedStatement</code>s which must
+     * be executed strictly sequentially. Because this method synchronizes on
+     * the persistence manager instance there is no need to synchronize on the
+     * shared statement. If the method would not be sychronized the shared
+     * statements would have to be synchronized.
+     */
+    public synchronized void store(NodeState state) throws ItemStateException {
+        if (!initialized) {
+            throw new IllegalStateException("not initialized");
+        }
+
+        // check if insert or update
+        //boolean update = exists((NodeId) state.getId());
+        boolean update = state.getStatus() != ItemState.STATUS_NEW;
+        PreparedStatement stmt = (update) ? nodeStateUpdate : nodeStateInsert;
+
+        try {
+            ByteArrayOutputStream out =
+                    new ByteArrayOutputStream(INITIAL_BUFFER_SIZE);
+            // serialize node state
+            ObjectPersistenceManager.serialize(state, out);
+
+            // we are synchronized on this instance, therefore we do not
+            // not have to additionally synchronize on the preparedStatement
+
+            stmt.setBytes(1, out.toByteArray());
+            stmt.setString(2, state.getId().toString());
+            stmt.execute();
+
+            // there's no need to close a ByteArrayOutputStream
+            //out.close();
+        } catch (Exception e) {
+            String msg = "failed to write node state: " + state.getId();
+            log.error(msg, e);
+            throw new ItemStateException(msg, e);
+        } finally {
+            resetStatement(stmt);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     * <p/>
+     * This method uses shared <code>PreparedStatement</code>s which must
+     * be executed strictly sequentially. Because this method synchronizes on
+     * the persistence manager instance there is no need to synchronize on the
+     * shared statement. If the method would not be sychronized the shared
+     * statements would have to be synchronized.
+     */
+    public synchronized void store(PropertyState state)
+            throws ItemStateException {
+        if (!initialized) {
+            throw new IllegalStateException("not initialized");
+        }
+
+        // check if insert or update
+        //boolean update = exists((PropertyId) state.getId());
+        boolean update = state.getStatus() != ItemState.STATUS_NEW;
+        PreparedStatement stmt = (update) ? propertyStateUpdate : propertyStateInsert;
+
+        try {
+            ByteArrayOutputStream out =
+                    new ByteArrayOutputStream(INITIAL_BUFFER_SIZE);
+            // serialize property state
+            ObjectPersistenceManager.serialize(state, out, this);
+
+            // we are synchronized on this instance, therefore we do not
+            // not have to additionally synchronize on the preparedStatement
+
+            stmt.setBytes(1, out.toByteArray());
+            stmt.setString(2, state.getId().toString());
+            stmt.execute();
+
+            // there's no need to close a ByteArrayOutputStream
+            //out.close();
+        } catch (Exception e) {
+            String msg = "failed to write property state: " + state.getId();
+            log.error(msg, e);
+            throw new ItemStateException(msg, e);
+        } finally {
+            resetStatement(stmt);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public synchronized void destroy(NodeState state)
+            throws ItemStateException {
+        if (!initialized) {
+            throw new IllegalStateException("not initialized");
+        }
+
+        PreparedStatement stmt = nodeStateDelete;
+        try {
+            stmt.setString(1, state.getId().toString());
+            stmt.execute();
+        } catch (Exception e) {
+            String msg = "failed to delete node state: " + state.getId();
+            log.error(msg, e);
+            throw new ItemStateException(msg, e);
+        } finally {
+            resetStatement(stmt);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public synchronized void destroy(PropertyState state)
+            throws ItemStateException {
+        if (!initialized) {
+            throw new IllegalStateException("not initialized");
+        }
+
+        // delete binary values (stored as files)
+        InternalValue[] values = state.getValues();
+        if (values != null) {
+            for (int i = 0; i < values.length; i++) {
+                InternalValue val = values[i];
+                if (val != null) {
+                    if (val.getType() == PropertyType.BINARY) {
+                        BLOBFileValue blobVal = (BLOBFileValue) val.internalValue();
+                        // delete blob file and prune empty parent folders
+                        blobVal.delete(true);
+                    }
+                }
+            }
+        }
+
+        PreparedStatement stmt = propertyStateDelete;
+        try {
+            stmt.setString(1, state.getId().toString());
+            stmt.execute();
+        } catch (Exception e) {
+            String msg = "failed to delete property state: " + state.getId();
+            log.error(msg, e);
+            throw new ItemStateException(msg, e);
+        } finally {
+            resetStatement(stmt);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public synchronized NodeReferences load(NodeReferencesId targetId)
+            throws NoSuchItemStateException, ItemStateException {
+        if (!initialized) {
+            throw new IllegalStateException("not initialized");
+        }
+
+        PreparedStatement stmt = nodeReferenceSelect;
+        ResultSet rs = null;
+        InputStream in = null;
+        try {
+            stmt.setString(1, targetId.toString());
+            stmt.execute();
+            rs = stmt.getResultSet();
+            if (!rs.next()) {
+                throw new NoSuchItemStateException(targetId.toString());
+            }
+
+            in = rs.getBinaryStream(1);
+            NodeReferences refs = new NodeReferences(targetId);
+            ObjectPersistenceManager.deserialize(refs, in);
+
+            return refs;
+        } catch (Exception e) {
+            if (e instanceof NoSuchItemStateException) {
+                throw (NoSuchItemStateException) e;
+            }
+            String msg = "failed to read references: " + targetId;
+            log.error(msg, e);
+            throw new ItemStateException(msg, e);
+        } finally {
+            closeStream(in);
+            closeResultSet(rs);
+            resetStatement(stmt);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     * <p/>
+     * This method uses shared <code>PreparedStatement</code>s which must
+     * be executed strictly sequentially. Because this method synchronizes on
+     * the persistence manager instance there is no need to synchronize on the
+     * shared statement. If the method would not be sychronized the shared
+     * statements would have to be synchronized.
+     */
+    public synchronized void store(NodeReferences refs)
+            throws ItemStateException {
+        if (!initialized) {
+            throw new IllegalStateException("not initialized");
+        }
+
+        // check if insert or update
+        boolean update = exists(refs.getTargetId());
+        PreparedStatement stmt = (update) ? nodeReferenceUpdate : nodeReferenceInsert;
+
+        try {
+            ByteArrayOutputStream out =
+                    new ByteArrayOutputStream(INITIAL_BUFFER_SIZE);
+            // serialize references
+            ObjectPersistenceManager.serialize(refs, out);
+
+            // we are synchronized on this instance, therefore we do not
+            // not have to additionally synchronize on the preparedStatement
+
+            stmt.setBytes(1, out.toByteArray());
+            stmt.setString(2, refs.getTargetId().toString());
+            stmt.execute();
+
+            // there's no need to close a ByteArrayOutputStream
+            //out.close();
+        } catch (Exception e) {
+            String msg = "failed to write property state: " + refs.getTargetId();
+            log.error(msg, e);
+            throw new ItemStateException(msg, e);
+        } finally {
+            resetStatement(stmt);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public synchronized void destroy(NodeReferences refs)
+            throws ItemStateException {
+        if (!initialized) {
+            throw new IllegalStateException("not initialized");
+        }
+
+        PreparedStatement stmt = nodeReferenceDelete;
+        try {
+            stmt.setString(1, refs.getTargetId().toString());
+            stmt.execute();
+        } catch (Exception e) {
+            String msg = "failed to delete references: " + refs.getTargetId();
+            log.error(msg, e);
+            throw new ItemStateException(msg, e);
+        } finally {
+            resetStatement(stmt);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean exists(NodeId id) throws ItemStateException {
+        if (!initialized) {
+            throw new IllegalStateException("not initialized");
+        }
+
+        PreparedStatement stmt = nodeStateSelect;
+        ResultSet rs = null;
+        try {
+            stmt.setString(1, id.toString());
+            stmt.execute();
+            rs = stmt.getResultSet();
+
+            // a node state exists if the result has at least one entry
+            return rs.next();
+        } catch (Exception e) {
+            String msg = "failed to check existence of node state: " + id;
+            log.error(msg, e);
+            throw new ItemStateException(msg, e);
+        } finally {
+            closeResultSet(rs);
+            resetStatement(stmt);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public boolean exists(PropertyId id) throws ItemStateException {
+        if (!initialized) {
+            throw new IllegalStateException("not initialized");
+        }
+
+        PreparedStatement stmt = propertyStateSelect;
+        ResultSet rs = null;
+        try {
+            stmt.setString(1, id.toString());
+            stmt.execute();
+            rs = stmt.getResultSet();
+
+            // a property state exists if the result has at least one entry
+            return rs.next();
+        } catch (Exception e) {
+            String msg = "failed to check existence of property state: " + id;
+            log.error(msg, e);
+            throw new ItemStateException(msg, e);
+        } finally {
+            closeResultSet(rs);
+            resetStatement(stmt);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public synchronized boolean exists(NodeReferencesId targetId)
+            throws ItemStateException {
+        if (!initialized) {
+            throw new IllegalStateException("not initialized");
+        }
+
+        PreparedStatement stmt = nodeReferenceSelect;
+        ResultSet rs = null;
+        try {
+            stmt.setString(1, targetId.toString());
+            stmt.execute();
+            rs = stmt.getResultSet();
+
+            // a reference exists if the result has at least one entry
+            return rs.next();
+        } catch (Exception e) {
+            String msg = "failed to check existence of node references: "
+                    + targetId;
+            log.error(msg, e);
+            throw new ItemStateException(msg, e);
+        } finally {
+            closeResultSet(rs);
+            resetStatement(stmt);
+        }
+    }
+
+    //-------------------------------------------------< misc. helper methods >
+    /**
+     * Resets the given <code>PreparedStatement</code> by clearing the parameters
+     * and warnings contained.
+     * <p/>
+     * NOTE: This method MUST be called in a synchronized context as neither
+     * this method nor the <code>PreparedStatement</code> instance on which it
+     * operates are thread safe.
+     *
+     * @param stmt The <code>PreparedStatement</code> to reset. If
+     *             <code>null</code> this method does nothing.
+     */
+    protected void resetStatement(PreparedStatement stmt) {
+        if (stmt != null) {
+            try {
+                stmt.clearParameters();
+                stmt.clearWarnings();
+            } catch (SQLException se) {
+                logException("failed resetting PreparedStatement", se);
+            }
+        }
+    }
+
+    protected void closeResultSet(ResultSet rs) {
+        if (rs != null) {
+            try {
+                rs.close();
+            } catch (SQLException se) {
+                logException("failed closing ResultSet", se);
+            }
+        }
+    }
+
+    protected void closeStream(InputStream in) {
+        if (in != null) {
+            try {
+                in.close();
+            } catch (IOException ignore) {
+            }
+        }
+    }
+
+    protected void closeStatement(Statement stmt) {
+        if (stmt != null) {
+            try {
+                stmt.close();
+            } catch (SQLException se) {
+                logException("failed closing Statement", se);
+            }
+        }
+    }
+
+    protected void logException(String message, SQLException se) {
+        if (message != null) {
+            log.error(message);
+        }
+        log.error("    reason: " + se.getMessage());
+        log.error("state/code: " + se.getSQLState() + "/" + se.getErrorCode());
+        log.debug("      dump:", se);
+    }
+
+    protected static String buildBlobFilePath(String parentUUID,
+                                              QName propName, int index) {
+        StringBuffer sb = new StringBuffer();
+        char[] chars = parentUUID.toCharArray();
+        int cnt = 0;
+        for (int i = 0; i < chars.length; i++) {
+            if (chars[i] == '-') {
+                continue;
+            }
+            //if (cnt > 0 && cnt % 4 == 0) {
+            if (cnt == 2 || cnt == 4) {
+                sb.append(FileSystem.SEPARATOR_CHAR);
+            }
+            sb.append(chars[i]);
+            cnt++;
+        }
+        sb.append(FileSystem.SEPARATOR_CHAR);
+        sb.append(FileSystemPathUtil.escapeName(propName.toString()));
+        sb.append('.');
+        sb.append(index);
+        sb.append(".bin");
+        return sb.toString();
+    }
+
+    /**
+     * Checks if the required schema objects exist and creates them if they
+     * don't exist yet.
+     * @throws Exception if an error occurs
+     */
+    protected void checkSchema() throws Exception {
+        ResultSet rs = con.getMetaData().getTables(null, null,
+                schemaObjectPrefix + "NODE", null);
+        boolean schemaExists;
+        try {
+            schemaExists = rs.next();
+        } finally {
+            rs.close();
+        }
+
+        if (!schemaExists) {
+            // read ddl from resources
+            InputStream in = getClass().getResourceAsStream(schema + ".ddl");
+            if (in == null) {
+                String msg = "Configuration error: unknown schema '" + schema + "'";
+                log.debug(msg);
+                throw new RepositoryException(msg);
+            }
+            BufferedReader reader = new BufferedReader(new InputStreamReader(in));
+            Statement stmt = con.createStatement();
+            try {
+                String sql = reader.readLine();
+                while (sql != null) {
+                    // replace prefix variable
+                    sql = Text.replace(sql, SCHEMA_OBJECT_PREFIX_VARIABLE, schemaObjectPrefix);
+                    // execute sql stmt
+                    stmt.execute(sql);
+                    // read next sql stmt
+                    sql = reader.readLine();
+                }
+                // commit the changes
+                con.commit();
+            } finally {
+                closeStream(in);
+                closeStatement(stmt);
+            }
+        }
+    }
+}

Propchange: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/db/SimpleDbPersistenceManager.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/db/SimpleDbPersistenceManager.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url

Added: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/db/daffodil.ddl
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/db/daffodil.ddl?rev=328071&view=auto
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/db/daffodil.ddl (added)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/db/daffodil.ddl Mon Oct 24 06:55:26 2005
@@ -0,0 +1,6 @@
+create table ${schemaObjectPrefix}NODE (NODE_ID char(36) not null, NODE_DATA blob not null)
+create index ${schemaObjectPrefix}NODE_IDX on ${schemaObjectPrefix}NODE (NODE_ID)
+create table ${schemaObjectPrefix}PROP (PROP_ID varchar(1024) not null, PROP_DATA blob not null)
+create index ${schemaObjectPrefix}PROP_IDX on ${schemaObjectPrefix}PROP (PROP_ID)
+create table ${schemaObjectPrefix}REFS (NODE_ID char(36) not null, REFS_DATA blob not null)
+create index ${schemaObjectPrefix}REFS_IDX on ${schemaObjectPrefix}REFS (NODE_ID)

Added: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/db/default.ddl
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/db/default.ddl?rev=328071&view=auto
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/db/default.ddl (added)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/db/default.ddl Mon Oct 24 06:55:26 2005
@@ -0,0 +1,6 @@
+create table ${schemaObjectPrefix}NODE (NODE_ID char(36) not null, NODE_DATA varbinary not null)
+create unique index ${schemaObjectPrefix}NODE_IDX on ${schemaObjectPrefix}NODE (NODE_ID)
+create table ${schemaObjectPrefix}PROP (PROP_ID varchar not null, PROP_DATA varbinary not null)
+create unique index ${schemaObjectPrefix}PROP_IDX on ${schemaObjectPrefix}PROP (PROP_ID)
+create table ${schemaObjectPrefix}REFS (NODE_ID char(36) not null, REFS_DATA varbinary not null)
+create unique index ${schemaObjectPrefix}REFS_IDX on ${schemaObjectPrefix}REFS (NODE_ID)

Added: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/db/derby.ddl
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/db/derby.ddl?rev=328071&view=auto
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/db/derby.ddl (added)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/db/derby.ddl Mon Oct 24 06:55:26 2005
@@ -0,0 +1,6 @@
+create table ${schemaObjectPrefix}NODE (NODE_ID char(36) not null, NODE_DATA blob not null)
+create unique index ${schemaObjectPrefix}NODE_IDX on ${schemaObjectPrefix}NODE (NODE_ID)
+create table ${schemaObjectPrefix}PROP (PROP_ID varchar(1024) not null, PROP_DATA blob not null)
+create unique index ${schemaObjectPrefix}PROP_IDX on ${schemaObjectPrefix}PROP (PROP_ID)
+create table ${schemaObjectPrefix}REFS (NODE_ID char(36) not null, REFS_DATA blob not null)
+create unique index ${schemaObjectPrefix}REFS_IDX on ${schemaObjectPrefix}REFS (NODE_ID)

Added: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/db/mssql.ddl
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/db/mssql.ddl?rev=328071&view=auto
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/db/mssql.ddl (added)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/db/mssql.ddl Mon Oct 24 06:55:26 2005
@@ -0,0 +1,6 @@
+create table ${schemaObjectPrefix}NODE (NODE_ID char(36) not null, NODE_DATA varbinary not null)
+create unique index ${schemaObjectPrefix}NODE_IDX on ${schemaObjectPrefix}NODE (NODE_ID)
+create table ${schemaObjectPrefix}PROP (PROP_ID varchar not null, PROP_DATA varbinary not null)
+create unique index ${schemaObjectPrefix}PROP_IDX on ${schemaObjectPrefix}PROP (PROP_ID)
+create table ${schemaObjectPrefix}REFS (NODE_ID char(36) not null, REFS_DATA varbinary not null)
+create unique index ${schemaObjectPrefix}REFS_IDX on ${schemaObjectPrefix}REFS (NODE_ID)

Added: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/db/mysql.ddl
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/db/mysql.ddl?rev=328071&view=auto
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/db/mysql.ddl (added)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/db/mysql.ddl Mon Oct 24 06:55:26 2005
@@ -0,0 +1,6 @@
+create table ${schemaObjectPrefix}NODE (NODE_ID char(36) not null, NODE_DATA blob not null)
+create unique index ${schemaObjectPrefix}NODE_IDX on ${schemaObjectPrefix}NODE (NODE_ID)
+create table ${schemaObjectPrefix}PROP (PROP_ID varchar(255) not null, PROP_DATA blob not null)
+create unique index ${schemaObjectPrefix}PROP_IDX on ${schemaObjectPrefix}PROP (PROP_ID)
+create table ${schemaObjectPrefix}REFS (NODE_ID char(36) not null, REFS_DATA blob not null)
+create unique index ${schemaObjectPrefix}REFS_IDX on ${schemaObjectPrefix}REFS (NODE_ID)

Added: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/db/package.html
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/db/package.html?rev=328071&view=auto
==============================================================================
--- incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/db/package.html (added)
+++ incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/db/package.html Mon Oct 24 06:55:26 2005
@@ -0,0 +1,16 @@
+<body>
+This package contains the class <code>{@link SimpleDbPersistenceManager}</code>,
+a simple generic JDBC-based <code>PersistenceManager</code> for Jackrabbit.
+<p/>
+It also contains [schemaName].ddl files which are read by
+<code>{@link SimpleDbPersistenceManager}</code>  in order to automatically
+create the required schema objects on the target database. Every line in a
+[schemaName].ddl file is executed separatly by calling
+<code>java.sql.Statement.execute(String)</code> where every occurence of the
+the string <code>"${schemaObjectPrefix}"</code> has been replaced with the
+value of the property <code>schemaObjectPrefix</code> (see
+ <code>{@link SimpleDbPersistenceManager#setSchemaObjectPrefix(String)}</code>).
+The schema name is either set programmtically by calling
+<code>{@link SimpleDbPersistenceManager#setSchema(String)}</code> or configured
+through the <code>schema</code> bean property.
+</body>

Propchange: incubator/jackrabbit/trunk/src/java/org/apache/jackrabbit/core/state/db/package.html
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: incubator/jackrabbit/trunk/xdocs/firststeps.xml
URL: http://svn.apache.org/viewcvs/incubator/jackrabbit/trunk/xdocs/firststeps.xml?rev=328071&r1=328070&r2=328071&view=diff
==============================================================================
--- incubator/jackrabbit/trunk/xdocs/firststeps.xml (original)
+++ incubator/jackrabbit/trunk/xdocs/firststeps.xml Mon Oct 24 06:55:26 2005
@@ -152,9 +152,8 @@
     repository implementation (named something like 
     <code>jackrabbit-x.xx-xxx-dev.jar</code>) that has been built by Maven
     into the <code>target</code> directory of your checkout.
-    By executing <code>maven copy-deps</code> all dependencies except
-    the optional runtime <code>cqfs-*</code> libaries are
-    being copied to the <code>target/lib</code> directory. I addition
+    By executing <code>maven copy-deps</code> all dependencies are
+    being copied to the <code>target/lib</code> directory. In addition
     to setting up the classpath, you need to include the JAAS configuration
     option <code>-Djava.security.auth.login.config==jaas.config</code>
     (note the double equal sign <code>==</code>) to the <code>java</code>



Mime
View raw message