| /* |
| * 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; |
| |
| import org.apache.jackrabbit.oak.api.CommitFailedException; |
| import org.apache.jackrabbit.oak.api.Type; |
| import org.apache.jackrabbit.oak.run.commons.Command; |
| import org.apache.jackrabbit.oak.plugins.document.DocumentNodeStore; |
| import org.apache.jackrabbit.oak.segment.SegmentNodeStoreBuilders; |
| import org.apache.jackrabbit.oak.segment.file.FileStore; |
| import org.apache.jackrabbit.oak.spi.cluster.ClusterRepositoryInfo; |
| import org.apache.jackrabbit.oak.spi.commit.CommitInfo; |
| import org.apache.jackrabbit.oak.spi.commit.EmptyHook; |
| import org.apache.jackrabbit.oak.spi.state.NodeBuilder; |
| import org.apache.jackrabbit.oak.spi.state.NodeStore; |
| |
| import com.google.common.io.Closer; |
| import com.mongodb.MongoClient; |
| import com.mongodb.MongoClientURI; |
| import com.mongodb.MongoURI; |
| |
| import joptsimple.OptionParser; |
| import joptsimple.OptionSet; |
| |
| import static org.apache.jackrabbit.oak.plugins.document.mongo.MongoDocumentNodeStoreBuilder.newMongoDocumentNodeStoreBuilder; |
| import static org.apache.jackrabbit.oak.segment.file.FileStoreBuilder.fileStoreBuilder; |
| |
| import java.io.File; |
| |
| /** |
| * OFFLINE utility to delete the clusterId stored as hidden |
| * property as defined by ClusterRepositoryInfo. |
| * <p> |
| * This utility is meant to be the only mechanism to delete |
| * this id and yes, it is meant to be used offline only |
| * (as otherwise this would correspond to breaking the |
| * requirement that the clusterId be stable and persistent). |
| * <p> |
| * Target use case for this tool is to avoid duplicate |
| * clusterIds after a repository was cloned. |
| */ |
| class ResetClusterIdCommand implements Command { |
| |
| private static void deleteClusterId(NodeStore store) { |
| NodeBuilder builder = store.getRoot().builder(); |
| NodeBuilder clusterConfigNode = builder.getChildNode( |
| ClusterRepositoryInfo.CLUSTER_CONFIG_NODE); |
| |
| if (!clusterConfigNode.exists()) { |
| // if it doesn't exist, then there is no way to delete |
| System.out.println("clusterId was never set or already deleted."); |
| return; |
| } |
| |
| if (!clusterConfigNode.hasProperty(ClusterRepositoryInfo.CLUSTER_ID_PROP)) { |
| // the config node exists, but the clusterId not |
| // so again, no way to delete |
| System.out.println("clusterId was never set or already deleted."); |
| return; |
| } |
| String oldClusterId = clusterConfigNode.getProperty(ClusterRepositoryInfo.CLUSTER_ID_PROP) |
| .getValue(Type.STRING); |
| clusterConfigNode.removeProperty(ClusterRepositoryInfo.CLUSTER_ID_PROP); |
| try { |
| store.merge(builder, EmptyHook.INSTANCE, CommitInfo.EMPTY); |
| |
| System.out.println("clusterId deleted successfully. (old id was " + oldClusterId + ")"); |
| } catch (CommitFailedException e) { |
| System.err.println("Failed to delete clusterId due to exception: "+e.getMessage()); |
| e.printStackTrace(); |
| } |
| } |
| |
| @Override |
| public void execute(String... args) throws Exception { |
| OptionParser parser = new OptionParser(); |
| OptionSet options = parser.parse(args); |
| |
| if (options.nonOptionArguments().isEmpty()) { |
| System.out.println("usage: resetclusterid {<path>|<mongo-uri>}"); |
| System.exit(1); |
| } |
| |
| String source = options.nonOptionArguments().get(0).toString(); |
| |
| Closer closer = Closer.create(); |
| try { |
| NodeStore store; |
| if (args[0].startsWith(MongoURI.MONGODB_PREFIX)) { |
| MongoClientURI uri = new MongoClientURI(source); |
| MongoClient client = new MongoClient(uri); |
| final DocumentNodeStore dns = newMongoDocumentNodeStoreBuilder() |
| .setMongoDB(client, uri.getDatabase()) |
| .build(); |
| closer.register(Utils.asCloseable(dns)); |
| store = dns; |
| } else { |
| FileStore fileStore = fileStoreBuilder(new File(source)) |
| .withStrictVersionCheck(true) |
| .build(); |
| closer.register(fileStore); |
| store = SegmentNodeStoreBuilders.builder(fileStore).build(); |
| } |
| |
| deleteClusterId(store); |
| } catch (Throwable e) { |
| throw closer.rethrow(e); |
| } finally { |
| closer.close(); |
| } |
| |
| } |
| |
| } |