You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by st...@apache.org on 2012/03/09 23:20:40 UTC

svn commit: r1299075 - in /jackrabbit/sandbox/jackrabbit-mongo-persistence: ./ src/ src/main/ src/main/java/ src/main/java/org/ src/main/java/org/apache/ src/main/java/org/apache/jackrabbit/ src/main/java/org/apache/jackrabbit/core/ src/main/java/org/a...

Author: stefan
Date: Fri Mar  9 22:20:39 2012
New Revision: 1299075

URL: http://svn.apache.org/viewvc?rev=1299075&view=rev
Log:
experimental mongo-based pm & ds

Added:
    jackrabbit/sandbox/jackrabbit-mongo-persistence/   (with props)
    jackrabbit/sandbox/jackrabbit-mongo-persistence/README.txt
    jackrabbit/sandbox/jackrabbit-mongo-persistence/pom.xml
    jackrabbit/sandbox/jackrabbit-mongo-persistence/src/
    jackrabbit/sandbox/jackrabbit-mongo-persistence/src/main/
    jackrabbit/sandbox/jackrabbit-mongo-persistence/src/main/java/
    jackrabbit/sandbox/jackrabbit-mongo-persistence/src/main/java/org/
    jackrabbit/sandbox/jackrabbit-mongo-persistence/src/main/java/org/apache/
    jackrabbit/sandbox/jackrabbit-mongo-persistence/src/main/java/org/apache/jackrabbit/
    jackrabbit/sandbox/jackrabbit-mongo-persistence/src/main/java/org/apache/jackrabbit/core/
    jackrabbit/sandbox/jackrabbit-mongo-persistence/src/main/java/org/apache/jackrabbit/core/data/
    jackrabbit/sandbox/jackrabbit-mongo-persistence/src/main/java/org/apache/jackrabbit/core/data/mongo/
    jackrabbit/sandbox/jackrabbit-mongo-persistence/src/main/java/org/apache/jackrabbit/core/data/mongo/MongoDataStore.java
    jackrabbit/sandbox/jackrabbit-mongo-persistence/src/main/java/org/apache/jackrabbit/core/persistence/
    jackrabbit/sandbox/jackrabbit-mongo-persistence/src/main/java/org/apache/jackrabbit/core/persistence/mongo/
    jackrabbit/sandbox/jackrabbit-mongo-persistence/src/main/java/org/apache/jackrabbit/core/persistence/mongo/MongoConfig.java
    jackrabbit/sandbox/jackrabbit-mongo-persistence/src/main/java/org/apache/jackrabbit/core/persistence/mongo/MongoPersistenceManager.java

Propchange: jackrabbit/sandbox/jackrabbit-mongo-persistence/
------------------------------------------------------------------------------
--- svn:ignore (added)
+++ svn:ignore Fri Mar  9 22:20:39 2012
@@ -0,0 +1,3 @@
+.idea
+
+jackrabbit-mongo-persistence.iml

Added: jackrabbit/sandbox/jackrabbit-mongo-persistence/README.txt
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-mongo-persistence/README.txt?rev=1299075&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-mongo-persistence/README.txt (added)
+++ jackrabbit/sandbox/jackrabbit-mongo-persistence/README.txt Fri Mar  9 22:20:39 2012
@@ -0,0 +1,24 @@
+This is an experimental implementation of a BundlePersistenceManager
+and DataStore using a MongoDB server [1,2].
+
+The MongoPersistenceManager is not transactional! If an error occurs while
+committing changes the workspace may become inconsistent and unreadable!
+
+Both MongoPersistenceManager and MongoDataStore support the following parameters:
+
+- host -> defaults to 127.0.0.1
+- port -> defaults to 27017
+- TODO document all configuration parameters
+
+MongoPersistenceManager also supports the following parameters:
+- TODO document all configuration parameters
+
+MongoDataStore also supports the following parameter:
+- TODO document all configuration parameters
+
+The methods related to data store garbage collection are not yet implemented.
+
+References:
+
+[1] http://www.mongodb.org/
+[2] http://api.mongodb.org/java/current/
\ No newline at end of file

Added: jackrabbit/sandbox/jackrabbit-mongo-persistence/pom.xml
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-mongo-persistence/pom.xml?rev=1299075&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-mongo-persistence/pom.xml (added)
+++ jackrabbit/sandbox/jackrabbit-mongo-persistence/pom.xml Fri Mar  9 22:20:39 2012
@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+   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.
+  -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
+                             http://maven.apache.org/maven-v4_0_0.xsd ">
+  <modelVersion>4.0.0</modelVersion>
+
+  <!-- ====================================================================== -->
+  <!-- P R O J E C T  D E S C R I P T I O N                                   -->
+  <!-- ====================================================================== -->
+
+  <parent>
+    <groupId>org.apache</groupId>
+    <artifactId>apache</artifactId>
+    <version>4</version>
+  </parent>
+
+  <groupId>org.apache.jackrabbit</groupId>
+  <artifactId>jackrabbit-mongo-persistence</artifactId>
+  <name>Apache Jackrabbit</name>
+  <version>2.6-SNAPSHOT</version>
+  <packaging>jar</packaging>
+
+  <dependencies>
+    <dependency>
+      <groupId>javax.jcr</groupId>
+      <artifactId>jcr</artifactId>
+      <version>2.0</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.jackrabbit</groupId>
+      <artifactId>jackrabbit-core</artifactId>
+      <version>2.6-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.mongodb</groupId>
+      <artifactId>mongo-java-driver</artifactId>
+      <version>2.7.1</version>
+    </dependency>
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-api</artifactId>
+      <version>1.6.4</version>
+    </dependency>
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>jcl-over-slf4j</artifactId>
+      <version>1.6.4</version>
+    </dependency>
+    <dependency>
+      <groupId>ch.qos.logback</groupId>
+      <artifactId>logback-classic</artifactId>
+      <version>1.0.0</version>
+    </dependency>
+
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <version>4.10</version>
+      <scope>test</scope>
+    </dependency>
+
+  </dependencies>
+
+</project>

Added: jackrabbit/sandbox/jackrabbit-mongo-persistence/src/main/java/org/apache/jackrabbit/core/data/mongo/MongoDataStore.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-mongo-persistence/src/main/java/org/apache/jackrabbit/core/data/mongo/MongoDataStore.java?rev=1299075&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-mongo-persistence/src/main/java/org/apache/jackrabbit/core/data/mongo/MongoDataStore.java (added)
+++ jackrabbit/sandbox/jackrabbit-mongo-persistence/src/main/java/org/apache/jackrabbit/core/data/mongo/MongoDataStore.java Fri Mar  9 22:20:39 2012
@@ -0,0 +1,247 @@
+/*
+ * 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.data.mongo;
+
+import com.mongodb.BasicDBObject;
+import com.mongodb.DB;
+import com.mongodb.DBCollection;
+import com.mongodb.Mongo;
+import com.mongodb.ServerAddress;
+import com.mongodb.WriteConcern;
+import com.mongodb.gridfs.GridFS;
+import org.apache.jackrabbit.core.data.DataIdentifier;
+import org.apache.jackrabbit.core.data.DataRecord;
+import org.apache.jackrabbit.core.data.DataStore;
+import org.apache.jackrabbit.core.data.DataStoreException;
+import org.apache.jackrabbit.core.persistence.mongo.MongoConfig;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.jcr.RepositoryException;
+import java.io.InputStream;
+import java.net.UnknownHostException;
+import java.util.Iterator;
+
+/**
+ *
+ */
+public class MongoDataStore implements DataStore {
+
+    private static final Logger log = LoggerFactory.getLogger(MongoDataStore.class);
+
+    /** flag indicating if this manager was initialized */
+    protected boolean initialized;
+
+    protected MongoConfig conf = new MongoConfig();
+
+    protected Mongo con;
+    protected DB db;
+    protected GridFS fs;
+
+    //--------------------------------------< configuration getters & setters >
+
+    public String getHost() {
+        return conf.getHost();
+    }
+
+    public void setHost(String host) {
+        conf.setHost(host);
+    }
+
+    public int getPort() {
+        return conf.getPort();
+    }
+
+    public void setPort(int port) {
+        conf.setPort(port);
+    }
+
+    public String getDescription() {
+        return conf.getDescription();
+    }
+
+    public void setDescription(String description) {
+        conf.setDescription(description);
+    }
+
+    public int getConnectionsPerHost() {
+        return conf.getConnectionsPerHost();
+    }
+
+    public void setConnectionsPerHost(int connectionsPerHost) {
+        conf.setConnectionsPerHost(connectionsPerHost);
+    }
+
+    public int getMaxWaitTime() {
+        return conf.getMaxWaitTime();
+    }
+
+    public void setMaxWaitTime(int maxWaitTime) {
+        conf.setMaxWaitTime(maxWaitTime);
+    }
+
+    public int getConnectTimeout() {
+        return conf.getConnectTimeout();
+    }
+
+    public void setConnectTimeout(int connectTimeout) {
+        conf.setConnectTimeout(connectTimeout);
+    }
+
+    public int getSocketTimeout() {
+        return conf.getSocketTimeout();
+    }
+
+    public void setSocketTimeout(int socketTimeout) {
+        conf.setSocketTimeout(socketTimeout);
+    }
+
+    public boolean isSocketKeepAlive() {
+        return conf.isSocketKeepAlive();
+    }
+
+    public void setSocketKeepAlive(boolean socketKeepAlive) {
+        conf.setSocketKeepAlive(socketKeepAlive);
+    }
+
+    public boolean isAutoConnectRetry() {
+        return conf.isAutoConnectRetry();
+    }
+
+    public void setAutoConnectRetry(boolean autoConnectRetry) {
+        conf.setAutoConnectRetry(autoConnectRetry);
+    }
+
+    public long getMaxAutoConnectRetryTime() {
+        return conf.getMaxAutoConnectRetryTime();
+    }
+
+    public void setMaxAutoConnectRetryTime(long maxAutoConnectRetryTime) {
+        conf.setMaxAutoConnectRetryTime(maxAutoConnectRetryTime);
+    }
+
+    public boolean isSlaveOk() {
+        return conf.isSlaveOk();
+    }
+
+    public void setSlaveOk(boolean slaveOk) {
+        conf.setSlaveOk(slaveOk);
+    }
+
+    public boolean isSafe() {
+        return conf.isSafe();
+    }
+
+    public void setSafe(boolean safe) {
+        conf.setSafe(safe);
+    }
+
+    public int getW() {
+        return conf.getW();
+    }
+
+    public void setW(int w) {
+        conf.setW(w);
+    }
+
+    public int getWtimeout() {
+        return conf.getWtimeout();
+    }
+
+    public void setWtimeout(int wtimeout) {
+        conf.setWtimeout(wtimeout);
+    }
+
+    public boolean isFsync() {
+        return conf.isFsync();
+    }
+
+    public void setFsync(boolean fsync) {
+        conf.setFsync(fsync);
+    }
+
+    public boolean isJ() {
+        return conf.isJ();
+    }
+
+    //------------------------------------------------------------< DataStore >
+
+    public void init(String homeDir) throws RepositoryException {
+        if (initialized) {
+            throw new IllegalStateException("already initialized");
+        }
+
+        try {
+            con = new Mongo(new ServerAddress(conf.getHost(), conf.getPort()), conf);
+        } catch (UnknownHostException e) {
+            log.error("failed to connect to mongodb", e);
+            throw new RepositoryException("failed to initialize MongoDataStore", e);
+        }
+
+        db = con.getDB("rep");
+        db.setWriteConcern(WriteConcern.SAFE);
+
+        fs = new GridFS(db);
+
+        initialized = true;
+    }
+
+    public void close() throws DataStoreException {
+        if (!initialized) {
+            throw new IllegalStateException("not initialized");
+        }
+
+        try {
+            con.close();
+            db = null;
+        } finally {
+            initialized = false;
+        }
+    }
+
+    public DataRecord getRecordIfStored(DataIdentifier identifier) throws DataStoreException {
+        return null; // TODO Auto-generated method stub
+    }
+
+    public DataRecord getRecord(DataIdentifier identifier) throws DataStoreException {
+        return null; // TODO Auto-generated method stub
+    }
+
+    public DataRecord addRecord(InputStream stream) throws DataStoreException {
+        return null; // TODO Auto-generated method stub
+    }
+
+    public void updateModifiedDateOnAccess(long before) {
+        // TODO Auto-generated method stub
+    }
+
+    public int deleteAllOlderThan(long min) throws DataStoreException {
+        return 0; // TODO Auto-generated method stub
+    }
+
+    public Iterator<DataIdentifier> getAllIdentifiers() throws DataStoreException {
+        return null; // TODO Auto-generated method stub
+    }
+
+    public int getMinRecordLength() {
+        return 0; // TODO Auto-generated method stub
+    }
+
+    public void clearInUse() {
+        // TODO Auto-generated method stub
+    }
+}

Added: jackrabbit/sandbox/jackrabbit-mongo-persistence/src/main/java/org/apache/jackrabbit/core/persistence/mongo/MongoConfig.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-mongo-persistence/src/main/java/org/apache/jackrabbit/core/persistence/mongo/MongoConfig.java?rev=1299075&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-mongo-persistence/src/main/java/org/apache/jackrabbit/core/persistence/mongo/MongoConfig.java (added)
+++ jackrabbit/sandbox/jackrabbit-mongo-persistence/src/main/java/org/apache/jackrabbit/core/persistence/mongo/MongoConfig.java Fri Mar  9 22:20:39 2012
@@ -0,0 +1,299 @@
+/*
+ * 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.mongo;
+
+import com.mongodb.MongoOptions;
+import com.mongodb.ServerAddress;
+
+/**
+ * 
+ */
+public class MongoConfig extends MongoOptions {
+
+    private String host = ServerAddress.defaultHost();
+    
+    private int port = ServerAddress.defaultPort();
+
+    public String getHost() {
+        return host;
+    }
+
+    public void setHost(String host) {
+        this.host = host;
+    }
+
+    public int getPort() {
+        return port;
+    }
+
+    public void setPort(int port) {
+        this.port = port;
+    }
+
+    //------------------------< getters & setters for MongoOptions attributes >
+    /**
+     * see {@link MongoOptions#description}
+     * 
+     * @return
+     */
+    public String getDescription() {
+        return description;
+    }
+
+    /**
+     * see {@link MongoOptions#description}
+     *
+     * @param description
+     */
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    /**
+     * see {@link MongoOptions#connectionsPerHost}
+     *
+     * @return
+     */
+    public int getConnectionsPerHost() {
+        return connectionsPerHost;
+    }
+
+    /**
+     * see {@link MongoOptions#connectionsPerHost}
+     *
+     * @param connectionsPerHost
+     */
+    public void setConnectionsPerHost(int connectionsPerHost) {
+        this.connectionsPerHost = connectionsPerHost;
+    }
+
+    /**
+     * see {@link MongoOptions#maxWaitTime}
+     *
+     * @return
+     */
+    public int getMaxWaitTime() {
+        return maxWaitTime;
+    }
+
+    /**
+     * see {@link MongoOptions#maxWaitTime}
+     *
+     * @param maxWaitTime
+     */
+    public void setMaxWaitTime(int maxWaitTime) {
+        this.maxWaitTime = maxWaitTime;
+    }
+
+    /**
+     * see {@link MongoOptions#connectTimeout}
+     *
+     * @return
+     */
+    public int getConnectTimeout() {
+        return connectTimeout;
+    }
+
+    /**
+     * see {@link MongoOptions#connectTimeout}
+     *
+     * @param connectTimeout
+     */
+    public void setConnectTimeout(int connectTimeout) {
+        this.connectTimeout = connectTimeout;
+    }
+
+    /**
+     * see {@link MongoOptions#socketTimeout}
+     *
+     * @return
+     */
+    public int getSocketTimeout() {
+        return socketTimeout;
+    }
+
+    /**
+     * see {@link MongoOptions#socketTimeout}
+     *
+     * @param socketTimeout
+     */
+    public void setSocketTimeout(int socketTimeout) {
+        this.socketTimeout = socketTimeout;
+    }
+
+    /**
+     * see {@link MongoOptions#socketKeepAlive}
+     *
+     * @return
+     */
+    public boolean isSocketKeepAlive() {
+        return socketKeepAlive;
+    }
+
+    /**
+     * see {@link MongoOptions#socketKeepAlive}
+     *
+     * @param socketKeepAlive
+     */
+    public void setSocketKeepAlive(boolean socketKeepAlive) {
+        this.socketKeepAlive = socketKeepAlive;
+    }
+
+    /**
+     * see {@link MongoOptions#autoConnectRetry}
+     *
+     * @return
+     */
+    public boolean isAutoConnectRetry() {
+        return autoConnectRetry;
+    }
+
+    /**
+     * see {@link MongoOptions#autoConnectRetry}
+     *
+     * @param autoConnectRetry
+     */
+    public void setAutoConnectRetry(boolean autoConnectRetry) {
+        this.autoConnectRetry = autoConnectRetry;
+    }
+
+    /**
+     * see {@link MongoOptions#maxAutoConnectRetryTime}
+     *
+     * @return
+     */
+    public long getMaxAutoConnectRetryTime() {
+        return maxAutoConnectRetryTime;
+    }
+
+    /**
+     * see {@link MongoOptions#maxAutoConnectRetryTime}
+     *
+     * @param maxAutoConnectRetryTime
+     */
+    public void setMaxAutoConnectRetryTime(long maxAutoConnectRetryTime) {
+        this.maxAutoConnectRetryTime = maxAutoConnectRetryTime;
+    }
+
+    /**
+     * see {@link MongoOptions#slaveOk}
+     * 
+     * @return
+     */
+    public boolean isSlaveOk() {
+        return slaveOk;
+    }
+
+    /**
+     * see {@link MongoOptions#slaveOk}
+     *
+     * @param slaveOk
+     */
+    public void setSlaveOk(boolean slaveOk) {
+        this.slaveOk = slaveOk;
+    }
+
+    /**
+     * see {@link MongoOptions#safe}
+     *
+     * @return
+     */
+    public boolean isSafe() {
+        return safe;
+    }
+
+    /**
+     * see {@link MongoOptions#safe}
+     *
+     * @param safe
+     */
+    public void setSafe(boolean safe) {
+        this.safe = safe;
+    }
+
+    /**
+     * see {@link MongoOptions#w}
+     *
+     * @return
+     */
+    public int getW() {
+        return w;
+    }
+
+    /**
+     * see {@link MongoOptions#w}
+     *
+     * @param w
+     */
+    public void setW(int w) {
+        this.w = w;
+    }
+
+    /**
+     * see {@link MongoOptions#wtimeout}
+     *
+     * @return
+     */
+    public int getWtimeout() {
+        return wtimeout;
+    }
+
+    /**
+     * see {@link MongoOptions#wtimeout}
+     *
+     * @param wtimeout
+     */
+    public void setWtimeout(int wtimeout) {
+        this.wtimeout = wtimeout;
+    }
+
+    /**
+     * see {@link MongoOptions#fsync}
+     *
+     * @return
+     */
+    public boolean isFsync() {
+        return fsync;
+    }
+
+    /**
+     * see {@link MongoOptions#fsync}
+     *
+     * @param fsync
+     */
+    public void setFsync(boolean fsync) {
+        this.fsync = fsync;
+    }
+
+    /**
+     * see {@link MongoOptions#j}
+     *
+     * @return
+     */
+    public boolean isJ() {
+        return j;
+    }
+
+    /**
+     * see {@link MongoOptions#j}
+     *
+     * @param j
+     */
+    public void setJ(boolean j) {
+        this.j = j;
+    }
+}

Added: jackrabbit/sandbox/jackrabbit-mongo-persistence/src/main/java/org/apache/jackrabbit/core/persistence/mongo/MongoPersistenceManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/jackrabbit-mongo-persistence/src/main/java/org/apache/jackrabbit/core/persistence/mongo/MongoPersistenceManager.java?rev=1299075&view=auto
==============================================================================
--- jackrabbit/sandbox/jackrabbit-mongo-persistence/src/main/java/org/apache/jackrabbit/core/persistence/mongo/MongoPersistenceManager.java (added)
+++ jackrabbit/sandbox/jackrabbit-mongo-persistence/src/main/java/org/apache/jackrabbit/core/persistence/mongo/MongoPersistenceManager.java Fri Mar  9 22:20:39 2012
@@ -0,0 +1,477 @@
+/*
+ * 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.mongo;
+
+import com.mongodb.BasicDBObject;
+import com.mongodb.DB;
+import com.mongodb.DBCollection;
+import com.mongodb.DBCursor;
+import com.mongodb.Mongo;
+import com.mongodb.ServerAddress;
+import com.mongodb.WriteConcern;
+import com.mongodb.gridfs.GridFS;
+import com.mongodb.gridfs.GridFSDBFile;
+import com.mongodb.gridfs.GridFSInputFile;
+import org.apache.jackrabbit.core.id.NodeId;
+import org.apache.jackrabbit.core.id.PropertyId;
+import org.apache.jackrabbit.core.persistence.PMContext;
+import org.apache.jackrabbit.core.persistence.bundle.AbstractBundlePersistenceManager;
+import org.apache.jackrabbit.core.persistence.util.BLOBStore;
+import org.apache.jackrabbit.core.persistence.util.BundleBinding;
+import org.apache.jackrabbit.core.persistence.util.ErrorHandling;
+import org.apache.jackrabbit.core.persistence.util.NodePropBundle;
+import org.apache.jackrabbit.core.persistence.util.Serializer;
+import org.apache.jackrabbit.core.state.ItemStateException;
+import org.apache.jackrabbit.core.state.NoSuchItemStateException;
+import org.apache.jackrabbit.core.state.NodeReferences;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.jcr.RepositoryException;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ *
+ */
+public class MongoPersistenceManager extends AbstractBundlePersistenceManager {
+
+    private static final Logger log = LoggerFactory.getLogger(MongoPersistenceManager.class);
+
+    /** initial size of buffer used to serialize objects */
+    protected static final int INITIAL_BUFFER_SIZE = 1024;
+
+    protected static final String ID_FIELD = ":id";
+    protected static final String DATA_FIELD = ":data";
+
+    /** flag indicating if this manager was initialized */
+    protected boolean initialized;
+
+    protected BundleBinding binding;
+
+    protected MongoConfig conf = new MongoConfig();
+
+    protected Mongo con;
+    protected DB db;
+    protected DBCollection bundles;
+    protected DBCollection refs;
+
+    protected MongoBlobStore blobStore;
+
+    //--------------------------------------< configuration getters & setters >
+
+    public String getHost() {
+        return conf.getHost();
+    }
+
+    public void setHost(String host) {
+        conf.setHost(host);
+    }
+
+    public int getPort() {
+        return conf.getPort();
+    }
+
+    public void setPort(int port) {
+        conf.setPort(port);
+    }
+
+    public String getDescription() {
+        return conf.getDescription();
+    }
+
+    public void setDescription(String description) {
+        conf.setDescription(description);
+    }
+
+    public int getConnectionsPerHost() {
+        return conf.getConnectionsPerHost();
+    }
+
+    public void setConnectionsPerHost(int connectionsPerHost) {
+        conf.setConnectionsPerHost(connectionsPerHost);
+    }
+
+    public int getMaxWaitTime() {
+        return conf.getMaxWaitTime();
+    }
+
+    public void setMaxWaitTime(int maxWaitTime) {
+        conf.setMaxWaitTime(maxWaitTime);
+    }
+
+    public int getConnectTimeout() {
+        return conf.getConnectTimeout();
+    }
+
+    public void setConnectTimeout(int connectTimeout) {
+        conf.setConnectTimeout(connectTimeout);
+    }
+
+    public int getSocketTimeout() {
+        return conf.getSocketTimeout();
+    }
+
+    public void setSocketTimeout(int socketTimeout) {
+        conf.setSocketTimeout(socketTimeout);
+    }
+
+    public boolean isSocketKeepAlive() {
+        return conf.isSocketKeepAlive();
+    }
+
+    public void setSocketKeepAlive(boolean socketKeepAlive) {
+        conf.setSocketKeepAlive(socketKeepAlive);
+    }
+
+    public boolean isAutoConnectRetry() {
+        return conf.isAutoConnectRetry();
+    }
+
+    public void setAutoConnectRetry(boolean autoConnectRetry) {
+        conf.setAutoConnectRetry(autoConnectRetry);
+    }
+
+    public long getMaxAutoConnectRetryTime() {
+        return conf.getMaxAutoConnectRetryTime();
+    }
+
+    public void setMaxAutoConnectRetryTime(long maxAutoConnectRetryTime) {
+        conf.setMaxAutoConnectRetryTime(maxAutoConnectRetryTime);
+    }
+
+    public boolean isSlaveOk() {
+        return conf.isSlaveOk();
+    }
+
+    public void setSlaveOk(boolean slaveOk) {
+        conf.setSlaveOk(slaveOk);
+    }
+
+    public boolean isSafe() {
+        return conf.isSafe();
+    }
+
+    public void setSafe(boolean safe) {
+        conf.setSafe(safe);
+    }
+
+    public int getW() {
+        return conf.getW();
+    }
+
+    public void setW(int w) {
+        conf.setW(w);
+    }
+
+    public int getWtimeout() {
+        return conf.getWtimeout();
+    }
+
+    public void setWtimeout(int wtimeout) {
+        conf.setWtimeout(wtimeout);
+    }
+
+    public boolean isFsync() {
+        return conf.isFsync();
+    }
+
+    public void setFsync(boolean fsync) {
+        conf.setFsync(fsync);
+    }
+
+    public boolean isJ() {
+        return conf.isJ();
+    }
+
+    //---------------------------------------------------< PersistenceManager >
+
+    @Override
+    public void init(PMContext context) throws Exception {
+        if (initialized) {
+            throw new IllegalStateException("already initialized");
+        }
+        super.init(context);
+
+        ErrorHandling errorHandling = new ErrorHandling();
+        //ErrorHandling errorHandling = new ErrorHandling(ErrorHandling.IGNORE_MISSING_BLOBS);
+        binding = new BundleBinding(errorHandling, blobStore, getNsIndex(), getNameIndex(), context.getDataStore());
+
+        try {
+            con = new Mongo(new ServerAddress(conf.getHost(), conf.getPort()), conf);
+        } catch (UnknownHostException e) {
+            log.error("failed to connect to mongodb", e);
+            throw new RepositoryException("failed to initialize MongoPersistenceManager", e);
+        }
+        db = con.getDB("rep");
+        db.setWriteConcern(WriteConcern.SAFE);
+
+        bundles = db.getCollection("bundles");
+        bundles.ensureIndex(
+                new BasicDBObject(ID_FIELD, 1),
+                new BasicDBObject("unique", true));
+        refs = db.getCollection("refs");
+        refs.ensureIndex(
+                new BasicDBObject(ID_FIELD, 1),
+                new BasicDBObject("unique", true));
+
+        blobStore = new MongoBlobStore();
+
+        initialized = true;
+    }
+
+    @Override
+    public void close() throws Exception {
+        if (!initialized) {
+            throw new IllegalStateException("not initialized");
+        }
+
+        try {
+            con.close();
+            db = null;
+
+            super.close();
+        } finally {
+            initialized = false;
+        }
+    }
+
+    //-------------------------------------< AbstractBundlePersistenceManager >
+
+    @Override
+    protected NodePropBundle loadBundle(NodeId nodeId) throws ItemStateException {
+        if (!initialized) {
+            throw new IllegalStateException("not initialized");
+        }
+        BasicDBObject key = new BasicDBObject();
+        key.put(ID_FIELD, nodeId.getRawBytes());
+        BasicDBObject bundleObject = (BasicDBObject) bundles.findOne(key);
+        if (bundleObject != null) {
+            byte[] bytes = (byte[]) bundleObject.get(DATA_FIELD);
+            try {
+                return binding.readBundle(new ByteArrayInputStream(bytes), nodeId);
+            } catch (Exception e) {
+                String msg = "failed to read bundle: " + nodeId + ": " + e;
+                log.error(msg);
+                throw new ItemStateException(msg, e);
+            }
+        } else {
+            throw new ItemStateException("failed to read bundle: " + nodeId);
+        }
+    }
+
+    @Override
+    protected void storeBundle(NodePropBundle nodePropBundle) throws ItemStateException {
+        if (!initialized) {
+            throw new IllegalStateException("not initialized");
+        }
+
+        ByteArrayOutputStream out = new ByteArrayOutputStream(INITIAL_BUFFER_SIZE);
+        try {
+            binding.writeBundle(out, nodePropBundle);
+
+            BasicDBObject key = new BasicDBObject();
+            key.put(ID_FIELD, nodePropBundle.getId().getRawBytes());
+
+            BasicDBObject bundleObject =
+                    new BasicDBObject(ID_FIELD, nodePropBundle.getId().getRawBytes())
+                            .append(DATA_FIELD, out.toByteArray());
+
+            bundles.update(key, bundleObject, true, false);
+        } catch (IOException e) {
+            String msg = "failed to write bundle: " + nodePropBundle.getId();
+            log.error(msg, e);
+            throw new ItemStateException(msg, e);
+        }
+    }
+
+    @Override
+    protected void destroyBundle(NodePropBundle nodePropBundle) throws ItemStateException {
+        if (!initialized) {
+            throw new IllegalStateException("not initialized");
+        }
+
+        BasicDBObject key = new BasicDBObject();
+        key.put(ID_FIELD, nodePropBundle.getId().getRawBytes());
+        bundles.remove(key);
+    }
+
+    public NodeReferences loadReferencesTo(NodeId nodeId) throws NoSuchItemStateException, ItemStateException {
+        if (!initialized) {
+            throw new IllegalStateException("not initialized");
+        }
+
+        BasicDBObject key = new BasicDBObject();
+        key.put(ID_FIELD, nodeId.getRawBytes());
+        BasicDBObject refsObjects = (BasicDBObject) refs.findOne(key);
+        if (refsObjects != null) {
+            byte[] bytes = (byte[]) refsObjects.get(DATA_FIELD);
+            NodeReferences refs = new NodeReferences(nodeId);
+            try {
+                Serializer.deserialize(refs, new ByteArrayInputStream(bytes));
+                return refs;
+            } catch (Exception e) {
+                String msg = "failed to load references: " + nodeId + ": " + e;
+                log.error(msg);
+                throw new ItemStateException(msg, e);
+            }
+        } else {
+            throw new ItemStateException("failed to load references: " + nodeId);
+        }
+    }
+
+    @Override
+    protected void store(NodeReferences nodeReferences) throws ItemStateException {
+        if (!initialized) {
+            throw new IllegalStateException("not initialized");
+        }
+
+        try {
+            ByteArrayOutputStream out = new ByteArrayOutputStream(INITIAL_BUFFER_SIZE);
+            // serialize references
+            Serializer.serialize(nodeReferences, out);
+
+            BasicDBObject key = new BasicDBObject();
+            key.put(ID_FIELD, nodeReferences.getTargetId().getRawBytes());
+
+            BasicDBObject refsObject =
+                    new BasicDBObject(ID_FIELD, nodeReferences.getTargetId().getRawBytes())
+                            .append(DATA_FIELD, out.toByteArray());
+
+            refs.update(key, refsObject, true, false);
+        } catch (Exception e) {
+            String msg = "failed to store references: " + nodeReferences.getTargetId();
+            log.debug(msg);
+            throw new ItemStateException(msg, e);
+        }
+    }
+
+    @Override
+    protected void destroy(NodeReferences nodeReferences) throws ItemStateException {
+        if (!initialized) {
+            throw new IllegalStateException("not initialized");
+        }
+
+        BasicDBObject key = new BasicDBObject();
+        key.put(ID_FIELD, nodeReferences.getTargetId().getRawBytes());
+        refs.remove(key);
+    }
+
+    @Override
+    protected BLOBStore getBlobStore() {
+        if (!initialized) {
+            throw new IllegalStateException("not initialized");
+        }
+
+        return blobStore;
+    }
+
+    public List<NodeId> getAllNodeIds(NodeId after, int maxCount) throws ItemStateException, RepositoryException {
+        if (!initialized) {
+            throw new IllegalStateException("not initialized");
+        }
+
+        BasicDBObject keys = new BasicDBObject();
+        keys.put(ID_FIELD, 1);
+        DBCursor cursor = bundles.find(new BasicDBObject(), keys);
+
+        ArrayList<NodeId> results = new ArrayList<NodeId>();
+        
+        maxCount = maxCount <= 0 ? Integer.MAX_VALUE : maxCount;
+        try {
+            while (cursor.hasNext()) {
+                BasicDBObject bundleObject  = (BasicDBObject) cursor.next();
+                byte[] bytes = (byte[]) bundleObject.get(ID_FIELD);
+                NodeId id = new NodeId(bytes);
+                if (after != null) {
+                    if (after.equals(id)) {
+                        after = null;
+                        continue;
+                    } else {
+                        results.add(id);
+                    }
+                }
+                
+            }
+        } finally {
+            cursor.close();
+        }
+        return results;
+    }
+
+    public boolean existsReferencesTo(NodeId nodeId) throws ItemStateException {
+        if (!initialized) {
+            throw new IllegalStateException("not initialized");
+        }
+
+        BasicDBObject key = new BasicDBObject();
+        key.put(ID_FIELD, nodeId.getRawBytes());
+        return (refs.findOne(key) != null);
+    }
+
+    //--------------------------------------------------------< inner classes >
+
+    protected class MongoBlobStore implements BLOBStore {
+
+        private GridFS fs;
+
+        protected MongoBlobStore() {
+            fs = new GridFS(db);
+        }
+
+        public String createId(PropertyId id, int index) {
+            StringBuilder buf = new StringBuilder();
+            buf.append(id.getParentId().toString());
+            buf.append('.');
+            buf.append(getNsIndex().stringToIndex(id.getName().getNamespaceURI()));
+            buf.append('.');
+            buf.append(getNameIndex().stringToIndex(id.getName().getLocalName()));
+            buf.append('.');
+            buf.append(index);
+            return buf.toString();
+        }
+
+        public void put(String blobId, InputStream in, long size) throws Exception {
+            GridFSInputFile f = fs.createFile(in, blobId, true);
+            //f.save(0x20000);   // save in 128k chunks
+            f.save();
+        }
+
+        public InputStream get(String blobId) throws Exception {
+            GridFSDBFile f = fs.findOne(blobId);
+            if (f == null) {
+                throw new Exception("no such BLOB: " + blobId);
+            }
+            return f.getInputStream();
+        }
+
+        public boolean remove(String blobId) throws Exception {
+            GridFSDBFile f = fs.findOne(blobId);
+            if (f != null) {
+                fs.remove(blobId);
+                return true;
+            } else {
+                return false;
+            }
+        }
+    }
+}