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 re...@apache.org on 2014/10/17 16:45:56 UTC
svn commit: r1632591 - in
/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/rdb:
RDBDocumentSerializer.java RDBDocumentStore.java
Author: reschke
Date: Fri Oct 17 14:45:55 2014
New Revision: 1632591
URL: http://svn.apache.org/r1632591
Log:
OAK-1941 - refactoring
Added:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/rdb/RDBDocumentSerializer.java (with props)
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/rdb/RDBDocumentStore.java
Added: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/rdb/RDBDocumentSerializer.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/rdb/RDBDocumentSerializer.java?rev=1632591&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/rdb/RDBDocumentSerializer.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/rdb/RDBDocumentSerializer.java Fri Oct 17 14:45:55 2014
@@ -0,0 +1,341 @@
+/*
+ * 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.plugins.document.rdb;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.util.Comparator;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.zip.GZIPInputStream;
+
+import javax.annotation.Nonnull;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.jackrabbit.oak.plugins.document.Collection;
+import org.apache.jackrabbit.oak.plugins.document.Document;
+import org.apache.jackrabbit.oak.plugins.document.DocumentStore;
+import org.apache.jackrabbit.oak.plugins.document.DocumentStoreException;
+import org.apache.jackrabbit.oak.plugins.document.Revision;
+import org.apache.jackrabbit.oak.plugins.document.StableRevisionComparator;
+import org.apache.jackrabbit.oak.plugins.document.UpdateOp;
+import org.apache.jackrabbit.oak.plugins.document.UpdateOp.Key;
+import org.apache.jackrabbit.oak.plugins.document.UpdateOp.Operation;
+import org.json.simple.JSONArray;
+import org.json.simple.JSONObject;
+import org.json.simple.parser.JSONParser;
+import org.json.simple.parser.ParseException;
+
+/**
+ * Serialization/Parsing of documents.
+ */
+public class RDBDocumentSerializer {
+
+ private final DocumentStore store;
+ private final Set<String> columnProperties;
+
+ private static final String MODIFIED = "_modified";
+ private static final String MODCOUNT = "_modCount";
+ private static final String ID = "_id";
+ private final Comparator<Revision> comparator = StableRevisionComparator.REVERSE;
+
+ public RDBDocumentSerializer(DocumentStore store, Set<String> columnProperties) {
+ this.store = store;
+ this.columnProperties = columnProperties;
+ }
+
+ public String asString(@Nonnull Document doc) {
+ StringBuilder sb = new StringBuilder(32768);
+ sb.append("{");
+ boolean needComma = false;
+ for (String key : doc.keySet()) {
+ if (!columnProperties.contains(key)) {
+ if (needComma) {
+ sb.append(",");
+ }
+ appendMember(sb, key, doc.get(key));
+ needComma = true;
+ }
+ }
+ sb.append("}");
+ return sb.toString();
+ }
+
+ /**
+ * Serializes the changes in the {@link UpdateOp} into a JSON array; each
+ * entry is another JSON array holding operation, key, revision, and value.
+ */
+ public String asString(UpdateOp update) {
+ StringBuilder sb = new StringBuilder("[");
+ boolean needComma = false;
+ for (Map.Entry<Key, Operation> change : update.getChanges().entrySet()) {
+ Operation op = change.getValue();
+ Key key = change.getKey();
+
+ // exclude properties that are serialized into special columns
+ if (columnProperties.contains(key.getName()) && null == key.getRevision())
+ continue;
+
+ // already checked
+ if (op.type == UpdateOp.Operation.Type.CONTAINS_MAP_ENTRY)
+ continue;
+
+ if (needComma) {
+ sb.append(",");
+ }
+ sb.append("[");
+ if (op.type == UpdateOp.Operation.Type.INCREMENT) {
+ sb.append("\"+\",");
+ } else if (op.type == UpdateOp.Operation.Type.SET || op.type == UpdateOp.Operation.Type.SET_MAP_ENTRY) {
+ sb.append("\"=\",");
+ } else if (op.type == UpdateOp.Operation.Type.MAX) {
+ sb.append("\"M\",");
+ } else if (op.type == UpdateOp.Operation.Type.REMOVE_MAP_ENTRY) {
+ sb.append("\"*\",");
+ } else {
+ throw new DocumentStoreException("Can't serialize " + update.toString() + " for JSON append");
+ }
+ appendString(sb, key.getName());
+ sb.append(",");
+ if (key.getRevision() != null) {
+ appendString(sb, key.getRevision().toString());
+ sb.append(",");
+ }
+ appendValue(sb, op.value);
+ sb.append("]");
+ needComma = true;
+ }
+ return sb.append("]").toString();
+ }
+
+ private static void appendMember(StringBuilder sb, String key, Object value) {
+ appendString(sb, key);
+ sb.append(":");
+ appendValue(sb, value);
+ }
+
+ private static void appendValue(StringBuilder sb, Object value) {
+ if (value == null) {
+ sb.append("null");
+ } else if (value instanceof Number) {
+ sb.append(value.toString());
+ } else if (value instanceof Boolean) {
+ sb.append(value.toString());
+ } else if (value instanceof String) {
+ appendString(sb, (String) value);
+ } else if (value instanceof Map) {
+ appendMap(sb, (Map<Object, Object>) value);
+ } else {
+ throw new DocumentStoreException("unexpected type: " + value.getClass());
+ }
+ }
+
+ private static void appendMap(StringBuilder sb, Map<Object, Object> map) {
+ sb.append("{");
+ boolean needComma = false;
+ for (Map.Entry<Object, Object> e : map.entrySet()) {
+ if (needComma) {
+ sb.append(",");
+ }
+ appendMember(sb, e.getKey().toString(), e.getValue());
+ needComma = true;
+ }
+ sb.append("}");
+ }
+
+ private static String[] JSONCONTROLS = new String[] { "\\u0000", "\\u0001", "\\u0002", "\\u0003", "\\u0004", "\\u0005",
+ "\\u0006", "\\u0007", "\\b", "\\t", "\\n", "\\u000b", "\\f", "\\r", "\\u000e", "\\u000f", "\\u0010", "\\u0011",
+ "\\u0012", "\\u0013", "\\u0014", "\\u0015", "\\u0016", "\\u0017", "\\u0018", "\\u0019", "\\u001a", "\\u001b",
+ "\\u001c", "\\u001d", "\\u001e", "\\u001f" };
+
+ private static void appendString(StringBuilder sb, String s) {
+ sb.append('"');
+ for (int i = 0; i < s.length(); i++) {
+ char c = s.charAt(i);
+ if (c == '"') {
+ sb.append("\\\"");
+ } else if (c == '\\') {
+ sb.append("\\\\");
+ } else if (c >= 0 && c < 0x20) {
+ sb.append(JSONCONTROLS[c]);
+ } else {
+ sb.append(c);
+ }
+ }
+ sb.append('"');
+ }
+
+ // JSON simple serializer
+ // private static String asString(@Nonnull Document doc) {
+ // JSONObject obj = new JSONObject();
+ // for (String key : doc.keySet()) {
+ // if (! COLUMNPROPERTIES.contains(key)) {
+ // Object value = doc.get(key);
+ // obj.put(key, value);
+ // }
+ // }
+ // return obj.toJSONString();
+ // }
+
+ public <T extends Document> T fromRow(Collection<T> collection, RDBRow row) throws DocumentStoreException {
+ T doc = collection.newDocument(store);
+ doc.put(ID, row.getId());
+ doc.put(MODIFIED, row.getModified());
+ doc.put(MODCOUNT, row.getModcount());
+
+ JSONParser jp = new JSONParser();
+
+ Map<String, Object> baseData = null;
+ byte[] bdata = row.getBdata();
+ JSONArray arr = null;
+
+ try {
+ if (bdata != null && bdata.length != 0) {
+ baseData = (Map<String, Object>) jp.parse(fromBlobData(bdata));
+ }
+ // TODO figure out a faster way
+ arr = (JSONArray) new JSONParser().parse("[" + row.getData() + "]");
+ } catch (ParseException ex) {
+ throw new DocumentStoreException(ex);
+ }
+
+ int updatesStartAt = 0;
+ if (baseData == null) {
+ // if we do not have a blob, the first part of the string data is
+ // the base JSON
+ baseData = (Map<String, Object>) arr.get(0);
+ updatesStartAt = 1;
+ }
+
+ for (Map.Entry<String, Object> entry : baseData.entrySet()) {
+ String key = entry.getKey();
+ Object value = entry.getValue();
+ if (value == null) {
+ // ???
+ doc.put(key, value);
+ } else if (value instanceof Boolean || value instanceof Long || value instanceof String) {
+ doc.put(key, value);
+ } else if (value instanceof JSONObject) {
+ doc.put(key, convertJsonObject((JSONObject) value));
+ } else {
+ throw new RuntimeException("unexpected type: " + value.getClass());
+ }
+ }
+
+ for (int u = updatesStartAt; u < arr.size(); u++) {
+ Object ob = arr.get(u);
+ if (ob instanceof JSONArray) {
+ JSONArray update = (JSONArray) ob;
+ for (int o = 0; o < update.size(); o++) {
+ JSONArray op = (JSONArray) update.get(o);
+ String opcode = op.get(0).toString();
+ String key = op.get(1).toString();
+ Revision rev = null;
+ Object value = null;
+ if (op.size() == 3) {
+ value = op.get(2);
+ } else {
+ rev = Revision.fromString(op.get(2).toString());
+ value = op.get(3);
+ }
+ Object old = doc.get(key);
+
+ if ("=".equals(opcode)) {
+ if (rev == null) {
+ doc.put(key, value);
+ } else {
+ @SuppressWarnings("unchecked")
+ Map<Revision, Object> m = (Map<Revision, Object>) old;
+ if (m == null) {
+ m = new TreeMap<Revision, Object>(comparator);
+ doc.put(key, m);
+ }
+ m.put(rev, value);
+ }
+ } else if ("*".equals(opcode)) {
+ if (rev == null) {
+ throw new RuntimeException("unexpected operation " + op + "in: " + ob);
+ } else {
+ @SuppressWarnings("unchecked")
+ Map<Revision, Object> m = (Map<Revision, Object>) old;
+ if (m != null) {
+ m.remove(rev);
+ }
+ }
+ } else if ("+".equals(opcode)) {
+ if (rev == null) {
+ Long x = (Long) value;
+ if (old == null) {
+ old = 0L;
+ }
+ doc.put(key, ((Long) old) + x);
+ } else {
+ throw new RuntimeException("unexpected operation " + op + "in: " + ob);
+ }
+ } else if ("M".equals(opcode)) {
+ if (rev == null) {
+ Comparable newValue = (Comparable) value;
+ if (old == null || newValue.compareTo(old) > 0) {
+ doc.put(key, value);
+ }
+ } else {
+ throw new RuntimeException("unexpected operation " + op + "in: " + ob);
+ }
+ } else {
+ throw new RuntimeException("unexpected operation " + op + "in: " + ob);
+ }
+ }
+ } else if (ob.toString().equals("blob") && u == 0) {
+ // expected placeholder
+ } else {
+ throw new RuntimeException("unexpected: " + ob);
+ }
+ }
+ return doc;
+ }
+
+ @Nonnull
+ private Map<Revision, Object> convertJsonObject(@Nonnull JSONObject obj) {
+ Map<Revision, Object> map = new TreeMap<Revision, Object>(comparator);
+ Set<Map.Entry> entries = obj.entrySet();
+ for (Map.Entry entry : entries) {
+ // not clear why every persisted map is a revision map
+ map.put(Revision.fromString(entry.getKey().toString()), entry.getValue());
+ }
+ return map;
+ }
+
+ // low level operations
+
+ private static byte[] GZIPSIG = { 31, -117 };
+
+ private static String fromBlobData(byte[] bdata) {
+ try {
+ if (bdata.length >= 2 && bdata[0] == GZIPSIG[0] && bdata[1] == GZIPSIG[1]) {
+ // GZIP
+ ByteArrayInputStream bis = new ByteArrayInputStream(bdata);
+ GZIPInputStream gis = new GZIPInputStream(bis, 65536);
+ return IOUtils.toString(gis, "UTF-8");
+ } else {
+ return IOUtils.toString(bdata, "UTF-8");
+ }
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
Propchange: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/rdb/RDBDocumentSerializer.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/rdb/RDBDocumentStore.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/rdb/RDBDocumentStore.java?rev=1632591&r1=1632590&r2=1632591&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/rdb/RDBDocumentStore.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/document/rdb/RDBDocumentStore.java Fri Oct 17 14:45:55 2014
@@ -18,7 +18,6 @@ package org.apache.jackrabbit.oak.plugin
import static com.google.common.base.Preconditions.checkNotNull;
-import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
@@ -39,19 +38,16 @@ import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
-import java.util.TreeMap;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.locks.Lock;
import java.util.zip.Deflater;
-import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
import javax.sql.DataSource;
-import org.apache.commons.io.IOUtils;
import org.apache.jackrabbit.oak.cache.CacheStats;
import org.apache.jackrabbit.oak.cache.CacheValue;
import org.apache.jackrabbit.oak.plugins.document.Collection;
@@ -66,11 +62,8 @@ import org.apache.jackrabbit.oak.plugins
import org.apache.jackrabbit.oak.plugins.document.UpdateOp.Operation;
import org.apache.jackrabbit.oak.plugins.document.UpdateUtils;
import org.apache.jackrabbit.oak.plugins.document.cache.CachingDocumentStore;
+import org.apache.jackrabbit.oak.plugins.document.mongo.MongoDocumentStore;
import org.apache.jackrabbit.oak.plugins.document.util.StringValue;
-import org.json.simple.JSONArray;
-import org.json.simple.JSONObject;
-import org.json.simple.parser.JSONParser;
-import org.json.simple.parser.ParseException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -358,6 +351,8 @@ public class RDBDocumentStore implements
// set of properties not serialized to JSON
private static Set<String> COLUMNPROPERTIES = new HashSet<String>(Arrays.asList(new String[] { ID, MODIFIED, MODCOUNT }));
+ private RDBDocumentSerializer SR = new RDBDocumentSerializer(this, COLUMNPROPERTIES);
+
private void initialize(DataSource ds, DocumentMK.Builder builder, RDBOptions options) throws Exception {
this.tablePrefix = options.getTablePrefix();
@@ -662,6 +657,7 @@ public class RDBDocumentStore implements
if (isAppendableUpdate(update) && !requiresPreviousState(update)) {
long modified = getModifiedFromUpdate(update);
+ String appendData = SR.asString(update);
for (List<String> chunkedIds : Lists.partition(ids, CHUNKSIZE)) {
// remember what we already have in the cache
@@ -678,7 +674,7 @@ public class RDBDocumentStore implements
boolean success = false;
try {
connection = getConnection();
- success = dbBatchedAppendingUpdate(connection, tableName, chunkedIds, modified, asString(update));
+ success = dbBatchedAppendingUpdate(connection, tableName, chunkedIds, modified, appendData);
connection.commit();
} catch (SQLException ex) {
success = false;
@@ -727,7 +723,7 @@ public class RDBDocumentStore implements
connection = getConnection();
List<RDBRow> dbresult = dbQuery(connection, tableName, fromKey, toKey, indexedProperty, startValue, limit);
for (RDBRow r : dbresult) {
- T doc = fromRow(collection, r);
+ T doc = SR.fromRow(collection, r);
doc.seal();
result.add(doc);
addToCacheIfNotNewer(collection, doc);
@@ -753,130 +749,6 @@ public class RDBDocumentStore implements
}
}
- private <T extends Document> T fromRow(Collection<T> collection, RDBRow row) throws ParseException {
- T doc = collection.newDocument(this);
- doc.put(ID, row.getId());
- doc.put(MODIFIED, row.getModified());
- doc.put(MODCOUNT, row.getModcount());
-
- JSONParser jp = new JSONParser();
-
- Map<String, Object> baseData = null;
- byte[] bdata = row.getBdata();
- if (bdata != null && bdata.length != 0) {
- baseData = (Map<String, Object>) jp.parse(fromBlobData(bdata));
- }
- // TODO figure out a faster way
- JSONArray arr = (JSONArray) new JSONParser().parse("[" + row.getData() + "]");
-
- int updatesStartAt = 0;
- if (baseData == null) {
- // if we do not have a blob, the first part of the string data is the base JSON
- baseData = (Map<String, Object>)arr.get(0);
- updatesStartAt = 1;
- }
-
- for (Map.Entry<String, Object> entry : baseData.entrySet()) {
- String key = entry.getKey();
- Object value = entry.getValue();
- if (value == null) {
- // ???
- doc.put(key, value);
- } else if (value instanceof Boolean || value instanceof Long || value instanceof String) {
- doc.put(key, value);
- } else if (value instanceof JSONObject) {
- doc.put(key, convertJsonObject((JSONObject) value));
- } else {
- throw new RuntimeException("unexpected type: " + value.getClass());
- }
- }
-
- for (int u = updatesStartAt; u < arr.size(); u++) {
- Object ob = arr.get(u);
- if (ob instanceof JSONArray) {
- JSONArray update = (JSONArray)ob;
- for (int o = 0; o < update.size(); o++) {
- JSONArray op = (JSONArray)update.get(o);
- String opcode = op.get(0).toString();
- String key = op.get(1).toString();
- Revision rev = null;
- Object value = null;
- if (op.size() == 3) {
- value = op.get(2);
- }
- else {
- rev = Revision.fromString(op.get(2).toString());
- value = op.get(3);
- }
- Object old = doc.get(key);
-
- if ("=".equals(opcode)) {
- if (rev == null) {
- doc.put(key, value);
- } else {
- @SuppressWarnings("unchecked")
- Map<Revision, Object> m = (Map<Revision, Object>) old;
- if (m == null) {
- m = new TreeMap<Revision, Object>(comparator);
- doc.put(key, m);
- }
- m.put(rev, value);
- }
- } else if ("*".equals(opcode)) {
- if (rev == null) {
- throw new RuntimeException("unexpected operation " + op + "in: " + ob);
- } else {
- @SuppressWarnings("unchecked")
- Map<Revision, Object> m = (Map<Revision, Object>) old;
- if (m != null) {
- m.remove(rev);
- }
- }
- } else if ("+".equals(opcode)) {
- if (rev == null) {
- Long x = (Long) value;
- if (old == null) {
- old = 0L;
- }
- doc.put(key, ((Long) old) + x);
- } else {
- throw new RuntimeException("unexpected operation " + op + "in: " + ob);
- }
- } else if ("M".equals(opcode)) {
- if (rev == null) {
- Comparable newValue = (Comparable) value;
- if (old == null || newValue.compareTo(old) > 0) {
- doc.put(key, value);
- }
- } else {
- throw new RuntimeException("unexpected operation " + op + "in: " + ob);
- }
- } else {
- throw new RuntimeException("unexpected operation " + op + "in: " + ob);
- }
- }
- }
- else if (ob.toString().equals("blob") && u == 0) {
- // expected placeholder
- }
- else {
- throw new RuntimeException("unexpected: " + ob);
- }
- }
- return doc;
- }
-
- @Nonnull
- private Map<Revision, Object> convertJsonObject(@Nonnull JSONObject obj) {
- Map<Revision, Object> map = new TreeMap<Revision, Object>(comparator);
- Set<Map.Entry> entries = obj.entrySet();
- for (Map.Entry entry : entries) {
- // not clear why every persisted map is a revision map
- map.put(Revision.fromString(entry.getKey().toString()), entry.getValue());
- }
- return map;
- }
-
@CheckForNull
private <T extends Document> T readDocumentUncached(Collection<T> collection, String id) {
Connection connection = null;
@@ -884,7 +756,7 @@ public class RDBDocumentStore implements
try {
connection = getConnection();
RDBRow row = dbRead(connection, tableName, id);
- return row != null ? fromRow(collection, row) : null;
+ return row != null ? SR.fromRow(collection, row) : null;
} catch (Exception ex) {
throw new DocumentStoreException(ex);
} finally {
@@ -937,11 +809,11 @@ public class RDBDocumentStore implements
// every 16th update is a full rewrite
if (isAppendableUpdate(update) && modcount % 16 != 0) {
- String appendData = asString(update);
+ String appendData = SR.asString(update);
if (appendData.length() < datalimit) {
try {
success = dbAppendingUpdate(connection, tableName, document.getId(), modified, hasBinary, modcount,
- cmodcount, oldmodcount, asString(update));
+ cmodcount, oldmodcount, appendData);
connection.commit();
} catch (SQLException ex) {
continueIfStringOverflow(ex);
@@ -951,7 +823,7 @@ public class RDBDocumentStore implements
}
}
if (! success) {
- String data = asString(document);
+ String data = SR.asString(document);
success = dbUpdate(connection, tableName, document.getId(), modified, hasBinary, modcount, cmodcount,
oldmodcount, data);
connection.commit();
@@ -1007,53 +879,6 @@ public class RDBDocumentStore implements
return 0L;
}
- /**
- * Serializes the changes in the {@link UpdateOp} into a JSON array; each entry is another
- * JSON array holding operation, key, revision, and value.
- */
- private static String asString(UpdateOp update) {
- StringBuilder sb = new StringBuilder("[");
- boolean needComma = false;
- for (Map.Entry<Key, Operation> change : update.getChanges().entrySet()) {
- Operation op = change.getValue();
- Key key = change.getKey();
-
- // exclude properties that are serialized into special columns
- if (MODCOUNT.equals(key.getName()) && null == key.getRevision()) continue;
- if (MODIFIED.equals(key.getName()) && null == key.getRevision()) continue;
- if (ID.equals(key.getName()) && null == key.getRevision()) continue;
-
- // already checked
- if (op.type == UpdateOp.Operation.Type.CONTAINS_MAP_ENTRY) continue;
-
- if (needComma) {
- sb.append(",");
- }
- sb.append("[");
- if (op.type == UpdateOp.Operation.Type.INCREMENT) {
- sb.append("\"+\",");
- } else if (op.type == UpdateOp.Operation.Type.SET || op.type == UpdateOp.Operation.Type.SET_MAP_ENTRY) {
- sb.append("\"=\",");
- } else if (op.type == UpdateOp.Operation.Type.MAX) {
- sb.append("\"M\",");
- } else if (op.type == UpdateOp.Operation.Type.REMOVE_MAP_ENTRY) {
- sb.append("\"*\",");
- } else {
- throw new RuntimeException("Can't serialize " + update.toString() + " for JSON append");
- }
- appendString(sb, key.getName());
- sb.append(",");
- if (key.getRevision() != null) {
- appendString(sb, key.getRevision().toString());
- sb.append(",");
- }
- appendValue(sb, op.value);
- sb.append("]");
- needComma = true;
- }
- return sb.append("]").toString();
- }
-
private <T extends Document> void insertDocuments(Collection<T> collection, List<T> documents) {
Connection connection = null;
String tableName = getTable(collection);
@@ -1061,7 +886,7 @@ public class RDBDocumentStore implements
try {
connection = getConnection();
for (T document : documents) {
- String data = asString(document);
+ String data = SR.asString(document);
Long modified = (Long) document.get(MODIFIED);
Number flag = (Number) document.get(NodeDocument.HAS_BINARY_FLAG);
Boolean hasBinary = flag == null ? false : flag.intValue() == NodeDocument.HAS_BINARY_VAL;
@@ -1092,25 +917,6 @@ public class RDBDocumentStore implements
// Number of documents to insert at once for batch create
private static int CHUNKSIZE = Integer.getInteger("org.apache.jackrabbit.oak.plugins.document.rdb.RDBDocumentStore.CHUNKSIZE", 64);
- // low level operations
-
- private static byte[] GZIPSIG = { 31, -117 };
-
- private static String fromBlobData(byte[] bdata) {
- try {
- if (bdata.length >= 2 && bdata[0] == GZIPSIG[0] && bdata[1] == GZIPSIG[1]) {
- // GZIP
- ByteArrayInputStream bis = new ByteArrayInputStream(bdata);
- GZIPInputStream gis = new GZIPInputStream(bis, 65536);
- return IOUtils.toString(gis, "UTF-8");
- } else {
- return IOUtils.toString(bdata, "UTF-8");
- }
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
-
private static byte[] asBytes(String data) {
byte[] bytes;
try {
@@ -1547,91 +1353,4 @@ public class RDBDocumentStore implements
}
return false;
}
-
- // custom serializer
- private static String asString(@Nonnull Document doc) {
- StringBuilder sb = new StringBuilder(32768);
- sb.append("{");
- boolean needComma = false;
- for (String key : doc.keySet()) {
- if (!COLUMNPROPERTIES.contains(key)) {
- if (needComma) {
- sb.append(",");
- }
- appendMember(sb, key, doc.get(key));
- needComma = true;
- }
- }
- sb.append("}");
- return sb.toString();
- }
-
- private static void appendMember(StringBuilder sb, String key, Object value) {
- appendString(sb, key);
- sb.append(":");
- appendValue(sb, value);
- }
-
- private static void appendValue(StringBuilder sb, Object value) {
- if (value == null) {
- sb.append("null");
- } else if (value instanceof Number) {
- sb.append(value.toString());
- } else if (value instanceof Boolean) {
- sb.append(value.toString());
- } else if (value instanceof String) {
- appendString(sb, (String) value);
- } else if (value instanceof Map) {
- appendMap(sb, (Map<Object, Object>) value);
- } else {
- throw new RuntimeException("unexpected type: " + value.getClass());
- }
- }
-
- private static void appendMap(StringBuilder sb, Map<Object, Object> map) {
- sb.append("{");
- boolean needComma = false;
- for (Map.Entry<Object, Object> e : map.entrySet()) {
- if (needComma) {
- sb.append(",");
- }
- appendMember(sb, e.getKey().toString(), e.getValue());
- needComma = true;
- }
- sb.append("}");
- }
-
- private static String[] JSONCONTROLS = new String[] { "\\u0000", "\\u0001", "\\u0002", "\\u0003", "\\u0004", "\\u0005",
- "\\u0006", "\\u0007", "\\b", "\\t", "\\n", "\\u000b", "\\f", "\\r", "\\u000e", "\\u000f", "\\u0010", "\\u0011",
- "\\u0012", "\\u0013", "\\u0014", "\\u0015", "\\u0016", "\\u0017", "\\u0018", "\\u0019", "\\u001a", "\\u001b",
- "\\u001c", "\\u001d", "\\u001e", "\\u001f" };
-
- private static void appendString(StringBuilder sb, String s) {
- sb.append('"');
- for (int i = 0; i < s.length(); i++) {
- char c = s.charAt(i);
- if (c == '"') {
- sb.append("\\\"");
- } else if (c == '\\') {
- sb.append("\\\\");
- } else if (c >= 0 && c < 0x20) {
- sb.append(JSONCONTROLS[c]);
- } else {
- sb.append(c);
- }
- }
- sb.append('"');
- }
-
- // JSON simple serializer
-// private static String asString(@Nonnull Document doc) {
-// JSONObject obj = new JSONObject();
-// for (String key : doc.keySet()) {
-// if (! COLUMNPROPERTIES.contains(key)) {
-// Object value = doc.get(key);
-// obj.put(key, value);
-// }
-// }
-// return obj.toJSONString();
-// }
}