You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by tr...@apache.org on 2006/10/26 11:11:20 UTC

svn commit: r467925 [1/6] - in /jackrabbit/trunk/jackrabbit: applications/test/ applications/test/workspaces/default/ applications/test/workspaces/test/ src/main/config/ src/main/java/org/apache/jackrabbit/core/ src/main/java/org/apache/jackrabbit/core...

Author: tripod
Date: Thu Oct 26 02:11:18 2006
New Revision: 467925

URL: http://svn.apache.org/viewvc?view=rev&rev=467925
Log:
JCR-595 Refactoring of the Persistence Managers (+changing some eol-styles)

Added:
    jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/persistence/
    jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/persistence/AbstractPersistenceManager.java   (with props)
    jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/persistence/PMContext.java   (with props)
    jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/persistence/PersistenceManager.java   (with props)
    jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/persistence/db/
    jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/persistence/db/DatabasePersistenceManager.java   (with props)
    jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/persistence/db/DerbyPersistenceManager.java   (with props)
    jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/persistence/db/JNDIDatabasePersistenceManager.java   (with props)
    jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/persistence/db/OraclePersistenceManager.java   (with props)
    jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/persistence/db/SimpleDbPersistenceManager.java   (with props)
    jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/persistence/db/daffodil.ddl
    jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/persistence/db/db2.ddl
    jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/persistence/db/default.ddl
    jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/persistence/db/derby.ddl
    jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/persistence/db/mssql.ddl
    jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/persistence/db/mysql.ddl
    jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/persistence/db/oracle.ddl
    jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/persistence/db/package.html   (with props)
    jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/persistence/db/postgresql.ddl
    jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/persistence/mem/
    jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/persistence/mem/InMemPersistenceManager.java   (with props)
    jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/persistence/obj/
    jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/persistence/obj/ObjectPersistenceManager.java   (with props)
    jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/persistence/util/
    jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/persistence/util/BLOBStore.java   (with props)
    jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/persistence/util/FileSystemBLOBStore.java   (with props)
    jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/persistence/util/ResourceBasedBLOBStore.java   (with props)
    jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/persistence/util/Serializer.java   (with props)
    jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/persistence/xml/
    jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/persistence/xml/XMLPersistenceManager.java   (with props)
Removed:
    jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/state/db/daffodil.ddl
    jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/state/db/db2.ddl
    jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/state/db/default.ddl
    jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/state/db/derby.ddl
    jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/state/db/mssql.ddl
    jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/state/db/mysql.ddl
    jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/state/db/oracle.ddl
    jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/state/db/package.html
    jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/state/db/postgresql.ddl
Modified:
    jackrabbit/trunk/jackrabbit/applications/test/repository.xml
    jackrabbit/trunk/jackrabbit/applications/test/workspaces/default/workspace.xml   (contents, props changed)
    jackrabbit/trunk/jackrabbit/applications/test/workspaces/test/workspace.xml   (contents, props changed)
    jackrabbit/trunk/jackrabbit/src/main/config/repository.xml
    jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/RepositoryImpl.java
    jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/repository.xml
    jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/state/AbstractPersistenceManager.java
    jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/state/PMContext.java
    jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/state/PersistenceManager.java
    jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/state/SharedItemStateManager.java
    jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/state/db/DatabasePersistenceManager.java
    jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/state/db/DerbyPersistenceManager.java
    jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/state/db/JNDIDatabasePersistenceManager.java
    jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/state/db/OraclePersistenceManager.java
    jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/state/db/SimpleDbPersistenceManager.java
    jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/state/mem/InMemPersistenceManager.java
    jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/state/obj/ObjectPersistenceManager.java
    jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/state/util/BLOBStore.java
    jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/state/util/FileSystemBLOBStore.java
    jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/state/util/ResourceBasedBLOBStore.java
    jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/state/util/Serializer.java
    jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/state/xml/XMLPersistenceManager.java
    jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/test-repository.xml
    jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/version/VersionManagerImpl.java
    jackrabbit/trunk/jackrabbit/src/site/xdoc/doc/config.xml
    jackrabbit/trunk/jackrabbit/src/test/java/org/apache/jackrabbit/core/config/RepositoryConfigTest.java
    jackrabbit/trunk/jackrabbit/src/test/java/org/apache/jackrabbit/core/config/WorkspaceConfigTest.java
    jackrabbit/trunk/jackrabbit/src/test/java/org/apache/jackrabbit/core/config/repository.xml   (contents, props changed)
    jackrabbit/trunk/jackrabbit/src/test/java/org/apache/jackrabbit/core/config/workspace.xml

Modified: jackrabbit/trunk/jackrabbit/applications/test/repository.xml
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit/applications/test/repository.xml?view=diff&rev=467925&r1=467924&r2=467925
==============================================================================
--- jackrabbit/trunk/jackrabbit/applications/test/repository.xml (original)
+++ jackrabbit/trunk/jackrabbit/applications/test/repository.xml Thu Oct 26 02:11:18 2006
@@ -193,7 +193,7 @@
             persistence manager of the workspace:
             class: FQN of class implementing the PersistenceManager interface
         -->
-        <PersistenceManager class="org.apache.jackrabbit.core.state.db.DerbyPersistenceManager">
+        <PersistenceManager class="org.apache.jackrabbit.core.persistence.db.DerbyPersistenceManager">
           <param name="url" value="jdbc:derby:${wsp.home}/db;create=true"/>
           <param name="schemaObjectPrefix" value="${wsp.name}_"/>
         </PersistenceManager>
@@ -224,7 +224,7 @@
             a 'normal' persistence manager, but this could change in future
             implementations.
         -->
-        <PersistenceManager class="org.apache.jackrabbit.core.state.db.DerbyPersistenceManager">
+        <PersistenceManager class="org.apache.jackrabbit.core.persistence.db.DerbyPersistenceManager">
           <param name="url" value="jdbc:derby:${rep.home}/version/db;create=true"/>
           <param name="schemaObjectPrefix" value="version_"/>
         </PersistenceManager>

Modified: jackrabbit/trunk/jackrabbit/applications/test/workspaces/default/workspace.xml
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit/applications/test/workspaces/default/workspace.xml?view=diff&rev=467925&r1=467924&r2=467925
==============================================================================
--- jackrabbit/trunk/jackrabbit/applications/test/workspaces/default/workspace.xml (original)
+++ jackrabbit/trunk/jackrabbit/applications/test/workspaces/default/workspace.xml Thu Oct 26 02:11:18 2006
@@ -1,46 +1,46 @@
-<?xml version="1.0"?>
-<!--
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   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.
-  -->
-<Workspace name="default">
-  <!--
-      virtual file system of the workspace:
-      class: FQN of class implementing FileSystem interface
-  -->
-  <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.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.
-  -->
-  <SearchIndex class="org.apache.jackrabbit.core.query.lucene.SearchIndex">
-    <param name="path" value="${wsp.home}/index" />
-    <!--
-        Set to zero for test purpose. This is *not* recommended at all for a
-        real system!
-    -->
-    <param name="idleTime" value="0"/>
-  </SearchIndex>
-</Workspace>
-
+<?xml version="1.0"?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   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.
+  -->
+<Workspace name="default">
+  <!--
+      virtual file system of the workspace:
+      class: FQN of class implementing FileSystem interface
+  -->
+  <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.persistence.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.
+  -->
+  <SearchIndex class="org.apache.jackrabbit.core.query.lucene.SearchIndex">
+    <param name="path" value="${wsp.home}/index" />
+    <!--
+        Set to zero for test purpose. This is *not* recommended at all for a
+        real system!
+    -->
+    <param name="idleTime" value="0"/>
+  </SearchIndex>
+</Workspace>
+

Propchange: jackrabbit/trunk/jackrabbit/applications/test/workspaces/default/workspace.xml
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: jackrabbit/trunk/jackrabbit/applications/test/workspaces/test/workspace.xml
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit/applications/test/workspaces/test/workspace.xml?view=diff&rev=467925&r1=467924&r2=467925
==============================================================================
--- jackrabbit/trunk/jackrabbit/applications/test/workspaces/test/workspace.xml (original)
+++ jackrabbit/trunk/jackrabbit/applications/test/workspaces/test/workspace.xml Thu Oct 26 02:11:18 2006
@@ -1,41 +1,41 @@
-<?xml version="1.0"?>
-<!--
-   Licensed to the Apache Software Foundation (ASF) under one or more
-   contributor license agreements.  See the NOTICE file distributed with
-   this work for additional information regarding copyright ownership.
-   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.
-  -->
-<Workspace name="test">
-  <!--
-      virtual file system of the workspace:
-      class: FQN of class implementing FileSystem interface
-  -->
-  <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.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.
-  -->
-  <SearchIndex class="org.apache.jackrabbit.core.query.lucene.SearchIndex">
-    <param name="path" value="${wsp.home}/index" />
-  </SearchIndex>
-</Workspace>
-
+<?xml version="1.0"?>
+<!--
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   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.
+  -->
+<Workspace name="test">
+  <!--
+      virtual file system of the workspace:
+      class: FQN of class implementing FileSystem interface
+  -->
+  <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.persistence.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.
+  -->
+  <SearchIndex class="org.apache.jackrabbit.core.query.lucene.SearchIndex">
+    <param name="path" value="${wsp.home}/index" />
+  </SearchIndex>
+</Workspace>
+

Propchange: jackrabbit/trunk/jackrabbit/applications/test/workspaces/test/workspace.xml
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: jackrabbit/trunk/jackrabbit/src/main/config/repository.xml
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit/src/main/config/repository.xml?view=diff&rev=467925&r1=467924&r2=467925
==============================================================================
--- jackrabbit/trunk/jackrabbit/src/main/config/repository.xml (original)
+++ jackrabbit/trunk/jackrabbit/src/main/config/repository.xml Thu Oct 26 02:11:18 2006
@@ -203,7 +203,7 @@
             persistence manager of the workspace:
             class: FQN of class implementing the PersistenceManager interface
         -->
-        <PersistenceManager class="org.apache.jackrabbit.core.state.db.DerbyPersistenceManager">
+        <PersistenceManager class="org.apache.jackrabbit.core.persistence.db.DerbyPersistenceManager">
             <param name="url" value="jdbc:derby:${wsp.home}/db;create=true"/>
             <param name="schemaObjectPrefix" value="${wsp.name}_"/>
         </PersistenceManager>
@@ -282,7 +282,7 @@
             a 'normal' persistence manager, but this could change in future
             implementations.
         -->
-        <PersistenceManager class="org.apache.jackrabbit.core.state.db.DerbyPersistenceManager">
+        <PersistenceManager class="org.apache.jackrabbit.core.persistence.db.DerbyPersistenceManager">
             <param name="url" value="jdbc:derby:${rep.home}/version/db;create=true"/>
             <param name="schemaObjectPrefix" value="version_"/>
         </PersistenceManager>

Modified: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/RepositoryImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/RepositoryImpl.java?view=diff&rev=467925&r1=467924&r2=467925
==============================================================================
--- jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/RepositoryImpl.java (original)
+++ jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/RepositoryImpl.java Thu Oct 26 02:11:18 2006
@@ -42,8 +42,8 @@
 import org.apache.jackrabbit.core.observation.ObservationDispatcher;
 import org.apache.jackrabbit.core.security.AuthContext;
 import org.apache.jackrabbit.core.state.ItemStateException;
-import org.apache.jackrabbit.core.state.PMContext;
-import org.apache.jackrabbit.core.state.PersistenceManager;
+import org.apache.jackrabbit.core.persistence.PMContext;
+import org.apache.jackrabbit.core.persistence.PersistenceManager;
 import org.apache.jackrabbit.core.state.SharedItemStateManager;
 import org.apache.jackrabbit.core.version.VersionManager;
 import org.apache.jackrabbit.core.version.VersionManagerImpl;

Added: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/persistence/AbstractPersistenceManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/persistence/AbstractPersistenceManager.java?view=auto&rev=467925
==============================================================================
--- jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/persistence/AbstractPersistenceManager.java (added)
+++ jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/persistence/AbstractPersistenceManager.java Thu Oct 26 02:11:18 2006
@@ -0,0 +1,148 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * 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.
+ */
+package org.apache.jackrabbit.core.persistence;
+
+import org.apache.jackrabbit.core.NodeId;
+import org.apache.jackrabbit.core.PropertyId;
+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.NodeReferences;
+import org.apache.jackrabbit.core.state.NodeState;
+import org.apache.jackrabbit.core.state.PropertyState;
+
+import java.util.Iterator;
+
+/**
+ * Implementation <code>PersistenceManager</code> that handles some
+ * concepts.
+ */
+public abstract class AbstractPersistenceManager implements PersistenceManager {
+
+    /**
+     * {@inheritDoc}
+     */
+    public NodeState createNew(NodeId id) {
+        return new NodeState(id, null, null, NodeState.STATUS_NEW, false);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public PropertyState createNew(PropertyId id) {
+        return new PropertyState(id, PropertyState.STATUS_NEW, false);
+    }
+
+    /**
+     * Right now, this iterates over all items in the changelog and
+     * calls the individual methods that handle single item states
+     * or node references objects. Properly implemented, this method
+     * should ensure that changes are either written completely to
+     * the underlying persistence layer, or not at all.
+     *
+     * {@inheritDoc}
+     */
+    public synchronized void store(ChangeLog changeLog) throws ItemStateException {
+        Iterator iter = changeLog.deletedStates();
+        while (iter.hasNext()) {
+            ItemState state = (ItemState) iter.next();
+            if (state.isNode()) {
+                destroy((NodeState) state);
+            } else {
+                destroy((PropertyState) state);
+            }
+        }
+        iter = changeLog.addedStates();
+        while (iter.hasNext()) {
+            ItemState state = (ItemState) iter.next();
+            if (state.isNode()) {
+                store((NodeState) state);
+            } else {
+                store((PropertyState) state);
+            }
+        }
+        iter = changeLog.modifiedStates();
+        while (iter.hasNext()) {
+            ItemState state = (ItemState) iter.next();
+            if (state.isNode()) {
+                store((NodeState) state);
+            } else {
+                store((PropertyState) state);
+            }
+        }
+        iter = changeLog.modifiedRefs();
+        while (iter.hasNext()) {
+            NodeReferences refs = (NodeReferences) iter.next();
+            if (refs.hasReferences()) {
+                store(refs);
+            } else {
+                if (exists(refs.getId())) {
+                    destroy(refs);
+                }
+            }
+        }
+    }
+
+    /**
+     * Store a node state. Subclass responsibility.
+     *
+     * @param state node state to store
+     * @throws ItemStateException if an error occurs
+     */
+    protected abstract void store(NodeState state) throws ItemStateException;
+
+    /**
+     * Store a property state. Subclass responsibility.
+     *
+     * @param state property state to store
+     * @throws ItemStateException if an error occurs
+     */
+    protected abstract void store(PropertyState state) throws ItemStateException;
+
+    /**
+     * Store a references object. Subclass responsibility.
+     *
+     * @param refs references object to store
+     * @throws ItemStateException if an error occurs
+     */
+    protected abstract void store(NodeReferences refs) throws ItemStateException;
+
+    /**
+     * Destroy a node state. Subclass responsibility.
+     *
+     * @param state node state to destroy
+     * @throws ItemStateException if an error occurs
+     */
+    protected abstract void destroy(NodeState state) throws ItemStateException;
+
+    /**
+     * Destroy a property state. Subclass responsibility.
+     *
+     * @param state property state to destroy
+     * @throws ItemStateException if an error occurs
+     */
+    protected abstract void destroy(PropertyState state) throws ItemStateException;
+
+    /**
+     * Destroy a node references object. Subclass responsibility.
+     *
+     * @param refs node references object to destroy
+     * @throws ItemStateException if an error occurs
+     */
+    protected abstract void destroy(NodeReferences refs)
+            throws ItemStateException;
+}

Propchange: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/persistence/AbstractPersistenceManager.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/persistence/AbstractPersistenceManager.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url rev

Added: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/persistence/PMContext.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/persistence/PMContext.java?view=auto&rev=467925
==============================================================================
--- jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/persistence/PMContext.java (added)
+++ jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/persistence/PMContext.java Thu Oct 26 02:11:18 2006
@@ -0,0 +1,123 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * 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.
+ */
+package org.apache.jackrabbit.core.persistence;
+
+import org.apache.jackrabbit.core.fs.FileSystem;
+import org.apache.jackrabbit.core.nodetype.NodeTypeRegistry;
+import org.apache.jackrabbit.core.NodeId;
+import org.apache.jackrabbit.core.persistence.PersistenceManager;
+
+import javax.jcr.NamespaceRegistry;
+import java.io.File;
+
+/**
+ * A <code>PMContext</code> is used to provide context information for a
+ * <code>PersistenceManager</code>.
+ *
+ * @see PersistenceManager#init(PMContext)
+ */
+public class PMContext {
+
+    /**
+     * the physcial home dir
+     */
+    private final File physicalHomeDir;
+
+    /**
+     * the virtual jackrabbit filesystem
+     */
+    private final FileSystem fs;
+
+    /**
+     * namespace registry
+     */
+    private final NamespaceRegistry nsReg;
+
+    /**
+     * node type registry
+     */
+    private final NodeTypeRegistry ntReg;
+
+    /**
+     * uuid of the root node
+     */
+    private final NodeId rootNodeId;
+
+    /**
+     * Creates a new <code>PMContext</code>.
+     *
+     * @param homeDir the physical home directory
+     * @param fs the virtual jackrabbit filesystem
+     * @param rootNodeId id of the root node
+     * @param nsReg        namespace registry
+     * @param ntReg        node type registry
+     */
+    public PMContext(File homeDir,
+                     FileSystem fs,
+                     NodeId rootNodeId,
+                     NamespaceRegistry nsReg,
+                     NodeTypeRegistry ntReg) {
+        this.physicalHomeDir = homeDir;
+        this.fs = fs;
+        this.rootNodeId = rootNodeId;
+        this.nsReg = nsReg;
+        this.ntReg = ntReg;
+    }
+
+
+    /**
+     * Returns the physical home directory for this persistence manager
+     * @return the physical home directory for this persistence manager
+     */
+    public File getHomeDir() {
+        return physicalHomeDir;
+    }
+
+    /**
+     * Returns the virtual filesystem for this persistence manager
+     * @return the virtual filesystem for this persistence manager
+     */
+    public FileSystem getFileSystem() {
+        return fs;
+    }
+
+    /**
+     * Returns the id of the root node
+     * @return the id of the root node
+     */
+    public NodeId getRootNodeId() {
+        return rootNodeId;
+    }
+
+    /**
+     * Returns the namespace registry
+     *
+     * @return the namespace registry
+     */
+    public NamespaceRegistry getNamespaceRegistry() {
+        return nsReg;
+    }
+
+    /**
+     * Returns the node type registry
+     *
+     * @return the node type registry
+     */
+    public NodeTypeRegistry getNodeTypeRegistry() {
+        return ntReg;
+    }
+}

Propchange: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/persistence/PMContext.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/persistence/PMContext.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url rev

Added: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/persistence/PersistenceManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/persistence/PersistenceManager.java?view=auto&rev=467925
==============================================================================
--- jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/persistence/PersistenceManager.java (added)
+++ jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/persistence/PersistenceManager.java Thu Oct 26 02:11:18 2006
@@ -0,0 +1,183 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * 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.
+ */
+package org.apache.jackrabbit.core.persistence;
+
+import org.apache.jackrabbit.core.NodeId;
+import org.apache.jackrabbit.core.PropertyId;
+import org.apache.jackrabbit.core.persistence.PMContext;
+import org.apache.jackrabbit.core.state.NodeState;
+import org.apache.jackrabbit.core.state.PropertyState;
+import org.apache.jackrabbit.core.state.NoSuchItemStateException;
+import org.apache.jackrabbit.core.state.ItemStateException;
+import org.apache.jackrabbit.core.state.NodeReferences;
+import org.apache.jackrabbit.core.state.NodeReferencesId;
+import org.apache.jackrabbit.core.state.ChangeLog;
+
+/**
+ * Persistence manager interface. Persistence managers are
+ * internal Jackrabbit components that handle the persistent
+ * storage of content nodes and properties. A persistence
+ * manager knows how to retrieve the persistent states of
+ * content items and how to atomically save a set of changes
+ * to the persistent state.
+ * <p>
+ * Each workspace of a Jackrabbit content repository uses separate
+ * persistence manager to store the content in that workspace. Also
+ * the Jackrabbit version handler uses a separate persistence manager.
+ * The persistence managers in use are configured in the Jackrabbit
+ * XML configuration files. The configured persistence managers are
+ * instantiated and initialized using the JavaBeans conventions.
+ *
+ * <h2>Persistence manager life cycle</h2>
+ * <p>
+ * The life cycle of a persistence manager instance contains four phases:
+ * <ol>
+ *   <li>Instantiation, where the instance is created and possible
+ *       configuration properties are set using the JavaBean conventions.
+ *       During this phase the persistence manager should not attempt to
+ *       reference any external resources.
+ *   <li>Initialization, where the {@link #init(PMContext) init} method
+ *       is invoked to bind the persistence manager with a given
+ *       {@link PMContext context}.
+ *   <li>Normal usage, where the various create, load, exists, and store
+ *       methods of the persistence manager are used to manage the
+ *       persistent content items.
+ *   <li>Closing, where the {@link #close() close} method is invoked
+ *       to close the persistence manager and release all acquired
+ *       resources.
+ * </ol>
+ */
+public interface PersistenceManager {
+
+    /**
+     * Initializes the persistence manager. The persistence manager is
+     * permanently bound to the given context, and any required external
+     * resources are acquired.
+     * <p>
+     * An appropriate exception is thrown if the persistence manager
+     * initialization fails for whatever reason. In this case the
+     * state of the persistence manager is undefined and the instance
+     * should be discarded.
+     *
+     * @param context persistence manager context
+     * @throws Exception if the persistence manager intialization failed
+     */
+    void init(PMContext context) throws Exception;
+
+    /**
+     * Closes the persistence manager. The consistency of the persistent
+     * storage is guaranteed and all acquired resources are released.
+     * It is an error to invoke any methods on a closed persistence manager,
+     * and implementations are free to enforce this constraint by throwing
+     * IllegalStateExceptions in such cases.
+     * <p>
+     * An appropriate exception is thrown if the persistence manager
+     * could not be closed properly. In this case the state of the
+     * persistence manager is undefined and the instance should be
+     * discarded.
+     *
+     * @throws Exception if the persistence manager failed to close properly
+     */
+    void close() throws Exception;
+
+    /**
+     * Creates a new node state instance with the given id.
+     *
+     * @param id node id
+     * @return node state instance
+     */
+    NodeState createNew(NodeId id);
+
+    /**
+     * Creates a new property state instance with the given id.
+     *
+     * @param id property id
+     * @return property state instance
+     */
+    PropertyState createNew(PropertyId id);
+
+    /**
+     * Load the persistent members of a node state.
+     *
+     * @param id node id
+     * @return loaded node state
+     * @throws NoSuchItemStateException if the node state does not exist
+     * @throws ItemStateException if another error occurs
+     */
+    NodeState load(NodeId id)
+            throws NoSuchItemStateException, ItemStateException;
+
+    /**
+     * Load the persistent members of a property state.
+     *
+     * @param id property id
+     * @return loaded property state
+     * @throws NoSuchItemStateException if the property state does not exist
+     * @throws ItemStateException if another error occurs
+     */
+    PropertyState load(PropertyId id)
+            throws NoSuchItemStateException, ItemStateException;
+
+    /**
+     * Load the persistent members of a node references object.
+     *
+     * @param id reference target node id
+     * @throws NoSuchItemStateException if the target node does not exist
+     * @throws ItemStateException if another error occurs
+     */
+    NodeReferences load(NodeReferencesId id)
+            throws NoSuchItemStateException, ItemStateException;
+
+    /**
+     * Checks whether the identified node exists.
+     *
+     * @param id node id
+     * @return <code>true</code> if the node exists,
+     *         <code>false</code> otherwise
+     * @throws ItemStateException on persistence manager errors
+     */
+    boolean exists(NodeId id) throws ItemStateException;
+
+    /**
+     * Checks whether the identified property exists.
+     *
+     * @param id property id
+     * @return <code>true</code> if the property exists,
+     *         <code>false</code> otherwise
+     * @throws ItemStateException on persistence manager errors
+     */
+    boolean exists(PropertyId id) throws ItemStateException;
+
+    /**
+     * Checks whether references of the identified target node exist.
+     *
+     * @param targetId target node id
+     * @return <code>true</code> if the references exist,
+     *         <code>false</code> otherwise
+     * @throws ItemStateException on persistence manager errors
+     */
+    boolean exists(NodeReferencesId targetId) throws ItemStateException;
+
+    /**
+     * Atomically saves the given set of changes.
+     *
+     * @param changeLog change log containing states that were changed
+     * @throws ItemStateException if the changes could not be saved
+     */
+    void store(ChangeLog changeLog) throws ItemStateException;
+
+}

Propchange: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/persistence/PersistenceManager.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/persistence/PersistenceManager.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url rev

Added: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/persistence/db/DatabasePersistenceManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/persistence/db/DatabasePersistenceManager.java?view=auto&rev=467925
==============================================================================
--- jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/persistence/db/DatabasePersistenceManager.java (added)
+++ jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/persistence/db/DatabasePersistenceManager.java Thu Oct 26 02:11:18 2006
@@ -0,0 +1,1075 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * 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.
+ */
+package org.apache.jackrabbit.core.persistence.db;
+
+import org.apache.jackrabbit.core.NodeId;
+import org.apache.jackrabbit.core.PropertyId;
+import org.apache.jackrabbit.core.persistence.AbstractPersistenceManager;
+import org.apache.jackrabbit.core.fs.FileSystem;
+import org.apache.jackrabbit.core.fs.local.LocalFileSystem;
+import org.apache.jackrabbit.core.state.ChangeLog;
+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.persistence.PMContext;
+import org.apache.jackrabbit.core.state.PropertyState;
+import org.apache.jackrabbit.core.state.ItemState;
+import org.apache.jackrabbit.core.persistence.db.SimpleDbPersistenceManager;
+import org.apache.jackrabbit.core.persistence.util.BLOBStore;
+import org.apache.jackrabbit.core.persistence.util.FileSystemBLOBStore;
+import org.apache.jackrabbit.core.persistence.util.Serializer;
+import org.apache.jackrabbit.core.value.BLOBFileValue;
+import org.apache.jackrabbit.core.value.InternalValue;
+import org.apache.jackrabbit.util.Text;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.jcr.PropertyType;
+import javax.jcr.RepositoryException;
+import java.io.BufferedReader;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.FilterInputStream;
+import java.io.ByteArrayInputStream;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.sql.DatabaseMetaData;
+
+/**
+ * Abstract base class for database persistence managers. This class
+ * contains common functionality for database persistence manager subclasses
+ * that normally differ only in the way the database connection is acquired.
+ * Subclasses should override the {@link #getConnection()} method to return
+ * the configured database connection.
+ * <p>
+ * See the {@link SimpleDbPersistenceManager} for a detailed description
+ * of the available configuration options and database behaviour.
+ */
+public abstract class DatabasePersistenceManager extends AbstractPersistenceManager {
+
+    /**
+     * Logger instance
+     */
+    private static Logger log = LoggerFactory.getLogger(DatabasePersistenceManager.class);
+
+    protected static final String SCHEMA_OBJECT_PREFIX_VARIABLE =
+            "${schemaObjectPrefix}";
+
+    protected boolean initialized;
+
+    protected String schema;
+    protected String schemaObjectPrefix;
+
+    protected boolean externalBLOBs;
+
+    // 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 nodeStateSelectExist;
+    protected PreparedStatement nodeStateDelete;
+
+    // shared prepared statements for PropertyState management
+    protected PreparedStatement propertyStateInsert;
+    protected PreparedStatement propertyStateUpdate;
+    protected PreparedStatement propertyStateSelect;
+    protected PreparedStatement propertyStateSelectExist;
+    protected PreparedStatement propertyStateDelete;
+
+    // shared prepared statements for NodeReference management
+    protected PreparedStatement nodeReferenceInsert;
+    protected PreparedStatement nodeReferenceUpdate;
+    protected PreparedStatement nodeReferenceSelect;
+    protected PreparedStatement nodeReferenceSelectExist;
+    protected PreparedStatement nodeReferenceDelete;
+
+    // shared prepared statements for BLOB management
+    // (if <code>externalBLOBs==false</code>)
+    protected PreparedStatement blobInsert;
+    protected PreparedStatement blobUpdate;
+    protected PreparedStatement blobSelect;
+    protected PreparedStatement blobSelectExist;
+    protected PreparedStatement blobDelete;
+
+    /**
+     * file system where BLOB data is stored
+     * (if <code>externalBLOBs==true</code>)
+     */
+    protected FileSystem blobFS;
+    /**
+     * BLOBStore that manages BLOB data in the file system
+     * (if <code>externalBLOBs==true</code>)
+     */
+    protected BLOBStore blobStore;
+
+    /**
+     * Creates a new <code>DatabasePersistenceManager</code> instance.
+     */
+    public DatabasePersistenceManager() {
+        schema = "default";
+        schemaObjectPrefix = "";
+        externalBLOBs = true;
+        initialized = false;
+    }
+
+    //----------------------------------------------------< setters & getters >
+
+    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;
+    }
+
+    public boolean isExternalBLOBs() {
+        return externalBLOBs;
+    }
+
+    public void setExternalBLOBs(boolean externalBLOBs) {
+        this.externalBLOBs = externalBLOBs;
+    }
+
+    public void setExternalBLOBs(String externalBLOBs) {
+        this.externalBLOBs = Boolean.valueOf(externalBLOBs).booleanValue();
+    }
+
+    //---------------------------------------------------< PersistenceManager >
+    /**
+     * {@inheritDoc}
+     */
+    public void init(PMContext context) throws Exception {
+        if (initialized) {
+            throw new IllegalStateException("already initialized");
+        }
+
+        // setup jdbc connection
+        initConnection();
+
+        // make sure schemaObjectPrefix consists of legal name characters only
+        prepareSchemaObjectPrefix();
+
+        // check if schema objects exist and create them if necessary
+        checkSchema();
+
+        // 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 = ?");
+        nodeStateSelectExist =
+                con.prepareStatement("select 1 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 = ?");
+        propertyStateSelectExist =
+                con.prepareStatement("select 1 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 = ?");
+        nodeReferenceSelectExist =
+                con.prepareStatement("select 1 from "
+                + schemaObjectPrefix + "REFS where NODE_ID = ?");
+        nodeReferenceDelete =
+                con.prepareStatement("delete from "
+                + schemaObjectPrefix + "REFS where NODE_ID = ?");
+
+        if (externalBLOBs) {
+            /**
+             * store BLOBs 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;
+            blobStore = new FileSystemBLOBStore(blobFS);
+        } else {
+            /**
+             * store BLOBs in db
+             */
+            blobStore = new DbBLOBStore();
+
+            blobInsert =
+                    con.prepareStatement("insert into "
+                    + schemaObjectPrefix + "BINVAL (BINVAL_DATA, BINVAL_ID) values (?, ?)");
+            blobUpdate =
+                    con.prepareStatement("update "
+                    + schemaObjectPrefix + "BINVAL set BINVAL_DATA = ? where BINVAL_ID = ?");
+            blobSelect =
+                    con.prepareStatement("select BINVAL_DATA from "
+                    + schemaObjectPrefix + "BINVAL where BINVAL_ID = ?");
+            blobSelectExist =
+                    con.prepareStatement("select 1 from "
+                    + schemaObjectPrefix + "BINVAL where BINVAL_ID = ?");
+            blobDelete =
+                    con.prepareStatement("delete from "
+                    + schemaObjectPrefix + "BINVAL where BINVAL_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(nodeStateSelectExist);
+            closeStatement(nodeStateDelete);
+
+            closeStatement(propertyStateInsert);
+            closeStatement(propertyStateUpdate);
+            closeStatement(propertyStateSelect);
+            closeStatement(propertyStateSelectExist);
+            closeStatement(propertyStateDelete);
+
+            closeStatement(nodeReferenceInsert);
+            closeStatement(nodeReferenceUpdate);
+            closeStatement(nodeReferenceSelect);
+            closeStatement(nodeReferenceSelectExist);
+            closeStatement(nodeReferenceDelete);
+
+            if (!externalBLOBs) {
+                closeStatement(blobInsert);
+                closeStatement(blobUpdate);
+                closeStatement(blobSelect);
+                closeStatement(blobSelectExist);
+                closeStatement(blobDelete);
+            } else {
+                // close BLOB file system
+                blobFS.close();
+                blobFS = null;
+            }
+            blobStore = null;
+
+            // close jdbc connection
+            closeConnection(con);
+
+        } 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 NodeState load(NodeId id)
+            throws NoSuchItemStateException, ItemStateException {
+        if (!initialized) {
+            throw new IllegalStateException("not initialized");
+        }
+
+        PreparedStatement stmt = nodeStateSelect;
+        synchronized (stmt) {
+            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);
+                Serializer.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 PropertyState load(PropertyId id)
+            throws NoSuchItemStateException, ItemStateException {
+        if (!initialized) {
+            throw new IllegalStateException("not initialized");
+        }
+
+        PreparedStatement stmt = propertyStateSelect;
+        synchronized (stmt) {
+            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);
+                Serializer.deserialize(state, in, blobStore);
+
+                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 = state.getStatus() != ItemState.STATUS_NEW;
+        //boolean update = exists(state.getId());
+        PreparedStatement stmt = (update) ? nodeStateUpdate : nodeStateInsert;
+
+        try {
+            ByteArrayOutputStream out =
+                    new ByteArrayOutputStream(INITIAL_BUFFER_SIZE);
+            // serialize node state
+            Serializer.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.getNodeId().toString());
+            stmt.executeUpdate();
+
+            // there's no need to close a ByteArrayOutputStream
+            //out.close();
+        } catch (Exception e) {
+            String msg = "failed to write node state: " + state.getNodeId();
+            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 = state.getStatus() != ItemState.STATUS_NEW;
+        //boolean update = exists(state.getId());
+        PreparedStatement stmt = (update) ? propertyStateUpdate : propertyStateInsert;
+
+        try {
+            ByteArrayOutputStream out =
+                    new ByteArrayOutputStream(INITIAL_BUFFER_SIZE);
+            // serialize property state
+            Serializer.serialize(state, out, blobStore);
+
+            // 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.getPropertyId().toString());
+            stmt.executeUpdate();
+
+            // there's no need to close a ByteArrayOutputStream
+            //out.close();
+        } catch (Exception e) {
+            String msg = "failed to write property state: " + state.getPropertyId();
+            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.getNodeId().toString());
+            stmt.executeUpdate();
+        } catch (Exception e) {
+            String msg = "failed to delete node state: " + state.getNodeId();
+            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");
+        }
+
+        // make sure binary values (BLOBs) are properly removed
+        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 internal resource representation of BLOB value
+                        blobVal.delete(true);
+                        // also remove from BLOBStore
+                        String blobId = blobStore.createId(state.getPropertyId(), i);
+                        try {
+                            blobStore.remove(blobId);
+                        } catch (Exception e) {
+                            log.warn("failed to remove from BLOBStore: " + blobId, e);
+                        }
+                    }
+                }
+            }
+        }
+
+        PreparedStatement stmt = propertyStateDelete;
+        try {
+            stmt.setString(1, state.getPropertyId().toString());
+            stmt.executeUpdate();
+        } catch (Exception e) {
+            String msg = "failed to delete property state: " + state.getPropertyId();
+            log.error(msg, e);
+            throw new ItemStateException(msg, e);
+        } finally {
+            resetStatement(stmt);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public NodeReferences load(NodeReferencesId targetId)
+            throws NoSuchItemStateException, ItemStateException {
+        if (!initialized) {
+            throw new IllegalStateException("not initialized");
+        }
+
+        PreparedStatement stmt = nodeReferenceSelect;
+        synchronized (stmt) {
+            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);
+                Serializer.deserialize(refs, in);
+
+                return refs;
+            } catch (Exception e) {
+                if (e instanceof NoSuchItemStateException) {
+                    throw (NoSuchItemStateException) e;
+                }
+                String msg = "failed to read node 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.getId());
+        PreparedStatement stmt = (update) ? nodeReferenceUpdate : nodeReferenceInsert;
+
+        try {
+            ByteArrayOutputStream out =
+                    new ByteArrayOutputStream(INITIAL_BUFFER_SIZE);
+            // serialize references
+            Serializer.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.getId().toString());
+            stmt.executeUpdate();
+
+            // there's no need to close a ByteArrayOutputStream
+            //out.close();
+        } catch (Exception e) {
+            String msg = "failed to write node references: " + refs.getId();
+            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.getId().toString());
+            stmt.executeUpdate();
+        } catch (Exception e) {
+            String msg = "failed to delete node references: " + refs.getId();
+            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 = nodeStateSelectExist;
+        synchronized (stmt) {
+            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 = propertyStateSelectExist;
+        synchronized (stmt) {
+            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 boolean exists(NodeReferencesId targetId) throws ItemStateException {
+        if (!initialized) {
+            throw new IllegalStateException("not initialized");
+        }
+
+        PreparedStatement stmt = nodeReferenceSelectExist;
+        synchronized (stmt) {
+            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 & overridables >
+
+    /**
+     * Initializes the database connection used by this file system.
+     * <p>
+     * Subclasses should normally override the {@link #getConnection()}
+     * method instead of this one. The default implementation calls
+     * {@link #getConnection()} to get the database connection and disables
+     * the autocommit feature.
+     *
+     * @throws Exception if an error occurs
+     */
+    protected void initConnection() throws Exception {
+        con = getConnection();
+        con.setAutoCommit(false);
+    }
+
+    /**
+     * Abstract factory method for creating a new database connection. This
+     * method is called by {@link #init(PMContext)} when the persistence
+     * manager is started. The returned connection should come with the default
+     * JDBC settings, as the {@link #init(PMContext)} method will explicitly
+     * set the <code>autoCommit</code> and other properties as needed.
+     * <p>
+     * Note that the returned database connection is kept during the entire
+     * lifetime of the persistence manager, after which it is closed by
+     * {@link #close()} using the {@link #closeConnection(Connection)} method.
+     *
+     * @return new connection
+     * @throws Exception if an error occurs
+     */
+    protected Connection getConnection() throws Exception {
+        throw new UnsupportedOperationException("Override in a subclass!");
+    }
+
+    /**
+     * Closes the given database connection. This method is called by
+     * {@link #close()} to close the connection acquired using
+     * {@link #getConnection()} when the persistence manager was started.
+     * <p>
+     * The default implementation just calls the {@link Connection#close()}
+     * method of the given connection, but subclasses can override this
+     * method to provide more extensive database and connection cleanup.
+     *
+     * @param connection database connection
+     * @throws Exception if an error occurs
+     */
+    protected void closeConnection(Connection connection) throws Exception {
+        connection.close();
+    }
+
+    /**
+     * 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);
+    }
+
+    /**
+     * Makes sure that <code>schemaObjectPrefix</code> does only consist of
+     * characters that are allowed in names on the target database. Illegal
+     * characters will be escaped as necessary.
+     *
+     * @throws Exception if an error occurs
+     */
+    protected void prepareSchemaObjectPrefix() throws Exception {
+        DatabaseMetaData metaData = con.getMetaData();
+        String legalChars = metaData.getExtraNameCharacters();
+        legalChars += "ABCDEFGHIJKLMNOPQRSTUVWXZY0123456789_";
+
+        String prefix = schemaObjectPrefix.toUpperCase();
+        StringBuffer escaped = new StringBuffer();
+        for (int i = 0; i < prefix.length(); i++) {
+            char c = prefix.charAt(i);
+            if (legalChars.indexOf(c) == -1) {
+                escaped.append("_x");
+                String hex = Integer.toHexString(c);
+                escaped.append("0000".toCharArray(), 0, 4 - hex.length());
+                escaped.append(hex);
+                escaped.append("_");
+            } else {
+                escaped.append(c);
+            }
+        }
+        schemaObjectPrefix = escaped.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 {
+        DatabaseMetaData metaData = con.getMetaData();
+        String tableName = schemaObjectPrefix + "NODE";
+        if (metaData.storesLowerCaseIdentifiers()) {
+            tableName = tableName.toLowerCase();
+        } else if (metaData.storesUpperCaseIdentifiers()) {
+            tableName = tableName.toUpperCase();
+        }
+
+        ResultSet rs = metaData.getTables(null, null, tableName, 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) {
+                    // Skip comments and empty lines
+                    if (!sql.startsWith("#") && sql.length() > 0) {
+                        // replace prefix variable
+                        sql = Text.replace(sql, SCHEMA_OBJECT_PREFIX_VARIABLE, schemaObjectPrefix);
+                        // execute sql stmt
+                        stmt.executeUpdate(sql);
+                    }
+                    // read next sql stmt
+                    sql = reader.readLine();
+                }
+                // commit the changes
+                con.commit();
+            } finally {
+                closeStream(in);
+                closeStatement(stmt);
+            }
+        }
+    }
+
+    //--------------------------------------------------------< inner classes >
+    class DbBLOBStore implements BLOBStore {
+        /**
+         * {@inheritDoc}
+         */
+        public String createId(PropertyId id, int index) {
+            // the blobId is a simple string concatenation of id plus index
+            StringBuffer sb = new StringBuffer();
+            sb.append(id.toString());
+            sb.append('[');
+            sb.append(index);
+            sb.append(']');
+            return sb.toString();
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        public InputStream get(String blobId) throws Exception {
+            PreparedStatement stmt = blobSelect;
+            synchronized (stmt) {
+                try {
+                    stmt.setString(1, blobId);
+                    stmt.execute();
+                    final ResultSet rs = stmt.getResultSet();
+                    if (!rs.next()) {
+                        closeResultSet(rs);
+                        throw new Exception("no such BLOB: " + blobId);
+                    }
+                    InputStream in = rs.getBinaryStream(1);
+                    if (in == null) {
+                        // some databases treat zero-length values as NULL;
+                        // return empty InputStream in such a case
+                        closeResultSet(rs);
+                        return new ByteArrayInputStream(new byte[0]);
+                    }
+
+                    /**
+                     * return an InputStream wrapper in order to
+                     * close the ResultSet when the stream is closed
+                     */
+                    return new FilterInputStream(in) {
+                        public void close() throws IOException {
+                            in.close();
+                            // now it's safe to close ResultSet
+                            closeResultSet(rs);
+                        }
+                    };
+                } finally {
+                    resetStatement(stmt);
+                }
+            }
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        public synchronized void put(String blobId, InputStream in, long size)
+                throws Exception {
+            PreparedStatement stmt = blobSelectExist;
+            try {
+                stmt.setString(1, blobId);
+                stmt.execute();
+                ResultSet rs = stmt.getResultSet();
+                // a BLOB exists if the result has at least one entry
+                boolean exists = rs.next();
+                resetStatement(stmt);
+                closeResultSet(rs);
+
+                stmt = (exists) ? blobUpdate : blobInsert;
+                stmt.setBinaryStream(1, in, (int) size);
+                stmt.setString(2, blobId);
+                stmt.executeUpdate();
+            } finally {
+                resetStatement(stmt);
+            }
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        public synchronized boolean remove(String blobId) throws Exception {
+            PreparedStatement stmt = blobDelete;
+            try {
+                stmt.setString(1, blobId);
+                return stmt.executeUpdate() == 1;
+            } finally {
+                resetStatement(stmt);
+            }
+        }
+    }
+}

Propchange: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/persistence/db/DatabasePersistenceManager.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/persistence/db/DatabasePersistenceManager.java
------------------------------------------------------------------------------
    svn:keywords = author date id revision url rev

Added: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/persistence/db/DerbyPersistenceManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/persistence/db/DerbyPersistenceManager.java?view=auto&rev=467925
==============================================================================
--- jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/persistence/db/DerbyPersistenceManager.java (added)
+++ jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/persistence/db/DerbyPersistenceManager.java Thu Oct 26 02:11:18 2006
@@ -0,0 +1,114 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * 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.
+ */
+package org.apache.jackrabbit.core.persistence.db;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.apache.jackrabbit.core.persistence.db.DatabasePersistenceManager;
+
+import java.sql.Connection;
+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>
+ * <li><code>externalBLOBs</code>: if <code>true</code> (the default) BINARY
+ * values (BLOBs) are stored in the local file system;
+ * if <code>false</code> BLOBs are stored in the database</li>
+ * </ul>
+ * See also {@link SimpleDbPersistenceManager}.
+ * <p/>
+ * The following is a fragment from a sample configuration:
+ * <pre>
+ *   &lt;PersistenceManager class="org.apache.jackrabbit.core.persistence.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;param name="externalBLOBs" value="false"/&gt;
+ *  &lt;/PersistenceManager&gt;
+ * </pre>
+ */
+public class DerbyPersistenceManager extends SimpleDbPersistenceManager {
+
+    /**
+     * Logger instance
+     */
+    private static Logger log = LoggerFactory.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 = "";
+    }
+
+    //------------------------------------------< DatabasePersistenceManager >
+
+    /**
+     * Closes the given connection by shutting down the embedded Derby
+     * database.
+     *
+     * @param connection database connection
+     * @throws SQLException if an error occurs
+     * @see DatabasePersistenceManager#closeConnection(Connection)
+     */
+    protected void closeConnection(Connection connection) throws SQLException {
+        // prepare connection url for issuing shutdown command
+        String url = connection.getMetaData().getURL();
+        int pos = url.lastIndexOf(';');
+        if (pos != -1) {
+            // strip any 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
+        connection.setAutoCommit(true);
+
+        // 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: jackrabbit/trunk/jackrabbit/src/main/java/org/apache/jackrabbit/core/persistence/db/DerbyPersistenceManager.java
------------------------------------------------------------------------------
    svn:eol-style = native

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