You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by st...@apache.org on 2011/08/25 10:18:59 UTC
svn commit: r1161434 [1/3] - in /jackrabbit/sandbox/microkernel: ./
src/main/java/org/apache/jackrabbit/mk/
src/main/java/org/apache/jackrabbit/mk/api/
src/main/java/org/apache/jackrabbit/mk/blobs/
src/main/java/org/apache/jackrabbit/mk/datastore/ src/...
Author: stefan
Date: Thu Aug 25 08:18:57 2011
New Revision: 1161434
URL: http://svn.apache.org/viewvc?rev=1161434&view=rev
Log:
some refactoring: extracting blob handling interface from loose object store interface
Added:
jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/blobs/
- copied from r1159622, jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/datastore/
jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/blobs/AbstractBlobStore.java
jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/blobs/BlobStoreInputStream.java
jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/blobs/DbBlobStore.java
jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/blobs/FileBlobStore.java
jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/blobs/MemoryBlobStore.java
jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/store/PersistenceManager.java
- copied, changed from r1159622, jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/store/ObjectStore.java
jackrabbit/sandbox/microkernel/src/test/java/org/apache/jackrabbit/mk/blobs/
- copied from r1159622, jackrabbit/sandbox/microkernel/src/test/java/org/apache/jackrabbit/mk/datastore/
jackrabbit/sandbox/microkernel/src/test/java/org/apache/jackrabbit/mk/blobs/DbBlobStoreTest.java
jackrabbit/sandbox/microkernel/src/test/java/org/apache/jackrabbit/mk/blobs/FileBlobStoreTest.java
jackrabbit/sandbox/microkernel/src/test/java/org/apache/jackrabbit/mk/blobs/MemoryBlobStoreTest.java
Removed:
jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/blobs/DbStore.java
jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/blobs/FileStore.java
jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/blobs/MemoryStore.java
jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/blobs/Store.java
jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/blobs/StoreInputStream.java
jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/datastore/
jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/store/DataStore.java
jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/store/ObjectStore.java
jackrabbit/sandbox/microkernel/src/test/java/org/apache/jackrabbit/mk/blobs/DbStoreTest.java
jackrabbit/sandbox/microkernel/src/test/java/org/apache/jackrabbit/mk/blobs/FileStoreTest.java
jackrabbit/sandbox/microkernel/src/test/java/org/apache/jackrabbit/mk/blobs/MemoryStoreTest.java
jackrabbit/sandbox/microkernel/src/test/java/org/apache/jackrabbit/mk/datastore/
Modified:
jackrabbit/sandbox/microkernel/pom.xml
jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/Constants.java
jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/MicroKernelFactory.java
jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/MicroKernelImpl.java
jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/Repository.java
jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/api/MicroKernel.java
jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/json/JsonBuilder.java
jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/json/JsopBuilder.java
jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/json/JsopTokenizer.java
jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/mem/MemoryKernelImpl.java
jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/mem/NodeImpl.java
jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/store/Blob.java
jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/store/Commit.java
jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/store/CommitBuilder.java
jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/store/Constants.java
jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/store/H2RevisionStore.java
jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/store/MutableCommit.java
jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/store/MutableNode.java
jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/store/Node.java
jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/store/NodeDelta.java
jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/store/NodeUtils.java
jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/store/PersistentId.java
jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/store/RevisionStore.java
jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/store/SimpleRevisionStore.java
jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/util/CommitGate.java
jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/util/IOUtils.java
jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/util/MicroKernelInputStream.java
jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/util/PathUtils.java
jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/util/SmallLRUCache.java
jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/util/StringUtils.java
jackrabbit/sandbox/microkernel/src/test/java/org/apache/jackrabbit/mk/ConcurrentWriteTest.java
jackrabbit/sandbox/microkernel/src/test/java/org/apache/jackrabbit/mk/HelloWorld.java
jackrabbit/sandbox/microkernel/src/test/java/org/apache/jackrabbit/mk/LargeObjectTest.java
jackrabbit/sandbox/microkernel/src/test/java/org/apache/jackrabbit/mk/Profiler.java
jackrabbit/sandbox/microkernel/src/test/java/org/apache/jackrabbit/mk/blobs/DataStoreTest.java
jackrabbit/sandbox/microkernel/src/test/java/org/apache/jackrabbit/mk/json/JsonBuilderTest.java
jackrabbit/sandbox/microkernel/src/test/java/org/apache/jackrabbit/mk/json/JsopTest.java
jackrabbit/sandbox/microkernel/src/test/java/org/apache/jackrabbit/mk/util/CommitGateTest.java
jackrabbit/sandbox/microkernel/src/test/java/org/apache/jackrabbit/mk/util/IOUtilsTest.java
jackrabbit/sandbox/microkernel/src/test/java/org/apache/jackrabbit/mk/util/NonDescendingClockTest.java
jackrabbit/sandbox/microkernel/src/test/java/org/apache/jackrabbit/mk/util/PathTest.java
jackrabbit/sandbox/microkernel/src/test/java/org/apache/jackrabbit/mk/util/StringUtilsTest.java
Modified: jackrabbit/sandbox/microkernel/pom.xml
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/pom.xml?rev=1161434&r1=1161433&r2=1161434&view=diff
==============================================================================
--- jackrabbit/sandbox/microkernel/pom.xml (original)
+++ jackrabbit/sandbox/microkernel/pom.xml Thu Aug 25 08:18:57 2011
@@ -27,16 +27,9 @@
<artifactId>microkernel</artifactId>
<version>0.1-SNAPSHOT</version>
<name>MicroKernel</name>
- <description>Hierarchical MVCC-based persistence store</description>
+ <description>Hierarchical MVCC-based persistence blobStore</description>
<dependencies>
- <!-- json-simple library -->
- <dependency>
- <groupId>com.googlecode.json-simple</groupId>
- <artifactId>json-simple</artifactId>
- <version>1.1</version>
- </dependency>
-
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
@@ -45,11 +38,18 @@
<!--Test Dependencies-->
<dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- <version>4.5</version>
- <scope>test</scope>
- </dependency>
+ <groupId>com.googlecode.json-simple</groupId>
+ <artifactId>json-simple</artifactId>
+ <version>1.1</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>4.5</version>
+ <scope>test</scope>
+ </dependency>
</dependencies>
<build>
@@ -67,17 +67,17 @@
-->
<plugin>
<groupId>org.pitest</groupId>
- <artifactId>pitest-maven</artifactId>
- <version>0.20</version>
- <configuration>
- <inScopeClasses>
- <param>org.apache.jackrabbit.mk.util.Path*</param>
- </inScopeClasses>
- <targetClasses>
- <param>org.apache.jackrabbit.mk.util.Path*</param>
- </targetClasses>
- </configuration>
- </plugin>
+ <artifactId>pitest-maven</artifactId>
+ <version>0.20</version>
+ <configuration>
+ <inScopeClasses>
+ <param>org.apache.jackrabbit.mk.util.Path*</param>
+ </inScopeClasses>
+ <targetClasses>
+ <param>org.apache.jackrabbit.mk.util.Path*</param>
+ </targetClasses>
+ </configuration>
+ </plugin>
</plugins>
</build>
Modified: jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/Constants.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/Constants.java?rev=1161434&r1=1161433&r2=1161434&view=diff
==============================================================================
--- jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/Constants.java (original)
+++ jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/Constants.java Thu Aug 25 08:18:57 2011
@@ -41,7 +41,7 @@ public class Constants {
public static final int MEM_MAP_ENTRY = 32;
public static final int MEM_EVENT = 64;
public static final int MEM_NODE_DATA = 48;
- public static final int MEM_VAL_LONG = 32;
+ public static final int MEM_VAL_LONG = 32;
public static final int MEM_VAL_BINARY = 32;
public static final int MEM_VAL_STRING = 64;
public static final int MEM_VAL_OBJ = 16;
Modified: jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/MicroKernelFactory.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/MicroKernelFactory.java?rev=1161434&r1=1161433&r2=1161434&view=diff
==============================================================================
--- jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/MicroKernelFactory.java (original)
+++ jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/MicroKernelFactory.java Thu Aug 25 08:18:57 2011
@@ -16,10 +16,11 @@
*/
package org.apache.jackrabbit.mk;
-import java.io.File;
import org.apache.jackrabbit.mk.api.MicroKernel;
import org.apache.jackrabbit.mk.mem.MemoryKernelImpl;
+import java.io.File;
+
/**
* A factory to create a MicroKernel instance.
*/
Modified: jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/MicroKernelImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/MicroKernelImpl.java?rev=1161434&r1=1161433&r2=1161434&view=diff
==============================================================================
--- jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/MicroKernelImpl.java (original)
+++ jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/MicroKernelImpl.java Thu Aug 25 08:18:57 2011
@@ -107,9 +107,9 @@ public class MicroKernelImpl implements
for (int i = history.size() - 1; i >= 0; i--) {
Commit commit = history.get(i);
buff.object().
- key("id").value(commit.getId()).
- key("ts").value(commit.getCommitTS()).
- endObject();
+ key("id").value(commit.getId()).
+ key("ts").value(commit.getCommitTS()).
+ endObject();
}
return buff.endArray().toString();
}
@@ -150,33 +150,33 @@ public class MicroKernelImpl implements
continue;
}
commitBuff.object().
- key("id").value(commit.getId()).
- key("ts").value(commit.getCommitTS()).
- key("msg").value(commit.getMsg());
+ key("id").value(commit.getId()).
+ key("ts").value(commit.getCommitTS()).
+ key("msg").value(commit.getMsg());
final JsopBuilder buff = new JsopBuilder();
// maps (key: id of target node, value: path/to/target)
// for tracking added/removed nodes; this allows us
// to detect 'move' operations
- final HashMap<String, String> addedNodes = new HashMap<String, String>();
- final HashMap<String, String> removedNodes = new HashMap<String, String>();
+ final HashMap<String, String> addedNodes = new HashMap<String, String>();
+ final HashMap<String, String> removedNodes = new HashMap<String, String>();
try {
String path = "/";
Node node1 = rep.getNode(commit.getParentId(), path);
Node node2 = rep.getNode(commit.getId(), path);
- NodeUtils.diff(path, node1, node2, true, rep.getStore(), new NodeDiffHandler() {
+ NodeUtils.diff(path, node1, node2, true, rep.getPersistenceManager(), new NodeDiffHandler() {
public void propAdded(String nodePath, String propName, String value) {
buff.append("+ ").
- key(PathUtils.concat(nodePath, propName)).
- encodedValue(value).
- appendWhitespace("\n");
+ key(PathUtils.concat(nodePath, propName)).
+ encodedValue(value).
+ appendWhitespace("\n");
}
public void propChanged(String nodePath, String propName, String oldValue, String newValue) {
buff.append("^ ").
- key(PathUtils.concat(nodePath, propName)).
- encodedValue(newValue).
- appendWhitespace("\n");
+ key(PathUtils.concat(nodePath, propName)).
+ encodedValue(newValue).
+ appendWhitespace("\n");
}
public void propDeleted(String nodePath, String propName, String value) {
@@ -184,17 +184,17 @@ public class MicroKernelImpl implements
// using the "- <path>" notation we're representing
// property deletions as "^ <path>:null"
buff.append("^ ").
- key(PathUtils.concat(nodePath, propName)).
- encodedValue("null").
- appendWhitespace("\n");
+ key(PathUtils.concat(nodePath, propName)).
+ encodedValue("null").
+ appendWhitespace("\n");
}
public void childNodeAdded(String nodePath, String childName, String id) {
addedNodes.put(id, PathUtils.concat(nodePath, childName));
buff.append("+ ").
- key(PathUtils.concat(nodePath, childName)).object();
+ key(PathUtils.concat(nodePath, childName)).object();
try {
- toJson(buff, rep.getStore().getNode(id), childName, Integer.MAX_VALUE, 0, -1);
+ toJson(buff, rep.getPersistenceManager().getNode(id), childName, Integer.MAX_VALUE, 0, -1);
} catch (Exception e) {
buff.value("ERROR: failed to retrieve node " + id);
}
@@ -225,19 +225,19 @@ public class MicroKernelImpl implements
buff.reset();
// TODO refactor code, avoid duplication
- NodeUtils.diff(path, node1, node2, true, rep.getStore(), new NodeDiffHandler() {
+ NodeUtils.diff(path, node1, node2, true, rep.getPersistenceManager(), new NodeDiffHandler() {
public void propAdded(String nodePath, String propName, String value) {
buff.append("+ ").
- key(PathUtils.concat(nodePath, propName)).
- encodedValue(value).
- append("\n");
+ key(PathUtils.concat(nodePath, propName)).
+ encodedValue(value).
+ append("\n");
}
public void propChanged(String nodePath, String propName, String oldValue, String newValue) {
buff.append("^ ").
- key(PathUtils.concat(nodePath, propName)).
- encodedValue(newValue).
- append("\n");
+ key(PathUtils.concat(nodePath, propName)).
+ encodedValue(newValue).
+ append("\n");
}
public void propDeleted(String nodePath, String propName, String value) {
@@ -245,9 +245,9 @@ public class MicroKernelImpl implements
// using the "- <path>" notation we're representing
// property deletions as "^ <path>:null"
buff.append("^ ").
- key(PathUtils.concat(nodePath, propName)).
- encodedValue("null").
- append("\n");
+ key(PathUtils.concat(nodePath, propName)).
+ encodedValue("null").
+ append("\n");
}
public void childNodeAdded(String nodePath, String childName, String id) {
@@ -256,9 +256,9 @@ public class MicroKernelImpl implements
return;
}
buff.append("+ ").
- key(PathUtils.concat(nodePath, childName)).object();
+ key(PathUtils.concat(nodePath, childName)).object();
try {
- toJson(buff, rep.getStore().getNode(id), childName, Integer.MAX_VALUE, 0, -1);
+ toJson(buff, rep.getPersistenceManager().getNode(id), childName, Integer.MAX_VALUE, 0, -1);
} catch (Exception e) {
buff.value("ERROR: failed to retrieve node " + id);
}
@@ -282,11 +282,11 @@ public class MicroKernelImpl implements
// finally process moved nodes
for (Map.Entry<String, String> entry : addedNodes.entrySet()) {
buff.append("> ").
- // path/to/deleted/node
- key(removedNodes.get(entry.getKey())).
- // path/to/added/node
- value(entry.getValue()).
- append("\n");
+ // path/to/deleted/node
+ key(removedNodes.get(entry.getKey())).
+ // path/to/added/node
+ value(entry.getValue()).
+ append("\n");
}
}
} catch (Exception e) {
@@ -331,49 +331,49 @@ public class MicroKernelImpl implements
break;
}
switch (r) {
- case '+': {
- String relPath = t.readString();
- t.read(':');
- t.read('{');
- String nodePath = PathUtils.concat(path, relPath);
- String parentPath = PathUtils.getParentPath(nodePath);
- String nodeName = PathUtils.getName(nodePath);
- // build the list of added nodes recursively
- LinkedList<AddNodeOperation> list = new LinkedList<AddNodeOperation>();
- addNode(list, parentPath, nodeName, t);
- for (AddNodeOperation op : list) {
- cb.addNode(op.path, op.name, op.props);
+ case '+': {
+ String relPath = t.readString();
+ t.read(':');
+ t.read('{');
+ String nodePath = PathUtils.concat(path, relPath);
+ String parentPath = PathUtils.getParentPath(nodePath);
+ String nodeName = PathUtils.getName(nodePath);
+ // build the list of added nodes recursively
+ LinkedList<AddNodeOperation> list = new LinkedList<AddNodeOperation>();
+ addNode(list, parentPath, nodeName, t);
+ for (AddNodeOperation op : list) {
+ cb.addNode(op.path, op.name, op.props);
+ }
+ break;
}
- break;
- }
- case '-': {
- String relPath = t.readString();
- cb.removeNode(PathUtils.concat(path, relPath));
- break;
- }
- case '^': {
- String relPath = t.readString();
- t.read(':');
- String value;
- if (t.matches(JsopTokenizer.NULL)) {
- value = null;
- } else {
- value = t.readRawValue().trim();
+ case '-': {
+ String relPath = t.readString();
+ cb.removeNode(PathUtils.concat(path, relPath));
+ break;
}
- String nodePath = PathUtils.concat(path, relPath);
- String parentPath = PathUtils.getParentPath(nodePath);
- String propName = PathUtils.getName(nodePath);
- cb.setProperty(parentPath, propName, value);
- break;
- }
- case '>': {
- String relPath = t.readString();
- t.read(':');
- String targetPath = t.readString();
- if (! PathUtils.isAbsolute(targetPath)) {
- targetPath = PathUtils.concat(path, targetPath);
+ case '^': {
+ String relPath = t.readString();
+ t.read(':');
+ String value;
+ if (t.matches(JsopTokenizer.NULL)) {
+ value = null;
+ } else {
+ value = t.readRawValue().trim();
+ }
+ String nodePath = PathUtils.concat(path, relPath);
+ String parentPath = PathUtils.getParentPath(nodePath);
+ String propName = PathUtils.getName(nodePath);
+ cb.setProperty(parentPath, propName, value);
+ break;
}
- cb.moveNode(PathUtils.concat(path, relPath), targetPath);
+ case '>': {
+ String relPath = t.readString();
+ t.read(':');
+ String targetPath = t.readString();
+ if (!PathUtils.isAbsolute(targetPath)) {
+ targetPath = PathUtils.concat(path, targetPath);
+ }
+ cb.moveNode(PathUtils.concat(path, relPath), targetPath);
/*
path = t.readString();
String from = PathUtils.concat(fromRoot, path);
@@ -432,10 +432,10 @@ public class MicroKernelImpl implements
headRoot = headRoot.cloneAndRemoveChildNode(from, headRevId);
}
*/
- break;
- }
- default:
- throw new AssertionError("token type: " + t.getTokenType());
+ break;
+ }
+ default:
+ throw new AssertionError("token type: " + t.getTokenType());
}
}
String newHead = cb.doCommit();
@@ -451,7 +451,7 @@ public class MicroKernelImpl implements
throw new IllegalStateException("this instance has already been disposed");
}
try {
- return rep.getStore().getBlobLength(blobId);
+ return rep.getPersistenceManager().getBlobLength(blobId);
} catch (Exception e) {
throw new MicroKernelException(e);
}
@@ -462,7 +462,7 @@ public class MicroKernelImpl implements
throw new IllegalStateException("this instance has already been disposed");
}
try {
- return rep.getStore().readBlob(blobId, pos, buff, off, length);
+ return rep.getPersistenceManager().readBlob(blobId, pos, buff, off, length);
} catch (Exception e) {
throw new MicroKernelException(e);
}
@@ -473,7 +473,7 @@ public class MicroKernelImpl implements
throw new IllegalStateException("this instance has already been disposed");
}
try {
- return rep.getStore().writeBlob(in);
+ return rep.getPersistenceManager().writeBlob(in);
} catch (Exception e) {
throw new MicroKernelException(e);
}
@@ -497,7 +497,7 @@ public class MicroKernelImpl implements
builder.key(childName).object();
if (depth > 0) {
String childId = child.getValue();
- toJson(builder, rep.getStore().getNode(childId), childName, depth - 1, 0, -1);
+ toJson(builder, rep.getPersistenceManager().getNode(childId), childName, depth - 1, 0, -1);
}
builder.endObject();
}
Modified: jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/Repository.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/Repository.java?rev=1161434&r1=1161433&r2=1161434&view=diff
==============================================================================
--- jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/Repository.java (original)
+++ jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/Repository.java Thu Aug 25 08:18:57 2011
@@ -16,10 +16,14 @@
*/
package org.apache.jackrabbit.mk;
+import org.apache.jackrabbit.mk.blobs.BlobStore;
+import org.apache.jackrabbit.mk.blobs.FileBlobStore;
import org.apache.jackrabbit.mk.store.Commit;
import org.apache.jackrabbit.mk.store.CommitBuilder;
+import org.apache.jackrabbit.mk.store.H2RevisionStore;
import org.apache.jackrabbit.mk.store.Node;
-import org.apache.jackrabbit.mk.store.ObjectStore;
+import org.apache.jackrabbit.mk.store.PersistenceManager;
+import org.apache.jackrabbit.mk.store.RevisionStore;
import org.apache.jackrabbit.mk.util.PathUtils;
import java.io.File;
@@ -32,11 +36,11 @@ public class Repository {
final String homeDir;
boolean initialized;
- final ObjectStore store;
+ final PersistenceManager pm;
public Repository(String homeDir) {
this.homeDir = homeDir == null ? "." : homeDir;
- store = new ObjectStore();
+ pm = new PersistenceManager();
initialized = false;
}
@@ -45,7 +49,20 @@ public class Repository {
return;
}
- store.initialize(new File(homeDir));
+ File home = new File(homeDir);
+
+ RevisionStore revStore = new H2RevisionStore();
+ //RevisionStore revStore = new SimpleRevisionStore();
+ revStore.initialize(home);
+
+ BlobStore blobStore;
+ if (revStore instanceof BlobStore) {
+ blobStore = (BlobStore) revStore;
+ } else {
+ blobStore = new FileBlobStore(new File(home, "blobs").getCanonicalPath());
+ }
+
+ pm.initialize(revStore, blobStore);
initialized = true;
}
@@ -55,38 +72,38 @@ public class Repository {
return;
}
- store.close();
+ pm.close();
initialized = false;
}
- public ObjectStore getStore() {
+ public PersistenceManager getPersistenceManager() {
if (!initialized) {
throw new IllegalStateException("not initialized");
}
- return store;
+ return pm;
}
public String getHeadRevision() throws Exception {
if (!initialized) {
throw new IllegalStateException("not initialized");
}
- return store.getHeadCommit().getId();
+ return pm.getHeadCommit().getId();
}
public Commit getHeadCommit() throws Exception {
if (!initialized) {
throw new IllegalStateException("not initialized");
}
- return store.getHeadCommit();
+ return pm.getHeadCommit();
}
public Commit getCommit(String id) throws Exception {
if (!initialized) {
throw new IllegalStateException("not initialized");
}
- return store.getCommit(id);
+ return pm.getCommit(id);
}
public Node getNode(String revId, String path) throws Exception {
@@ -95,10 +112,10 @@ public class Repository {
}
String[] ids = resolvePath(revId, path);
- return store.getNode(ids[ids.length - 1]);
+ return pm.getNode(ids[ids.length - 1]);
}
- public boolean nodeExists(String revId, String path) {
+ public boolean nodeExists(String revId, String path) {
if (!initialized) {
throw new IllegalStateException("not initialized");
}
@@ -109,13 +126,13 @@ public class Repository {
try {
String[] names = PathUtils.split(path);
- Node parent = store.getNode(store.getCommit(revId).getRootNodeId());
+ Node parent = pm.getNode(pm.getCommit(revId).getRootNodeId());
for (int i = 0; i < names.length; i++) {
String id = parent.getChildNodeEntries().get(names[i]);
if (id == null) {
return false;
}
- parent = store.getNode(id);
+ parent = pm.getNode(id);
}
return true;
} catch (Exception e) {
@@ -134,25 +151,25 @@ public class Repository {
throw new IllegalArgumentException("illegal path");
}
- Commit commit = store.getCommit(revId);
+ Commit commit = pm.getCommit(revId);
if (PathUtils.denotesRoot(path)) {
- return new String[] { commit.getRootNodeId() };
+ return new String[]{commit.getRootNodeId()};
}
String[] names = PathUtils.split(path);
String[] ids = new String[names.length + 1];
// get root node
ids[0] = commit.getRootNodeId();
- Node parent = store.getNode(ids[0]);
- // traverse path and store id of each element
+ Node parent = pm.getNode(ids[0]);
+ // traverse path and pm id of each element
for (int i = 0; i < names.length; i++) {
String id = parent.getChildNodeEntries().get(names[i]);
if (id == null) {
throw new Exception("path not found: " + path);
}
ids[i + 1] = id;
- parent = store.getNode(id);
+ parent = pm.getNode(id);
}
return ids;
}
Modified: jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/api/MicroKernel.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/api/MicroKernel.java?rev=1161434&r1=1161433&r2=1161434&view=diff
==============================================================================
--- jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/api/MicroKernel.java (original)
+++ jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/api/MicroKernel.java Thu Aug 25 08:18:57 2011
@@ -29,10 +29,10 @@ import java.io.InputStream;
* <li>predefined timeout (e.g. 50ms) for reading methods</li>
* <li>portable to C</li>
* <li>efficient support for large number of child nodes</li>
- * <li>integrated API for storing/retrieving large binaries (similar to DataStore API)</li>
+ * <li>integrated API for storing/retrieving large binaries (similar to existing DataStore API)</li>
* <li>human-readable data serialization (e.g. JSON, YAML)</li>
* </ul>
- *
+ * <p/>
* The MicroKernel <b>Data Model</b>:
* <ul>
* <li>simple JSON-inspired data model: just nodes and properties</li>
@@ -47,45 +47,45 @@ import java.io.InputStream;
* <li>properties and child nodes share the same namespace, i.e. a property and
* a child node, sharing the same parent node, cannot have the same name</li>
* </ul>
- *
+ * <p/>
* <b>Architecture (overview)</b>:
* <ol>
* <li>JCR (full TCK-compliant implementation)</li>
* <li>SPI (node types, workspaces, namespaces, access control, search, locking, ...)</li>
* <li><i>MicroKernel</i></li>
* </ol>
- *
+ * <p/>
* <b>TBD</b>:
* <ul>
* <li>The concept of JCR workspaces is decorated by the SPI layer as top-level nodes
- * in the MicroKernel (e.g. /default. /system); there's no need for
- * inter-workspace operations, allows simplified versioning implementation</li>
+ * in the MicroKernel (e.g. /default. /system); there's no need for
+ * inter-workspace operations, allows simplified versioning implementation</li>
* <li>should the MicroKernel support (polling) observation?
- * => <code>getRevisions/getJournal</code> should be sufficient</li>
+ * => <code>getRevisions/getJournal</code> should be sufficient</li>
* <li>nodes are primarily accessed by path. node identifiers (nodeId) are
- * optional. if a new node is committed with a special marker property
- * (e.g. <code>":id" : null</code>), a system-generated unique identifier will be
- * assigned and exposed through the same <code>:id</code> property;
- * the MicroKernel maintains an id<->path index</li>
+ * optional. if a new node is committed with a special marker property
+ * (e.g. <code>":id" : null</code>), a system-generated unique identifier will be
+ * assigned and exposed through the same <code>:id</code> property;
+ * the MicroKernel maintains an id<->path index</li>
* <li>should the API provide methods for looking up id/path mappings
- * (<code>getId/getPath</code>) or should every node with an assigned
- * id expose a <code>:path</code> property (in addition to <code>:id</code>)?</li>
+ * (<code>getId/getPath</code>) or should every node with an assigned
+ * id expose a <code>:path</code> property (in addition to <code>:id</code>)?</li>
* <li><code>jcr:uuid</code> is decorated by the SPI on top of MicroKernel;
- * <code>jcr:uuid</code> is equivalent to the MicroKernel node identifier (<code>:id</code>)</li>
+ * <code>jcr:uuid</code> is equivalent to the MicroKernel node identifier (<code>:id</code>)</li>
* <li>should the MicroKernel provide built-in support for shareable nodes?
- * => no (tentative)</li>
+ * => no (tentative)</li>
* </ul>
- *
+ * <p/>
* <b>JSON/JSOP</b>:
* <ul>
* <li>do we need to specify a 'reorder' op in jsop? perhaps based on 'move'?
- * => check full JSOP spec and davex</li>
+ * => check full JSOP spec and davex</li>
* <li>do we need to specify a 'copy' op in jsop?
- * => check full JSOP spec and davex</li>
+ * => check full JSOP spec and davex</li>
* <li>how should an incomplete list of child nodes be represented in json?
- * => length(array) != :childNodeCount</li>
+ * => length(array) != :childNodeCount</li>
* <li>consider YAML as an alternative to the JSON representation =>
- * supports ordered sequence of name:value pairs, richer set of data/collection types</li>
+ * supports ordered sequence of name:value pairs, richer set of data/collection types</li>
* </ul>
*
* @todo check DavEx protocol for potential overlap/input (e.g. JSON format)
@@ -116,26 +116,25 @@ public interface MicroKernel {
* [ { "id" : "<revisionId>", "ts" : <revisionTimestamp> }, ... ]
* </pre>
*
- * @todo provide a per revision size hint? (TBD)
- *
- * @param since timestamp (ms) of earliest revision to be returned
+ * @param since timestamp (ms) of earliest revision to be returned
* @param maxEntries maximum #entries to be returned;
* if < 0, no limit will be applied.
* @return a chronological list of revisions in JSON format.
* @throws MicroKernelException if an error occurs
+ * @todo provide a per revision size hint? (TBD)
*/
String /* jsonArray */ getRevisions(long since, int maxEntries)
throws MicroKernelException;
/**
* Wait for a commit to occur that is newer than the given revision number.
- *
+ * <p/>
* This method is useful efficient polling. The method will return the current head revision
* if it is newer than the given old revision number, or wait until the given number of
* milliseconds passed or a new head revision is available.
*
* @param maxWaitMillis the maximum number of milliseconds to wait (0 if the
- * method should not wait).
+ * method should not wait).
* @return the current head revision
* @throws MicroKernelException if an error occurs
* @throws InterruptedException if the thread was interrupted
@@ -153,7 +152,7 @@ public interface MicroKernel {
* </pre>
*
* @param fromRevisionId first revision to be returned in journal
- * @param toRevisionId last revision to be returned in journal
+ * @param toRevisionId last revision to be returned in journal
* @return a chronological list of revisions in JSON format
* @throws MicroKernelException if an error occurs
*/
@@ -166,7 +165,7 @@ public interface MicroKernel {
/**
* Determines whether the specified node exists.
*
- * @param path path denoting node
+ * @param path path denoting node
* @param revisionId revision
* @return <code>true</code> if the specified node exists, otherwise <code>false</code>
* @throws MicroKernelException if an error occurs
@@ -194,7 +193,7 @@ public interface MicroKernel {
* </pre>
* The collection of name/value pairs denoting child nodes is assumed to be
* ordered.
- *
+ * <p/>
* Remarks:
* <ul>
* <li>If the property <code>:childNodeCount</code> is 0, then the
@@ -207,7 +206,7 @@ public interface MicroKernel {
* This method is a convenience method for
* <code>getNodes(path, revisionId, 1, 0, -1)</code>
*
- * @param path path denoting root of node tree to be retrieved
+ * @param path path denoting root of node tree to be retrieved
* @param revisionId revision
* @return node tree in JSON format
* @throws MicroKernelException if an error occurs
@@ -236,13 +235,13 @@ public interface MicroKernel {
* </table>
* Offset and count only affect the returned child node list of this node.
*
- * @param path path denoting root of node tree to be retrieved
+ * @param path path denoting root of node tree to be retrieved
* @param revisionId revision
- * @param depth maximum depth of returned tree
- * @param offset start position in child node list (0 to start at the
- * beginning)
- * @param count maximum number of child nodes to retrieve (-1 for as many as
- * possible)
+ * @param depth maximum depth of returned tree
+ * @param offset start position in child node list (0 to start at the
+ * beginning)
+ * @param count maximum number of child nodes to retrieve (-1 for as many as
+ * possible)
* @return node tree in JSON format
* @throws MicroKernelException if an error occurs
*/
@@ -253,10 +252,10 @@ public interface MicroKernel {
/**
* Applies the specified changes on the specified target node.
*
- * @param path path denoting target node
- * @param jsonDiff changes to be applied in JSON diff format.
+ * @param path path denoting target node
+ * @param jsonDiff changes to be applied in JSON diff format.
* @param revisionId revision the changes are based on
- * @param message commit message
+ * @param message commit message
* @return id of newly created revision
* @throws MicroKernelException if an error occurs
*/
@@ -269,11 +268,10 @@ public interface MicroKernel {
/**
* Returns the length of the specified blob.
*
- * @todo encode length in id?
- *
* @param blobId blob identifier
* @return length of the specified blob
* @throws MicroKernelException if an error occurs
+ * @todo encode length in id?
*/
long getLength(String blobId) throws MicroKernelException;
@@ -284,10 +282,10 @@ public interface MicroKernel {
* The number of bytes actually read is returned as an integer.
*
* @param blobId blob identifier
- * @param pos the offset within the blob
- * @param buff the buffer into which the data is read.
- * @param off the start offset in array <code>buff</code>
- * at which the data is written.
+ * @param pos the offset within the blob
+ * @param buff the buffer into which the data is read.
+ * @param off the start offset in array <code>buff</code>
+ * at which the data is written.
* @param length the maximum number of bytes to read
* @return the total number of bytes read into the buffer, or
* <code>-1</code> if there is no more data because the end of
@@ -303,7 +301,7 @@ public interface MicroKernel {
* <p/>
* If identical stream content has been stored previously, then the existing
* identifier will be returned instead of storing a redundant copy.
-
+ *
* @param in InputStream providing the blob content
* @return blob identifier associated with the given content
* @throws MicroKernelException if an error occurs
Added: jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/blobs/AbstractBlobStore.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/blobs/AbstractBlobStore.java?rev=1161434&view=auto
==============================================================================
--- jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/blobs/AbstractBlobStore.java (added)
+++ jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/blobs/AbstractBlobStore.java Thu Aug 25 08:18:57 2011
@@ -0,0 +1,235 @@
+/*
+ * 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.mk.blobs;
+
+import org.apache.jackrabbit.mk.util.IOUtils;
+import org.apache.jackrabbit.mk.util.StringUtils;
+import org.h2.util.SmallLRUCache;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.DigestOutputStream;
+import java.security.MessageDigest;
+
+/**
+ * An abstract data store that splits the binaries in relatively small blocks.
+ * Each data store id a list of zero or more entries. Each entry is either
+ * <ul>
+ * <li>data (a number of bytes), or</li>
+ * <li>the hash code of the content of a number of bytes, or</li>
+ * <li>the hash code of the content of a data store id (indirect hash)</li>
+ * </ul>
+ * Thanks to the indirection, blocks can be kept relatively small, so that
+ * caching is simpler, and so that the storage backend doesn't need to support
+ * arbitrary size blobs (some storage backends buffer blobs in memory) and fast
+ * seeks (some storage backends re-read the whole blob when seeking).
+ * <p/>
+ * The the format of a 'data' entry is: type (one byte; 0 for data), length
+ * (variable size int), data (bytes).
+ * <p/>
+ * The format of a 'hash of content' entry is: type (one byte; 1 for hash),
+ * level (variable size int, 0 meaning not nested), size (variable size long),
+ * hash code length (variable size int), hash code.
+ * <p/>
+ * The format of a 'hash of data store id' entry is: type (one byte; 1 for
+ * hash), level (variable size int, nesting level), total size (variable size
+ * long), size of data store id (variable size long), hash code length (variable
+ * size int), hash code.
+ */
+public abstract class AbstractBlobStore implements BlobStore {
+
+ protected static final int TYPE_DATA = 0;
+ protected static final int TYPE_HASH = 1;
+ protected static final int TYPE_HASH_COMPRESSED = 2;
+
+ /**
+ * The minimum size of a block. Smaller blocks are stored (the data store id
+ * is the data itself).
+ */
+ private int blockSizeMin = 256;
+
+ /**
+ * The size of a block. This number has been found to be as fast as larger
+ * values, and faster than smaller values.
+ */
+ private int blockSize = 128 * 1024;
+
+ private static final String HASH_ALGORITHM = "SHA-1";
+
+ public void setBlockSizeMin(int x) {
+ this.blockSizeMin = x;
+ }
+
+ public void setBlockSize(int x) {
+ this.blockSize = x;
+ }
+
+ private SmallLRUCache<String, byte[]> cache = SmallLRUCache.newInstance(5);
+
+ public String writeBlob(InputStream in) throws Exception {
+ ByteArrayOutputStream idStream = new ByteArrayOutputStream();
+ convertBlobToId(in, idStream, 0, 0);
+ byte[] id = idStream.toByteArray();
+ // System.out.println(" write blob " + StringUtils.convertBytesToHex(id));
+ return StringUtils.convertBytesToHex(id);
+ }
+
+ private void convertBlobToId(InputStream in, ByteArrayOutputStream idStream, int level, long totalLength) throws Exception {
+ byte[] block = new byte[blockSize];
+ int count = 0;
+ while (true) {
+ MessageDigest digest = MessageDigest.getInstance(HASH_ALGORITHM);
+ ByteArrayOutputStream buff = new ByteArrayOutputStream();
+ DigestOutputStream dout = new DigestOutputStream(buff, digest);
+ int blockLen = IOUtils.readFully(in, block, 0, block.length);
+ count++;
+ if (blockLen == 0) {
+ break;
+ } else if (blockLen < blockSizeMin) {
+ idStream.write(TYPE_DATA);
+ IOUtils.writeVarInt(idStream, blockLen);
+ idStream.write(block, 0, blockLen);
+ totalLength += blockLen;
+ } else {
+ dout.write(block, 0, blockLen);
+ byte[] blockId = digest.digest();
+ idStream.write(TYPE_HASH);
+ IOUtils.writeVarInt(idStream, level);
+ if (level > 0) {
+ IOUtils.writeVarLong(idStream, totalLength);
+ }
+ IOUtils.writeVarLong(idStream, blockLen);
+ totalLength += blockLen;
+ IOUtils.writeVarInt(idStream, blockId.length);
+ idStream.write(blockId);
+ byte[] data = buff.toByteArray();
+ storeBlock(blockId, level, data);
+ }
+ if (idStream.size() > blockSize / 2) {
+ // convert large ids to a block, but ensure it can be stored as
+ // one block (otherwise the indirection no longer works)
+ byte[] idBlock = idStream.toByteArray();
+ idStream.reset();
+ convertBlobToId(new ByteArrayInputStream(idBlock), idStream, level + 1, totalLength);
+ count = 1;
+ }
+ }
+ if (count > 0 && idStream.size() > blockSizeMin) {
+ // at the very end, convert large ids to a block,
+ // because large block ids are not handy
+ // (specially if they are used to read data in small chunks)
+ byte[] idBlock = idStream.toByteArray();
+ idStream.reset();
+ convertBlobToId(new ByteArrayInputStream(idBlock), idStream, level + 1, totalLength);
+ }
+ }
+
+ protected abstract void storeBlock(byte[] blockId, int level, byte[] data) throws Exception;
+
+ public int readBlob(String blobId, long pos, byte[] buff, int off, int length) throws Exception {
+ byte[] id = StringUtils.convertHexToBytes(blobId);
+ ByteArrayInputStream idStream = new ByteArrayInputStream(id);
+ while (true) {
+ int type = idStream.read();
+ if (type == -1) {
+ return -1;
+ } else if (type == TYPE_DATA) {
+ int len = IOUtils.readVarInt(idStream);
+ if (pos < len) {
+ IOUtils.skipFully(idStream, (int) pos);
+ len -= pos;
+ if (length < len) {
+ len = length;
+ }
+ IOUtils.readFully(idStream, buff, off, len);
+ return len;
+ }
+ IOUtils.skipFully(idStream, len);
+ pos -= len;
+ } else if (type == TYPE_HASH) {
+ int level = IOUtils.readVarInt(idStream);
+ long totalLength = IOUtils.readVarLong(idStream);
+ if (level > 0) {
+ // block length (ignored)
+ IOUtils.readVarLong(idStream);
+ }
+ byte[] digest = new byte[IOUtils.readVarInt(idStream)];
+ IOUtils.readFully(idStream, digest, 0, digest.length);
+ if (pos >= totalLength) {
+ pos -= totalLength;
+ } else {
+ byte[] block = readBlock(digest);
+ if (level > 0) {
+ idStream = new ByteArrayInputStream(block);
+ } else {
+ ByteArrayInputStream in = new ByteArrayInputStream(block);
+ IOUtils.skipFully(in, (int) pos);
+ return IOUtils.readFully(in, buff, off, length);
+ }
+ }
+ } else {
+ throw new IOException("Unknown blobs id type " + type + " for blob " + blobId);
+ }
+ }
+ }
+
+ private byte[] readBlock(byte[] digest) throws Exception {
+ String id = StringUtils.convertBytesToHex(digest);
+ byte[] block = cache.get(id);
+ if (block == null) {
+ block = readBlockFromBackend(digest);
+ cache.put(id, block);
+ }
+ return block;
+ }
+
+ protected abstract byte[] readBlockFromBackend(byte[] blockId) throws Exception;
+
+ public long getBlobLength(String blobId) throws IOException {
+ byte[] id = StringUtils.convertHexToBytes(blobId);
+ ByteArrayInputStream idStream = new ByteArrayInputStream(id);
+ long totalLength = 0;
+ while (true) {
+ int type = idStream.read();
+ if (type == -1) {
+ break;
+ }
+ if (type == TYPE_DATA) {
+ int len = IOUtils.readVarInt(idStream);
+ IOUtils.skipFully(idStream, len);
+ totalLength += len;
+ } else if (type == TYPE_HASH) {
+ int level = IOUtils.readVarInt(idStream);
+ totalLength += IOUtils.readVarLong(idStream);
+ if (level > 0) {
+ // block length (ignored)
+ IOUtils.readVarLong(idStream);
+ }
+ int digestLength = IOUtils.readVarInt(idStream);
+ IOUtils.skipFully(idStream, digestLength);
+ } else {
+ throw new IOException("Datastore id type " + type + " for blob " + blobId);
+ }
+ }
+ return totalLength;
+ }
+
+ public abstract void clear();
+
+}
Added: jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/blobs/BlobStoreInputStream.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/blobs/BlobStoreInputStream.java?rev=1161434&view=auto
==============================================================================
--- jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/blobs/BlobStoreInputStream.java (added)
+++ jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/blobs/BlobStoreInputStream.java Thu Aug 25 08:18:57 2011
@@ -0,0 +1,73 @@
+/*
+ * 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.mk.blobs;
+
+import org.apache.jackrabbit.mk.util.IOUtils;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * An input stream to simplify reading from a store.
+ * See also MicroKernelInputStream.
+ */
+public class BlobStoreInputStream extends InputStream {
+
+ private final AbstractBlobStore store;
+ private final String id;
+ private long pos;
+ private byte[] oneByteBuff;
+
+ public BlobStoreInputStream(AbstractBlobStore store, String id) {
+ this.store = store;
+ this.id = id;
+ }
+
+ public int read(byte[] b, int off, int len) throws IOException {
+ int l;
+ try {
+ l = store.readBlob(id, pos, b, off, len);
+ } catch (Exception e) {
+ throw new IOException(e);
+ }
+ if (l < 0) {
+ return l;
+ }
+ pos += l;
+ return l;
+ }
+
+ public int read() throws IOException {
+ if (oneByteBuff == null) {
+ oneByteBuff = new byte[1];
+ }
+ int len = read(oneByteBuff, 0, 1);
+ if (len < 0) {
+ return len;
+ }
+ return oneByteBuff[0] & 0xff;
+ }
+
+ public static byte[] readFully(AbstractBlobStore store, String id) throws IOException {
+ int len = (int) store.getBlobLength(id);
+ byte[] buff = new byte[len];
+ BlobStoreInputStream in = new BlobStoreInputStream(store, id);
+ IOUtils.readFully(in, buff, 0, len);
+ return buff;
+ }
+
+}
\ No newline at end of file
Added: jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/blobs/DbBlobStore.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/blobs/DbBlobStore.java?rev=1161434&view=auto
==============================================================================
--- jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/blobs/DbBlobStore.java (added)
+++ jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/blobs/DbBlobStore.java Thu Aug 25 08:18:57 2011
@@ -0,0 +1,126 @@
+/*
+ * 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.mk.blobs;
+
+import org.apache.jackrabbit.mk.util.StringUtils;
+import org.h2.jdbcx.JdbcConnectionPool;
+
+import java.io.IOException;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+
+/**
+ * A database blob store.
+ */
+public class DbBlobStore extends AbstractBlobStore {
+
+ private JdbcConnectionPool cp;
+
+ public void setConnectionPool(JdbcConnectionPool cp) throws SQLException {
+ this.cp = cp;
+ Connection conn = cp.getConnection();
+ Statement stat = conn.createStatement();
+ stat.execute("create table if not exists datastore_meta" +
+ "(id varchar primary key, level int, lastMod bigint)");
+ stat.execute("create table if not exists datastore_data" +
+ "(id varchar primary key, data binary)");
+ conn.close();
+ }
+
+ @Override
+ protected void storeBlock(byte[] blockId, int level, byte[] data) throws SQLException {
+ Connection conn = cp.getConnection();
+ try {
+ String id = StringUtils.convertBytesToHex(blockId);
+ long now = System.currentTimeMillis();
+ PreparedStatement prep = conn.prepareStatement(
+ "update datastore_meta set lastMod = ? where id = ?");
+ int count;
+ try {
+ prep.setLong(1, now);
+ prep.setString(2, id);
+ count = prep.executeUpdate();
+ } finally {
+ prep.close();
+ }
+ if (count == 0) {
+ try {
+ prep = conn.prepareStatement(
+ "insert into datastore_meta(id, level, lastMod) values(?, ?, ?)");
+ try {
+ prep.setString(1, id);
+ prep.setInt(2, level);
+ prep.setLong(3, now);
+ prep.execute();
+ } finally {
+ prep.close();
+ }
+ } catch (SQLException e) {
+ // already exists - ok
+ }
+ try {
+ prep = conn.prepareStatement(
+ "insert into datastore_data(id, data) values(?, ?)");
+ try {
+ prep.setString(1, id);
+ prep.setBytes(2, data);
+ prep.execute();
+ } finally {
+ prep.close();
+ }
+ } catch (SQLException e) {
+ // already exists - ok
+ }
+ }
+ } finally {
+ conn.close();
+ }
+ }
+
+ @Override
+ protected byte[] readBlockFromBackend(byte[] blockId) throws Exception {
+ Connection conn = cp.getConnection();
+ try {
+ PreparedStatement prep = conn.prepareStatement(
+ "select data from datastore_data where id = ?");
+ try {
+ String id = StringUtils.convertBytesToHex(blockId);
+ prep.setString(1, id);
+ ResultSet rs = prep.executeQuery();
+ if (!rs.next()) {
+ throw new IOException("Datastore block " + id + " not found");
+ }
+ byte[] data = rs.getBytes(1);
+ // System.out.println(" read block " + id + " blockLen: " + data.length + " [0]: " + data[0]);
+ return data;
+ } finally {
+ prep.close();
+ }
+ } finally {
+ conn.close();
+ }
+ }
+
+ @Override
+ public void clear() {
+ // TODO currently not cleared
+ }
+
+}
Added: jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/blobs/FileBlobStore.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/blobs/FileBlobStore.java?rev=1161434&view=auto
==============================================================================
--- jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/blobs/FileBlobStore.java (added)
+++ jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/blobs/FileBlobStore.java Thu Aug 25 08:18:57 2011
@@ -0,0 +1,82 @@
+/*
+ * 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.mk.blobs;
+
+import org.apache.jackrabbit.mk.util.StringUtils;
+import org.h2.util.IOUtils;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+/**
+ * A file blob store.
+ */
+public class FileBlobStore extends AbstractBlobStore {
+
+ final private File baseDir;
+
+ public FileBlobStore(String dir) {
+ baseDir = new File(dir);
+ baseDir.mkdirs();
+ }
+
+ @Override
+ protected void storeBlock(byte[] blockId, int level, byte[] data) throws IOException {
+ File f = getFile(blockId);
+ if (f.exists()) {
+ return;
+ }
+ File parent = f.getParentFile();
+ if (!parent.exists()) {
+ parent.mkdirs();
+ }
+ File temp = new File(parent, f.getName() + ".temp");
+ FileOutputStream out = new FileOutputStream(temp);
+ out.write(data);
+ out.close();
+ temp.renameTo(f);
+ }
+
+ private File getFile(byte[] blockId) {
+ String id = StringUtils.convertBytesToHex(blockId) + ".dat";
+ File dir = new File(baseDir, id.substring(0, 2));
+ File f = new File(dir, id);
+ return f;
+ }
+
+ @Override
+ protected byte[] readBlockFromBackend(byte[] blockId) throws IOException {
+ File f = getFile(blockId);
+ int length = (int) f.length();
+ byte[] data = new byte[length];
+ FileInputStream in = new FileInputStream(f);
+ try {
+ IOUtils.readFully(in, data, 0, length);
+ } finally {
+ in.close();
+ }
+ return data;
+ }
+
+ @Override
+ public void clear() {
+ // TODO currently not cleared
+ }
+
+}
\ No newline at end of file
Added: jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/blobs/MemoryBlobStore.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/blobs/MemoryBlobStore.java?rev=1161434&view=auto
==============================================================================
--- jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/blobs/MemoryBlobStore.java (added)
+++ jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/blobs/MemoryBlobStore.java Thu Aug 25 08:18:57 2011
@@ -0,0 +1,49 @@
+/*
+ * 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.mk.blobs;
+
+import org.apache.jackrabbit.mk.util.StringUtils;
+
+import java.util.HashMap;
+
+/**
+ * A memory blob store. Useful for testing.
+ */
+public class MemoryBlobStore extends AbstractBlobStore {
+
+ private HashMap<String, byte[]> map = new HashMap<String, byte[]>();
+
+ @Override
+ protected byte[] readBlockFromBackend(byte[] blockId) {
+ return map.get(getId(blockId));
+ }
+
+ private String getId(byte[] blockId) {
+ return StringUtils.convertBytesToHex(blockId);
+ }
+
+ @Override
+ protected void storeBlock(byte[] blockId, int level, byte[] data) {
+ map.put(getId(blockId), data);
+ }
+
+ @Override
+ public void clear() {
+ map.clear();
+ }
+
+}
Modified: jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/json/JsonBuilder.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/json/JsonBuilder.java?rev=1161434&r1=1161433&r2=1161434&view=diff
==============================================================================
--- jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/json/JsonBuilder.java (original)
+++ jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/json/JsonBuilder.java Thu Aug 25 08:18:57 2011
@@ -146,8 +146,7 @@ public final class JsonBuilder {
private void optionalComma() throws IOException {
if (hasKeys) {
writer.append(',');
- }
- else {
+ } else {
hasKeys = true;
}
}
@@ -233,8 +232,7 @@ public final class JsonBuilder {
private void optionalComma() throws IOException {
if (hasValues) {
writer.append(',');
- }
- else {
+ } else {
hasValues = true;
}
}
@@ -244,14 +242,14 @@ public final class JsonBuilder {
* Escape quotes, \, /, \r, \n, \b, \f, \t and other control characters (U+0000 through U+001F).
*/
public static String escape(String string) {
- if(string == null) {
+ if (string == null) {
return null;
}
StringBuilder sb = new StringBuilder();
- for(int i = 0; i < string.length(); i++) {
+ for (int i = 0; i < string.length(); i++) {
char ch = string.charAt(i);
- switch(ch) {
+ switch (ch) {
case '"':
sb.append("\\\"");
break;
@@ -285,8 +283,7 @@ public final class JsonBuilder {
sb.append('0');
}
sb.append(ss.toUpperCase());
- }
- else {
+ } else {
sb.append(ch);
}
}
@@ -314,15 +311,15 @@ public final class JsonBuilder {
public static String encode(float value) {
// TODO silently losing data, should probably throw an exception instead
return Float.isInfinite(value) || Float.isNaN(value)
- ? "null"
- : Float.toString(value);
+ ? "null"
+ : Float.toString(value);
}
public static String encode(double value) {
// TODO silently losing data, should probably throw an exception instead
return Double.isInfinite(value) || Double.isNaN(value)
- ? "null"
- : Double.toString(value);
+ ? "null"
+ : Double.toString(value);
}
public static String encode(Number value) {
Modified: jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/json/JsopBuilder.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/json/JsopBuilder.java?rev=1161434&r1=1161433&r2=1161434&view=diff
==============================================================================
--- jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/json/JsopBuilder.java (original)
+++ jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/json/JsopBuilder.java Thu Aug 25 08:18:57 2011
@@ -215,63 +215,63 @@ public class JsopBuilder {
/**
* Escape a string into the target buffer.
*
- * @param s the string to escape
+ * @param s the string to escape
* @param length the number of characters.
- * @param buff the target buffer
+ * @param buff the target buffer
*/
public static void escape(String s, int length, StringBuilder buff) {
for (int i = 0; i < length; i++) {
char c = s.charAt(i);
switch (c) {
- case '"':
- // quotation mark
- buff.append("\\\"");
- break;
- case '\\':
- // backslash
- buff.append("\\\\");
- break;
- case '\b':
- // backspace
- buff.append("\\b");
- break;
- case '\f':
- // formfeed
- buff.append("\\f");
- break;
- case '\n':
- // newline
- buff.append("\\n");
- break;
- case '\r':
- // carriage return
- buff.append("\\r");
- break;
- case '\t':
- // horizontal tab
- buff.append("\\t");
- break;
- default:
- int ch = c;
- if (ch < ' ') {
- // guaranteed to be 1 or 2 hex digits only
- buff.append("\\u00");
- String hex = Integer.toHexString(c);
- if (hex.length() == 1) {
- buff.append('0');
+ case '"':
+ // quotation mark
+ buff.append("\\\"");
+ break;
+ case '\\':
+ // backslash
+ buff.append("\\\\");
+ break;
+ case '\b':
+ // backspace
+ buff.append("\\b");
+ break;
+ case '\f':
+ // formfeed
+ buff.append("\\f");
+ break;
+ case '\n':
+ // newline
+ buff.append("\\n");
+ break;
+ case '\r':
+ // carriage return
+ buff.append("\\r");
+ break;
+ case '\t':
+ // horizontal tab
+ buff.append("\\t");
+ break;
+ default:
+ int ch = c;
+ if (ch < ' ') {
+ // guaranteed to be 1 or 2 hex digits only
+ buff.append("\\u00");
+ String hex = Integer.toHexString(c);
+ if (hex.length() == 1) {
+ buff.append('0');
+ }
+ buff.append(hex);
+ } else if (ch >= 127) {
+ // ascii only mode
+ buff.append("\\u");
+ String hex = Integer.toHexString(c);
+ for (int len = hex.length(); len < 4; len++) {
+ buff.append('0');
+ }
+ buff.append(hex);
+ } else {
+ buff.append(c);
}
- buff.append(hex);
- } else if (ch >= 127) {
- // ascii only mode
- buff.append("\\u");
- String hex = Integer.toHexString(c);
- for (int len = hex.length(); len < 4; len++) {
- buff.append('0');
- }
- buff.append(hex);
- } else {
- buff.append(c);
- }
}
}
}
Modified: jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/json/JsopTokenizer.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/json/JsopTokenizer.java?rev=1161434&r1=1161433&r2=1161434&view=diff
==============================================================================
--- jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/json/JsopTokenizer.java (original)
+++ jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/json/JsopTokenizer.java Thu Aug 25 08:18:57 2011
@@ -25,7 +25,7 @@ public class JsopTokenizer {
public final static int COMMENT = 5, ERROR = 6, END = 7;
private static final String[] TYPE = {
- "string", "number", "true", "false", "null", "error", "end"
+ "string", "number", "true", "false", "null", "error", "end"
};
private final String jsop;
@@ -153,63 +153,54 @@ public class JsopTokenizer {
}
int start = pos++;
switch (ch) {
- case '\"': {
- while (true) {
- ch = jsop.charAt(pos++);
- if (ch == '\"') {
- break;
- } else if (ch == '\\') {
- currentEscaped = true;
- pos++;
+ case '\"': {
+ while (true) {
+ ch = jsop.charAt(pos++);
+ if (ch == '\"') {
+ break;
+ } else if (ch == '\\') {
+ currentEscaped = true;
+ pos++;
+ }
}
+ currentToken = jsop.substring(start + 1, pos - 1);
+ return STRING;
}
- currentToken = jsop.substring(start + 1, pos - 1);
- return STRING;
- }
- case '{':
- case '}':
- case '[':
- case ']':
- case '+':
- case ':':
- case ',':
- case '>':
- case '^':
- return ch;
- case '/': {
- ch = jsop.charAt(pos);
- if (ch != '*') {
- return '/';
- }
- pos++;
- while (true) {
- ch = jsop.charAt(pos++);
- if (ch == '*' && jsop.charAt(pos) == '/') {
- break;
+ case '{':
+ case '}':
+ case '[':
+ case ']':
+ case '+':
+ case ':':
+ case ',':
+ case '>':
+ case '^':
+ return ch;
+ case '/': {
+ ch = jsop.charAt(pos);
+ if (ch != '*') {
+ return '/';
}
- }
- currentToken = jsop.substring(start + 2, pos - 1);
- pos += 2;
- return COMMENT;
- }
- case '-':
- ch = jsop.charAt(pos);
- if (ch < '0' || ch > '9') {
- // lookahead
- return '-';
- }
- // else fall though
- default:
- if (ch >= '0' && ch <= '9') {
- while (pos < length) {
- ch = jsop.charAt(pos);
- if (ch < '0' || ch > '9') {
+ pos++;
+ while (true) {
+ ch = jsop.charAt(pos++);
+ if (ch == '*' && jsop.charAt(pos) == '/') {
break;
}
- pos++;
}
- if (ch == '.') {
- pos++;
+ currentToken = jsop.substring(start + 2, pos - 1);
+ pos += 2;
+ return COMMENT;
+ }
+ case '-':
+ ch = jsop.charAt(pos);
+ if (ch < '0' || ch > '9') {
+ // lookahead
+ return '-';
+ }
+ // else fall though
+ default:
+ if (ch >= '0' && ch <= '9') {
while (pos < length) {
ch = jsop.charAt(pos);
if (ch < '0' || ch > '9') {
@@ -217,44 +208,53 @@ public class JsopTokenizer {
}
pos++;
}
- }
- if (ch == 'e' || ch == 'E') {
- ch = jsop.charAt(++pos);
- if (ch == '+' || ch == '-') {
+ if (ch == '.') {
+ pos++;
+ while (pos < length) {
+ ch = jsop.charAt(pos);
+ if (ch < '0' || ch > '9') {
+ break;
+ }
+ pos++;
+ }
+ }
+ if (ch == 'e' || ch == 'E') {
ch = jsop.charAt(++pos);
+ if (ch == '+' || ch == '-') {
+ ch = jsop.charAt(++pos);
+ }
+ while (pos < length) {
+ ch = jsop.charAt(pos);
+ if (ch < '0' || ch > '9') {
+ break;
+ }
+ pos++;
+ }
}
+ currentToken = jsop.substring(start, pos);
+ return NUMBER;
+ } else if (ch >= 'a' && ch <= 'z') {
while (pos < length) {
ch = jsop.charAt(pos);
- if (ch < '0' || ch > '9') {
+ if (ch < 'a' || ch > 'z') {
break;
}
pos++;
}
- }
- currentToken = jsop.substring(start, pos);
- return NUMBER;
- } else if (ch >= 'a' && ch <= 'z') {
- while (pos < length) {
- ch = jsop.charAt(pos);
- if (ch < 'a' || ch > 'z') {
- break;
+ String s = jsop.substring(start, pos);
+ if ("null".equals(s)) {
+ return NULL;
+ } else if ("true".equals(s)) {
+ return TRUE;
+ } else if ("false".equals(s)) {
+ return FALSE;
+ } else {
+ // currentToken = s;
+ // return STRING;
+ throw getFormatException(jsop, pos);
}
- pos++;
- }
- String s = jsop.substring(start, pos);
- if ("null".equals(s)) {
- return NULL;
- } else if ("true".equals(s)) {
- return TRUE;
- } else if ("false".equals(s)) {
- return FALSE;
- } else {
- // currentToken = s;
- // return STRING;
- throw getFormatException(jsop, pos);
}
- }
- throw getFormatException(jsop, pos);
+ throw getFormatException(jsop, pos);
}
}
@@ -275,42 +275,42 @@ public class JsopTokenizer {
}
c = s.charAt(++i);
switch (c) {
- case '"':
- buff.append('"');
- break;
- case '\\':
- buff.append('\\');
- break;
- case '/':
- buff.append('/');
- break;
- case 'b':
- buff.append('\b');
- break;
- case 'f':
- buff.append('\f');
- break;
- case 'n':
- buff.append('\n');
- break;
- case 'r':
- buff.append('\r');
- break;
- case 't':
- buff.append('\t');
- break;
- case 'u': {
- try {
- c = (char) (Integer.parseInt(s.substring(i + 1, i + 5), 16));
- } catch (NumberFormatException e) {
- throw getFormatException(s, i);
+ case '"':
+ buff.append('"');
+ break;
+ case '\\':
+ buff.append('\\');
+ break;
+ case '/':
+ buff.append('/');
+ break;
+ case 'b':
+ buff.append('\b');
+ break;
+ case 'f':
+ buff.append('\f');
+ break;
+ case 'n':
+ buff.append('\n');
+ break;
+ case 'r':
+ buff.append('\r');
+ break;
+ case 't':
+ buff.append('\t');
+ break;
+ case 'u': {
+ try {
+ c = (char) (Integer.parseInt(s.substring(i + 1, i + 5), 16));
+ } catch (NumberFormatException e) {
+ throw getFormatException(s, i);
+ }
+ i += 4;
+ buff.append(c);
+ break;
}
- i += 4;
- buff.append(c);
- break;
- }
- default:
- throw getFormatException(s, i);
+ default:
+ throw getFormatException(s, i);
}
} else {
buff.append(c);
@@ -335,7 +335,7 @@ public class JsopTokenizer {
* Add an asterisk ('[*]') at the given position. This format is used to
* show where parsing failed in a statement.
*
- * @param s the text
+ * @param s the text
* @param index the position
* @return the text with asterisk
*/
@@ -360,36 +360,36 @@ public class JsopTokenizer {
private void skipRawValue() {
switch (currentType) {
- case '[':
- read();
- if (!matches(']')) {
- do {
- skipRawValue();
- } while (matches(','));
- read(']');
- }
- break;
- case '{':
- read();
- if (!matches('}')) {
- do {
- readString();
- read(':');
- skipRawValue();
- } while (matches(','));
- read('}');
- }
- break;
- case NULL:
- case NUMBER:
- case TRUE:
- case FALSE:
- case COMMENT:
- case STRING:
- read();
- break;
- default:
- throw getFormatException(jsop, pos, "value");
+ case '[':
+ read();
+ if (!matches(']')) {
+ do {
+ skipRawValue();
+ } while (matches(','));
+ read(']');
+ }
+ break;
+ case '{':
+ read();
+ if (!matches('}')) {
+ do {
+ readString();
+ read(':');
+ skipRawValue();
+ } while (matches(','));
+ read('}');
+ }
+ break;
+ case NULL:
+ case NUMBER:
+ case TRUE:
+ case FALSE:
+ case COMMENT:
+ case STRING:
+ read();
+ break;
+ default:
+ throw getFormatException(jsop, pos, "value");
}
}