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;
+ }
+ }
+ }
+}