Package voldemort.tools.admin.command

Source Code of voldemort.tools.admin.command.AdminCommandMeta$SubCommandMetaCheck

/*
* Copyright 2008-2014 LinkedIn, Inc
*
* Licensed 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 voldemort.tools.admin.command;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Set;

import joptsimple.OptionParser;
import joptsimple.OptionSet;

import org.apache.commons.io.FileUtils;

import voldemort.VoldemortException;
import voldemort.client.protocol.admin.AdminClient;
import voldemort.cluster.Cluster;
import voldemort.cluster.Node;
import voldemort.serialization.Serializer;
import voldemort.serialization.StringSerializer;
import voldemort.server.rebalance.RebalancerState;
import voldemort.store.StoreDefinition;
import voldemort.store.metadata.MetadataStore;
import voldemort.store.metadata.MetadataStore.VoldemortState;
import voldemort.store.system.SystemStoreConstants;
import voldemort.tools.admin.AdminParserUtils;
import voldemort.tools.admin.AdminToolUtils;
import voldemort.utils.ByteArray;
import voldemort.utils.MetadataVersionStoreUtils;
import voldemort.utils.Pair;
import voldemort.utils.StoreDefinitionUtils;
import voldemort.utils.Utils;
import voldemort.versioning.VectorClock;
import voldemort.versioning.Version;
import voldemort.versioning.Versioned;
import voldemort.xml.ClusterMapper;
import voldemort.xml.StoreDefinitionsMapper;

import com.google.common.base.Joiner;
import com.google.common.collect.Lists;

/**
* Implements all meta commands.
*/
public class AdminCommandMeta extends AbstractAdminCommand {

    private static final String METAKEY_ALL = "all";

    /**
     * Parses command-line and directs to sub-commands.
     *
     * @param args Command-line input
     * @throws Exception
     */
    public static void executeCommand(String[] args) throws Exception {
        String subCmd = (args.length > 0) ? args[0] : "";
        args = AdminToolUtils.copyArrayCutFirst(args);
        if(subCmd.equals("check")) {
            SubCommandMetaCheck.executeCommand(args);
        } else if(subCmd.equals("clear-rebalance")) {
            SubCommandMetaClearRebalance.executeCommand(args);
        } else if(subCmd.equals("get")) {
            SubCommandMetaGet.executeCommand(args);
        } else if(subCmd.equals("set")) {
            SubCommandMetaSet.executeCommand(args);
        } else if(subCmd.equals("sync-version")) {
            SubCommandMetaSyncVersion.executeCommand(args);
        } else if(subCmd.equals("check-version")) {
            SubCommandMetaCheckVersion.executeCommand(args);
        } else {
            printHelp(System.out);
        }
    }

    /**
     * Prints command-line help menu.
     */
    public static void printHelp(PrintStream stream) {
        stream.println();
        stream.println("Voldemort Admin Tool Meta Commands");
        stream.println("----------------------------------");
        stream.println("check             Check if metadata is consistent across all nodes.");
        stream.println("clear-rebalance   Remove metadata related to rebalancing.");
        stream.println("get               Get metadata from nodes.");
        stream.println("set               Set metadata on nodes.");
        stream.println("sync-version      Synchronize metadata versions across all nodes.");
        stream.println("check-version     Verify metadata versions on all the cluster nodes.");
        stream.println();
        stream.println("To get more information on each command,");
        stream.println("please try \'help meta <command-name>\'.");
        stream.println();
    }

    /**
     * Parses command-line input and prints help menu.
     *
     * @throws Exception
     */
    public static void executeHelp(String[] args, PrintStream stream) throws Exception {
        String subCmd = (args.length > 0) ? args[0] : "";
        if(subCmd.equals("check")) {
            SubCommandMetaCheck.printHelp(stream);
        } else if(subCmd.equals("clear-rebalance")) {
            SubCommandMetaClearRebalance.printHelp(stream);
        } else if(subCmd.equals("get")) {
            SubCommandMetaGet.printHelp(stream);
        } else if(subCmd.equals("set")) {
            SubCommandMetaSet.printHelp(stream);
        } else if(subCmd.equals("sync-version")) {
            SubCommandMetaSyncVersion.printHelp(stream);
        } else if(subCmd.equals("check-version")) {
            SubCommandMetaCheckVersion.printHelp(stream);
        } else {
            printHelp(stream);
        }
    }

    /**
     * meta check command
     */
    public static class SubCommandMetaCheck extends AbstractAdminCommand {

        private static final String OPT_HEAD_META_CHECK = "meta-check";

        /**
         * Initializes parser
         *
         * @return OptionParser object with all available options
         */
        protected static OptionParser getParser() {
            OptionParser parser = new OptionParser();
            // help options
            AdminParserUtils.acceptsHelp(parser);
            // required options
            parser.accepts(OPT_HEAD_META_CHECK, "metadata keys to be checked")
                  .withOptionalArg()
                  .describedAs("meta-key-list")
                  .withValuesSeparatedBy(',')
                  .ofType(String.class);
            AdminParserUtils.acceptsUrl(parser);
            return parser;
        }

        /**
         * Prints help menu for command.
         *
         * @param stream PrintStream object for output
         * @throws IOException
         */
        public static void printHelp(PrintStream stream) throws IOException {
            stream.println();
            stream.println("NAME");
            stream.println("  meta check - Check if metadata is consistent across all nodes");
            stream.println();
            stream.println("SYNOPSIS");
            stream.println("  meta check (<meta-key-list> | all) -u <url>");
            stream.println();
            stream.println("COMMENTS");
            stream.println("  Valid meta keys are:");
            stream.println("    " + MetadataStore.CLUSTER_KEY);
            stream.println("    " + MetadataStore.STORES_KEY);
            stream.println("    " + MetadataStore.SERVER_STATE_KEY);
            stream.println();
            getParser().printHelpOn(stream);
            stream.println();
        }

        /**
         * Parses command-line and checks if metadata is consistent across all
         * nodes.
         *
         * @param args Command-line input
         * @param printHelp Tells whether to print help only or execute command
         *        actually
         * @throws IOException
         *
         */
        @SuppressWarnings("unchecked")
        public static void executeCommand(String[] args) throws IOException {

            OptionParser parser = getParser();

            // declare parameters
            List<String> metaKeys = null;
            String url = null;

            // parse command-line input
            args = AdminToolUtils.copyArrayAddFirst(args, "--" + OPT_HEAD_META_CHECK);
            OptionSet options = parser.parse(args);
            if(options.has(AdminParserUtils.OPT_HELP)) {
                printHelp(System.out);
                return;
            }

            // check required options and/or conflicting options
            AdminParserUtils.checkRequired(options, OPT_HEAD_META_CHECK);
            AdminParserUtils.checkRequired(options, AdminParserUtils.OPT_URL);

            // load parameters
            metaKeys = (List<String>) options.valuesOf(OPT_HEAD_META_CHECK);
            url = (String) options.valueOf(AdminParserUtils.OPT_URL);

            // execute command
            if(metaKeys.size() == 1 && metaKeys.get(0).equals(METAKEY_ALL)) {
                metaKeys = Lists.newArrayList();
                metaKeys.add(MetadataStore.CLUSTER_KEY);
                metaKeys.add(MetadataStore.STORES_KEY);
                metaKeys.add(MetadataStore.SERVER_STATE_KEY);
            }

            AdminClient adminClient = AdminToolUtils.getAdminClient(url);

            doMetaCheck(adminClient, metaKeys);
        }

        private static void addMetadataValue(Map<Object, List<String>> allValues,
                                             Object metadataValue,
                                             String node) {
            if(allValues.containsKey(metadataValue) == false) {
                allValues.put(metadataValue, new ArrayList<String>());
            }
            allValues.get(metadataValue).add(node);
        }

        private static Boolean checkDiagnostics(String keyName,
                                                Map<Object, List<String>> metadataValues,
                                                Collection<String> allNodeNames) {

            Collection<String> nodesInResult = new ArrayList<String>();
            Boolean checkResult = true;

            if(metadataValues.size() == 1) {
                Map.Entry<Object, List<String>> entry = metadataValues.entrySet().iterator().next();
                nodesInResult.addAll(entry.getValue());
            } else {
                // Some nodes have different set of data than the others.
                checkResult = false;
                int groupCount = 0;
                for(Map.Entry<Object, List<String>> entry: metadataValues.entrySet()) {
                    groupCount++;
                    System.err.println("Nodes with same value for " + keyName + ". Id :"
                                       + groupCount);
                    nodesInResult.addAll(entry.getValue());
                    for(String nodeName: entry.getValue()) {
                        System.err.println("Node " + nodeName);
                    }
                    System.out.println();
                }
            }

            // Some times when a store could be missing from one of the nodes
            // In that case the map will have only one value, but total number
            // of nodes will be lesser. The following code handles that.

            // removeAll modifies the list that is being called on. so create a
            // copy
            Collection<String> nodesDiff = new ArrayList<String>(allNodeNames.size());
            nodesDiff.addAll(allNodeNames);
            nodesDiff.removeAll(nodesInResult);

            if(nodesDiff.size() > 0) {
                checkResult = false;
                for(String nodeName: nodesDiff) {
                    System.err.println("key " + keyName + " is missing in the Node " + nodeName);
                }
            }
            return checkResult;
        }

        /**
         * Checks if metadata is consistent across all nodes.
         *
         * @param adminClient An instance of AdminClient points to given cluster
         * @param metaKeys List of metakeys to check
         *
         */
        public static void doMetaCheck(AdminClient adminClient, List<String> metaKeys) {
            for(String key: metaKeys) {
                Map<String, Map<Object, List<String>>> storeNodeValueMap = new HashMap<String, Map<Object, List<String>>>();
                Map<Object, List<String>> metadataNodeValueMap = new HashMap<Object, List<String>>();
                Collection<Node> allNodes = adminClient.getAdminClientCluster().getNodes();
                Collection<String> allNodeNames = new ArrayList<String>();

                Boolean checkResult = true;
                for(Node node: allNodes) {
                    String nodeName = "Host '" + node.getHost() + "' : ID " + node.getId();
                    allNodeNames.add(nodeName);

                    System.out.println("processing " + nodeName);

                    Versioned<String> versioned = adminClient.metadataMgmtOps.getRemoteMetadata(node.getId(),
                                                                                                key);
                    if(versioned == null || versioned.getValue() == null) {
                        throw new VoldemortException("Value returned from node " + node.getId()
                                                     + " was null");
                    } else if(key.compareTo(MetadataStore.STORES_KEY) == 0) {
                        List<StoreDefinition> storeDefinitions = new StoreDefinitionsMapper().readStoreList(new StringReader(versioned.getValue()));
                        for(StoreDefinition storeDef: storeDefinitions) {
                            String storeName = storeDef.getName();
                            if(storeNodeValueMap.containsKey(storeName) == false) {
                                storeNodeValueMap.put(storeName,
                                                      new HashMap<Object, List<String>>());
                            }
                            Map<Object, List<String>> storeDefMap = storeNodeValueMap.get(storeName);
                            addMetadataValue(storeDefMap, storeDef, nodeName);
                        }
                    } else {
                        if(key.compareTo(MetadataStore.CLUSTER_KEY) == 0
                           || key.compareTo(MetadataStore.REBALANCING_SOURCE_CLUSTER_XML) == 0) {
                            Cluster cluster = new ClusterMapper().readCluster(new StringReader(versioned.getValue()));
                            addMetadataValue(metadataNodeValueMap, cluster, nodeName);
                        } else if(key.compareTo(MetadataStore.SERVER_STATE_KEY) == 0) {
                            VoldemortState voldemortStateValue = VoldemortState.valueOf(versioned.getValue());
                            addMetadataValue(metadataNodeValueMap, voldemortStateValue, nodeName);
                        } else {
                            throw new VoldemortException("Incorrect metadata key");
                        }

                    }
                }

                if(metadataNodeValueMap.size() > 0) {
                    checkResult &= checkDiagnostics(key, metadataNodeValueMap, allNodeNames);
                }

                if(storeNodeValueMap.size() > 0) {
                    for(Map.Entry<String, Map<Object, List<String>>> storeNodeValueEntry: storeNodeValueMap.entrySet()) {
                        String storeName = storeNodeValueEntry.getKey();
                        Map<Object, List<String>> storeDefMap = storeNodeValueEntry.getValue();
                        checkResult &= checkDiagnostics(storeName, storeDefMap, allNodeNames);
                    }
                }

                System.out.println(key + " metadata check : " + (checkResult ? "PASSED" : "FAILED"));
            }
        }
    }

    /**
     * meta clear-rebalance command
     */
    public static class SubCommandMetaClearRebalance extends AbstractAdminCommand {

        /**
         * Initializes parser
         *
         * @return OptionParser object with all available options
         */
        protected static OptionParser getParser() {
            OptionParser parser = new OptionParser();
            // help options
            AdminParserUtils.acceptsHelp(parser);
            // required options
            AdminParserUtils.acceptsUrl(parser);
            // optional options
            AdminParserUtils.acceptsNodeMultiple(parser); // either
                                                          // --node or
                                                          // --all-nodes
            AdminParserUtils.acceptsAllNodes(parser); // either --node or
                                                      // --all-nodes
            AdminParserUtils.acceptsConfirm(parser);
            return parser;
        }

        /**
         * Prints help menu for command.
         *
         * @param stream PrintStream object for output
         * @throws IOException
         */
        public static void printHelp(PrintStream stream) throws IOException {
            stream.println();
            stream.println("NAME");
            stream.println("  meta clear-rebalance - Remove metadata related to rebalancing");
            stream.println();
            stream.println("SYNOPSIS");
            stream.println("  meta clear-rebalance -u <url> [-n <node-id-list> | --all-nodes] [--confirm]");
            stream.println();
            getParser().printHelpOn(stream);
            stream.println();
        }

        /**
         * Parses command-line and removes metadata related to rebalancing.
         *
         * @param args Command-line input
         * @param printHelp Tells whether to print help only or execute command
         *        actually
         * @throws IOException
         *
         */
        @SuppressWarnings("unchecked")
        public static void executeCommand(String[] args) throws IOException {

            OptionParser parser = getParser();

            // declare parameters
            String url = null;
            List<Integer> nodeIds = null;
            Boolean allNodes = true;
            Boolean confirm = false;

            // parse command-line input
            OptionSet options = parser.parse(args);
            if(options.has(AdminParserUtils.OPT_HELP)) {
                printHelp(System.out);
                return;
            }

            // check required options and/or conflicting options
            AdminParserUtils.checkRequired(options, AdminParserUtils.OPT_URL);
            AdminParserUtils.checkOptional(options,
                                           AdminParserUtils.OPT_NODE,
                                           AdminParserUtils.OPT_ALL_NODES);

            // load parameters
            url = (String) options.valueOf(AdminParserUtils.OPT_URL);
            if(options.has(AdminParserUtils.OPT_NODE)) {
                nodeIds = (List<Integer>) options.valuesOf(AdminParserUtils.OPT_NODE);
                allNodes = false;
            }
            if(options.has(AdminParserUtils.OPT_CONFIRM)) {
                confirm = true;
            }

            // print summary
            System.out.println("Remove metadata related to rebalancing");
            System.out.println("Location:");
            System.out.println("  bootstrap url = " + url);
            if(allNodes) {
                System.out.println("  node = all nodes");
            } else {
                System.out.println("  node = " + Joiner.on(", ").join(nodeIds));
            }

            // execute command
            if(!AdminToolUtils.askConfirm(confirm, "remove metadata related to rebalancing")) {
                return;
            }
            AdminClient adminClient = AdminToolUtils.getAdminClient(url);

            if(allNodes) {
                nodeIds = AdminToolUtils.getAllNodeIds(adminClient);
            }

            AdminToolUtils.assertServerNotInRebalancingState(adminClient, nodeIds);

            doMetaClearRebalance(adminClient, nodeIds);
        }

        /**
         * Removes metadata related to rebalancing.
         *
         * @param adminClient An instance of AdminClient points to given cluster
         * @param nodeIds Node ids to clear metadata after rebalancing
         *
         */
        public static void doMetaClearRebalance(AdminClient adminClient, List<Integer> nodeIds) {
            AdminToolUtils.assertServerNotInOfflineState(adminClient, nodeIds);
            System.out.println("Setting " + MetadataStore.SERVER_STATE_KEY + " to "
                               + MetadataStore.VoldemortState.NORMAL_SERVER);
            doMetaSet(adminClient,
                      nodeIds,
                      MetadataStore.SERVER_STATE_KEY,
                      MetadataStore.VoldemortState.NORMAL_SERVER.toString());
            RebalancerState state = RebalancerState.create("[]");
            System.out.println("Cleaning up " + MetadataStore.REBALANCING_STEAL_INFO + " to "
                               + state.toJsonString());
            doMetaSet(adminClient,
                      nodeIds,
                      MetadataStore.REBALANCING_STEAL_INFO,
                      state.toJsonString());
            System.out.println("Cleaning up " + MetadataStore.REBALANCING_SOURCE_CLUSTER_XML
                               + " to empty string");
            doMetaSet(adminClient, nodeIds, MetadataStore.REBALANCING_SOURCE_CLUSTER_XML, "");
        }
    }

    /**
     * meta get command
     */
    public static class SubCommandMetaGet extends AbstractAdminCommand {

        public static final String OPT_HEAD_META_GET = "meta-get";
        public static final String OPT_VERBOSE = "verbose";

        /**
         * Initializes parser
         *
         * @return OptionParser object with all available options
         */
        protected static OptionParser getParser() {
            OptionParser parser = new OptionParser();
            // help options
            AdminParserUtils.acceptsHelp(parser);
            // required options
            parser.accepts(OPT_HEAD_META_GET, "metadata keys to fetch")
                  .withOptionalArg()
                  .describedAs("meta-key-list")
                  .withValuesSeparatedBy(',')
                  .ofType(String.class);
            AdminParserUtils.acceptsUrl(parser);
            // optional options
            AdminParserUtils.acceptsDir(parser);
            AdminParserUtils.acceptsNodeMultiple(parser); // either
                                                          // --node or
                                                          // --all-nodes
            AdminParserUtils.acceptsAllNodes(parser); // either --node or
                                                      // --all-nodes
            parser.accepts(OPT_VERBOSE, "print all metadata");
            return parser;
        }

        /**
         * Prints help menu for command.
         *
         * @param stream PrintStream object for output
         * @throws IOException
         */
        public static void printHelp(PrintStream stream) throws IOException {
            stream.println();
            stream.println("NAME");
            stream.println("  meta get - Get metadata from nodes");
            stream.println();
            stream.println("SYNOPSIS");
            stream.println("  meta get (<meta-key-list> | all) -u <url> [-d <output-dir>]");
            stream.println("           [-n <node-id-list> | --all-nodes] [--verbose]");
            stream.println();
            stream.println("COMMENTS");
            stream.println("  Valid meta keys are:");
            for(Object key: MetadataStore.METADATA_KEYS) {
                stream.println("    " + (String) key);
            }
            stream.println();
            getParser().printHelpOn(stream);
            stream.println();
        }

        /**
         * Parses command-line and gets metadata.
         *
         * @param args Command-line input
         * @param printHelp Tells whether to print help only or execute command
         *        actually
         * @throws IOException
         */
        @SuppressWarnings("unchecked")
        public static void executeCommand(String[] args) throws IOException {

            OptionParser parser = getParser();

            // declare parameters
            List<String> metaKeys = null;
            String url = null;
            String dir = null;
            List<Integer> nodeIds = null;
            Boolean allNodes = true;
            Boolean verbose = false;

            // parse command-line input
            args = AdminToolUtils.copyArrayAddFirst(args, "--" + OPT_HEAD_META_GET);
            OptionSet options = parser.parse(args);
            if(options.has(AdminParserUtils.OPT_HELP)) {
                printHelp(System.out);
                return;
            }

            // check required options and/or conflicting options
            AdminParserUtils.checkRequired(options, OPT_HEAD_META_GET);
            AdminParserUtils.checkRequired(options, AdminParserUtils.OPT_URL);
            AdminParserUtils.checkOptional(options,
                                           AdminParserUtils.OPT_NODE,
                                           AdminParserUtils.OPT_ALL_NODES);

            // load parameters
            metaKeys = (List<String>) options.valuesOf(OPT_HEAD_META_GET);
            url = (String) options.valueOf(AdminParserUtils.OPT_URL);
            if(options.has(AdminParserUtils.OPT_DIR)) {
                dir = (String) options.valueOf(AdminParserUtils.OPT_DIR);
            }
            if(options.has(AdminParserUtils.OPT_NODE)) {
                nodeIds = (List<Integer>) options.valuesOf(AdminParserUtils.OPT_NODE);
                allNodes = false;
            }
            if(options.has(OPT_VERBOSE)) {
                verbose = true;
            }

            // execute command
            File directory = AdminToolUtils.createDir(dir);
            AdminClient adminClient = AdminToolUtils.getAdminClient(url);

            if(allNodes) {
                nodeIds = AdminToolUtils.getAllNodeIds(adminClient);
            }

            if(metaKeys.size() == 1 && metaKeys.get(0).equals(METAKEY_ALL)) {
                metaKeys = Lists.newArrayList();
                for(Object key: MetadataStore.METADATA_KEYS) {
                    metaKeys.add((String) key);
                }
            }

            doMetaGet(adminClient, nodeIds, metaKeys, directory, verbose);
        }

        /**
         * Gets metadata.
         *
         * @param adminClient An instance of AdminClient points to given cluster
         * @param nodeIds Node ids to fetch metadata from
         * @param metaKeys List of metadata to fetch
         * @param directory Directory to output to
         * @param verbose Tells whether to print metadata verbosely
         * @throws IOException
         */
        @SuppressWarnings({ "unchecked", "cast", "rawtypes" })
        public static void doMetaGet(AdminClient adminClient,
                                     Collection<Integer> nodeIds,
                                     List<String> metaKeys,
                                     File directory,
                                     Boolean verbose) throws IOException {
            Map<String, List<Node>> nodeMap = new HashMap<String, List<Node>>();
            Map<Node, Version> versionMap = new HashMap<Node, Version>();
            for(String key: metaKeys) {
                nodeMap.clear();
                versionMap.clear();
                System.out.println("Metadata: " + key);
                for(Integer nodeId: nodeIds) {
                    Versioned<String> versioned = null;
                    try {
                        versioned = adminClient.metadataMgmtOps.getRemoteMetadata(nodeId, key);
                    } catch(Exception e) {
                        System.out.println("Error in retrieving " + e.getMessage());
                        System.out.println();
                        continue;
                    }
                    if(directory != null) {
                        FileUtils.writeStringToFile(new File(directory, key + "_" + nodeId),
                                                    ((versioned == null) ? ""
                                                                        : versioned.getValue()));
                    } else {
                        Node node = adminClient.getAdminClientCluster().getNodeById(nodeId);
                        if(verbose) {
                            System.out.println(node.getHost() + ":" + nodeId);
                            if(versioned == null) {
                                System.out.println("null");
                            } else {
                                System.out.println(versioned.getVersion());
                                System.out.print(": ");
                                System.out.println(versioned.getValue());
                                System.out.println();
                            }
                        } else {
                            if(!nodeMap.containsKey(versioned.getValue())) {
                                nodeMap.put(versioned.getValue(), new ArrayList<Node>());
                            }
                            nodeMap.get(versioned.getValue()).add(node);
                            if(!versionMap.containsKey(node)) {
                                versionMap.put(node, versioned.getVersion());
                            }
                        }
                    }
                }
                if(!verbose && !nodeMap.isEmpty()) {
                    Iterator<Entry<String, List<Node>>> iter = nodeMap.entrySet().iterator();
                    while(iter.hasNext()) {
                        Map.Entry entry = (Map.Entry) iter.next();
                        String metaValue = (String) entry.getKey();
                        List<Node> nodeList = (List<Node>) entry.getValue();
                        for(Node node: nodeList) {
                            System.out.println(node.getHost() + ":" + node.getId() + "   "
                                               + versionMap.get(node));
                        }
                        System.out.println(metaValue);
                        System.out.println();
                    }
                }
            }
        }
    }

    /**
     * meta set command
     */
    public static class SubCommandMetaSet extends AbstractAdminCommand {

        public static final String OPT_HEAD_META_SET = "meta-set";
        public static final String KEY_OFFLINE = "offline";

        /**
         * Initializes parser
         *
         * @return OptionParser object with all available options
         */
        protected static OptionParser getParser() {
            OptionParser parser = new OptionParser();
            // help options
            AdminParserUtils.acceptsHelp(parser);
            // required options
            parser.accepts(OPT_HEAD_META_SET, "metadata key-file pairs")
                  .withOptionalArg()
                  .describedAs("meta-key>=<meta-file")
                  .withValuesSeparatedBy(',')
                  .ofType(String.class);
            AdminParserUtils.acceptsUrl(parser);
            // optional options
            AdminParserUtils.acceptsNodeMultiple(parser); // either
                                                          // --node or
                                                          // --all-nodes
            AdminParserUtils.acceptsAllNodes(parser); // either --node or
                                                      // --all-nodes
            AdminParserUtils.acceptsConfirm(parser);
            return parser;
        }

        /**
         * Prints help menu for command.
         *
         * @param stream PrintStream object for output
         * @throws IOException
         */
        public static void printHelp(PrintStream stream) throws IOException {
            stream.println();
            stream.println("NAME");
            stream.println("  meta set - Set metadata on nodes");
            stream.println();
            stream.println("SYNOPSIS");
            stream.println("  meta set <meta-key>=<meta-value>[,<meta-key2>=<meta-value2>] -u <url>");
            stream.println("           [-n <node-id-list> | --all-nodes] [--confirm]");
            stream.println();
            stream.println("COMMENTS");
            stream.println("  To set one metadata, please specify one of the following:");
            stream.println("    " + MetadataStore.CLUSTER_KEY
                           + " (meta-value is cluster.xml file path)");
            stream.println("    " + MetadataStore.STORES_KEY
                           + " (meta-value is stores.xml file path)");
            stream.println("    " + MetadataStore.SLOP_STREAMING_ENABLED_KEY);
            stream.println("    " + MetadataStore.PARTITION_STREAMING_ENABLED_KEY);
            stream.println("    " + MetadataStore.READONLY_FETCH_ENABLED_KEY);
            stream.println("    " + MetadataStore.REBALANCING_SOURCE_CLUSTER_XML);
            stream.println("    " + MetadataStore.REBALANCING_STEAL_INFO);
            stream.println("    " + KEY_OFFLINE);
            stream.println("  To set a pair of metadata values, valid meta keys are:");
            stream.println("    " + MetadataStore.CLUSTER_KEY
                           + " (meta-value is cluster.xml file path)");
            stream.println("    " + MetadataStore.STORES_KEY
                           + " (meta-value is stores.xml file path)");
            stream.println();
            getParser().printHelpOn(stream);
            stream.println();
        }

        /**
         * Parses command-line and sets metadata.
         *
         * @param args Command-line input
         * @param printHelp Tells whether to print help only or execute command
         *        actually
         * @throws Exception
         *
         */
        @SuppressWarnings("unchecked")
        public static void executeCommand(String[] args) throws Exception {

            OptionParser parser = getParser();

            // declare parameters
            List<String> meta = null;
            String url = null;
            List<Integer> nodeIds = null;
            Boolean allNodes = true;
            Boolean confirm = false;

            // parse command-line input
            args = AdminToolUtils.copyArrayAddFirst(args, "--" + OPT_HEAD_META_SET);
            OptionSet options = parser.parse(args);
            if(options.has(AdminParserUtils.OPT_HELP)) {
                printHelp(System.out);
                return;
            }

            // check required options and/or conflicting options
            AdminParserUtils.checkRequired(options, OPT_HEAD_META_SET);
            AdminParserUtils.checkRequired(options, AdminParserUtils.OPT_URL);
            AdminParserUtils.checkOptional(options,
                                           AdminParserUtils.OPT_NODE,
                                           AdminParserUtils.OPT_ALL_NODES);

            // load parameters
            meta = AdminToolUtils.getValueList((List<String>) options.valuesOf(OPT_HEAD_META_SET),
                                               "=");
            if(meta.size() != 2 && meta.size() != 4) {
                throw new VoldemortException("Invalid metakey-metafile pairs.");
            }
            url = (String) options.valueOf(AdminParserUtils.OPT_URL);
            if(options.has(AdminParserUtils.OPT_NODE)) {
                nodeIds = (List<Integer>) options.valuesOf(AdminParserUtils.OPT_NODE);
                allNodes = false;
            }
            if(options.has(AdminParserUtils.OPT_CONFIRM)) {
                confirm = true;
            }

            // print summary
            System.out.println("Set metadata");
            System.out.println("Metadata:");
            for(Integer i = 0; i < meta.size(); i += 2) {
                System.out.println("  set \'" + meta.get(i) + "\' from file \'" + meta.get(i + 1)
                                   + "\'");
            }
            System.out.println("Location:");
            System.out.println("  bootstrap url = " + url);
            if(allNodes) {
                System.out.println("  node = all nodes");
            } else {
                System.out.println("  node = " + Joiner.on(", ").join(nodeIds));
            }

            // execute command
            if(!AdminToolUtils.askConfirm(confirm, "set metadata")) {
                return;
            }

            AdminClient adminClient = AdminToolUtils.getAdminClient(url);

            if(allNodes) {
                nodeIds = AdminToolUtils.getAllNodeIds(adminClient);
            }

            AdminToolUtils.assertServerNotInRebalancingState(adminClient, nodeIds);

            if(meta.size() == 2) {
                String metaKey = meta.get(0), metaValue = meta.get(1);
                String metaFile = metaValue.replace("~", System.getProperty("user.home"));

                if(metaKey.equals(MetadataStore.CLUSTER_KEY)
                   || metaKey.equals(MetadataStore.REBALANCING_SOURCE_CLUSTER_XML)) {
                    if(!Utils.isReadableFile(metaFile)) {
                        throw new VoldemortException("Cluster xml file path incorrect");
                    }
                    ClusterMapper mapper = new ClusterMapper();
                    Cluster newCluster = mapper.readCluster(new File(metaFile));
                    doMetaSet(adminClient, nodeIds, metaKey, mapper.writeCluster(newCluster));
                } else if(metaKey.equals(MetadataStore.STORES_KEY)) {
                    if(!Utils.isReadableFile(metaFile)) {
                        throw new VoldemortException("Stores definition xml file path incorrect");
                    }
                    StoreDefinitionsMapper mapper = new StoreDefinitionsMapper();
                    List<StoreDefinition> newStoreDefs = mapper.readStoreList(new File(metaFile));
                    StoreDefinitionUtils.validateSchemasAsNeeded(newStoreDefs);

                    // original metadata
                    Integer nodeIdToGetStoreXMLFrom = nodeIds.iterator().next();
                    Versioned<String> storesXML = adminClient.metadataMgmtOps.getRemoteMetadata(nodeIdToGetStoreXMLFrom,
                                                                                                MetadataStore.STORES_KEY);

                    List<StoreDefinition> oldStoreDefs = mapper.readStoreList(new StringReader(storesXML.getValue()));

                    doMetaSet(adminClient, nodeIds, metaKey, mapper.writeStoreList(newStoreDefs));
                    if(!allNodes) {
                        System.err.println("WARNING: Metadata version update of stores goes to all servers, "
                                           + "although this set-metadata oprations only goes to node: ");
                        for(Integer nodeId: nodeIds) {
                            System.err.println(nodeId);
                        }
                    }
                    doMetaUpdateVersionsOnStores(adminClient, oldStoreDefs, newStoreDefs);
                } else if(metaKey.equals(MetadataStore.SLOP_STREAMING_ENABLED_KEY)
                          || metaKey.equals(MetadataStore.PARTITION_STREAMING_ENABLED_KEY)
                          || metaKey.equals(MetadataStore.READONLY_FETCH_ENABLED_KEY)) {
                    doMetaSet(adminClient, nodeIds, metaKey, metaValue);
                } else if(metaKey.equals(KEY_OFFLINE)) {
                    for(Integer nodeId: nodeIds) {
                        adminClient.metadataMgmtOps.setRemoteOfflineState(nodeId,
                                                                          Boolean.parseBoolean(metaValue));
                    }
                } else if(metaKey.equals(MetadataStore.REBALANCING_STEAL_INFO)) {
                    if(!Utils.isReadableFile(metaFile)) {
                        throw new VoldemortException("Rebalancing steal info file path incorrect");
                    }
                    String rebalancingStealInfoJsonString = FileUtils.readFileToString(new File(metaFile));
                    RebalancerState state = RebalancerState.create(rebalancingStealInfoJsonString);
                    doMetaSet(adminClient, nodeIds, metaKey, state.toJsonString());
                } else {
                    throw new VoldemortException("Incorrect metadata key");
                }
            } else if(meta.size() == 4) {
                // set metadata pair cluster.xml, stores.xml
                String clusterFile, storesFile;

                if(meta.get(0).equals(MetadataStore.CLUSTER_KEY)
                   && meta.get(2).equals(MetadataStore.STORES_KEY)) {
                    clusterFile = meta.get(1);
                    storesFile = meta.get(3);
                } else if(meta.get(0).equals(MetadataStore.STORES_KEY)
                          && meta.get(2).equals(MetadataStore.CLUSTER_KEY)) {
                    storesFile = meta.get(1);
                    clusterFile = meta.get(3);
                } else {
                    throw new VoldemortException("meta set-pair keys must be <cluster.xml, stores.xml>");
                }

                clusterFile = clusterFile.replace("~", System.getProperty("user.home"));
                storesFile = storesFile.replace("~", System.getProperty("user.home"));

                ClusterMapper clusterMapper = new ClusterMapper();
                StoreDefinitionsMapper storeDefsMapper = new StoreDefinitionsMapper();

                // original metadata
                Integer nodeIdToGetStoreXMLFrom = nodeIds.iterator().next();
                Versioned<String> storesXML = adminClient.metadataMgmtOps.getRemoteMetadata(nodeIdToGetStoreXMLFrom,
                                                                                            MetadataStore.STORES_KEY);

                List<StoreDefinition> oldStoreDefs = storeDefsMapper.readStoreList(new StringReader(storesXML.getValue()));

                if(!Utils.isReadableFile(clusterFile)) {
                    throw new VoldemortException("Cluster xml file path incorrect");
                }
                Cluster cluster = clusterMapper.readCluster(new File(clusterFile));

                if(!Utils.isReadableFile(storesFile)) {
                    throw new VoldemortException("Stores definition xml file path incorrect");
                }
                List<StoreDefinition> newStoreDefs = storeDefsMapper.readStoreList(new File(storesFile));

                StoreDefinitionUtils.validateSchemasAsNeeded(newStoreDefs);

                doMetaSetPair(adminClient,
                              nodeIds,
                              clusterMapper.writeCluster(cluster),
                              storeDefsMapper.writeStoreList(newStoreDefs));
                if(!allNodes) {
                    System.err.println("WARNING: Metadata version update of stores goes to all servers, "
                                       + "although this set-metadata oprations only goes to node: ");
                    for(Integer nodeId: nodeIds) {
                        System.err.println(nodeId);
                    }
                }
                doMetaUpdateVersionsOnStores(adminClient, oldStoreDefs, newStoreDefs);
            }
        }

        /**
         * Sets <cluster.xml,stores.xml> metadata pair atomically.
         *
         * @param adminClient An instance of AdminClient points to given cluster
         * @param nodeIds Node ids to set metadata
         * @param clusterValue Cluster value to set
         * @param storesValue Stores value to set
         */
        public static void doMetaSetPair(AdminClient adminClient,
                                         List<Integer> nodeIds,
                                         Object clusterValue,
                                         Object storesValue) {
            VectorClock updatedClusterVersion = null;
            VectorClock updatedStoresVersion = null;
            for(Integer nodeId: nodeIds) {
                if(updatedClusterVersion == null && updatedStoresVersion == null) {
                    updatedClusterVersion = (VectorClock) adminClient.metadataMgmtOps.getRemoteMetadata(nodeId,
                                                                                                        MetadataStore.CLUSTER_KEY)
                                                                                     .getVersion();
                    updatedStoresVersion = (VectorClock) adminClient.metadataMgmtOps.getRemoteMetadata(nodeId,
                                                                                                       MetadataStore.STORES_KEY)
                                                                                    .getVersion();
                } else {
                    updatedClusterVersion = updatedClusterVersion.merge((VectorClock) adminClient.metadataMgmtOps.getRemoteMetadata(nodeId,
                                                                                                                                    MetadataStore.CLUSTER_KEY)
                                                                                                                 .getVersion());
                    updatedStoresVersion = updatedStoresVersion.merge((VectorClock) adminClient.metadataMgmtOps.getRemoteMetadata(nodeId,
                                                                                                                                  MetadataStore.STORES_KEY)
                                                                                                               .getVersion());
                }

                // TODO: This will work for now but we should take a step back
                // and
                // think about a uniform clock for the metadata values.
                updatedClusterVersion = updatedClusterVersion.incremented(nodeIds.iterator().next(),
                                                                          System.currentTimeMillis());
                updatedStoresVersion = updatedStoresVersion.incremented(nodeIds.iterator().next(),
                                                                        System.currentTimeMillis());
            }
            adminClient.metadataMgmtOps.updateRemoteMetadataPair(nodeIds,
                                                                 MetadataStore.CLUSTER_KEY,
                                                                 Versioned.value(clusterValue.toString(),
                                                                                 updatedClusterVersion),
                                                                 MetadataStore.STORES_KEY,
                                                                 Versioned.value(storesValue.toString(),
                                                                                 updatedStoresVersion));
        }

        /**
         * Updates metadata versions on stores.
         *
         * @param adminClient An instance of AdminClient points to given cluster
         * @param oldStoreDefs List of old store definitions
         * @param newStoreDefs List of new store definitions
         */
        public static void doMetaUpdateVersionsOnStores(AdminClient adminClient,
                                                        List<StoreDefinition> oldStoreDefs,
                                                        List<StoreDefinition> newStoreDefs) {
            Set<String> storeNamesUnion = new HashSet<String>();
            Map<String, StoreDefinition> oldStoreDefinitionMap = new HashMap<String, StoreDefinition>();
            Map<String, StoreDefinition> newStoreDefinitionMap = new HashMap<String, StoreDefinition>();
            List<String> storesChanged = new ArrayList<String>();
            for(StoreDefinition storeDef: oldStoreDefs) {
                String storeName = storeDef.getName();
                storeNamesUnion.add(storeName);
                oldStoreDefinitionMap.put(storeName, storeDef);
            }
            for(StoreDefinition storeDef: newStoreDefs) {
                String storeName = storeDef.getName();
                storeNamesUnion.add(storeName);
                newStoreDefinitionMap.put(storeName, storeDef);
            }
            for(String storeName: storeNamesUnion) {
                StoreDefinition oldStoreDef = oldStoreDefinitionMap.get(storeName);
                StoreDefinition newStoreDef = newStoreDefinitionMap.get(storeName);
                if(oldStoreDef == null && newStoreDef != null || oldStoreDef != null
                   && newStoreDef == null || oldStoreDef != null && newStoreDef != null
                   && !oldStoreDef.equals(newStoreDef)) {
                    storesChanged.add(storeName);
                }
            }
            System.out.println("Updating metadata version for the following stores: "
                               + storesChanged);
            try {
                adminClient.metadataMgmtOps.updateMetadataversion(storesChanged);
            } catch(Exception e) {
                System.err.println("Error while updating metadata version for the specified store.");
            }
        }
    }

    /**
     * meta sync-version command
     */
    public static class SubCommandMetaSyncVersion extends AbstractAdminCommand {

        /**
         * Initializes parser
         *
         * @return OptionParser object with all available options
         */
        protected static OptionParser getParser() {
            OptionParser parser = new OptionParser();
            // help options
            AdminParserUtils.acceptsHelp(parser);
            // required options
            AdminParserUtils.acceptsNodeSingle(parser);
            AdminParserUtils.acceptsUrl(parser);
            // optional options
            AdminParserUtils.acceptsConfirm(parser);
            return parser;
        }

        /**
         * Prints help menu for command.
         *
         * @param stream PrintStream object for output
         * @throws IOException
         */
        public static void printHelp(PrintStream stream) throws IOException {
            stream.println();
            stream.println("NAME");
            stream.println("  meta sync-version - Synchronize metadata versions across all nodes");
            stream.println();
            stream.println("SYNOPSIS");
            stream.println("  meta sync-version -n <base-node-id> -u <url> [--confirm]");
            stream.println();
            getParser().printHelpOn(stream);
            stream.println();
        }

        /**
         * Parses command-line and synchronizes metadata versions across all
         * nodes.
         *
         * @param args Command-line input
         * @param printHelp Tells whether to print help only or execute command
         *        actually
         * @throws IOException
         *
         */
        public static void executeCommand(String[] args) throws IOException {

            OptionParser parser = getParser();

            // declare parameters
            Integer nodeId = null;
            String url = null;
            Boolean confirm = false;

            // parse command-line input
            OptionSet options = parser.parse(args);
            if(options.has(AdminParserUtils.OPT_HELP)) {
                printHelp(System.out);
                return;
            }

            // check required options and/or conflicting options
            AdminParserUtils.checkRequired(options, AdminParserUtils.OPT_NODE);
            AdminParserUtils.checkRequired(options, AdminParserUtils.OPT_URL);

            // load parameters
            nodeId = (Integer) options.valueOf(AdminParserUtils.OPT_NODE);
            url = (String) options.valueOf(AdminParserUtils.OPT_URL);
            if(options.has(AdminParserUtils.OPT_CONFIRM)) {
                confirm = true;
            }

            // print summary
            System.out.println("Synchronize metadata versions across all nodes");
            System.out.println("Base node id = " + nodeId);
            System.out.println("Location:");
            System.out.println("  bootstrap url = " + url);
            System.out.println("  node = all nodes");

            // execute command
            if(!AdminToolUtils.askConfirm(confirm, "synchronize metadata version"))
                return;

            AdminClient adminClient = AdminToolUtils.getAdminClient(url);

            AdminToolUtils.assertServerNotInRebalancingState(adminClient);

            doMetaSyncVersion(adminClient, nodeId);
        }

        /**
         * Synchronizes metadata versions across all nodes.
         *
         * @param adminClient An instance of AdminClient points to given cluster
         * @param nodeId Base node id to get metadata version from
         *
         */
        public static void doMetaSyncVersion(AdminClient adminClient, Integer nodeId) {
            String valueObject = doMetaGetVersionsForNode(adminClient, nodeId);
            Properties props = new Properties();
            try {
                props.load(new ByteArrayInputStream(valueObject.getBytes()));
                if(props.size() == 0) {
                    System.err.println("The specified node does not have any versions metadata ! Exiting ...");
                    System.exit(-1);
                }
                adminClient.metadataMgmtOps.setMetadataversion(props);
                System.out.println("Metadata versions synchronized successfully.");
            } catch(IOException e) {
                System.err.println("Error while retrieving Metadata versions from node : " + nodeId
                                   + ". Exception = \n");
                e.printStackTrace();
                System.exit(-1);
            }
        }
    }

    /**
     * meta check-version command
     */
    public static class SubCommandMetaCheckVersion extends AbstractAdminCommand {

        /**
         * Initializes parser
         *
         * @return OptionParser object with all available options
         */
        protected static OptionParser getParser() {
            OptionParser parser = new OptionParser();
            // help options
            AdminParserUtils.acceptsHelp(parser);
            // required options
            AdminParserUtils.acceptsUrl(parser);
            return parser;
        }

        /**
         * Prints help menu for command.
         *
         * @param stream PrintStream object for output
         * @throws IOException
         */
        public static void printHelp(PrintStream stream) throws IOException {
            stream.println();
            stream.println("NAME");
            stream.println("  meta check-version - Verify metadata versions on all the cluster nodes");
            stream.println();
            stream.println("SYNOPSIS");
            stream.println("  meta check-version -u <url>");
            stream.println();
            getParser().printHelpOn(stream);
            stream.println();
        }

        /**
         * Parses command-line and verifies metadata versions on all the cluster
         * nodes
         *
         * @param args Command-line input
         * @param printHelp Tells whether to print help only or execute command
         *        actually
         * @throws IOException
         *
         */
        public static void executeCommand(String[] args) throws IOException {

            OptionParser parser = getParser();

            // declare parameters
            String url = null;

            // parse command-line input
            OptionSet options = parser.parse(args);
            if(options.has(AdminParserUtils.OPT_HELP)) {
                printHelp(System.out);
                return;
            }

            // check required options and/or conflicting options
            AdminParserUtils.checkRequired(options, AdminParserUtils.OPT_URL);

            // load parameters
            url = (String) options.valueOf(AdminParserUtils.OPT_URL);

            // execute command
            AdminClient adminClient = AdminToolUtils.getAdminClient(url);

            doMetaCheckVersion(adminClient);
        }

        /**
         * Verifies metadata versions for all the cluster nodes
         *
         * @param adminClient An instance of AdminClient points to given cluster
         *
         */
        public static void doMetaCheckVersion(AdminClient adminClient) {
            Map<Properties, Integer> versionsNodeMap = new HashMap<Properties, Integer>();

            for(Integer nodeId: adminClient.getAdminClientCluster().getNodeIds()) {
                String valueObject = doMetaGetVersionsForNode(adminClient, nodeId);
                Properties props = new Properties();
                try {
                    props.load(new ByteArrayInputStream(valueObject.getBytes()));
                } catch(IOException e) {
                    System.err.println("Error while parsing Metadata versions for node : " + nodeId
                                       + ". Exception = \n");
                    e.printStackTrace();
                    System.exit(-1);
                }
                versionsNodeMap.put(props, nodeId);
            }

            if(versionsNodeMap.keySet().size() > 1) {
                System.err.println("Mismatching versions detected !!!");
                for(Entry<Properties, Integer> entry: versionsNodeMap.entrySet()) {
                    System.out.println("**************************** Node: " + entry.getValue()
                                       + " ****************************");
                    System.out.println(entry.getKey());
                }
            } else {
                System.err.println("All the nodes have the same metadata versions.");
            }
        }
    }

    /**
     * Sets metadata.
     *
     * @param adminClient An instance of AdminClient points to given cluster
     * @param nodeIds Node ids to set metadata
     * @param metaKey Metadata key to set
     * @param metaValue Metadata value to set
     */
    public static void doMetaSet(AdminClient adminClient,
                                 List<Integer> nodeIds,
                                 String metaKey,
                                 String metaValue) {
        VectorClock updatedVersion = null;
        for(Integer nodeId: nodeIds) {
            if(updatedVersion == null) {
                updatedVersion = (VectorClock) adminClient.metadataMgmtOps.getRemoteMetadata(nodeId,
                                                                                             metaKey)
                                                                          .getVersion();
            } else {
                updatedVersion = updatedVersion.merge((VectorClock) adminClient.metadataMgmtOps.getRemoteMetadata(nodeId,
                                                                                                                  metaKey)
                                                                                               .getVersion());
            }
            // Bump up version on first node
            updatedVersion = updatedVersion.incremented(nodeIds.iterator().next(),
                                                        System.currentTimeMillis());
        }
        adminClient.metadataMgmtOps.updateRemoteMetadata(nodeIds,
                                                         metaKey,
                                                         Versioned.value(metaValue, updatedVersion));
    }

    /**
     * Gets metadata versions for a given node.
     *
     * @param adminClient An instance of AdminClient points to given cluster
     * @param nodeId Node id to get metadata version from
     */
    private static String doMetaGetVersionsForNode(AdminClient adminClient, Integer nodeId) {
        List<Integer> partitionIdList = Lists.newArrayList();

        for(Node nodeIter: adminClient.getAdminClientCluster().getNodes()) {
            partitionIdList.addAll(nodeIter.getPartitionIds());
        }

        Iterator<Pair<ByteArray, Versioned<byte[]>>> entriesIterator = adminClient.bulkFetchOps.fetchEntries(nodeId,
                                                                                                             SystemStoreConstants.SystemStoreName.voldsys$_metadata_version_persistence.name(),
                                                                                                             partitionIdList,
                                                                                                             null,
                                                                                                             true);

        Serializer<String> serializer = new StringSerializer("UTF8");
        String keyObject = null;
        String valueObject = null;

        while(entriesIterator.hasNext()) {
            try {
                Pair<ByteArray, Versioned<byte[]>> kvPair = entriesIterator.next();
                byte[] keyBytes = kvPair.getFirst().get();
                byte[] valueBytes = kvPair.getSecond().getValue();
                keyObject = serializer.toObject(keyBytes);
                if(!keyObject.equals(MetadataVersionStoreUtils.VERSIONS_METADATA_KEY)) {
                    continue;
                }
                valueObject = serializer.toObject(valueBytes);
            } catch(Exception e) {
                System.err.println("Error while retrieving Metadata versions from node : " + nodeId
                                   + ". Exception = \n");
                e.printStackTrace();
                System.exit(-1);
            }
        }

        return valueObject;
    }
}
TOP

Related Classes of voldemort.tools.admin.command.AdminCommandMeta$SubCommandMetaCheck

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.