Index: oak-run/src/main/java/org/apache/jackrabbit/oak/run/build/DocumentNodeStoreBuilder.java =================================================================== --- oak-run/src/main/java/org/apache/jackrabbit/oak/run/build/DocumentNodeStoreBuilder.java (revision 0) +++ oak-run/src/main/java/org/apache/jackrabbit/oak/run/build/DocumentNodeStoreBuilder.java (working copy) @@ -0,0 +1,189 @@ +/* + * 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.run.build; + +import static com.google.common.collect.Sets.newHashSet; + +import java.io.Closeable; +import java.io.IOException; +import java.net.URI; +import java.net.UnknownHostException; +import java.util.List; +import java.util.Set; + +import com.google.common.base.Joiner; +import com.google.common.collect.Lists; +import com.google.common.io.Closer; +import com.mongodb.MongoClientURI; +import org.apache.jackrabbit.oak.plugins.document.DocumentMK; +import org.apache.jackrabbit.oak.plugins.document.DocumentNodeStore; +import org.apache.jackrabbit.oak.plugins.document.util.MongoConnection; +import org.apache.jackrabbit.oak.spi.blob.BlobStore; + +class DocumentNodeStoreBuilder { + + private DocumentNodeStoreBuilder() { + // Prevent instantiation. + } + + static DocumentNodeStore buildMongoDocumentStore(URI uri, BlobStore blobStore, Closer closer) throws IOException { + StringBuilder urlBuilder = new StringBuilder("mongodb://"); + + // Add the user authentication info (optional) + + if (uri.getUserInfo() != null) { + urlBuilder.append(uri.getUserInfo()).append("@"); + } + + // Add the host name (mandatory) + + if (uri.getHost() != null) { + urlBuilder.append(uri.getHost()); + } else { + throw new IllegalArgumentException("uri: host not specified"); + } + + // Add the port (optional) + + if (uri.getPort() != -1) { + urlBuilder.append(":").append(uri.getPort()); + } + + // Add the database and collection name (mandatory) + + if (uri.getPath() != null) { + urlBuilder.append(uri.getPath()); + } else { + throw new IllegalArgumentException("uri: database not specified"); + } + + // Extract query parameters. Some of them, like the cluster ID, are + // mandatory. Every unrecognized parameter is send straight to MongoDB. + + int clusterId; + + if (uri.getQuery() != null) { + + // Extract and parse the cluster ID (mandatory) + + String clusterIdValue = getQueryParameter(uri.getQuery(), "clusterId"); + + if (clusterIdValue == null) { + throw new IllegalArgumentException("uri: clusterId not specified"); + } + + try { + clusterId = Integer.parseInt(clusterIdValue); + } catch (NumberFormatException e) { + throw new IllegalArgumentException("uri: clusterId is not valid"); + } + + // Attach the rest of the query, if any + + String query = getFilteredQuery(uri.getQuery(), newHashSet("clusterId")); + + if (query != null && query.length() > 0) { + urlBuilder.append("?").append(query); + } + } else { + throw new IllegalArgumentException("uri: query parameters not specified"); + } + + MongoClientURI mongoUri = new MongoClientURI(urlBuilder.toString()); + + if (mongoUri.getDatabase() == null) { + throw new IllegalArgumentException("Database missing in MongoDB URI: " + mongoUri.getURI()); + } + + MongoConnection mongo; + + try { + mongo = new MongoConnection(mongoUri.getURI()); + } catch (UnknownHostException e) { + throw new IOException(e); + } + + closer.register(asCloseable(mongo)); + + DocumentNodeStore store = new DocumentMK.Builder() + .setMongoDB(mongo.getDB()) + .setLeaseCheck(false) + .setClusterId(clusterId) + .setBlobStore(blobStore) + .getNodeStore(); + + closer.register(asCloseable(store)); + + return store; + } + + private static String getFilteredQuery(String query, Set excludes) { + List elements = Lists.newArrayList(); + + for (String element : query.split("&")) { + int equals = element.indexOf("="); + + if (equals != -1 && excludes.contains(element.substring(0, equals))) { + continue; + } + + elements.add(element); + } + + return Joiner.on("&").join(elements); + } + + private static String getQueryParameter(String query, String name) { + for (String element : query.split("&")) { + int equals = element.indexOf("="); + + if (equals == -1) { + continue; + } + + if (element.substring(0, equals).equals(name)) { + return element.substring(equals + 1); + } + } + + return null; + } + + private static Closeable asCloseable(final MongoConnection mongoConnection) { + return new Closeable() { + + @Override + public void close() throws IOException { + mongoConnection.close(); + } + + }; + } + + private static Closeable asCloseable(final DocumentNodeStore store) { + return new Closeable() { + + @Override + public void close() throws IOException { + store.dispose(); + } + + }; + } + +} Property changes on: oak-run/src/main/java/org/apache/jackrabbit/oak/run/build/DocumentNodeStoreBuilder.java ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: oak-run/src/main/java/org/apache/jackrabbit/oak/run/build/NodeStoreBuilder.java =================================================================== --- oak-run/src/main/java/org/apache/jackrabbit/oak/run/build/NodeStoreBuilder.java (revision 0) +++ oak-run/src/main/java/org/apache/jackrabbit/oak/run/build/NodeStoreBuilder.java (working copy) @@ -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.oak.run.build; + +import static org.apache.jackrabbit.oak.run.build.DocumentNodeStoreBuilder.buildMongoDocumentStore; +import static org.apache.jackrabbit.oak.run.build.SegmentNodeStoreBuilder.buildMemorySegmentNodeStore; +import static org.apache.jackrabbit.oak.run.build.SegmentNodeStoreBuilder.buildTarSegmentNodeStore; +import static org.apache.jackrabbit.oak.run.build.SegmentNodeStoreLegacyBuilder.buildLegacySegmentNodeStore; + +import java.io.IOException; +import java.net.URI; + +import com.google.common.io.Closer; +import org.apache.jackrabbit.oak.spi.blob.BlobStore; +import org.apache.jackrabbit.oak.spi.state.NodeStore; + +/** + * Utility methods to create a {@link NodeStore} from its URI specification. + */ +public class NodeStoreBuilder { + + private NodeStoreBuilder() { + // Prevent instantiation. + } + + /** + * Creates a new {@code NodeStore} described by the given URI. + *

+ * This method is able to build instances of {@code NodeStore} if URIs in + * the following form are used. + *

+ * {@code segment:///path/to/dir} - builds an old-style, file-based {@code + * NodeStore} located at the specified path. + *

+ * {@code segment:tar:///path/to/dir} - builds a segment-based {@code + * NodeStore} located at the specified path. + *

+ * {@code segment:mem:///} - builds an unpersisted, segment-based {@code + * NodeStore} that stores its data in memory. + *

+ * {@code document:mongo://user:pass@host:port/database?clusterId=N} - + * builds a document {@code NodeStore} using the information provided in the + * URI to connect to a MongoDB host. Moreover, it is mandatory to provide a + * {@code clusterId} parameter to specify the identifier of the current + * cluster. + * + * @param uri An URI describing the {@code NodeStore} to build. + * @param blobStore An instance of {@code BlobStore} to be used by the new + * {@code NodeStore}. It can be {@code null}. + * @param closer An instance of {@code Closer} to register every closable + * resource used by the {@code NodeStore}. + * @return An instance of {@code NodeStore} or {@code null} for an invalid + * URI. + * @throws IOException if an error occurs while building and initializing + * the {@code NodeStore}. + */ + public static NodeStore buildNodeStore(URI uri, BlobStore blobStore, Closer closer) throws IOException { + String scheme = uri.getScheme(); + + if (scheme == null) { + throw new IllegalArgumentException("uri: no scheme provided"); + } + + switch (scheme) { + case "segment": + return buildSegmentNodeStore(getSchemeSpecificPart(uri), blobStore, closer); + case "document": + return buildDocumentNodeStore(getSchemeSpecificPart(uri), blobStore, closer); + default: + throw new IllegalArgumentException("uri: invalid scheme " + scheme); + } + } + + private static NodeStore buildSegmentNodeStore(URI uri, BlobStore blobStore, Closer closer) throws IOException { + String scheme = uri.getScheme(); + + if (scheme == null) { + return buildLegacySegmentNodeStore(uri, blobStore, closer); + } + + switch (scheme) { + case "mem": + return buildMemorySegmentNodeStore(); + case "tar": + return buildTarSegmentNodeStore(getSchemeSpecificPart(uri), blobStore, closer); + default: + throw new IllegalArgumentException("uri: invalid scheme " + scheme); + } + } + + private static NodeStore buildDocumentNodeStore(URI uri, BlobStore blobStore, Closer closer) throws IOException { + String scheme = uri.getScheme(); + + if (scheme == null) { + throw new IllegalArgumentException("uri: scheme not provided"); + } + + switch (scheme) { + case "mongo": + return buildMongoDocumentStore(getSchemeSpecificPart(uri), blobStore, closer); + default: + throw new IllegalArgumentException("uri: invalid scheme " + scheme); + } + } + + private static URI getSchemeSpecificPart(URI uri) { + return URI.create(uri.getRawSchemeSpecificPart()); + } + +} + Property changes on: oak-run/src/main/java/org/apache/jackrabbit/oak/run/build/NodeStoreBuilder.java ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: oak-run/src/main/java/org/apache/jackrabbit/oak/run/build/SegmentNodeStoreBuilder.java =================================================================== --- oak-run/src/main/java/org/apache/jackrabbit/oak/run/build/SegmentNodeStoreBuilder.java (revision 0) +++ oak-run/src/main/java/org/apache/jackrabbit/oak/run/build/SegmentNodeStoreBuilder.java (working copy) @@ -0,0 +1,79 @@ +/* + * 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.run.build; + +import java.io.Closeable; +import java.io.File; +import java.io.IOException; +import java.net.URI; + +import com.google.common.io.Closer; +import org.apache.jackrabbit.oak.segment.SegmentNodeStore; +import org.apache.jackrabbit.oak.segment.SegmentStore; +import org.apache.jackrabbit.oak.segment.file.FileStore; +import org.apache.jackrabbit.oak.segment.memory.MemoryStore; +import org.apache.jackrabbit.oak.spi.blob.BlobStore; + +class SegmentNodeStoreBuilder { + + private SegmentNodeStoreBuilder() { + // Prevent instantiation. + } + + static SegmentNodeStore buildMemorySegmentNodeStore() throws IOException { + return buildSegmentNodeStore(buildMemorySegmentStore()); + } + + static SegmentNodeStore buildTarSegmentNodeStore(URI uri, BlobStore blobStore, Closer closer) throws IOException { + return buildSegmentNodeStore(buildTarSegmentStore(uri, blobStore, closer)); + } + + private static SegmentNodeStore buildSegmentNodeStore(SegmentStore store) { + return SegmentNodeStore.builder(store).build(); + } + + private static MemoryStore buildMemorySegmentStore() throws IOException { + return new MemoryStore(); + } + + private static FileStore buildTarSegmentStore(URI uri, BlobStore blobStore, Closer closer) throws IOException { + FileStore.Builder builder = FileStore.builder(new File(uri.getPath())); + + if (blobStore != null) { + builder.withBlobStore(blobStore); + } + + FileStore store = builder.build(); + + closer.register(asCloseable(store)); + + return store; + } + + private static Closeable asCloseable(final FileStore store) { + return new Closeable() { + + @Override + public void close() throws IOException { + store.close(); + } + + }; + } + +} Property changes on: oak-run/src/main/java/org/apache/jackrabbit/oak/run/build/SegmentNodeStoreBuilder.java ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: oak-run/src/main/java/org/apache/jackrabbit/oak/run/build/SegmentNodeStoreLegacyBuilder.java =================================================================== --- oak-run/src/main/java/org/apache/jackrabbit/oak/run/build/SegmentNodeStoreLegacyBuilder.java (revision 0) +++ oak-run/src/main/java/org/apache/jackrabbit/oak/run/build/SegmentNodeStoreLegacyBuilder.java (working copy) @@ -0,0 +1,64 @@ +/* + * 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.run.build; + +import static org.apache.jackrabbit.oak.plugins.segment.FileStoreHelper.TAR_SEGMENT_CACHE_SIZE; +import static org.apache.jackrabbit.oak.plugins.segment.FileStoreHelper.TAR_STORAGE_MEMORY_MAPPED; + +import java.io.Closeable; +import java.io.File; +import java.io.IOException; +import java.net.URI; + +import com.google.common.io.Closer; +import org.apache.jackrabbit.oak.plugins.segment.SegmentNodeStore; +import org.apache.jackrabbit.oak.plugins.segment.file.FileStore; +import org.apache.jackrabbit.oak.spi.blob.BlobStore; + +class SegmentNodeStoreLegacyBuilder { + + private SegmentNodeStoreLegacyBuilder() { + // Prevent instantiation + } + + static SegmentNodeStore buildLegacySegmentNodeStore(URI uri, BlobStore blobStore, Closer closer) throws IOException { + FileStore.Builder builder = FileStore.builder(new File(uri.getPath())) + .withCacheSize(TAR_SEGMENT_CACHE_SIZE) + .withMemoryMapping(TAR_STORAGE_MEMORY_MAPPED); + + if (blobStore != null) { + builder.withBlobStore(blobStore); + } + + FileStore store = builder.build(); + closer.register(asCloseable(store)); + return SegmentNodeStore.builder(store).build(); + } + + private static Closeable asCloseable(final FileStore store) { + return new Closeable() { + + @Override + public void close() throws IOException { + store.close(); + } + + }; + } + +} Property changes on: oak-run/src/main/java/org/apache/jackrabbit/oak/run/build/SegmentNodeStoreLegacyBuilder.java ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property