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 2013/10/18 21:38:45 UTC
svn commit: r1533608 - in
/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak:
kernel/JsonSerializer.java kernel/JsopDiff.java kernel/NodeStoreKernel.java
plugins/memory/AbstractBlob.java
Author: jukka
Date: Fri Oct 18 19:38:45 2013
New Revision: 1533608
URL: http://svn.apache.org/r1533608
Log:
OAK-987: Implement the MicroKernel API
Improved JSON serialization
Added:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/JsonSerializer.java
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/JsopDiff.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/NodeStoreKernel.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/AbstractBlob.java
Added: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/JsonSerializer.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/JsonSerializer.java?rev=1533608&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/JsonSerializer.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/JsonSerializer.java Fri Oct 18 19:38:45 2013
@@ -0,0 +1,154 @@
+/*
+ * 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.oak.kernel;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.apache.jackrabbit.oak.api.Type.BINARY;
+import static org.apache.jackrabbit.oak.api.Type.BOOLEAN;
+import static org.apache.jackrabbit.oak.api.Type.DOUBLE;
+import static org.apache.jackrabbit.oak.api.Type.LONG;
+import static org.apache.jackrabbit.oak.api.Type.STRING;
+
+import javax.jcr.PropertyType;
+
+import org.apache.jackrabbit.mk.json.JsopBuilder;
+import org.apache.jackrabbit.oak.api.Blob;
+import org.apache.jackrabbit.oak.api.PropertyState;
+import org.apache.jackrabbit.oak.api.Type;
+import org.apache.jackrabbit.oak.plugins.memory.AbstractBlob;
+import org.apache.jackrabbit.oak.spi.state.ChildNodeEntry;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+
+/**
+ * Utility class for serializing node and property states to JSON.
+ */
+class JsonSerializer {
+
+ private final JsopBuilder json;
+
+ private final int depth;
+
+ private final long offset;
+
+ private final int maxChildNodes;
+
+ private final boolean includeChildNodeCount;
+
+ private JsonSerializer(
+ JsopBuilder json, int depth, long offset, int maxChildNodes,
+ boolean includeChildNodeCount) {
+ this.json = checkNotNull(json);
+ this.depth = depth;
+ this.offset = offset;
+ this.maxChildNodes = maxChildNodes;
+ this.includeChildNodeCount = includeChildNodeCount;
+ }
+
+ JsonSerializer(int depth, long offset, int maxChildNodes) {
+ this(new JsopBuilder(), depth, offset, maxChildNodes, true);
+ }
+
+ JsonSerializer(JsopBuilder json) {
+ this(json, Integer.MAX_VALUE, 0, Integer.MAX_VALUE, false);
+ }
+
+ protected JsonSerializer getChildSerializer() {
+ return new JsonSerializer(
+ json, depth - 1, 0, maxChildNodes, includeChildNodeCount);
+ }
+
+ protected String getBlobId(Blob blob) {
+ return AbstractBlob.calculateSha256(blob).toString();
+ }
+
+ void serialize(NodeState node) {
+ json.object();
+
+ for (PropertyState property : node.getProperties()) {
+ json.key(property.getName());
+ serialize(property);
+ }
+
+ if (includeChildNodeCount) {
+ json.key(":childNodeCount");
+ json.value(node.getChildNodeCount(Integer.MAX_VALUE));
+ }
+
+ int index = 0;
+ int count = 0;
+ for (ChildNodeEntry child : node.getChildNodeEntries()) {
+ if (index++ >= offset) {
+ if (count++ >= maxChildNodes) {
+ break;
+ }
+
+ json.key(child.getName());
+ if (depth > 0) {
+ getChildSerializer().serialize(child.getNodeState());
+ } else {
+ json.object();
+ json.endObject();
+ }
+ }
+ }
+
+ json.endObject();
+ }
+
+ void serialize(PropertyState property) {
+ Type<?> type = property.getType();
+ if (!type.isArray()) {
+ serialize(property, type, 0);
+ } else {
+ Type<?> base = type.getBaseType();
+ int count = property.count();
+ if (base == STRING || count > 0) {
+ json.array();
+ for (int i = 0; i < count; i++) {
+ serialize(property, base, i);
+ }
+ json.endArray();
+ } else {
+ // type-safe encoding of an empty array
+ json.value(TypeCodes.EMPTY_ARRAY
+ + PropertyType.nameFromValue(type.tag()));
+ }
+ }
+ }
+
+ void serialize(PropertyState property, Type<?> type, int index) {
+ if (type == BOOLEAN) {
+ json.value(property.getValue(BOOLEAN, index).booleanValue());
+ } else if (type == LONG) {
+ json.value(property.getValue(LONG, index).longValue());
+ } else if (type == BINARY) {
+ Blob blob = property.getValue(BINARY, index);
+ json.value(TypeCodes.encode(type.tag(), getBlobId(blob)));
+ } else {
+ String value = property.getValue(STRING, index);
+ if (type != STRING || TypeCodes.split(value) != -1) {
+ value = TypeCodes.encode(type.tag(), value);
+ }
+ json.value(value);
+ }
+ }
+
+ public String toString() {
+ return json.toString();
+ }
+
+}
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/JsopDiff.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/JsopDiff.java?rev=1533608&r1=1533607&r2=1533608&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/JsopDiff.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/JsopDiff.java Fri Oct 18 19:38:45 2013
@@ -16,21 +16,12 @@
*/
package org.apache.jackrabbit.oak.kernel;
-import static org.apache.jackrabbit.oak.api.Type.BINARIES;
-import static org.apache.jackrabbit.oak.api.Type.BOOLEANS;
-import static org.apache.jackrabbit.oak.api.Type.LONGS;
-import static org.apache.jackrabbit.oak.api.Type.STRINGS;
-
import java.io.IOException;
-import javax.jcr.PropertyType;
-
import org.apache.jackrabbit.mk.json.JsopBuilder;
import org.apache.jackrabbit.oak.api.Blob;
import org.apache.jackrabbit.oak.api.PropertyState;
-import org.apache.jackrabbit.oak.api.Type;
import org.apache.jackrabbit.oak.commons.PathUtils;
-import org.apache.jackrabbit.oak.spi.state.ChildNodeEntry;
import org.apache.jackrabbit.oak.spi.state.NodeState;
import org.apache.jackrabbit.oak.spi.state.NodeStateDiff;
@@ -41,7 +32,7 @@ public class JsopDiff implements NodeSta
private final KernelNodeStore store;
- protected final JsopBuilder jsop;
+ private final JsopBuilder jsop;
protected final String path;
@@ -109,7 +100,6 @@ public class JsopDiff implements NodeSta
return diff.toString();
}
-
protected JsopDiff createChildDiff(JsopBuilder jsop, String path) {
return new JsopDiff(store, jsop, path);
}
@@ -119,14 +109,14 @@ public class JsopDiff implements NodeSta
@Override
public boolean propertyAdded(PropertyState after) {
jsop.tag('^').key(buildPath(after.getName()));
- toJson(after, jsop);
+ new DiffJsonSerializer().serialize(after);
return true;
}
@Override
public boolean propertyChanged(PropertyState before, PropertyState after) {
jsop.tag('^').key(buildPath(after.getName()));
- toJson(after, jsop);
+ new DiffJsonSerializer().serialize(after);
return true;
}
@@ -139,7 +129,7 @@ public class JsopDiff implements NodeSta
@Override
public boolean childNodeAdded(String name, NodeState after) {
jsop.tag('+').key(buildPath(name));
- toJson(after, jsop);
+ new DiffJsonSerializer().serialize(after);
return true;
}
@@ -169,67 +159,10 @@ public class JsopDiff implements NodeSta
return PathUtils.concat(path, name);
}
- private void toJson(NodeState nodeState, JsopBuilder jsop) {
- jsop.object();
- for (PropertyState property : nodeState.getProperties()) {
- jsop.key(property.getName());
- toJson(property, jsop);
- }
- for (ChildNodeEntry child : nodeState.getChildNodeEntries()) {
- jsop.key(child.getName());
- toJson(child.getNodeState(), jsop);
- }
- jsop.endObject();
- }
-
- private void toJson(PropertyState propertyState, JsopBuilder jsop) {
- if (propertyState.isArray()) {
- Type<?> type = propertyState.getType();
- if (type == STRINGS || propertyState.count() > 0) {
- jsop.array();
- toJsonValue(propertyState, jsop);
- jsop.endArray();
- } else {
- jsop.value(TypeCodes.EMPTY_ARRAY
- + PropertyType.nameFromValue(type.tag()));
- }
- } else {
- toJsonValue(propertyState, jsop);
- }
- }
-
- private void toJsonValue(PropertyState property, JsopBuilder jsop) {
- int type = property.getType().tag();
- switch (type) {
- case PropertyType.BOOLEAN:
- for (boolean value : property.getValue(BOOLEANS)) {
- jsop.value(value);
- }
- break;
- case PropertyType.LONG:
- for (long value : property.getValue(LONGS)) {
- jsop.value(value);
- }
- break;
- case PropertyType.BINARY:
- for (Blob value : property.getValue(BINARIES)) {
- String binId = writeBlob(value);
- jsop.value(TypeCodes.encode(type, binId));
- }
- break;
- default:
- for (String value : property.getValue(STRINGS)) {
- if (PropertyType.STRING != type || TypeCodes.split(value) != -1) {
- value = TypeCodes.encode(type, value);
- }
- jsop.value(value);
- }
- break;
- }
- }
-
/**
- * Make sure {@code blob} is persisted and return the id of the persisted blob.
+ * Make sure {@code blob} is persisted and return the id of
+ * the persisted blob.
+ *
* @param blob blob to persist
* @return id of the persisted blob
*/
@@ -247,4 +180,29 @@ public class JsopDiff implements NodeSta
return kernelBlob.getBinaryID();
}
+ private class DiffJsonSerializer extends JsonSerializer {
+
+ DiffJsonSerializer() {
+ super(jsop);
+ }
+
+ @Override
+ protected JsonSerializer getChildSerializer() {
+ return new DiffJsonSerializer();
+ }
+
+ /**
+ * Make sure {@code blob} is persisted and return the id of
+ * the persisted blob.
+ *
+ * @param blob blob to persist
+ * @return id of the persisted blob
+ */
+ @Override
+ protected String getBlobId(Blob blob) {
+ return writeBlob(blob);
+ }
+
+ }
+
}
\ No newline at end of file
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/NodeStoreKernel.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/NodeStoreKernel.java?rev=1533608&r1=1533607&r2=1533608&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/NodeStoreKernel.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/kernel/NodeStoreKernel.java Fri Oct 18 19:38:45 2013
@@ -37,12 +37,10 @@ import org.apache.jackrabbit.mk.json.Jso
import org.apache.jackrabbit.mk.json.JsopTokenizer;
import org.apache.jackrabbit.oak.api.Blob;
import org.apache.jackrabbit.oak.api.CommitFailedException;
-import org.apache.jackrabbit.oak.api.PropertyState;
import org.apache.jackrabbit.oak.api.Type;
import org.apache.jackrabbit.oak.commons.PathUtils;
import org.apache.jackrabbit.oak.spi.commit.CommitInfo;
import org.apache.jackrabbit.oak.spi.commit.EmptyHook;
-import org.apache.jackrabbit.oak.spi.state.ChildNodeEntry;
import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
import org.apache.jackrabbit.oak.spi.state.NodeState;
import org.apache.jackrabbit.oak.spi.state.NodeStore;
@@ -162,16 +160,20 @@ public class NodeStoreKernel implements
case '>':
tokenizer.read(':');
String moveTarget = tokenizer.readString();
- getNode(builder, path).moveTo(
+ if (!getNode(builder, path).moveTo(
getNode(builder, getParentPath(moveTarget)),
- getName(moveTarget));
+ getName(moveTarget))) {
+ throw new MicroKernelException("Move failed");
+ }
break;
case '*':
tokenizer.read(':');
String copyTarget = tokenizer.readString();
- getNode(builder, path).copyTo(
+ if (!getNode(builder, path).copyTo(
getNode(builder, getParentPath(copyTarget)),
- getName(copyTarget));
+ getName(copyTarget))) {
+ throw new MicroKernelException("Copy failed");
+ }
break;
default:
throw new MicroKernelException(
@@ -335,77 +337,18 @@ public class NodeStoreKernel implements
}
if (node.exists()) {
- JsopBuilder json = new JsopBuilder();
if (maxChildNodes < 0) {
maxChildNodes = Integer.MAX_VALUE;
}
- serialize(getNode(revisionId, path), json, depth, offset, maxChildNodes);
+ JsonSerializer json =
+ new JsonSerializer(depth, offset, maxChildNodes);
+ json.serialize(node);
return json.toString();
} else {
return null;
}
}
- private void serialize(
- NodeState state, JsopBuilder json,
- int depth, long offset, int maxChildNodes) {
- json.object();
-
- for (PropertyState property : state.getProperties()) {
- json.key(property.getName());
- Type<?> type = property.getType();
- if (type.isArray()) {
- type = type.getBaseType();
- json.array();
- for (int i = 0; i < property.size(); i++) {
- if (type == Type.BOOLEAN) {
- json.value(property.getValue(Type.BOOLEAN, i).booleanValue());
- } else if (type == Type.LONG) {
- json.value(property.getValue(Type.LONG, i).longValue());
- } else if (type == Type.DOUBLE) {
- json.encodedValue(property.getValue(Type.DOUBLE, i).toString());
- } else {
- json.value(property.getValue(Type.STRING, i));
- }
- }
- json.endArray();
- } else if (type == Type.BOOLEAN) {
- json.value(property.getValue(Type.BOOLEAN).booleanValue());
- } else if (type == Type.LONG) {
- json.value(property.getValue(Type.LONG).longValue());
- } else if (type == Type.DOUBLE) {
- json.encodedValue(property.getValue(Type.DOUBLE).toString());
- } else {
- json.value(property.getValue(Type.STRING));
- }
- }
-
- json.key(":childNodeCount");
- json.value(state.getChildNodeCount(Long.MAX_VALUE));
-
- long index = 0;
- int count = 0;
- for (ChildNodeEntry entry : state.getChildNodeEntries()) {
- if (index++ >= offset) {
- if (count++ >= maxChildNodes) {
- break;
- }
-
- json.key(entry.getName());
- if (depth > 0) {
- serialize(
- entry.getNodeState(), json,
- depth - 1, 0, maxChildNodes);
- } else {
- json.object();
- json.endObject();
- }
- }
- }
-
- json.endObject();
- }
-
@Override
public synchronized String commit(
String path, String jsonDiff, String revisionId, String message)
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/AbstractBlob.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/AbstractBlob.java?rev=1533608&r1=1533607&r2=1533608&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/AbstractBlob.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/memory/AbstractBlob.java Fri Oct 18 19:38:45 2013
@@ -35,34 +35,32 @@ import org.apache.jackrabbit.oak.api.Blo
*/
public abstract class AbstractBlob implements Blob {
- private static class BlobSupplier implements InputSupplier<InputStream> {
-
- private final Blob blob;
-
- private BlobSupplier(Blob blob) {
- this.blob = blob;
- }
-
- @Override
- public InputStream getInput() throws IOException {
- return blob.getNewStream();
- }
-
+ private static InputSupplier<InputStream> supplier(final Blob blob) {
+ return new InputSupplier<InputStream>() {
+ @Override
+ public InputStream getInput() throws IOException {
+ return blob.getNewStream();
+ }
+ };
}
public static boolean equal(Blob a, Blob b) {
try {
- return ByteStreams.equal(new BlobSupplier(a), new BlobSupplier(b));
+ return ByteStreams.equal(supplier(a), supplier(b));
} catch (IOException e) {
- throw new RuntimeException("Blob equality check failed", e);
+ throw new IllegalStateException("Blob equality check failed", e);
}
}
- private static HashCode calculateSha256(final Blob blob) {
- try {
- return ByteStreams.hash(new BlobSupplier(blob), Hashing.sha256());
- } catch (IOException e) {
- throw new RuntimeException("Blob hash calculation failed", e);
+ public static HashCode calculateSha256(Blob blob) {
+ if (blob instanceof AbstractBlob) {
+ return ((AbstractBlob) blob).getSha256();
+ } else {
+ try {
+ return ByteStreams.hash(supplier(blob), Hashing.sha256());
+ } catch (IOException e) {
+ throw new IllegalStateException("Hash calculation failed", e);
+ }
}
}