You are viewing a plain text version of this content. The canonical link for it is here.
Posted to oak-commits@jackrabbit.apache.org by ju...@apache.org on 2012/09/17 14:54:06 UTC
svn commit: r1386591 [4/7] - in /jackrabbit/oak/trunk: ./ oak-mongomk-api/
oak-mongomk-api/src/ oak-mongomk-api/src/main/
oak-mongomk-api/src/main/java/ oak-mongomk-api/src/main/java/org/
oak-mongomk-api/src/main/java/org/apache/ oak-mongomk-api/src/ma...
Added: jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/NodeStoreMongo.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/NodeStoreMongo.java?rev=1386591&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/NodeStoreMongo.java (added)
+++ jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/NodeStoreMongo.java Mon Sep 17 12:54:01 2012
@@ -0,0 +1,206 @@
+/*
+ * 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.mongomk;
+
+import java.util.List;
+
+import org.apache.jackrabbit.mk.json.JsopBuilder;
+import org.apache.jackrabbit.mongomk.api.NodeStore;
+import org.apache.jackrabbit.mongomk.api.command.Command;
+import org.apache.jackrabbit.mongomk.api.command.CommandExecutor;
+import org.apache.jackrabbit.mongomk.api.model.Commit;
+import org.apache.jackrabbit.mongomk.api.model.Node;
+import org.apache.jackrabbit.mongomk.command.CommitCommandMongo;
+import org.apache.jackrabbit.mongomk.command.GetHeadRevisionCommandMongo;
+import org.apache.jackrabbit.mongomk.command.GetNodesCommandMongo;
+import org.apache.jackrabbit.mongomk.command.NodeExistsCommandMongo;
+import org.apache.jackrabbit.mongomk.impl.command.CommandExecutorImpl;
+import org.apache.jackrabbit.mongomk.model.CommitMongo;
+import org.apache.jackrabbit.mongomk.model.HeadMongo;
+import org.apache.jackrabbit.mongomk.query.FetchValidCommitsQuery;
+import org.apache.jackrabbit.mongomk.util.MongoUtil;
+
+import com.mongodb.DBCollection;
+
+/**
+ * Implementation of {@link NodeStore} for the {@code MongoDB}.
+ *
+ * @author <a href="mailto:pmarx@adobe.com>Philipp Marx</a>
+ */
+public class NodeStoreMongo implements NodeStore {
+
+ private static final long WAIT_FOR_COMMIT_POLL_MILLIS = 1000;
+
+ private final CommandExecutor commandExecutor;
+ private final MongoConnection mongoConnection;
+
+ /**
+ * Constructs a new {@code NodeStoreMongo}.
+ *
+ * @param mongoConnection The {@link MongoConnection}.
+ */
+ public NodeStoreMongo(MongoConnection mongoConnection) {
+ this.mongoConnection = mongoConnection;
+ commandExecutor = new CommandExecutorImpl();
+ }
+
+ @Override
+ public String commit(Commit commit) throws Exception {
+ Command<String> command = new CommitCommandMongo(mongoConnection, commit);
+
+ return commandExecutor.execute(command);
+ }
+
+ @Override
+ public String getHeadRevision() throws Exception {
+ Command<String> command = new GetHeadRevisionCommandMongo(mongoConnection);
+
+ return commandExecutor.execute(command);
+ }
+
+ @Override
+ public Node getNodes(String path, String revisionId, int depth, long offset,
+ int maxChildNodes, String filter) throws Exception {
+ Command<Node> command = new GetNodesCommandMongo(mongoConnection, path, revisionId, depth);
+ return commandExecutor.execute(command);
+ }
+
+ @Override
+ public boolean nodeExists(String path, String revId) throws Exception {
+ Command<Boolean> command = new NodeExistsCommandMongo(mongoConnection, path, revId);
+
+ return commandExecutor.execute(command);
+ }
+
+ @Override
+ public String getJournal(String fromRevisionId, String toRevisionId, String path) {
+ path = (path == null || "".equals(path)) ? "/" : path;
+ boolean filtered = !"/".equals(path);
+
+ // FIXME [Mete] There's more work here.
+
+ if (toRevisionId == null) {
+ try {
+ toRevisionId = new GetHeadRevisionCommandMongo(mongoConnection).execute();
+ } catch (Exception e) {
+ // FIXME Handle
+ }
+ }
+
+ List<CommitMongo> commits = new FetchValidCommitsQuery(mongoConnection,
+ fromRevisionId, toRevisionId).execute();
+
+ CommitMongo toCommit = getCommit(commits, toRevisionId);
+
+ CommitMongo fromCommit;
+ if (toRevisionId.equals(fromRevisionId)) {
+ fromCommit = toCommit;
+ } else {
+ fromCommit = getCommit(commits, fromRevisionId);
+ if (fromCommit == null || (fromCommit.getTimestamp() > toCommit.getTimestamp())) {
+ // negative range, return empty journal
+ return "[]";
+ }
+ }
+
+ JsopBuilder commitBuff = new JsopBuilder().array();
+ // iterate over commits in chronological order,
+ // starting with oldest commit
+ for (int i = commits.size() - 1; i >= 0; i--) {
+ CommitMongo commit = commits.get(i);
+ //if (commit.getParentId() == null) {
+ // continue;
+ //}
+ String diff = commit.getDiff();
+ // FIXME Check that filter really works.
+ if (!filtered || commit.getAffectedPaths().contains(path)) {
+ commitBuff.object()
+ .key("id").value(String.valueOf(commit.getRevisionId()))
+ .key("ts").value(commit.getTimestamp())
+ .key("msg").value(commit.getMessage())
+ .key("changes").value(diff).endObject();
+ }
+ }
+ return commitBuff.endArray().toString();
+ }
+
+ private CommitMongo getCommit(List<CommitMongo> commits, String toRevisionId) {
+ for (CommitMongo commit : commits) {
+ if (String.valueOf(commit.getRevisionId()).equals(toRevisionId)) {
+ return commit;
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public String getRevisionHistory(long since, int maxEntries, String path) {
+ path = (path == null || "".equals(path)) ? "/" : path;
+ boolean filtered = !"/".equals(path);
+ maxEntries = maxEntries < 0 ? Integer.MAX_VALUE : maxEntries;
+
+ List<CommitMongo> history = new FetchValidCommitsQuery(mongoConnection, maxEntries).execute();
+ JsopBuilder buff = new JsopBuilder().array();
+ for (int i = history.size() - 1; i >= 0; i--) {
+ CommitMongo commit = history.get(i);
+ if (commit.getTimestamp() >= since) {
+ // FIXME [Mete] Check that filter really works.
+ if (!filtered || commit.getAffectedPaths().contains(path)) {
+ buff.object()
+ .key("id").value(String.valueOf(commit.getRevisionId()))
+ .key("ts").value(commit.getTimestamp())
+ .key("msg").value(commit.getMessage())
+ .endObject();
+ }
+ }
+ }
+
+ return buff.endArray().toString();
+ }
+
+ @Override
+ public String waitForCommit(String oldHeadRevisionId, long timeout) throws InterruptedException {
+ long startTimestamp = System.currentTimeMillis();
+ long initialHeadRevisionId = getHeadRevisionId();
+
+ if (timeout <= 0) {
+ return String.valueOf(initialHeadRevisionId);
+ }
+
+ long oldHeadRevision = MongoUtil.toMongoRepresentation(oldHeadRevisionId);
+ if (oldHeadRevision < initialHeadRevisionId) {
+ return String.valueOf(initialHeadRevisionId);
+ }
+
+ long waitForCommitPollMillis = Math.min(WAIT_FOR_COMMIT_POLL_MILLIS, timeout);
+ while (true) {
+ long headRevisionId = getHeadRevisionId();
+ long now = System.currentTimeMillis();
+ if (headRevisionId != initialHeadRevisionId || now - startTimestamp >= timeout) {
+ return String.valueOf(headRevisionId);
+ }
+ Thread.sleep(waitForCommitPollMillis);
+ }
+ }
+
+ private long getHeadRevisionId() {
+ DBCollection headCollection = mongoConnection.getHeadCollection();
+ HeadMongo headMongo = (HeadMongo)headCollection.findOne();
+ long headRevisionId = headMongo.getHeadRevisionId();
+ return headRevisionId;
+ }
+}
Propchange: jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/NodeStoreMongo.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/command/CommitCommandMongo.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/command/CommitCommandMongo.java?rev=1386591&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/command/CommitCommandMongo.java (added)
+++ jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/command/CommitCommandMongo.java Mon Sep 17 12:54:01 2012
@@ -0,0 +1,289 @@
+/*
+ * 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.mongomk.command;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.jackrabbit.mongomk.MongoConnection;
+import org.apache.jackrabbit.mongomk.api.command.AbstractCommand;
+import org.apache.jackrabbit.mongomk.api.model.Commit;
+import org.apache.jackrabbit.mongomk.api.model.Instruction;
+import org.apache.jackrabbit.mongomk.model.CommitCommandInstructionVisitor;
+import org.apache.jackrabbit.mongomk.model.CommitMongo;
+import org.apache.jackrabbit.mongomk.model.HeadMongo;
+import org.apache.jackrabbit.mongomk.model.NodeMongo;
+import org.apache.jackrabbit.mongomk.query.FetchNodesForRevisionQuery;
+import org.apache.jackrabbit.mongomk.query.ReadAndIncHeadRevisionQuery;
+import org.apache.jackrabbit.mongomk.query.SaveAndSetHeadRevisionQuery;
+import org.apache.jackrabbit.mongomk.query.SaveCommitQuery;
+import org.apache.jackrabbit.mongomk.query.SaveNodesQuery;
+import org.apache.log4j.Logger;
+
+import com.mongodb.BasicDBObject;
+import com.mongodb.DBCollection;
+import com.mongodb.DBObject;
+import com.mongodb.QueryBuilder;
+import com.mongodb.WriteResult;
+
+/**
+ * A {@code Command} for committing into {@code MongoDB}.
+ *
+ * @author <a href="mailto:pmarx@adobe.com>Philipp Marx</a>
+ */
+public class CommitCommandMongo extends AbstractCommand<String> {
+
+ private static final Logger logger = Logger.getLogger(CommitCommandMongo.class);
+
+ private final Commit commit;
+ private final MongoConnection mongoConnection;
+
+ private Set<String> affectedPaths;
+ private CommitMongo commitMongo;
+ private List<NodeMongo> existingNodes;
+ private HeadMongo headMongo;
+ private Set<NodeMongo> nodeMongos;
+ private String revisionId;
+
+ /**
+ * Constructs a new {@code CommitCommandMongo}.
+ *
+ * @param mongoConnection {@link MongoConnection}
+ * @param commit {@link Commit}
+ */
+ public CommitCommandMongo(MongoConnection mongoConnection, Commit commit) {
+ this.mongoConnection = mongoConnection;
+ this.commit = commit;
+ }
+
+ @Override
+ public String execute() throws Exception {
+ logger.debug(String.format("Trying to commit: %s", commit.getDiff()));
+
+ readAndIncHeadRevision();
+ createRevision();
+ createMongoNodes();
+ createMongoCommit();
+ readExistingNodes();
+ mergeNodes();
+ prepareMongoNodes();
+ saveNodes();
+ saveCommit();
+ boolean success = saveAndSetHeadRevision();
+
+ logger.debug(String.format("Success was: %b", success));
+
+ if (!success) {
+ markAsFailed();
+
+ throw new ConflictingCommitException();
+ }
+
+ addRevisionId();
+
+ return revisionId;
+ }
+
+ @Override
+ public int getNumOfRetries() {
+ return 10;
+ }
+
+ @Override
+ public boolean needsRetry(Exception e) {
+ return e instanceof ConflictingCommitException;
+ }
+
+ /**
+ * This is protected for testing purposed only.
+ *
+ * @return N/A
+ * @throws Exception
+ */
+ protected boolean saveAndSetHeadRevision() throws Exception {
+ boolean success = true;
+
+ HeadMongo headMongo = new SaveAndSetHeadRevisionQuery(mongoConnection, this.headMongo.getHeadRevisionId(),
+ HeadMongo.toDBRepresentation(revisionId)).execute();
+ if (headMongo == null) {
+ // TODO: Check for conflicts!
+ logger.warn(String
+ .format("Encounterd a conflicting update, thus can't commit revision %s and will be retried with new revision",
+ revisionId));
+
+ success = false;
+ }
+
+ return success;
+ }
+
+ private void addRevisionId() {
+ commit.setRevisionId(revisionId);
+ }
+
+ private void createMongoCommit() throws Exception {
+ commitMongo = CommitMongo.fromCommit(commit);
+ commitMongo.setRevisionId(revisionId);
+ commitMongo.setAffectedPaths(new LinkedList<String>(affectedPaths));
+ commitMongo.setBaseRevId(headMongo.getHeadRevisionId());
+ }
+
+ private void createMongoNodes() throws Exception {
+ CommitCommandInstructionVisitor visitor = new CommitCommandInstructionVisitor(mongoConnection,
+ headMongo.getHeadRevisionId());
+ for (Instruction instruction : commit.getInstructions()) {
+ instruction.accept(visitor);
+ }
+
+ Map<String, NodeMongo> pathNodeMap = visitor.getPathNodeMap();
+
+ affectedPaths = pathNodeMap.keySet(); // TODO Original copies and moved nodes must be included!
+ nodeMongos = new HashSet<NodeMongo>(pathNodeMap.values());
+ for (NodeMongo nodeMongo : nodeMongos) {
+ nodeMongo.setRevisionId(revisionId);
+ }
+ }
+
+ private void createRevision() {
+ revisionId = String.valueOf(headMongo.getNextRevisionId() - 1);
+ }
+
+ private void markAsFailed() throws Exception {
+ DBCollection commitCollection = mongoConnection.getCommitCollection();
+ DBObject query = QueryBuilder.start("_id").is(commitMongo.getObjectId("_id")).get();
+ DBObject update = new BasicDBObject("$set", new BasicDBObject(CommitMongo.KEY_FAILED, Boolean.TRUE));
+ WriteResult writeResult = commitCollection.update(query, update);
+ if (writeResult.getError() != null) {
+ throw new Exception(String.format("Update wasn't successful: %s", writeResult)); // TODO now what?
+ }
+ }
+
+ private void mergeNodes() {
+ for (NodeMongo existingNode : existingNodes) {
+ for (NodeMongo committingNode : nodeMongos) {
+ if (existingNode.getPath().equals(committingNode.getPath())) {
+ logger.debug(String.format("Found existing node to merge: %s", existingNode.getPath()));
+ logger.debug(String.format("Existing node: %s", existingNode));
+ logger.debug(String.format("Committing node: %s", committingNode));
+
+ Map<String, Object> existingProperties = existingNode.getProperties();
+
+ if (existingProperties != null) {
+ committingNode.setProperties(existingProperties);
+
+ logger.debug(String.format("Merged properties for %s: %s", existingNode.getPath(),
+ existingProperties));
+ }
+
+ List<String> existingChildren = existingNode.getChildren();
+
+ if (existingChildren != null) {
+ committingNode.setChildren(existingChildren);
+
+ logger.debug(String.format("Merged children for %s: %s", existingNode.getPath(), existingChildren));
+ }
+
+ committingNode.setBaseRevisionId(existingNode.getRevisionId());
+
+ logger.debug(String.format("Merged node for %s: %s", existingNode.getPath(), committingNode));
+
+ break;
+ }
+ }
+ }
+ }
+
+ private void prepareMongoNodes() {
+ for (NodeMongo committingNode : nodeMongos) {
+ logger.debug(String.format("Preparing children (added and removed) of %s", committingNode.getPath()));
+ logger.debug(String.format("Committing node: %s", committingNode));
+
+ List<String> children = committingNode.getChildren();
+ if (children == null) {
+ children = new LinkedList<String>();
+ }
+
+ List<String> addedChildren = committingNode.getAddedChildren();
+ if (addedChildren != null) {
+ children.addAll(addedChildren);
+ }
+
+ List<String> removedChildren = committingNode.getRemovedChildren();
+ if (removedChildren != null) {
+ children.removeAll(removedChildren);
+ }
+
+ if (!children.isEmpty()) {
+ Set<String> temp = new HashSet<String>(children); // remove all duplicates
+ committingNode.setChildren(new LinkedList<String>(temp));
+ } else {
+ committingNode.setChildren(null);
+ }
+
+ Map<String, Object> properties = committingNode.getProperties();
+ if (properties == null) {
+ properties = new HashMap<String, Object>();
+ }
+
+ Map<String, Object> addedProperties = committingNode.getAddedProps();
+ if (addedProperties != null) {
+ properties.putAll(addedProperties);
+ }
+
+ Map<String, Object> removedProperties = committingNode.getRemovedProps();
+ if (removedProperties != null) {
+ for (Map.Entry<String, Object> entry : removedProperties.entrySet()) {
+ properties.remove(entry.getKey());
+ }
+ }
+
+ if (!properties.isEmpty()) {
+ committingNode.setProperties(properties);
+ } else {
+ committingNode.setProperties(null);
+ }
+
+ logger.debug(String.format("Prepared committing node: %s", committingNode));
+ }
+ }
+
+ private void readAndIncHeadRevision() throws Exception {
+ headMongo = new ReadAndIncHeadRevisionQuery(mongoConnection).execute();
+ }
+
+ private void readExistingNodes() {
+ Set<String> paths = new HashSet<String>();
+ for (NodeMongo nodeMongo : nodeMongos) {
+ paths.add(nodeMongo.getPath());
+ }
+
+ existingNodes = new FetchNodesForRevisionQuery(mongoConnection, paths,
+ String.valueOf(headMongo.getHeadRevisionId())).execute();
+ }
+
+ private void saveCommit() throws Exception {
+ new SaveCommitQuery(mongoConnection, commitMongo).execute();
+ }
+
+ private void saveNodes() throws Exception {
+ new SaveNodesQuery(mongoConnection, nodeMongos).execute();
+ }
+}
Propchange: jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/command/CommitCommandMongo.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/command/ConflictingCommitException.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/command/ConflictingCommitException.java?rev=1386591&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/command/ConflictingCommitException.java (added)
+++ jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/command/ConflictingCommitException.java Mon Sep 17 12:54:01 2012
@@ -0,0 +1,38 @@
+/*
+ * 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.mongomk.command;
+
+public class ConflictingCommitException extends Exception {
+
+ private static final long serialVersionUID = -5827664000083665577L;
+
+ public ConflictingCommitException() {
+ super();
+ }
+
+ public ConflictingCommitException(String message) {
+ super(message);
+ }
+
+ public ConflictingCommitException(Throwable t) {
+ super(t);
+ }
+
+ public ConflictingCommitException(String message, Throwable t) {
+ super(message, t);
+ }
+}
Propchange: jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/command/ConflictingCommitException.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/command/GetBlobLengthCommandMongo.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/command/GetBlobLengthCommandMongo.java?rev=1386591&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/command/GetBlobLengthCommandMongo.java (added)
+++ jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/command/GetBlobLengthCommandMongo.java Mon Sep 17 12:54:01 2012
@@ -0,0 +1,45 @@
+/*
+ * 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.mongomk.command;
+
+import org.apache.jackrabbit.mongomk.MongoConnection;
+import org.apache.jackrabbit.mongomk.api.command.AbstractCommand;
+
+import com.mongodb.BasicDBObject;
+import com.mongodb.gridfs.GridFS;
+import com.mongodb.gridfs.GridFSDBFile;
+
+public class GetBlobLengthCommandMongo extends AbstractCommand<Long> {
+
+ private final MongoConnection mongoConnection;
+ private final String blobId;
+
+ public GetBlobLengthCommandMongo(MongoConnection mongoConnection, String blobId) {
+ this.mongoConnection = mongoConnection;
+ this.blobId = blobId;
+ }
+
+ @Override
+ public Long execute() throws Exception {
+ GridFS gridFS = mongoConnection.getGridFS();
+ GridFSDBFile gridFSDBFile = gridFS.findOne(new BasicDBObject("md5", blobId));
+ if (gridFSDBFile == null) {
+ throw new Exception("Blob does not exiss");
+ }
+ return gridFSDBFile.getLength();
+ }
+}
Propchange: jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/command/GetBlobLengthCommandMongo.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/command/GetHeadRevisionCommandMongo.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/command/GetHeadRevisionCommandMongo.java?rev=1386591&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/command/GetHeadRevisionCommandMongo.java (added)
+++ jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/command/GetHeadRevisionCommandMongo.java Mon Sep 17 12:54:01 2012
@@ -0,0 +1,56 @@
+/*
+ * 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.mongomk.command;
+
+import org.apache.jackrabbit.mongomk.MongoConnection;
+import org.apache.jackrabbit.mongomk.api.command.AbstractCommand;
+import org.apache.jackrabbit.mongomk.query.FetchHeadRevisionQuery;
+
+/**
+ * A {@code Command} for getting the head revision from {@code MongoDB}.
+ *
+ * @author <a href="mailto:pmarx@adobe.com>Philipp Marx</a>
+ */
+public class GetHeadRevisionCommandMongo extends AbstractCommand<String> {
+
+ private final MongoConnection mongoConnection;
+
+ /**
+ * Constructs a new {@code GetHeadRevisionCommandMongo}.
+ *
+ * @param mongoConnection The {@link MongoConnection}.
+ */
+ public GetHeadRevisionCommandMongo(MongoConnection mongoConnection) {
+ this.mongoConnection = mongoConnection;
+ }
+
+ @Override
+ public String execute() throws Exception {
+ long headRevision = fetchHeadRevision();
+ String revisionId = convertToRevisionId(headRevision);
+
+ return revisionId;
+ }
+
+ private String convertToRevisionId(long headRevision) {
+ return String.valueOf(headRevision);
+ }
+
+ private long fetchHeadRevision() throws Exception {
+ return new FetchHeadRevisionQuery(mongoConnection).execute();
+ }
+}
Propchange: jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/command/GetHeadRevisionCommandMongo.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/command/GetNodesCommandMongo.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/command/GetNodesCommandMongo.java?rev=1386591&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/command/GetNodesCommandMongo.java (added)
+++ jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/command/GetNodesCommandMongo.java Mon Sep 17 12:54:01 2012
@@ -0,0 +1,241 @@
+/*
+ * 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.mongomk.command;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.jackrabbit.mongomk.MongoConnection;
+import org.apache.jackrabbit.mongomk.api.command.AbstractCommand;
+import org.apache.jackrabbit.mongomk.api.model.Node;
+import org.apache.jackrabbit.mongomk.impl.model.NodeImpl;
+import org.apache.jackrabbit.mongomk.model.CommitMongo;
+import org.apache.jackrabbit.mongomk.model.NodeMongo;
+import org.apache.jackrabbit.mongomk.query.FetchNodesByPathAndDepthQuery;
+import org.apache.jackrabbit.mongomk.query.FetchValidCommitsQuery;
+import org.apache.jackrabbit.mongomk.util.MongoUtil;
+import org.apache.jackrabbit.oak.commons.PathUtils;
+import org.apache.log4j.Logger;
+
+/**
+ * A {@code Command} for getting nodes from {@code MongoDB}.
+ *
+ * @author <a href="mailto:pmarx@adobe.com>Philipp Marx</a>
+ */
+public class GetNodesCommandMongo extends AbstractCommand<Node> {
+
+ class InconsitentNodeHierarchyException extends Exception {
+ private static final long serialVersionUID = 8155418280936077632L;
+ }
+
+ private static final Logger LOG = Logger.getLogger(GetNodesCommandMongo.class);
+
+ private final MongoConnection mongoConnection;
+ private final String path;
+ private final int depth;
+
+ private String revisionId;
+ private List<CommitMongo> lastCommits;
+ private List<NodeMongo> nodeMongos;
+
+ private Map<String, NodeMongo> pathAndNodeMap;
+ private Map<String, Long> problematicNodes;
+ private Node rootOfPath;
+
+ /**
+ * Constructs a new {@code GetNodesCommandMongo}.
+ *
+ * @param mongoConnection The {@link MongoConnection}.
+ * @param path The root path of the nodes to get.
+ * @param revisionId The {@link RevisionId} or {@code null}.
+ * @param depth The depth.
+ */
+ public GetNodesCommandMongo(MongoConnection mongoConnection, String path,
+ String revisionId, int depth) {
+ this.mongoConnection = mongoConnection;
+ this.path = path;
+ this.revisionId = revisionId;
+ this.depth = depth;
+ }
+
+ @Override
+ public Node execute() throws Exception {
+ ensureRevisionId();
+ readLastCommits();
+ deriveProblematicNodes();
+
+ readNodesByPath();
+ createPathAndNodeMap();
+ boolean verified = verifyProblematicNodes() && verifyNodeHierarchy();
+
+ if (!verified) {
+ throw new InconsitentNodeHierarchyException();
+ }
+
+ this.buildNodeStructure();
+
+ return rootOfPath;
+ }
+
+ @Override
+ public int getNumOfRetries() {
+ return 3;
+ }
+
+ @Override
+ public boolean needsRetry(Exception e) {
+ return e instanceof InconsitentNodeHierarchyException;
+ }
+
+ private void buildNodeStructure() {
+ NodeMongo nodeMongoRootOfPath = pathAndNodeMap.get(path);
+ rootOfPath = this.buildNodeStructure(nodeMongoRootOfPath);
+ }
+
+ private NodeImpl buildNodeStructure(NodeMongo nodeMongo) {
+ NodeImpl node = NodeMongo.toNode(nodeMongo);
+ Set<Node> children = node.getChildren();
+ if (children != null) {
+ for (Node child : children) {
+ NodeMongo nodeMongoChild = pathAndNodeMap.get(child.getPath());
+ if (nodeMongoChild != null) {
+ NodeImpl nodeChild = this.buildNodeStructure(nodeMongoChild);
+ node.addChild(nodeChild);
+ }
+ }
+ }
+
+ return node;
+ }
+
+ private void createPathAndNodeMap() {
+ pathAndNodeMap = new HashMap<String, NodeMongo>();
+ for (NodeMongo nodeMongo : nodeMongos) {
+ pathAndNodeMap.put(nodeMongo.getPath(), nodeMongo);
+ }
+ }
+
+ private void deriveProblematicNodes() {
+ problematicNodes = new HashMap<String, Long>();
+
+ for (ListIterator<CommitMongo> iterator = lastCommits.listIterator(); iterator.hasPrevious();) {
+ CommitMongo commitMongo = iterator.previous();
+ long revisionId = commitMongo.getRevisionId();
+ List<String> affectedPath = commitMongo.getAffectedPaths();
+
+ for (String path : affectedPath) {
+ problematicNodes.put(path, revisionId);
+ }
+ }
+ }
+
+ private void ensureRevisionId() throws Exception {
+ if (revisionId == null) {
+ revisionId = new GetHeadRevisionCommandMongo(mongoConnection).execute();
+ }
+ }
+
+ private void readLastCommits() throws Exception {
+ lastCommits = new FetchValidCommitsQuery(mongoConnection, revisionId).execute();
+
+ // TODO Move this into the Query which should throw the exception in case the commit doesn't exist
+ if (revisionId != null) {
+ boolean revisionExists = false;
+ long revId = MongoUtil.toMongoRepresentation(revisionId);
+ for (CommitMongo commitMongo : lastCommits) {
+ if (commitMongo.getRevisionId() == revId) {
+ revisionExists = true;
+
+ break;
+ }
+ }
+
+ if (!revisionExists) {
+ throw new Exception(String.format("The revisionId %d could not be found", revId));
+ }
+ }
+ }
+
+ private void readNodesByPath() {
+ FetchNodesByPathAndDepthQuery query = new FetchNodesByPathAndDepthQuery(mongoConnection, path, revisionId,
+ depth);
+ nodeMongos = query.execute();
+ }
+
+ private boolean verifyNodeHierarchy() {
+ boolean verified = false;
+
+ verified = verifyNodeHierarchyRec(path, 0);
+
+ if (!verified) {
+ LOG.error(String.format("Node hierarchy could not be verified because some nodes were inconsistent: %s",
+ path));
+ }
+
+ return verified;
+ }
+
+ private boolean verifyNodeHierarchyRec(String path, int currentDepth) {
+ boolean verified = false;
+
+ NodeMongo nodeMongo = pathAndNodeMap.get(path);
+ if (nodeMongo != null) {
+ verified = true;
+ if ((depth == -1) || (currentDepth < depth)) {
+ List<String> childNames = nodeMongo.getChildren();
+ if (childNames != null) {
+ for (String childName : childNames) {
+ String childPath = PathUtils.concat(path, childName);
+ verified = verifyNodeHierarchyRec(childPath, ++currentDepth);
+ if (!verified) {
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ return verified;
+ }
+
+ private boolean verifyProblematicNodes() {
+ boolean verified = true;
+
+ for (Map.Entry<String, Long> entry : problematicNodes.entrySet()) {
+ String path = entry.getKey();
+ Long revisionId = entry.getValue();
+
+ NodeMongo nodeMongo = pathAndNodeMap.get(path);
+ if (nodeMongo != null) {
+ if (!revisionId.equals(nodeMongo.getRevisionId())) {
+ verified = false;
+
+ LOG.error(String
+ .format("Node could not be verified because the expected revisionId did not match: %d (expected) vs %d (actual)",
+ revisionId, nodeMongo.getRevisionId()));
+
+ break;
+ }
+ }
+ }
+
+ return verified;
+ }
+}
Propchange: jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/command/GetNodesCommandMongo.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/command/NodeExistsCommandMongo.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/command/NodeExistsCommandMongo.java?rev=1386591&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/command/NodeExistsCommandMongo.java (added)
+++ jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/command/NodeExistsCommandMongo.java Mon Sep 17 12:54:01 2012
@@ -0,0 +1,92 @@
+/*
+ * 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.mongomk.command;
+
+import java.util.List;
+
+import org.apache.jackrabbit.mongomk.MongoConnection;
+import org.apache.jackrabbit.mongomk.api.command.AbstractCommand;
+import org.apache.jackrabbit.mongomk.model.NodeMongo;
+import org.apache.jackrabbit.mongomk.query.FetchNodeByPathQuery;
+import org.apache.jackrabbit.mongomk.util.MongoUtil;
+import org.apache.jackrabbit.oak.commons.PathUtils;
+
+/**
+ * A {@code Command} for determine whether a node exists from {@code MongoDB}.
+ *
+ * @author <a href="mailto:pmarx@adobe.com>Philipp Marx</a>
+ */
+public class NodeExistsCommandMongo extends AbstractCommand<Boolean> {
+ private final MongoConnection mongoConnection;
+ private NodeMongo parentNode;
+ private final String path;
+ private String revisionId;
+
+ /**
+ * Constructs a new {@code NodeExistsCommandMongo}.
+ *
+ * @param mongoConnection The {@link MongoConnection}.
+ * @param path The root path of the nodes to get.
+ * @param revisionId The {@link RevisionId} or {@code null}.
+ */
+ public NodeExistsCommandMongo(MongoConnection mongoConnection, String path, String revisionId) {
+ this.mongoConnection = mongoConnection;
+ this.path = path;
+ this.revisionId = revisionId;
+ }
+
+ @Override
+ public Boolean execute() throws Exception {
+ if (PathUtils.denotesRoot(path)) {
+ return true;
+ }
+ ensureRevisionId();
+ readParentNode();
+ return childExists();
+ }
+
+ private void ensureRevisionId() throws Exception {
+ if (revisionId == null) {
+ revisionId = new GetHeadRevisionCommandMongo(mongoConnection).execute();
+ }
+ }
+
+ private void readParentNode() throws Exception {
+ String parentPath = PathUtils.getParentPath(path);
+ FetchNodeByPathQuery query = new FetchNodeByPathQuery(mongoConnection, parentPath, MongoUtil.toMongoRepresentation(revisionId));
+ parentNode = query.execute();
+ }
+
+ private boolean childExists() {
+ if (parentNode == null) {
+ return false;
+ }
+
+ List<String> children = parentNode.getChildren();
+ if (children == null || children.isEmpty()) {
+ return false;
+ }
+
+ for (String child : children) {
+ if (child.equals(PathUtils.getName(path))) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+}
Propchange: jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/command/NodeExistsCommandMongo.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/command/ReadBlobCommandMongo.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/command/ReadBlobCommandMongo.java?rev=1386591&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/command/ReadBlobCommandMongo.java (added)
+++ jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/command/ReadBlobCommandMongo.java Mon Sep 17 12:54:01 2012
@@ -0,0 +1,75 @@
+/*
+ * 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.mongomk.command;
+
+import java.io.InputStream;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.jackrabbit.mongomk.MongoConnection;
+import org.apache.jackrabbit.mongomk.api.command.AbstractCommand;
+
+import com.mongodb.BasicDBObject;
+import com.mongodb.gridfs.GridFS;
+import com.mongodb.gridfs.GridFSDBFile;
+
+public class ReadBlobCommandMongo extends AbstractCommand<Integer> {
+
+ private final MongoConnection mongoConnection;
+ private final String blobId;
+ private final long blobOffset;
+ private final byte[] buffer;
+ private final int bufferOffset;
+ private final int length;
+
+ public ReadBlobCommandMongo(MongoConnection mongoConnection, String blobId, long blobOffset, byte[] buffer,
+ int bufferOffset, int length) {
+ this.mongoConnection = mongoConnection;
+ this.blobId = blobId;
+ this.blobOffset = blobOffset;
+ this.buffer = buffer;
+ this.bufferOffset = bufferOffset;
+ this.length = length;
+ }
+
+ @Override
+ public Integer execute() throws Exception {
+ return fetchBlobFromMongo();
+ }
+
+ // FIXME [Mete] This takes a long time, see MicroKernelIT#readBlob. See if
+ // it can be improved.
+ private int fetchBlobFromMongo() throws Exception {
+ GridFS gridFS = mongoConnection.getGridFS();
+ GridFSDBFile gridFile = gridFS.findOne(new BasicDBObject("md5", blobId));
+ long fileLength = gridFile.getLength();
+
+ long start = blobOffset;
+ long end = blobOffset + length;
+ if (end > fileLength) {
+ end = fileLength;
+ }
+
+ int totalBytes = -1;
+ if (start < end) {
+ InputStream is = gridFile.getInputStream();
+ IOUtils.skipFully(is, blobOffset);
+ totalBytes = is.read(buffer, bufferOffset, length);
+ is.close();
+ }
+ return totalBytes;
+ }
+}
Propchange: jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/command/ReadBlobCommandMongo.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/command/WriteBlobCommandMongo.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/command/WriteBlobCommandMongo.java?rev=1386591&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/command/WriteBlobCommandMongo.java (added)
+++ jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/command/WriteBlobCommandMongo.java Mon Sep 17 12:54:01 2012
@@ -0,0 +1,68 @@
+/*
+ * 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.mongomk.command;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.apache.commons.codec.digest.DigestUtils;
+import org.apache.jackrabbit.mongomk.MongoConnection;
+import org.apache.jackrabbit.mongomk.api.command.AbstractCommand;
+
+import com.mongodb.BasicDBObject;
+import com.mongodb.gridfs.GridFS;
+import com.mongodb.gridfs.GridFSDBFile;
+import com.mongodb.gridfs.GridFSInputFile;
+
+public class WriteBlobCommandMongo extends AbstractCommand<String> {
+
+ private final MongoConnection mongoConnection;
+ private final InputStream is;
+
+ public WriteBlobCommandMongo(MongoConnection mongoConnection, InputStream is) {
+ this.mongoConnection = mongoConnection;
+ this.is = is;
+ }
+
+ @Override
+ public String execute() throws Exception {
+ return saveBlob();
+ }
+
+ private String saveBlob() throws IOException {
+ GridFS gridFS = mongoConnection.getGridFS();
+ BufferedInputStream bis = new BufferedInputStream(is);
+ String md5 = calculateMd5(bis);
+ GridFSDBFile gridFile = gridFS.findOne(new BasicDBObject("md5", md5));
+ if (gridFile != null) {
+ is.close();
+ return md5;
+ }
+
+ GridFSInputFile gridFSInputFile = gridFS.createFile(bis, true);
+ gridFSInputFile.save();
+ return gridFSInputFile.getMD5();
+ }
+
+ private String calculateMd5(BufferedInputStream bis) throws IOException {
+ bis.mark(Integer.MAX_VALUE);
+ String md5 = DigestUtils.md5Hex(bis);
+ bis.reset();
+ return md5;
+ }
+}
Propchange: jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/command/WriteBlobCommandMongo.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/model/CommitCommandInstructionVisitor.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/model/CommitCommandInstructionVisitor.java?rev=1386591&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/model/CommitCommandInstructionVisitor.java (added)
+++ jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/model/CommitCommandInstructionVisitor.java Mon Sep 17 12:54:01 2012
@@ -0,0 +1,261 @@
+/*
+ * 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.mongomk.model;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.jackrabbit.mongomk.MongoConnection;
+import org.apache.jackrabbit.mongomk.api.model.Instruction.AddNodeInstruction;
+import org.apache.jackrabbit.mongomk.api.model.Instruction.AddPropertyInstruction;
+import org.apache.jackrabbit.mongomk.api.model.Instruction.CopyNodeInstruction;
+import org.apache.jackrabbit.mongomk.api.model.Instruction.MoveNodeInstruction;
+import org.apache.jackrabbit.mongomk.api.model.Instruction.RemoveNodeInstruction;
+import org.apache.jackrabbit.mongomk.api.model.Instruction.SetPropertyInstruction;
+import org.apache.jackrabbit.mongomk.api.model.InstructionVisitor;
+import org.apache.jackrabbit.mongomk.query.FetchNodeByPathQuery;
+import org.apache.jackrabbit.oak.commons.PathUtils;
+
+public class CommitCommandInstructionVisitor implements InstructionVisitor {
+
+ private final long headRevisionId;
+ private final MongoConnection mongoConnection;
+ private final Map<String, NodeMongo> pathNodeMap;
+
+ public CommitCommandInstructionVisitor(MongoConnection mongoConnection,
+ long headRevisionId) {
+ this.mongoConnection = mongoConnection;
+ this.headRevisionId = headRevisionId;
+ pathNodeMap = new HashMap<String, NodeMongo>();
+ }
+
+ public Map<String, NodeMongo> getPathNodeMap() {
+ return pathNodeMap;
+ }
+
+ @Override
+ public void visit(AddNodeInstruction instruction) {
+// Old code
+// String path = instruction.getPath();
+// getStagedNode(path);
+// if (!PathUtils.denotesRoot(path)) {
+// String parentPath = PathUtils.getParentPath(path);
+// NodeMongo parentNode = getStagedNode(parentPath);
+// parentNode.addChild(PathUtils.getName(path));
+// }
+
+ String path = instruction.getPath();
+ getStagedNode(path);
+ String nodeName = PathUtils.getName(path);
+ String parentNodePath = PathUtils.getParentPath(path);
+ NodeMongo parent = null;
+ if (!PathUtils.denotesRoot(parentNodePath)) {
+ parent = getStoredNode(parentNodePath);
+ if (parent == null) {
+ throw new RuntimeException("No such parent: " + PathUtils.getName(parentNodePath));
+ }
+ // FIXME [Mete] Add once tests are fixed.
+ //if (parent.childExists(nodeName)) {
+ // throw new RuntimeException("There's already a child node with name '" + nodeName + "'");
+ //}
+ } else {
+ parent = getStagedNode(parentNodePath);
+ }
+ parent.addChild(nodeName);
+ }
+
+ @Override
+ public void visit(AddPropertyInstruction instruction) {
+ NodeMongo node = getStagedNode(instruction.getPath());
+ node.addProperty(instruction.getKey(), instruction.getValue());
+ }
+
+ @Override
+ public void visit(CopyNodeInstruction instruction) {
+ String srcPath = instruction.getSourcePath();
+ String destPath = instruction.getDestPath();
+
+ String srcParentPath = PathUtils.getParentPath(srcPath);
+ String srcNodeName = PathUtils.getName(srcPath);
+
+ String destParentPath = PathUtils.getParentPath(destPath);
+ String destNodeName = PathUtils.getName(destPath);
+
+ NodeMongo srcParent = pathNodeMap.get(srcParentPath);
+ if (srcParent == null) {
+ // The subtree to be copied has not been modified
+ boolean entryExists = getStoredNode(srcParentPath).childExists(srcNodeName);
+ if (!entryExists) {
+ throw new RuntimeException("Not found: " + srcPath);
+ }
+ NodeMongo destParent = getStagedNode(destParentPath);
+ if (destParent.childExists(destNodeName)) {
+ throw new RuntimeException("Node already exists at copy destination path: " + destPath);
+ }
+
+ // Copy src node to destPath.
+ NodeMongo srcNode = getStoredNode(srcPath);
+ NodeMongo destNode = NodeMongo.fromDBObject(srcNode);
+ destNode.setPath(destPath);
+ // FIXME - [Mete] This needs to do proper merge instead of just add.
+ List<String> addedChildren = srcNode.getAddedChildren();
+ if (addedChildren != null && !addedChildren.isEmpty()) {
+ for (String child : addedChildren) {
+ getStagedNode(PathUtils.concat(destPath, child));
+ destNode.addChild(child);
+ }
+ }
+ pathNodeMap.put(destPath, destNode);
+
+ // Add to destParent.
+ destParent.addChild(destNodeName);
+
+ return;
+ }
+
+ boolean srcEntryExists = srcParent.childExists(srcNodeName);
+ if (!srcEntryExists) {
+ throw new RuntimeException(srcPath);
+ }
+
+ // FIXME - [Mete] The rest is not totally correct.
+ NodeMongo destParent = getStagedNode(destParentPath);
+ NodeMongo srcNode = getStagedNode(srcPath);
+
+ if (srcNode != null) {
+ // Copy the modified subtree
+ NodeMongo destNode = NodeMongo.fromDBObject(srcNode);
+ destNode.setPath(destPath);
+ pathNodeMap.put(destPath, destNode);
+ destParent.addChild(destNodeName);
+ //destParent.add(destNodeName, srcNode.copy());
+ } else {
+ NodeMongo destNode = NodeMongo.fromDBObject(srcNode);
+ destNode.setPath(destPath);
+ pathNodeMap.put(destPath, destNode);
+ destParent.addChild(destNodeName);
+ //destParent.add(new ChildNodeEntry(destNodeName, srcEntry.getId()));
+ }
+
+ // [Mete] Old code from Philipp.
+ // retrieve all nodes beyond and add them as new children to the dest location
+// List<NodeMongo> childNodesToCopy = new FetchNodesByPathAndDepthQuery(mongoConnection, srcPath,
+// revisionId, -1).execute();
+// for (NodeMongo nodeMongo : childNodesToCopy) {
+// String oldPath = nodeMongo.getPath();
+// String oldPathRel = PathUtils.relativize(srcPath, oldPath);
+// String newPath = PathUtils.concat(destPath, oldPathRel);
+//
+// nodeMongo.setPath(newPath);
+// nodeMongo.removeField("_id");
+// pathNodeMap.put(newPath, nodeMongo);
+// }
+
+ // tricky part now: In case we already know about any changes to these existing nodes we need to merge
+ // those now.
+ }
+
+ @Override
+ public void visit(MoveNodeInstruction instruction) {
+ String srcPath = instruction.getSourcePath();
+ String destPath = instruction.getDestPath();
+
+ if (PathUtils.isAncestor(srcPath, destPath)) {
+ throw new RuntimeException("Target path cannot be descendant of source path: "
+ + destPath);
+ }
+
+ String srcParentPath = PathUtils.getParentPath(srcPath);
+ String srcNodeName = PathUtils.getName(srcPath);
+
+ String destParentPath = PathUtils.getParentPath(destPath);
+ String destNodeName = PathUtils.getName(destPath);
+
+ // Add the old node with the new path.
+ NodeMongo destNode = pathNodeMap.get(destPath);
+ if (destNode == null) {
+ NodeMongo srcNode = getStoredNode(srcPath);
+ destNode = srcNode;
+ destNode.setPath(destPath);
+ pathNodeMap.put(destPath, destNode);
+ }
+
+ // Remove from srcParent - [Mete] What if there is no such child?
+ NodeMongo scrParentNode = getStoredNode(srcParentPath);
+ scrParentNode.removeChild(srcNodeName);
+
+ // Add to destParent
+ NodeMongo destParentNode = getStoredNode(destParentPath);
+ if (destParentNode.childExists(destNodeName)) {
+ throw new RuntimeException("Node already exists at move destination path: " + destPath);
+ }
+ destParentNode.addChild(destNodeName);
+
+ // [Mete] Siblings?
+ }
+
+ @Override
+ public void visit(RemoveNodeInstruction instruction) {
+ String path = instruction.getPath();
+ String parentPath = PathUtils.getParentPath(path);
+ NodeMongo parentNode = getStagedNode(parentPath);
+ // [Mete] What if there is no such child?
+ parentNode.removeChild(PathUtils.getName(path));
+ }
+
+ @Override
+ public void visit(SetPropertyInstruction instruction) {
+ String path = instruction.getPath();
+ String key = instruction.getKey();
+ Object value = instruction.getValue();
+ NodeMongo node = getStagedNode(path);
+ if (value == null) {
+ node.removeProp(key);
+ } else {
+ node.addProperty(key, value);
+ }
+ }
+
+ // TODO - [Mete] I think we need a way to distinguish between Staged
+ // and Stored nodes. For example, what if a node is retrieved as Staged
+ // but later it needs to be retrieved as Stored?
+ private NodeMongo getStagedNode(String path) {
+ NodeMongo node = pathNodeMap.get(path);
+ if (node == null) {
+ node = new NodeMongo();
+ node.setPath(path);
+ pathNodeMap.put(path, node);
+ }
+ return node;
+ }
+
+ private NodeMongo getStoredNode(String path) {
+ NodeMongo node = pathNodeMap.get(path);
+ if (node == null) {
+ FetchNodeByPathQuery query = new FetchNodeByPathQuery(mongoConnection,
+ path, headRevisionId);
+ query.setFetchAll(true);
+ node = query.execute();
+ if (node != null) {
+ node.removeField("_id");
+ pathNodeMap.put(path, node);
+ }
+ }
+ return node;
+ }
+}
\ No newline at end of file
Propchange: jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/model/CommitCommandInstructionVisitor.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/model/CommitMongo.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/model/CommitMongo.java?rev=1386591&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/model/CommitMongo.java (added)
+++ jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/model/CommitMongo.java Mon Sep 17 12:54:01 2012
@@ -0,0 +1,155 @@
+/*
+ * 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.mongomk.model;
+
+import java.util.Date;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.jackrabbit.mongomk.api.model.Commit;
+import org.apache.jackrabbit.mongomk.api.model.Instruction;
+import org.apache.jackrabbit.mongomk.api.model.Instruction.AddNodeInstruction;
+import org.apache.jackrabbit.mongomk.util.MongoUtil;
+import org.apache.jackrabbit.oak.commons.PathUtils;
+
+import com.mongodb.BasicDBObject;
+
+/**
+ * The {@code MongoDB} representation of a commit.
+ *
+ * @author <a href="mailto:pmarx@adobe.com>Philipp Marx</a>
+ */
+@SuppressWarnings("javadoc")
+public class CommitMongo extends BasicDBObject {
+
+ public static final String KEY_AFFECTED_PATH = "affPaths";
+ public static final String KEY_BASE_REVISION_ID = "baseRevId";
+ public static final String KEY_DIFF = "diff";
+ public static final String KEY_FAILED = "failed";
+ public static final String KEY_MESSAGE = "msg";
+ public static final String KEY_PATH = "path";
+ public static final String KEY_REVISION_ID = "revId";
+ public static final String KEY_TIMESTAMP = "ts";
+ private static final long serialVersionUID = 6656294757102309827L;
+
+ public static CommitMongo fromCommit(Commit commit) {
+ CommitMongo commitMongo = new CommitMongo();
+
+ String message = commit.getMessage();
+ commitMongo.setMessage(message);
+
+ String path = commit.getPath();
+ commitMongo.setPath(path);
+
+ String diff = commit.getDiff();
+ commitMongo.setDiff(diff);
+
+ String revisionId = commit.getRevisionId();
+ if (revisionId != null) {
+ commitMongo.setRevisionId(revisionId);
+ }
+
+ commitMongo.setTimestamp(commit.getTimestamp());
+
+ Set<String> affectedPaths = new HashSet<String>();
+ for (Instruction instruction : commit.getInstructions()) {
+ affectedPaths.add(instruction.getPath());
+
+ if (instruction instanceof AddNodeInstruction) {
+ affectedPaths.add(PathUtils.getParentPath(instruction.getPath()));
+ }
+ }
+ commitMongo.setAffectedPaths(new LinkedList<String>(affectedPaths));
+
+ return commitMongo;
+ }
+
+ public CommitMongo() {
+ setTimestamp(new Date().getTime());
+ }
+
+ @SuppressWarnings("unchecked")
+ public List<String> getAffectedPaths() {
+ return (List<String>) this.get(KEY_AFFECTED_PATH);
+ }
+
+ public long getBaseRevisionId() {
+ return getLong(KEY_BASE_REVISION_ID);
+ }
+
+ public String getDiff() {
+ return getString(KEY_DIFF);
+ }
+
+ public String getMessage() {
+ return getString(KEY_MESSAGE);
+ }
+
+ public String getPath() {
+ return getString(KEY_PATH);
+ }
+
+ public long getRevisionId() {
+ return getLong(KEY_REVISION_ID);
+ }
+
+ public boolean hasFailed() {
+ return this.getBoolean(KEY_FAILED);
+ }
+
+ public void setAffectedPaths(List<String> affectedPaths) {
+ put(KEY_AFFECTED_PATH, affectedPaths);
+ }
+
+ public void setBaseRevId(long baseRevisionId) {
+ put(KEY_BASE_REVISION_ID, baseRevisionId);
+ }
+
+ public void setDiff(String diff) {
+ put(KEY_DIFF, diff);
+ }
+
+ public void setFailed() {
+ put(KEY_FAILED, Boolean.TRUE);
+ }
+
+ public void setMessage(String message) {
+ put(KEY_MESSAGE, message);
+ }
+
+ public void setPath(String path) {
+ put(KEY_PATH, path);
+ }
+
+ public void setRevisionId(long revisionId) {
+ put(KEY_REVISION_ID, revisionId);
+ }
+
+ public void setRevisionId(String revisionId) {
+ this.setRevisionId(MongoUtil.toMongoRepresentation(revisionId));
+ }
+
+ public void setTimestamp(long timestamp) {
+ put(KEY_TIMESTAMP, timestamp);
+ }
+
+ public Long getTimestamp() {
+ return getLong(KEY_TIMESTAMP);
+ }
+}
\ No newline at end of file
Propchange: jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/model/CommitMongo.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/model/HeadMongo.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/model/HeadMongo.java?rev=1386591&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/model/HeadMongo.java (added)
+++ jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/model/HeadMongo.java Mon Sep 17 12:54:01 2012
@@ -0,0 +1,60 @@
+/*
+ * 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.mongomk.model;
+
+import com.mongodb.BasicDBObject;
+import com.mongodb.DBObject;
+
+/**
+ * The {@code MongoDB} representation of the head revision.
+ *
+ * @author <a href="mailto:pmarx@adobe.com>Philipp Marx</a>
+ */
+@SuppressWarnings("javadoc")
+public class HeadMongo extends BasicDBObject {
+
+ public static final String KEY_HEAD_REVISION_ID = "headRevId";
+ public static final String KEY_NEXT_REVISION_ID = "nextRevId";
+ private static final long serialVersionUID = 3541425042129003691L;
+
+ public static HeadMongo fromDBObject(DBObject dbObject) {
+ HeadMongo headMongo = new HeadMongo();
+ headMongo.putAll(dbObject);
+
+ return headMongo;
+ }
+
+ public static long toDBRepresentation(String revisionId) {
+ return Long.valueOf(revisionId);
+ }
+
+ public long getHeadRevisionId() {
+ return getLong(KEY_HEAD_REVISION_ID);
+ }
+
+ public long getNextRevisionId() {
+ return getLong(KEY_NEXT_REVISION_ID);
+ }
+
+ public void setHeadRevisionId(long revisionId) {
+ put(KEY_HEAD_REVISION_ID, revisionId);
+ }
+
+ public void setNextRevisionId(long revisionId) {
+ put(KEY_NEXT_REVISION_ID, revisionId);
+ }
+}
Propchange: jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/model/HeadMongo.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/model/NodeMongo.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/model/NodeMongo.java?rev=1386591&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/model/NodeMongo.java (added)
+++ jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/model/NodeMongo.java Mon Sep 17 12:54:01 2012
@@ -0,0 +1,270 @@
+/*
+ * 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.mongomk.model;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.jackrabbit.mongomk.api.model.Node;
+import org.apache.jackrabbit.mongomk.impl.model.NodeImpl;
+import org.apache.jackrabbit.mongomk.util.MongoUtil;
+import org.apache.jackrabbit.oak.commons.PathUtils;
+
+import com.mongodb.BasicDBObject;
+import com.mongodb.DBObject;
+
+/**
+ * The {@code MongoDB} representation of a node.
+ *
+ * @author <a href="mailto:pmarx@adobe.com>Philipp Marx</a>
+ */
+@SuppressWarnings("javadoc")
+public class NodeMongo extends BasicDBObject {
+
+ public static final String KEY_BASE_REVISION_ID = "baseRevId";
+ public static final String KEY_CHILDREN = "kids";
+ public static final String KEY_PATH = "path";
+ public static final String KEY_PROPERTIES = "props";
+ public static final String KEY_REVISION_ID = "revId";
+ private static final long serialVersionUID = 3153393934945155106L;
+
+ public static NodeMongo fromDBObject(DBObject node) {
+ NodeMongo nodeMongo = new NodeMongo();
+ nodeMongo.putAll(node);
+
+ return nodeMongo;
+ }
+
+ public static NodeMongo fromNode(Node node) {
+ NodeMongo nodeMongo = new NodeMongo();
+
+ String path = node.getPath();
+ nodeMongo.setPath(path);
+
+ String revisionId = node.getRevisionId();
+ if (revisionId != null) {
+ nodeMongo.setRevisionId(revisionId);
+ }
+
+ Map<String, Object> properties = node.getProperties();
+ if (properties != null) {
+ nodeMongo.setProperties(properties);
+ }
+
+ Set<Node> children = node.getChildren();
+ if (children != null) {
+ List<String> childNames = new LinkedList<String>();
+ for (Node child : children) {
+ childNames.add(child.getName());
+ }
+ nodeMongo.setChildren(childNames);
+ }
+
+ return nodeMongo;
+ }
+
+ public static Set<NodeMongo> fromNodes(Collection<Node> nodes) {
+ Set<NodeMongo> nodeMongos = new HashSet<NodeMongo>(nodes.size());
+ for (Node node : nodes) {
+ NodeMongo nodeMongo = NodeMongo.fromNode(node);
+ nodeMongos.add(nodeMongo);
+ }
+
+ return nodeMongos;
+ }
+
+ public static List<Node> toNode(Collection<NodeMongo> nodeMongos) {
+ List<Node> nodes = new ArrayList<Node>(nodeMongos.size());
+ for (NodeMongo nodeMongo : nodeMongos) {
+ Node node = NodeMongo.toNode(nodeMongo);
+ nodes.add(node);
+ }
+
+ return nodes;
+ }
+
+ public static NodeImpl toNode(NodeMongo nodeMongo) {
+ String revisionId = String.valueOf(nodeMongo.getRevisionId());
+ String path = nodeMongo.getPath();
+ List<String> childNames = nodeMongo.getChildren();
+ long childCount = childNames != null ? childNames.size() : 0;
+ Map<String, Object> properties = nodeMongo.getProperties();
+ Set<Node> children = null;
+ if (childNames != null) {
+ children = new HashSet<Node>();
+ for (String childName : childNames) {
+ NodeImpl child = new NodeImpl();
+ child.setPath(PathUtils.concat(path, childName));
+ children.add(child);
+ }
+ }
+
+ NodeImpl nodeImpl = new NodeImpl();
+ nodeImpl.setPath(path);
+ nodeImpl.setChildCount(childCount);
+ nodeImpl.setRevisionId(revisionId);
+ nodeImpl.setProperties(properties);
+ nodeImpl.setChildren(children);
+
+ return nodeImpl;
+ }
+
+ private List<String> addedChildren;
+ private Map<String, Object> addedProps;
+ private List<String> removedChildren;
+ private Map<String, Object> removedProps;
+
+ public void addChild(String childName) {
+ if (addedChildren == null) {
+ addedChildren = new LinkedList<String>();
+ }
+
+ addedChildren.add(childName);
+ }
+
+ public void addProperty(String key, Object value) {
+ if (addedProps == null) {
+ addedProps = new HashMap<String, Object>();
+ }
+
+ addedProps.put(key, value);
+ }
+
+ public List<String> getAddedChildren() {
+ return addedChildren;
+ }
+
+ public Map<String, Object> getAddedProps() {
+ return addedProps;
+ }
+
+ @SuppressWarnings("unchecked")
+ public List<String> getChildren() {
+ return (List<String>) this.get(KEY_CHILDREN);
+ }
+
+ public boolean childExists(String childName) {
+ List<String> children = getChildren();
+ if (children != null && !children.isEmpty()) {
+ if (children.contains(childName)) {
+ return true;
+ }
+ }
+ return addedChildExists(childName);
+ }
+
+ private boolean addedChildExists(String childName) {
+ return addedChildren != null && !addedChildren.isEmpty()?
+ addedChildren.contains(childName) : false;
+ }
+
+ public String getName() {
+ return PathUtils.getName(getString(KEY_PATH));
+ }
+
+ public String getPath() {
+ return getString(KEY_PATH);
+ }
+
+ @SuppressWarnings("unchecked")
+ public Map<String, Object> getProperties() {
+ return (Map<String, Object>) this.get(KEY_PROPERTIES);
+ }
+
+ public List<String> getRemovedChildren() {
+ return removedChildren;
+ }
+
+ public Map<String, Object> getRemovedProps() {
+ return removedProps;
+ }
+
+ public Long getRevisionId() {
+ return getLong(KEY_REVISION_ID);
+ }
+
+ public void removeChild(String childName) {
+ if (removedChildren == null) {
+ removedChildren = new LinkedList<String>();
+ }
+
+ removedChildren.add(childName);
+ }
+
+ public void removeProp(String key) {
+ if (removedProps == null) {
+ removedProps = new HashMap<String, Object>();
+ }
+
+ removedProps.put(key, null);
+ }
+
+ public void setBaseRevisionId(long baseRevisionId) {
+ put(KEY_BASE_REVISION_ID, baseRevisionId);
+ }
+
+ public void setChildren(List<String> children) {
+ if (children != null) {
+ put(KEY_CHILDREN, children);
+ } else {
+ removeField(KEY_CHILDREN);
+ }
+ }
+
+ public void setPath(String path) {
+ put(KEY_PATH, path);
+ }
+
+ public void setProperties(Map<String, Object> properties) {
+ if (properties != null) {
+ put(KEY_PROPERTIES, properties);
+ } else {
+ removeField(KEY_PROPERTIES);
+ }
+ }
+
+ public void setRevisionId(long revisionId) {
+ put(KEY_REVISION_ID, revisionId);
+ }
+
+ public void setRevisionId(String revisionId) {
+ this.setRevisionId(MongoUtil.toMongoRepresentation(revisionId));
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append(super.toString());
+ sb.append(" internal props: ");
+ sb.append("AddedChildren = ");
+ sb.append(addedChildren);
+ sb.append(", RemovedChildren = ");
+ sb.append(removedChildren);
+ sb.append(", AddedProps = ");
+ sb.append(addedProps);
+ sb.append(", RemovedProps = ");
+ sb.append(removedProps);
+
+ return sb.toString();
+ }
+}
Propchange: jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/model/NodeMongo.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/query/AbstractQuery.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/query/AbstractQuery.java?rev=1386591&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/query/AbstractQuery.java (added)
+++ jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/query/AbstractQuery.java Mon Sep 17 12:54:01 2012
@@ -0,0 +1,52 @@
+/*
+ * 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.mongomk.query;
+
+import org.apache.jackrabbit.mongomk.MongoConnection;
+
+/**
+ * An abstract base class for queries performed with {@code MongoDB}.
+ *
+ * @param <T>
+ * The result type of the query.
+ *
+ * @author <a href="mailto:pmarx@adobe.com>Philipp Marx</a>
+ */
+public abstract class AbstractQuery<T> {
+
+ /** The {@link MongoConnection}. */
+ protected MongoConnection mongoConnection;
+
+ /**
+ * Constructs a new {@code AbstractQuery}.
+ *
+ * @param mongoConnection
+ * The {@link MongoConnection}.
+ */
+ protected AbstractQuery(MongoConnection mongoConnection) {
+ this.mongoConnection = mongoConnection;
+ }
+
+ /**
+ * Executes this query.
+ *
+ * @return The result of the query.
+ * @throws Exception
+ * If an error occurred while executing the query.
+ */
+ public abstract T execute() throws Exception;
+}
Propchange: jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/query/AbstractQuery.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/query/FetchHeadQuery.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/query/FetchHeadQuery.java?rev=1386591&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/query/FetchHeadQuery.java (added)
+++ jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/query/FetchHeadQuery.java Mon Sep 17 12:54:01 2012
@@ -0,0 +1,48 @@
+/*
+ * 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.mongomk.query;
+
+import org.apache.jackrabbit.mongomk.MongoConnection;
+import org.apache.jackrabbit.mongomk.model.HeadMongo;
+
+import com.mongodb.DBCollection;
+
+/**
+ * An query for fetching the current head.
+ *
+ * @author <a href="mailto:pmarx@adobe.com>Philipp Marx</a>
+ */
+public class FetchHeadQuery extends AbstractQuery<HeadMongo> {
+
+ /**
+ * Constructs a new {@code FetchHeadQuery}.
+ *
+ * @param mongoConnection
+ * The {@link MongoConnection}.
+ */
+ public FetchHeadQuery(MongoConnection mongoConnection) {
+ super(mongoConnection);
+ }
+
+ @Override
+ public HeadMongo execute() throws Exception {
+ DBCollection headCollection = mongoConnection.getHeadCollection();
+ HeadMongo headMongo = (HeadMongo) headCollection.findOne();
+
+ return headMongo;
+ }
+}
Propchange: jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/query/FetchHeadQuery.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/query/FetchHeadRevisionQuery.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/query/FetchHeadRevisionQuery.java?rev=1386591&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/query/FetchHeadRevisionQuery.java (added)
+++ jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/query/FetchHeadRevisionQuery.java Mon Sep 17 12:54:01 2012
@@ -0,0 +1,51 @@
+/*
+ * 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.mongomk.query;
+
+import org.apache.jackrabbit.mongomk.MongoConnection;
+import org.apache.jackrabbit.mongomk.model.HeadMongo;
+
+
+/**
+ * An query for fetching the head revision.
+ *
+ * @author <a href="mailto:pmarx@adobe.com>Philipp Marx</a>
+ */
+public class FetchHeadRevisionQuery extends AbstractQuery<Long> {
+
+ /**
+ * Constructs a new {@code FetchHeadRevisionQuery}.
+ *
+ * @param mongoConnection
+ * The {@link MongoConnection}.
+ */
+ public FetchHeadRevisionQuery(MongoConnection mongoConnection) {
+ super(mongoConnection);
+ }
+
+ @Override
+ public Long execute() throws Exception {
+ HeadMongo headMongo = fetchHead();
+ long headRevision = headMongo.getHeadRevisionId();
+
+ return headRevision;
+ }
+
+ private HeadMongo fetchHead() throws Exception {
+ return new FetchHeadQuery(mongoConnection).execute();
+ }
+}
Propchange: jackrabbit/oak/trunk/oak-mongomk/src/main/java/org/apache/jackrabbit/mongomk/query/FetchHeadRevisionQuery.java
------------------------------------------------------------------------------
svn:eol-style = native