geode-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From dschnei...@apache.org
Subject [16/47] geode git commit: GEODE-3436: Restore refactoring of IndexCommands
Date Thu, 31 Aug 2017 01:25:53 GMT
GEODE-3436: Restore refactoring of IndexCommands

* See initial commit GEODE-3262 (ed293e817e547fb5ecd399bf4ba10d694af51e0a)


Project: http://git-wip-us.apache.org/repos/asf/geode/repo
Commit: http://git-wip-us.apache.org/repos/asf/geode/commit/0dc67f0e
Tree: http://git-wip-us.apache.org/repos/asf/geode/tree/0dc67f0e
Diff: http://git-wip-us.apache.org/repos/asf/geode/diff/0dc67f0e

Branch: refs/heads/feature/GEODE-3543
Commit: 0dc67f0e7798a38afff906aa26e9bb89ab42b53c
Parents: 3bfe7a2
Author: YehEmily <emilyyeh1997@gmail.com>
Authored: Mon Aug 7 12:35:14 2017 -0700
Committer: Jinmei Liao <jiliao@pivotal.io>
Committed: Tue Aug 29 09:27:26 2017 -0700

----------------------------------------------------------------------
 .../commands/ClearDefinedIndexesCommand.java    |  40 ++
 .../commands/CreateDefinedIndexesCommand.java   | 155 +++++
 .../cli/commands/CreateIndexCommand.java        | 197 ++++++
 .../cli/commands/DefineIndexCommand.java        |  95 +++
 .../cli/commands/DestroyIndexCommand.java       | 174 +++++
 .../internal/cli/commands/IndexCommands.java    | 668 -------------------
 .../internal/cli/commands/IndexDefinition.java  |  27 +
 .../internal/cli/commands/ListIndexCommand.java | 158 +++++
 .../functions/CreateDefinedIndexesFunction.java |   3 +-
 .../controllers/IndexCommandsController.java    |  13 +-
 .../cli/commands/IndexCommandsJUnitTest.java    | 223 -------
 .../cli/commands/ListIndexCommandDUnitTest.java |  38 +-
 .../cli/commands/ListIndexCommandJUnitTest.java | 223 +++++++
 .../internal/security/TestCommand.java          |   3 +-
 14 files changed, 1103 insertions(+), 914 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/geode/blob/0dc67f0e/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/ClearDefinedIndexesCommand.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/ClearDefinedIndexesCommand.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/ClearDefinedIndexesCommand.java
new file mode 100644
index 0000000..d12f2c7
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/ClearDefinedIndexesCommand.java
@@ -0,0 +1,40 @@
+/*
+ * 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.geode.management.internal.cli.commands;
+
+import org.springframework.shell.core.annotation.CliCommand;
+
+import org.apache.geode.management.cli.CliMetaData;
+import org.apache.geode.management.cli.Result;
+import org.apache.geode.management.internal.cli.i18n.CliStrings;
+import org.apache.geode.management.internal.cli.result.InfoResultData;
+import org.apache.geode.management.internal.cli.result.ResultBuilder;
+import org.apache.geode.management.internal.security.ResourceOperation;
+import org.apache.geode.security.ResourcePermission;
+
+public class ClearDefinedIndexesCommand implements GfshCommand {
+  @CliCommand(value = CliStrings.CLEAR_DEFINED_INDEXES, help = CliStrings.CLEAR_DEFINED__HELP)
+  @CliMetaData(relatedTopic = {CliStrings.TOPIC_GEODE_REGION, CliStrings.TOPIC_GEODE_DATA})
+  @ResourceOperation(resource = ResourcePermission.Resource.CLUSTER,
+      operation = ResourcePermission.Operation.MANAGE, target = ResourcePermission.Target.QUERY)
+  // TODO : Add optionContext for indexName
+  public Result clearDefinedIndexes() {
+    IndexDefinition.indexDefinitions.clear();
+    InfoResultData infoResult = ResultBuilder.createInfoResultData();
+    infoResult.addLine(CliStrings.CLEAR_DEFINED_INDEX__SUCCESS__MSG);
+    return ResultBuilder.buildResult(infoResult);
+  }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/0dc67f0e/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/CreateDefinedIndexesCommand.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/CreateDefinedIndexesCommand.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/CreateDefinedIndexesCommand.java
new file mode 100644
index 0000000..3487279
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/CreateDefinedIndexesCommand.java
@@ -0,0 +1,155 @@
+/*
+ * 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.geode.management.internal.cli.commands;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.springframework.shell.core.annotation.CliCommand;
+import org.springframework.shell.core.annotation.CliOption;
+
+import org.apache.geode.cache.CacheFactory;
+import org.apache.geode.cache.execute.ResultCollector;
+import org.apache.geode.distributed.DistributedMember;
+import org.apache.geode.management.cli.CliMetaData;
+import org.apache.geode.management.cli.ConverterHint;
+import org.apache.geode.management.cli.Result;
+import org.apache.geode.management.internal.cli.CliUtil;
+import org.apache.geode.management.internal.cli.functions.CliFunctionResult;
+import org.apache.geode.management.internal.cli.functions.CreateDefinedIndexesFunction;
+import org.apache.geode.management.internal.cli.i18n.CliStrings;
+import org.apache.geode.management.internal.cli.result.ErrorResultData;
+import org.apache.geode.management.internal.cli.result.InfoResultData;
+import org.apache.geode.management.internal.cli.result.ResultBuilder;
+import org.apache.geode.management.internal.configuration.domain.XmlEntity;
+import org.apache.geode.management.internal.security.ResourceOperation;
+import org.apache.geode.security.ResourcePermission;
+
+public class CreateDefinedIndexesCommand implements GfshCommand {
+  private static final CreateDefinedIndexesFunction createDefinedIndexesFunction =
+      new CreateDefinedIndexesFunction();
+
+  @CliCommand(value = CliStrings.CREATE_DEFINED_INDEXES, help = CliStrings.CREATE_DEFINED__HELP)
+  @CliMetaData(relatedTopic = {CliStrings.TOPIC_GEODE_REGION, CliStrings.TOPIC_GEODE_DATA})
+  @ResourceOperation(resource = ResourcePermission.Resource.CLUSTER,
+      operation = ResourcePermission.Operation.MANAGE, target = ResourcePermission.Target.QUERY)
+  // TODO : Add optionContext for indexName
+  public Result createDefinedIndexes(
+
+      @CliOption(key = {CliStrings.MEMBER, CliStrings.MEMBERS},
+          optionContext = ConverterHint.MEMBERIDNAME,
+          help = CliStrings.CREATE_DEFINED_INDEXES__MEMBER__HELP) final String[] memberNameOrID,
+
+      @CliOption(key = {CliStrings.GROUP, CliStrings.GROUPS},
+          optionContext = ConverterHint.MEMBERGROUP,
+          help = CliStrings.CREATE_DEFINED_INDEXES__GROUP__HELP) final String[] group) {
+
+    Result result;
+    AtomicReference<XmlEntity> xmlEntity = new AtomicReference<>();
+
+    if (IndexDefinition.indexDefinitions.isEmpty()) {
+      final InfoResultData infoResult = ResultBuilder.createInfoResultData();
+      infoResult.addLine(CliStrings.DEFINE_INDEX__FAILURE__MSG);
+      return ResultBuilder.buildResult(infoResult);
+    }
+
+    try {
+      final Set<DistributedMember> targetMembers = CliUtil.findMembers(group, memberNameOrID);
+
+      if (targetMembers.isEmpty()) {
+        return ResultBuilder.createUserErrorResult(CliStrings.NO_MEMBERS_FOUND_MESSAGE);
+      }
+
+      // TODO PSR: is this safe to remove?
+      CacheFactory.getAnyInstance();
+      final ResultCollector<?, ?> rc = CliUtil.executeFunction(createDefinedIndexesFunction,
+          IndexDefinition.indexDefinitions, targetMembers);
+
+      final List<Object> funcResults = (List<Object>) rc.getResult();
+      final Set<String> successfulMembers = new TreeSet<>();
+      final Map<String, Set<String>> indexOpFailMap = new HashMap<>();
+
+      for (final Object funcResult : funcResults) {
+        if (funcResult instanceof CliFunctionResult) {
+          final CliFunctionResult cliFunctionResult = (CliFunctionResult) funcResult;
+
+          if (cliFunctionResult.isSuccessful()) {
+            successfulMembers.add(cliFunctionResult.getMemberIdOrName());
+
+            if (xmlEntity.get() == null) {
+              xmlEntity.set(cliFunctionResult.getXmlEntity());
+            }
+          } else {
+            final String exceptionMessage = cliFunctionResult.getMessage();
+            Set<String> failedMembers = indexOpFailMap.get(exceptionMessage);
+
+            if (failedMembers == null) {
+              failedMembers = new TreeSet<>();
+            }
+            failedMembers.add(cliFunctionResult.getMemberIdOrName());
+            indexOpFailMap.put(exceptionMessage, failedMembers);
+          }
+        }
+      }
+
+      if (!successfulMembers.isEmpty()) {
+        final InfoResultData infoResult = ResultBuilder.createInfoResultData();
+        infoResult.addLine(CliStrings.CREATE_DEFINED_INDEXES__SUCCESS__MSG);
+
+        int num = 0;
+
+        for (final String memberId : successfulMembers) {
+          ++num;
+          infoResult.addLine(CliStrings
+              .format(CliStrings.CREATE_DEFINED_INDEXES__NUMBER__AND__MEMBER, num, memberId));
+        }
+        result = ResultBuilder.buildResult(infoResult);
+
+      } else {
+        // Group members by the exception thrown.
+        final ErrorResultData erd = ResultBuilder.createErrorResultData();
+
+        final Set<String> exceptionMessages = indexOpFailMap.keySet();
+
+        for (final String exceptionMessage : exceptionMessages) {
+          erd.addLine(exceptionMessage);
+          erd.addLine(CliStrings.CREATE_INDEX__EXCEPTION__OCCURRED__ON);
+          final Set<String> memberIds = indexOpFailMap.get(exceptionMessage);
+
+          int num = 0;
+          for (final String memberId : memberIds) {
+            ++num;
+            erd.addLine(CliStrings.format(CliStrings.CREATE_DEFINED_INDEXES__NUMBER__AND__MEMBER,
+                num, memberId));
+          }
+        }
+        result = ResultBuilder.buildResult(erd);
+      }
+    } catch (Exception e) {
+      result = ResultBuilder.createGemFireErrorResult(e.getMessage());
+    }
+
+    if (xmlEntity.get() != null) {
+      persistClusterConfiguration(result,
+          () -> getSharedConfiguration().addXmlEntity(xmlEntity.get(), group));
+    }
+    return result;
+  }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/0dc67f0e/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/CreateIndexCommand.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/CreateIndexCommand.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/CreateIndexCommand.java
new file mode 100644
index 0000000..5bae92d
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/CreateIndexCommand.java
@@ -0,0 +1,197 @@
+/*
+ * 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.geode.management.internal.cli.commands;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.springframework.shell.core.annotation.CliCommand;
+import org.springframework.shell.core.annotation.CliOption;
+
+import org.apache.geode.cache.CacheFactory;
+import org.apache.geode.cache.Region;
+import org.apache.geode.cache.execute.ResultCollector;
+import org.apache.geode.distributed.DistributedMember;
+import org.apache.geode.internal.lang.StringUtils;
+import org.apache.geode.management.cli.CliMetaData;
+import org.apache.geode.management.cli.ConverterHint;
+import org.apache.geode.management.cli.Result;
+import org.apache.geode.management.internal.cli.CliUtil;
+import org.apache.geode.management.internal.cli.domain.IndexInfo;
+import org.apache.geode.management.internal.cli.functions.CliFunctionResult;
+import org.apache.geode.management.internal.cli.functions.CreateIndexFunction;
+import org.apache.geode.management.internal.cli.i18n.CliStrings;
+import org.apache.geode.management.internal.cli.result.ErrorResultData;
+import org.apache.geode.management.internal.cli.result.InfoResultData;
+import org.apache.geode.management.internal.cli.result.ResultBuilder;
+import org.apache.geode.management.internal.configuration.domain.XmlEntity;
+import org.apache.geode.management.internal.security.ResourceOperation;
+import org.apache.geode.security.ResourcePermission;
+
+public class CreateIndexCommand implements GfshCommand {
+  private static final CreateIndexFunction createIndexFunction = new CreateIndexFunction();
+
+  @CliCommand(value = CliStrings.CREATE_INDEX, help = CliStrings.CREATE_INDEX__HELP)
+  @CliMetaData(relatedTopic = {CliStrings.TOPIC_GEODE_REGION, CliStrings.TOPIC_GEODE_DATA})
+  // TODO : Add optionContext for indexName
+  @ResourceOperation(resource = ResourcePermission.Resource.CLUSTER,
+      operation = ResourcePermission.Operation.MANAGE, target = ResourcePermission.Target.QUERY)
+  public Result createIndex(@CliOption(key = CliStrings.CREATE_INDEX__NAME, mandatory = true,
+      help = CliStrings.CREATE_INDEX__NAME__HELP) final String indexName,
+
+      @CliOption(key = CliStrings.CREATE_INDEX__EXPRESSION, mandatory = true,
+          help = CliStrings.CREATE_INDEX__EXPRESSION__HELP) final String indexedExpression,
+
+      @CliOption(key = CliStrings.CREATE_INDEX__REGION, mandatory = true,
+          optionContext = ConverterHint.REGION_PATH,
+          help = CliStrings.CREATE_INDEX__REGION__HELP) String regionPath,
+
+      @CliOption(key = {CliStrings.MEMBER, CliStrings.MEMBERS},
+          optionContext = ConverterHint.MEMBERIDNAME,
+          help = CliStrings.CREATE_INDEX__MEMBER__HELP) final String[] memberNameOrID,
+
+      @CliOption(key = CliStrings.CREATE_INDEX__TYPE, unspecifiedDefaultValue = "range",
+          optionContext = ConverterHint.INDEX_TYPE,
+          help = CliStrings.CREATE_INDEX__TYPE__HELP) final String indexType,
+
+      @CliOption(key = {CliStrings.GROUP, CliStrings.GROUPS},
+          optionContext = ConverterHint.MEMBERGROUP,
+          help = CliStrings.CREATE_INDEX__GROUP__HELP) final String[] group) {
+
+    Result result;
+    AtomicReference<XmlEntity> xmlEntity = new AtomicReference<>();
+
+    try {
+      // TODO PSR: Is this safe to remove?
+      CacheFactory.getAnyInstance();
+      int idxType;
+
+      // Index type check
+      if ("range".equalsIgnoreCase(indexType)) {
+        idxType = IndexInfo.RANGE_INDEX;
+      } else if ("hash".equalsIgnoreCase(indexType)) {
+        idxType = IndexInfo.HASH_INDEX;
+      } else if ("key".equalsIgnoreCase(indexType)) {
+        idxType = IndexInfo.KEY_INDEX;
+      } else {
+        return ResultBuilder
+            .createUserErrorResult(CliStrings.CREATE_INDEX__INVALID__INDEX__TYPE__MESSAGE);
+      }
+
+      if (indexName == null || indexName.isEmpty()) {
+        return ResultBuilder.createUserErrorResult(CliStrings.CREATE_INDEX__INVALID__INDEX__NAME);
+      }
+
+      if (indexedExpression == null || indexedExpression.isEmpty()) {
+        return ResultBuilder.createUserErrorResult(CliStrings.CREATE_INDEX__INVALID__EXPRESSION);
+      }
+
+      if (StringUtils.isBlank(regionPath) || regionPath.equals(Region.SEPARATOR)) {
+        return ResultBuilder.createUserErrorResult(CliStrings.CREATE_INDEX__INVALID__REGIONPATH);
+      }
+
+      if (!regionPath.startsWith(Region.SEPARATOR)) {
+        regionPath = Region.SEPARATOR + regionPath;
+      }
+
+      IndexInfo indexInfo = new IndexInfo(indexName, indexedExpression, regionPath, idxType);
+      final Set<DistributedMember> targetMembers = CliUtil.findMembers(group, memberNameOrID);
+
+      if (targetMembers.isEmpty()) {
+        return ResultBuilder.createUserErrorResult(CliStrings.NO_MEMBERS_FOUND_MESSAGE);
+      }
+
+      final ResultCollector<?, ?> rc =
+          CliUtil.executeFunction(createIndexFunction, indexInfo, targetMembers);
+
+      final List<Object> funcResults = (List<Object>) rc.getResult();
+      final Set<String> successfulMembers = new TreeSet<>();
+      final Map<String, Set<String>> indexOpFailMap = new HashMap<>();
+
+      for (final Object funcResult : funcResults) {
+        if (funcResult instanceof CliFunctionResult) {
+          final CliFunctionResult cliFunctionResult = (CliFunctionResult) funcResult;
+
+          if (cliFunctionResult.isSuccessful()) {
+            successfulMembers.add(cliFunctionResult.getMemberIdOrName());
+
+            if (xmlEntity.get() == null) {
+              xmlEntity.set(cliFunctionResult.getXmlEntity());
+            }
+          } else {
+            final String exceptionMessage = cliFunctionResult.getMessage();
+            Set<String> failedMembers = indexOpFailMap.get(exceptionMessage);
+
+            if (failedMembers == null) {
+              failedMembers = new TreeSet<>();
+            }
+            failedMembers.add(cliFunctionResult.getMemberIdOrName());
+            indexOpFailMap.put(exceptionMessage, failedMembers);
+          }
+        }
+      }
+
+      if (!successfulMembers.isEmpty()) {
+        final InfoResultData infoResult = ResultBuilder.createInfoResultData();
+        infoResult.addLine(CliStrings.CREATE_INDEX__SUCCESS__MSG);
+        infoResult.addLine(CliStrings.format(CliStrings.CREATE_INDEX__NAME__MSG, indexName));
+        infoResult.addLine(
+            CliStrings.format(CliStrings.CREATE_INDEX__EXPRESSION__MSG, indexedExpression));
+        infoResult.addLine(CliStrings.format(CliStrings.CREATE_INDEX__REGIONPATH__MSG, regionPath));
+        infoResult.addLine(CliStrings.CREATE_INDEX__MEMBER__MSG);
+
+        int num = 0;
+
+        for (final String memberId : successfulMembers) {
+          ++num;
+          infoResult.addLine(
+              CliStrings.format(CliStrings.CREATE_INDEX__NUMBER__AND__MEMBER, num, memberId));
+        }
+        result = ResultBuilder.buildResult(infoResult);
+
+      } else {
+        // Group members by the exception thrown.
+        final ErrorResultData erd = ResultBuilder.createErrorResultData();
+        erd.addLine(CliStrings.format(CliStrings.CREATE_INDEX__FAILURE__MSG, indexName));
+        final Set<String> exceptionMessages = indexOpFailMap.keySet();
+
+        for (final String exceptionMessage : exceptionMessages) {
+          erd.addLine(exceptionMessage);
+          erd.addLine(CliStrings.CREATE_INDEX__EXCEPTION__OCCURRED__ON);
+          final Set<String> memberIds = indexOpFailMap.get(exceptionMessage);
+          int num = 0;
+          for (final String memberId : memberIds) {
+            ++num;
+            erd.addLine(
+                CliStrings.format(CliStrings.CREATE_INDEX__NUMBER__AND__MEMBER, num, memberId));
+          }
+        }
+        result = ResultBuilder.buildResult(erd);
+      }
+    } catch (Exception e) {
+      result = ResultBuilder.createGemFireErrorResult(e.getMessage());
+    }
+    if (xmlEntity.get() != null) {
+      persistClusterConfiguration(result,
+          () -> getSharedConfiguration().addXmlEntity(xmlEntity.get(), group));
+    }
+    return result;
+  }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/0dc67f0e/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/DefineIndexCommand.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/DefineIndexCommand.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/DefineIndexCommand.java
new file mode 100644
index 0000000..1102cd8
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/DefineIndexCommand.java
@@ -0,0 +1,95 @@
+/*
+ * 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.geode.management.internal.cli.commands;
+
+import org.springframework.shell.core.annotation.CliCommand;
+import org.springframework.shell.core.annotation.CliOption;
+
+import org.apache.geode.cache.Region;
+import org.apache.geode.internal.lang.StringUtils;
+import org.apache.geode.management.cli.CliMetaData;
+import org.apache.geode.management.cli.ConverterHint;
+import org.apache.geode.management.cli.Result;
+import org.apache.geode.management.internal.cli.domain.IndexInfo;
+import org.apache.geode.management.internal.cli.i18n.CliStrings;
+import org.apache.geode.management.internal.cli.result.InfoResultData;
+import org.apache.geode.management.internal.cli.result.ResultBuilder;
+import org.apache.geode.management.internal.security.ResourceOperation;
+import org.apache.geode.security.ResourcePermission;
+
+public class DefineIndexCommand implements GfshCommand {
+  @CliCommand(value = CliStrings.DEFINE_INDEX, help = CliStrings.DEFINE_INDEX__HELP)
+  @CliMetaData(relatedTopic = {CliStrings.TOPIC_GEODE_REGION, CliStrings.TOPIC_GEODE_DATA})
+  // TODO : Add optionContext for indexName
+  @ResourceOperation(resource = ResourcePermission.Resource.CLUSTER,
+      operation = ResourcePermission.Operation.MANAGE, target = ResourcePermission.Target.QUERY)
+  public Result defineIndex(
+      @CliOption(key = CliStrings.DEFINE_INDEX_NAME, mandatory = true,
+          help = CliStrings.DEFINE_INDEX__HELP) final String indexName,
+      @CliOption(key = CliStrings.DEFINE_INDEX__EXPRESSION, mandatory = true,
+          help = CliStrings.DEFINE_INDEX__EXPRESSION__HELP) final String indexedExpression,
+      @CliOption(key = CliStrings.DEFINE_INDEX__REGION, mandatory = true,
+          optionContext = ConverterHint.REGION_PATH,
+          help = CliStrings.DEFINE_INDEX__REGION__HELP) String regionPath,
+      @CliOption(key = CliStrings.DEFINE_INDEX__TYPE, unspecifiedDefaultValue = "range",
+          optionContext = ConverterHint.INDEX_TYPE,
+          help = CliStrings.DEFINE_INDEX__TYPE__HELP) final String indexType) {
+
+    Result result;
+    int idxType;
+
+    // Index type check
+    if ("range".equalsIgnoreCase(indexType)) {
+      idxType = IndexInfo.RANGE_INDEX;
+    } else if ("hash".equalsIgnoreCase(indexType)) {
+      idxType = IndexInfo.HASH_INDEX;
+    } else if ("key".equalsIgnoreCase(indexType)) {
+      idxType = IndexInfo.KEY_INDEX;
+    } else {
+      return ResultBuilder
+          .createUserErrorResult(CliStrings.DEFINE_INDEX__INVALID__INDEX__TYPE__MESSAGE);
+    }
+
+    if (indexName == null || indexName.isEmpty()) {
+      return ResultBuilder.createUserErrorResult(CliStrings.DEFINE_INDEX__INVALID__INDEX__NAME);
+    }
+
+    if (indexedExpression == null || indexedExpression.isEmpty()) {
+      return ResultBuilder.createUserErrorResult(CliStrings.DEFINE_INDEX__INVALID__EXPRESSION);
+    }
+
+    if (StringUtils.isBlank(regionPath) || regionPath.equals(Region.SEPARATOR)) {
+      return ResultBuilder.createUserErrorResult(CliStrings.DEFINE_INDEX__INVALID__REGIONPATH);
+    }
+
+    if (!regionPath.startsWith(Region.SEPARATOR)) {
+      regionPath = Region.SEPARATOR + regionPath;
+    }
+
+    IndexInfo indexInfo = new IndexInfo(indexName, indexedExpression, regionPath, idxType);
+    IndexDefinition.indexDefinitions.add(indexInfo);
+
+    final InfoResultData infoResult = ResultBuilder.createInfoResultData();
+    infoResult.addLine(CliStrings.DEFINE_INDEX__SUCCESS__MSG);
+    infoResult.addLine(CliStrings.format(CliStrings.DEFINE_INDEX__NAME__MSG, indexName));
+    infoResult
+        .addLine(CliStrings.format(CliStrings.DEFINE_INDEX__EXPRESSION__MSG, indexedExpression));
+    infoResult.addLine(CliStrings.format(CliStrings.DEFINE_INDEX__REGIONPATH__MSG, regionPath));
+    result = ResultBuilder.buildResult(infoResult);
+
+    return result;
+  }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/0dc67f0e/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/DestroyIndexCommand.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/DestroyIndexCommand.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/DestroyIndexCommand.java
new file mode 100644
index 0000000..c9f2b64
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/DestroyIndexCommand.java
@@ -0,0 +1,174 @@
+/*
+ * 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.geode.management.internal.cli.commands;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.apache.commons.lang.ArrayUtils;
+import org.springframework.shell.core.annotation.CliCommand;
+import org.springframework.shell.core.annotation.CliOption;
+
+import org.apache.geode.cache.Cache;
+import org.apache.geode.cache.CacheFactory;
+import org.apache.geode.cache.execute.ResultCollector;
+import org.apache.geode.distributed.DistributedMember;
+import org.apache.geode.internal.lang.StringUtils;
+import org.apache.geode.management.cli.CliMetaData;
+import org.apache.geode.management.cli.ConverterHint;
+import org.apache.geode.management.cli.Result;
+import org.apache.geode.management.internal.cli.CliUtil;
+import org.apache.geode.management.internal.cli.domain.IndexInfo;
+import org.apache.geode.management.internal.cli.functions.CliFunctionResult;
+import org.apache.geode.management.internal.cli.functions.DestroyIndexFunction;
+import org.apache.geode.management.internal.cli.i18n.CliStrings;
+import org.apache.geode.management.internal.cli.result.ErrorResultData;
+import org.apache.geode.management.internal.cli.result.InfoResultData;
+import org.apache.geode.management.internal.cli.result.ResultBuilder;
+import org.apache.geode.management.internal.configuration.domain.XmlEntity;
+import org.apache.geode.management.internal.security.ResourceOperation;
+import org.apache.geode.security.ResourcePermission;
+
+public class DestroyIndexCommand implements GfshCommand {
+  private static final DestroyIndexFunction destroyIndexFunction = new DestroyIndexFunction();
+
+  @CliCommand(value = CliStrings.DESTROY_INDEX, help = CliStrings.DESTROY_INDEX__HELP)
+  @CliMetaData(relatedTopic = {CliStrings.TOPIC_GEODE_REGION, CliStrings.TOPIC_GEODE_DATA})
+  @ResourceOperation(resource = ResourcePermission.Resource.CLUSTER,
+      operation = ResourcePermission.Operation.MANAGE, target = ResourcePermission.Target.QUERY)
+  public Result destroyIndex(
+      @CliOption(key = CliStrings.DESTROY_INDEX__NAME, unspecifiedDefaultValue = "",
+          help = CliStrings.DESTROY_INDEX__NAME__HELP) final String indexName,
+
+      @CliOption(key = CliStrings.DESTROY_INDEX__REGION, optionContext = ConverterHint.REGION_PATH,
+          help = CliStrings.DESTROY_INDEX__REGION__HELP) final String regionPath,
+
+      @CliOption(key = {CliStrings.MEMBER, CliStrings.MEMBERS},
+          optionContext = ConverterHint.MEMBERIDNAME,
+          help = CliStrings.DESTROY_INDEX__MEMBER__HELP) final String[] memberNameOrID,
+
+      @CliOption(key = {CliStrings.GROUP, CliStrings.GROUPS},
+          optionContext = ConverterHint.MEMBERGROUP,
+          help = CliStrings.DESTROY_INDEX__GROUP__HELP) final String[] group) {
+
+    Result result;
+
+    if (StringUtils.isBlank(indexName) && StringUtils.isBlank(regionPath)
+        && ArrayUtils.isEmpty(group) && ArrayUtils.isEmpty(memberNameOrID)) {
+      return ResultBuilder.createUserErrorResult(
+          CliStrings.format(CliStrings.PROVIDE_ATLEAST_ONE_OPTION, CliStrings.DESTROY_INDEX));
+    }
+
+    final Cache cache = CacheFactory.getAnyInstance();
+    String regionName = null;
+    if (regionPath != null) {
+      regionName = regionPath.startsWith("/") ? regionPath.substring(1) : regionPath;
+    }
+    IndexInfo indexInfo = new IndexInfo(indexName, regionName);
+    Set<DistributedMember> targetMembers = CliUtil.findMembers(group, memberNameOrID);
+
+    if (targetMembers.isEmpty()) {
+      return ResultBuilder.createUserErrorResult(CliStrings.NO_MEMBERS_FOUND_MESSAGE);
+    }
+
+    ResultCollector rc = CliUtil.executeFunction(destroyIndexFunction, indexInfo, targetMembers);
+    List<Object> funcResults = (List<Object>) rc.getResult();
+
+    Set<String> successfulMembers = new TreeSet<>();
+    Map<String, Set<String>> indexOpFailMap = new HashMap<>();
+
+    AtomicReference<XmlEntity> xmlEntity = new AtomicReference<>();
+    for (Object funcResult : funcResults) {
+      if (!(funcResult instanceof CliFunctionResult)) {
+        continue;
+      }
+      CliFunctionResult cliFunctionResult = (CliFunctionResult) funcResult;
+
+      if (cliFunctionResult.isSuccessful()) {
+        successfulMembers.add(cliFunctionResult.getMemberIdOrName());
+        if (xmlEntity.get() == null) {
+          xmlEntity.set(cliFunctionResult.getXmlEntity());
+        }
+      } else {
+        String exceptionMessage = cliFunctionResult.getMessage();
+        Set<String> failedMembers = indexOpFailMap.get(exceptionMessage);
+
+        if (failedMembers == null) {
+          failedMembers = new TreeSet<>();
+        }
+        failedMembers.add(cliFunctionResult.getMemberIdOrName());
+        indexOpFailMap.put(exceptionMessage, failedMembers);
+      }
+    }
+    if (!successfulMembers.isEmpty()) {
+      InfoResultData infoResult = ResultBuilder.createInfoResultData();
+      if (StringUtils.isNotBlank(indexName)) {
+        if (StringUtils.isNotBlank(regionPath)) {
+          infoResult.addLine(CliStrings.format(CliStrings.DESTROY_INDEX__ON__REGION__SUCCESS__MSG,
+              indexName, regionPath));
+        } else {
+          infoResult.addLine(CliStrings.format(CliStrings.DESTROY_INDEX__SUCCESS__MSG, indexName));
+        }
+      } else {
+        if (StringUtils.isNotBlank(regionPath)) {
+          infoResult.addLine(CliStrings
+              .format(CliStrings.DESTROY_INDEX__ON__REGION__ONLY__SUCCESS__MSG, regionPath));
+        } else {
+          infoResult.addLine(CliStrings.DESTROY_INDEX__ON__MEMBERS__ONLY__SUCCESS__MSG);
+        }
+      }
+      int num = 0;
+      for (String memberId : successfulMembers) {
+        infoResult.addLine(CliStrings.format(
+            CliStrings.format(CliStrings.DESTROY_INDEX__NUMBER__AND__MEMBER, ++num, memberId)));
+      }
+      result = ResultBuilder.buildResult(infoResult);
+    } else {
+      ErrorResultData erd = ResultBuilder.createErrorResultData();
+      if (StringUtils.isNotBlank(indexName)) {
+        erd.addLine(CliStrings.format(CliStrings.DESTROY_INDEX__FAILURE__MSG, indexName));
+      } else {
+        erd.addLine("Indexes could not be destroyed for following reasons");
+      }
+
+      Set<String> exceptionMessages = indexOpFailMap.keySet();
+
+      for (String exceptionMessage : exceptionMessages) {
+        erd.addLine(CliStrings.format(CliStrings.DESTROY_INDEX__REASON_MESSAGE, exceptionMessage));
+        erd.addLine(CliStrings.DESTROY_INDEX__EXCEPTION__OCCURRED__ON);
+
+        Set<String> memberIds = indexOpFailMap.get(exceptionMessage);
+        int num = 0;
+
+        for (String memberId : memberIds) {
+          erd.addLine(CliStrings.format(
+              CliStrings.format(CliStrings.DESTROY_INDEX__NUMBER__AND__MEMBER, ++num, memberId)));
+        }
+        erd.addLine("");
+      }
+      result = ResultBuilder.buildResult(erd);
+    }
+    if (xmlEntity.get() != null) {
+      persistClusterConfiguration(result,
+          () -> getSharedConfiguration().deleteXmlEntity(xmlEntity.get(), group));
+    }
+    return result;
+  }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/0dc67f0e/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/IndexCommands.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/IndexCommands.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/IndexCommands.java
deleted file mode 100644
index 4734b4c..0000000
--- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/IndexCommands.java
+++ /dev/null
@@ -1,668 +0,0 @@
-/*
- * 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.geode.management.internal.cli.commands;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeSet;
-import java.util.concurrent.atomic.AtomicReference;
-
-import org.apache.commons.lang.ArrayUtils;
-import org.springframework.shell.core.annotation.CliCommand;
-import org.springframework.shell.core.annotation.CliOption;
-
-import org.apache.geode.SystemFailure;
-import org.apache.geode.cache.Cache;
-import org.apache.geode.cache.CacheFactory;
-import org.apache.geode.cache.Region;
-import org.apache.geode.cache.execute.Execution;
-import org.apache.geode.cache.execute.FunctionInvocationTargetException;
-import org.apache.geode.cache.execute.ResultCollector;
-import org.apache.geode.distributed.DistributedMember;
-import org.apache.geode.internal.cache.execute.AbstractExecution;
-import org.apache.geode.internal.lang.StringUtils;
-import org.apache.geode.management.cli.CliMetaData;
-import org.apache.geode.management.cli.ConverterHint;
-import org.apache.geode.management.cli.Result;
-import org.apache.geode.management.internal.cli.CliUtil;
-import org.apache.geode.management.internal.cli.domain.IndexDetails;
-import org.apache.geode.management.internal.cli.domain.IndexDetails.IndexStatisticsDetails;
-import org.apache.geode.management.internal.cli.domain.IndexInfo;
-import org.apache.geode.management.internal.cli.functions.CliFunctionResult;
-import org.apache.geode.management.internal.cli.functions.CreateDefinedIndexesFunction;
-import org.apache.geode.management.internal.cli.functions.CreateIndexFunction;
-import org.apache.geode.management.internal.cli.functions.DestroyIndexFunction;
-import org.apache.geode.management.internal.cli.functions.ListIndexFunction;
-import org.apache.geode.management.internal.cli.i18n.CliStrings;
-import org.apache.geode.management.internal.cli.result.ErrorResultData;
-import org.apache.geode.management.internal.cli.result.InfoResultData;
-import org.apache.geode.management.internal.cli.result.ResultBuilder;
-import org.apache.geode.management.internal.cli.result.TabularResultData;
-import org.apache.geode.management.internal.configuration.domain.XmlEntity;
-import org.apache.geode.management.internal.security.ResourceOperation;
-import org.apache.geode.security.ResourcePermission.Operation;
-import org.apache.geode.security.ResourcePermission.Resource;
-import org.apache.geode.security.ResourcePermission.Target;
-
-/**
- * The IndexCommands class encapsulates all GemFire shell (Gfsh) commands related to indexes defined
- * in GemFire.
- *
- * @see GfshCommand
- * @see org.apache.geode.management.internal.cli.domain.IndexDetails
- * @see org.apache.geode.management.internal.cli.functions.ListIndexFunction
- * @since GemFire 7.0
- */
-@SuppressWarnings("unused")
-public class IndexCommands implements GfshCommand {
-
-  private static final CreateIndexFunction createIndexFunction = new CreateIndexFunction();
-  private static final DestroyIndexFunction destroyIndexFunction = new DestroyIndexFunction();
-  private static final CreateDefinedIndexesFunction createDefinedIndexesFunction =
-      new CreateDefinedIndexesFunction();
-  private static final Set<IndexInfo> indexDefinitions =
-      Collections.synchronizedSet(new HashSet<IndexInfo>());
-
-  @CliCommand(value = CliStrings.LIST_INDEX, help = CliStrings.LIST_INDEX__HELP)
-  @CliMetaData(relatedTopic = {CliStrings.TOPIC_GEODE_REGION, CliStrings.TOPIC_GEODE_DATA})
-  @ResourceOperation(resource = Resource.CLUSTER, operation = Operation.READ, target = Target.QUERY)
-  public Result listIndex(@CliOption(key = CliStrings.LIST_INDEX__STATS,
-      specifiedDefaultValue = "true", unspecifiedDefaultValue = "false",
-      help = CliStrings.LIST_INDEX__STATS__HELP) final boolean showStats) {
-    try {
-      return toTabularResult(getIndexListing(), showStats);
-    } catch (FunctionInvocationTargetException ignore) {
-      return ResultBuilder.createGemFireErrorResult(
-          CliStrings.format(CliStrings.COULD_NOT_EXECUTE_COMMAND_TRY_AGAIN, CliStrings.LIST_INDEX));
-    } catch (VirtualMachineError e) {
-      SystemFailure.initiateFailure(e);
-      throw e;
-    } catch (Throwable t) {
-      SystemFailure.checkFailure();
-      getCache().getLogger().error(t);
-      return ResultBuilder.createGemFireErrorResult(
-          String.format(CliStrings.LIST_INDEX__ERROR_MESSAGE, toString(t, isDebugging())));
-    }
-  }
-
-  @SuppressWarnings("unchecked")
-  protected List<IndexDetails> getIndexListing() {
-    final Execution functionExecutor = getMembersFunctionExecutor(getMembers(getCache()));
-
-    if (functionExecutor instanceof AbstractExecution) {
-      ((AbstractExecution) functionExecutor).setIgnoreDepartedMembers(true);
-    }
-
-    final ResultCollector<?, ?> resultsCollector =
-        functionExecutor.execute(new ListIndexFunction());
-
-    final List<?> results = (List<?>) resultsCollector.getResult();
-    final List<IndexDetails> indexDetailsList = new ArrayList<>(results.size());
-
-    for (Object result : results) {
-      if (result instanceof Set) { // ignore FunctionInvocationTargetExceptions and other Exceptions
-        indexDetailsList.addAll((Set<IndexDetails>) result);
-      }
-    }
-
-    Collections.sort(indexDetailsList);
-
-    return indexDetailsList;
-  }
-
-  protected Result toTabularResult(final List<IndexDetails> indexDetailsList,
-      final boolean showStats) {
-    if (!indexDetailsList.isEmpty()) {
-      final TabularResultData indexData = ResultBuilder.createTabularResultData();
-
-      for (final IndexDetails indexDetails : indexDetailsList) {
-        indexData.accumulate("Member Name",
-            StringUtils.defaultString(indexDetails.getMemberName()));
-        indexData.accumulate("Member ID", indexDetails.getMemberId());
-        indexData.accumulate("Region Path", indexDetails.getRegionPath());
-        indexData.accumulate("Name", indexDetails.getIndexName());
-        indexData.accumulate("Type", StringUtils.defaultString(indexDetails.getIndexType()));
-        indexData.accumulate("Indexed Expression", indexDetails.getIndexedExpression());
-        indexData.accumulate("From Clause", indexDetails.getFromClause());
-
-        if (showStats) {
-          final IndexStatisticsDetailsAdapter adapter =
-              new IndexStatisticsDetailsAdapter(indexDetails.getIndexStatisticsDetails());
-
-          indexData.accumulate("Uses", adapter.getTotalUses());
-          indexData.accumulate("Updates", adapter.getNumberOfUpdates());
-          indexData.accumulate("Update Time", adapter.getTotalUpdateTime());
-          indexData.accumulate("Keys", adapter.getNumberOfKeys());
-          indexData.accumulate("Values", adapter.getNumberOfValues());
-        }
-      }
-
-      return ResultBuilder.buildResult(indexData);
-    } else {
-      return ResultBuilder.createInfoResult(CliStrings.LIST_INDEX__INDEXES_NOT_FOUND_MESSAGE);
-    }
-  }
-
-  @CliCommand(value = CliStrings.CREATE_INDEX, help = CliStrings.CREATE_INDEX__HELP)
-  @CliMetaData(relatedTopic = {CliStrings.TOPIC_GEODE_REGION, CliStrings.TOPIC_GEODE_DATA})
-  // TODO : Add optionContext for indexName
-  @ResourceOperation(resource = Resource.CLUSTER, operation = Operation.MANAGE,
-      target = Target.QUERY)
-  public Result createIndex(@CliOption(key = CliStrings.CREATE_INDEX__NAME, mandatory = true,
-      help = CliStrings.CREATE_INDEX__NAME__HELP) final String indexName,
-
-      @CliOption(key = CliStrings.CREATE_INDEX__EXPRESSION, mandatory = true,
-          help = CliStrings.CREATE_INDEX__EXPRESSION__HELP) final String indexedExpression,
-
-      @CliOption(key = CliStrings.CREATE_INDEX__REGION, mandatory = true,
-          optionContext = ConverterHint.REGION_PATH,
-          help = CliStrings.CREATE_INDEX__REGION__HELP) String regionPath,
-
-      @CliOption(key = {CliStrings.MEMBER, CliStrings.MEMBERS},
-          optionContext = ConverterHint.MEMBERIDNAME,
-          help = CliStrings.CREATE_INDEX__MEMBER__HELP) final String[] memberNameOrID,
-
-      @CliOption(key = CliStrings.CREATE_INDEX__TYPE, unspecifiedDefaultValue = "range",
-          optionContext = ConverterHint.INDEX_TYPE,
-          help = CliStrings.CREATE_INDEX__TYPE__HELP) final String indexType,
-
-      @CliOption(key = {CliStrings.GROUP, CliStrings.GROUPS},
-          optionContext = ConverterHint.MEMBERGROUP,
-          help = CliStrings.CREATE_INDEX__GROUP__HELP) final String[] group) {
-
-    Result result;
-    AtomicReference<XmlEntity> xmlEntity = new AtomicReference<>();
-
-    try {
-      final Cache cache = CacheFactory.getAnyInstance();
-
-      int idxType;
-
-      // Index type check
-      if ("range".equalsIgnoreCase(indexType)) {
-        idxType = IndexInfo.RANGE_INDEX;
-      } else if ("hash".equalsIgnoreCase(indexType)) {
-        idxType = IndexInfo.HASH_INDEX;
-      } else if ("key".equalsIgnoreCase(indexType)) {
-        idxType = IndexInfo.KEY_INDEX;
-      } else {
-        return ResultBuilder
-            .createUserErrorResult(CliStrings.CREATE_INDEX__INVALID__INDEX__TYPE__MESSAGE);
-      }
-
-      if (indexName == null || indexName.isEmpty()) {
-        return ResultBuilder.createUserErrorResult(CliStrings.CREATE_INDEX__INVALID__INDEX__NAME);
-      }
-
-      if (indexedExpression == null || indexedExpression.isEmpty()) {
-        return ResultBuilder.createUserErrorResult(CliStrings.CREATE_INDEX__INVALID__EXPRESSION);
-      }
-
-      if (StringUtils.isBlank(regionPath) || regionPath.equals(Region.SEPARATOR)) {
-        return ResultBuilder.createUserErrorResult(CliStrings.CREATE_INDEX__INVALID__REGIONPATH);
-      }
-
-      if (!regionPath.startsWith(Region.SEPARATOR)) {
-        regionPath = Region.SEPARATOR + regionPath;
-      }
-
-      IndexInfo indexInfo = new IndexInfo(indexName, indexedExpression, regionPath, idxType);
-
-      final Set<DistributedMember> targetMembers = CliUtil.findMembers(group, memberNameOrID);
-
-      if (targetMembers.isEmpty()) {
-        return ResultBuilder.createUserErrorResult(CliStrings.NO_MEMBERS_FOUND_MESSAGE);
-      }
-
-      final ResultCollector<?, ?> rc =
-          CliUtil.executeFunction(createIndexFunction, indexInfo, targetMembers);
-
-      final List<Object> funcResults = (List<Object>) rc.getResult();
-      final Set<String> successfulMembers = new TreeSet<>();
-      final Map<String, Set<String>> indexOpFailMap = new HashMap<>();
-
-      for (final Object funcResult : funcResults) {
-        if (funcResult instanceof CliFunctionResult) {
-          final CliFunctionResult cliFunctionResult = (CliFunctionResult) funcResult;
-
-          if (cliFunctionResult.isSuccessful()) {
-            successfulMembers.add(cliFunctionResult.getMemberIdOrName());
-
-            if (xmlEntity.get() == null) {
-              xmlEntity.set(cliFunctionResult.getXmlEntity());
-            }
-          } else {
-            final String exceptionMessage = cliFunctionResult.getMessage();
-            Set<String> failedMembers = indexOpFailMap.get(exceptionMessage);
-
-            if (failedMembers == null) {
-              failedMembers = new TreeSet<>();
-            }
-            failedMembers.add(cliFunctionResult.getMemberIdOrName());
-            indexOpFailMap.put(exceptionMessage, failedMembers);
-          }
-        }
-      }
-
-      if (!successfulMembers.isEmpty()) {
-
-        final InfoResultData infoResult = ResultBuilder.createInfoResultData();
-        infoResult.addLine(CliStrings.CREATE_INDEX__SUCCESS__MSG);
-        infoResult.addLine(CliStrings.format(CliStrings.CREATE_INDEX__NAME__MSG, indexName));
-        infoResult.addLine(
-            CliStrings.format(CliStrings.CREATE_INDEX__EXPRESSION__MSG, indexedExpression));
-        infoResult.addLine(CliStrings.format(CliStrings.CREATE_INDEX__REGIONPATH__MSG, regionPath));
-        infoResult.addLine(CliStrings.CREATE_INDEX__MEMBER__MSG);
-
-        int num = 0;
-
-        for (final String memberId : successfulMembers) {
-          ++num;
-          infoResult.addLine(
-              CliStrings.format(CliStrings.CREATE_INDEX__NUMBER__AND__MEMBER, num, memberId));
-        }
-        result = ResultBuilder.buildResult(infoResult);
-
-      } else {
-        // Group members by the exception thrown.
-        final ErrorResultData erd = ResultBuilder.createErrorResultData();
-        erd.addLine(CliStrings.format(CliStrings.CREATE_INDEX__FAILURE__MSG, indexName));
-
-        final Set<String> exceptionMessages = indexOpFailMap.keySet();
-
-        for (final String exceptionMessage : exceptionMessages) {
-          erd.addLine(exceptionMessage);
-          erd.addLine(CliStrings.CREATE_INDEX__EXCEPTION__OCCURRED__ON);
-          final Set<String> memberIds = indexOpFailMap.get(exceptionMessage);
-
-          int num = 0;
-          for (final String memberId : memberIds) {
-            ++num;
-            erd.addLine(
-                CliStrings.format(CliStrings.CREATE_INDEX__NUMBER__AND__MEMBER, num, memberId));
-          }
-        }
-        result = ResultBuilder.buildResult(erd);
-      }
-    } catch (Exception e) {
-      result = ResultBuilder.createGemFireErrorResult(e.getMessage());
-    }
-
-    if (xmlEntity.get() != null) {
-      persistClusterConfiguration(result,
-          () -> getSharedConfiguration().addXmlEntity(xmlEntity.get(), group));
-    }
-
-    return result;
-  }
-
-  @CliCommand(value = CliStrings.DESTROY_INDEX, help = CliStrings.DESTROY_INDEX__HELP)
-  @CliMetaData(relatedTopic = {CliStrings.TOPIC_GEODE_REGION, CliStrings.TOPIC_GEODE_DATA})
-  @ResourceOperation(resource = Resource.CLUSTER, operation = Operation.MANAGE,
-      target = Target.QUERY)
-  public Result destroyIndex(
-      @CliOption(key = CliStrings.DESTROY_INDEX__NAME, unspecifiedDefaultValue = "",
-          help = CliStrings.DESTROY_INDEX__NAME__HELP) final String indexName,
-
-      @CliOption(key = CliStrings.DESTROY_INDEX__REGION, optionContext = ConverterHint.REGION_PATH,
-          help = CliStrings.DESTROY_INDEX__REGION__HELP) final String regionPath,
-
-      @CliOption(key = {CliStrings.MEMBER, CliStrings.MEMBERS},
-          optionContext = ConverterHint.MEMBERIDNAME,
-          help = CliStrings.DESTROY_INDEX__MEMBER__HELP) final String[] memberNameOrID,
-
-      @CliOption(key = {CliStrings.GROUP, CliStrings.GROUPS},
-          optionContext = ConverterHint.MEMBERGROUP,
-          help = CliStrings.DESTROY_INDEX__GROUP__HELP) final String[] group) {
-
-    Result result;
-
-    if (StringUtils.isBlank(indexName) && StringUtils.isBlank(regionPath)
-        && ArrayUtils.isEmpty(group) && ArrayUtils.isEmpty(memberNameOrID)) {
-      return ResultBuilder.createUserErrorResult(
-          CliStrings.format(CliStrings.PROVIDE_ATLEAST_ONE_OPTION, CliStrings.DESTROY_INDEX));
-    }
-
-    final Cache cache = CacheFactory.getAnyInstance();
-    String regionName = null;
-    if (regionPath != null) {
-      regionName = regionPath.startsWith("/") ? regionPath.substring(1) : regionPath;
-    }
-    IndexInfo indexInfo = new IndexInfo(indexName, regionName);
-    Set<DistributedMember> targetMembers = CliUtil.findMembers(group, memberNameOrID);
-
-    if (targetMembers.isEmpty()) {
-      return ResultBuilder.createUserErrorResult(CliStrings.NO_MEMBERS_FOUND_MESSAGE);
-    }
-
-    ResultCollector rc = CliUtil.executeFunction(destroyIndexFunction, indexInfo, targetMembers);
-    List<Object> funcResults = (List<Object>) rc.getResult();
-
-    Set<String> successfulMembers = new TreeSet<>();
-    Map<String, Set<String>> indexOpFailMap = new HashMap<>();
-
-    AtomicReference<XmlEntity> xmlEntity = new AtomicReference<>();
-    for (Object funcResult : funcResults) {
-      if (!(funcResult instanceof CliFunctionResult)) {
-        continue;
-      }
-
-      CliFunctionResult cliFunctionResult = (CliFunctionResult) funcResult;
-
-      if (cliFunctionResult.isSuccessful()) {
-        successfulMembers.add(cliFunctionResult.getMemberIdOrName());
-        if (xmlEntity.get() == null) {
-          xmlEntity.set(cliFunctionResult.getXmlEntity());
-        }
-      } else {
-        String exceptionMessage = cliFunctionResult.getMessage();
-        Set<String> failedMembers = indexOpFailMap.get(exceptionMessage);
-
-        if (failedMembers == null) {
-          failedMembers = new TreeSet<>();
-        }
-        failedMembers.add(cliFunctionResult.getMemberIdOrName());
-        indexOpFailMap.put(exceptionMessage, failedMembers);
-      }
-    }
-
-    if (!successfulMembers.isEmpty()) {
-      InfoResultData infoResult = ResultBuilder.createInfoResultData();
-
-      if (StringUtils.isNotBlank(indexName)) {
-        if (StringUtils.isNotBlank(regionPath)) {
-          infoResult.addLine(CliStrings.format(CliStrings.DESTROY_INDEX__ON__REGION__SUCCESS__MSG,
-              indexName, regionPath));
-        } else {
-          infoResult.addLine(CliStrings.format(CliStrings.DESTROY_INDEX__SUCCESS__MSG, indexName));
-        }
-      } else {
-        if (StringUtils.isNotBlank(regionPath)) {
-          infoResult.addLine(CliStrings
-              .format(CliStrings.DESTROY_INDEX__ON__REGION__ONLY__SUCCESS__MSG, regionPath));
-        } else {
-          infoResult.addLine(CliStrings.DESTROY_INDEX__ON__MEMBERS__ONLY__SUCCESS__MSG);
-        }
-      }
-
-      int num = 0;
-      for (String memberId : successfulMembers) {
-        infoResult.addLine(CliStrings.format(
-            CliStrings.format(CliStrings.DESTROY_INDEX__NUMBER__AND__MEMBER, ++num, memberId)));
-      }
-      result = ResultBuilder.buildResult(infoResult);
-
-    } else {
-
-      ErrorResultData erd = ResultBuilder.createErrorResultData();
-      if (StringUtils.isNotBlank(indexName)) {
-        erd.addLine(CliStrings.format(CliStrings.DESTROY_INDEX__FAILURE__MSG, indexName));
-      } else {
-        erd.addLine("Indexes could not be destroyed for following reasons");
-      }
-
-      Set<String> exceptionMessages = indexOpFailMap.keySet();
-
-      for (String exceptionMessage : exceptionMessages) {
-        erd.addLine(CliStrings.format(CliStrings.DESTROY_INDEX__REASON_MESSAGE, exceptionMessage));
-        erd.addLine(CliStrings.DESTROY_INDEX__EXCEPTION__OCCURRED__ON);
-
-        Set<String> memberIds = indexOpFailMap.get(exceptionMessage);
-        int num = 0;
-
-        for (String memberId : memberIds) {
-          erd.addLine(CliStrings.format(
-              CliStrings.format(CliStrings.DESTROY_INDEX__NUMBER__AND__MEMBER, ++num, memberId)));
-        }
-        erd.addLine("");
-      }
-      result = ResultBuilder.buildResult(erd);
-    }
-    if (xmlEntity.get() != null) {
-      persistClusterConfiguration(result,
-          () -> getSharedConfiguration().deleteXmlEntity(xmlEntity.get(), group));
-    }
-
-    return result;
-  }
-
-  @CliCommand(value = CliStrings.DEFINE_INDEX, help = CliStrings.DEFINE_INDEX__HELP)
-  @CliMetaData(relatedTopic = {CliStrings.TOPIC_GEODE_REGION, CliStrings.TOPIC_GEODE_DATA})
-  // TODO : Add optionContext for indexName
-  @ResourceOperation(resource = Resource.CLUSTER, operation = Operation.MANAGE,
-      target = Target.QUERY)
-  public Result defineIndex(@CliOption(key = CliStrings.DEFINE_INDEX_NAME, mandatory = true,
-      help = CliStrings.DEFINE_INDEX__HELP) final String indexName,
-
-      @CliOption(key = CliStrings.DEFINE_INDEX__EXPRESSION, mandatory = true,
-          help = CliStrings.DEFINE_INDEX__EXPRESSION__HELP) final String indexedExpression,
-
-      @CliOption(key = CliStrings.DEFINE_INDEX__REGION, mandatory = true,
-          optionContext = ConverterHint.REGION_PATH,
-          help = CliStrings.DEFINE_INDEX__REGION__HELP) String regionPath,
-
-      @CliOption(key = CliStrings.DEFINE_INDEX__TYPE, unspecifiedDefaultValue = "range",
-          optionContext = ConverterHint.INDEX_TYPE,
-          help = CliStrings.DEFINE_INDEX__TYPE__HELP) final String indexType) {
-
-    Result result;
-    XmlEntity xmlEntity = null;
-
-    int idxType;
-
-    // Index type check
-    if ("range".equalsIgnoreCase(indexType)) {
-      idxType = IndexInfo.RANGE_INDEX;
-    } else if ("hash".equalsIgnoreCase(indexType)) {
-      idxType = IndexInfo.HASH_INDEX;
-    } else if ("key".equalsIgnoreCase(indexType)) {
-      idxType = IndexInfo.KEY_INDEX;
-    } else {
-      return ResultBuilder
-          .createUserErrorResult(CliStrings.DEFINE_INDEX__INVALID__INDEX__TYPE__MESSAGE);
-    }
-
-    if (indexName == null || indexName.isEmpty()) {
-      return ResultBuilder.createUserErrorResult(CliStrings.DEFINE_INDEX__INVALID__INDEX__NAME);
-    }
-
-    if (indexedExpression == null || indexedExpression.isEmpty()) {
-      return ResultBuilder.createUserErrorResult(CliStrings.DEFINE_INDEX__INVALID__EXPRESSION);
-    }
-
-    if (StringUtils.isBlank(regionPath) || regionPath.equals(Region.SEPARATOR)) {
-      return ResultBuilder.createUserErrorResult(CliStrings.DEFINE_INDEX__INVALID__REGIONPATH);
-    }
-
-    if (!regionPath.startsWith(Region.SEPARATOR)) {
-      regionPath = Region.SEPARATOR + regionPath;
-    }
-
-    IndexInfo indexInfo = new IndexInfo(indexName, indexedExpression, regionPath, idxType);
-    indexDefinitions.add(indexInfo);
-
-    final InfoResultData infoResult = ResultBuilder.createInfoResultData();
-    infoResult.addLine(CliStrings.DEFINE_INDEX__SUCCESS__MSG);
-    infoResult.addLine(CliStrings.format(CliStrings.DEFINE_INDEX__NAME__MSG, indexName));
-    infoResult
-        .addLine(CliStrings.format(CliStrings.DEFINE_INDEX__EXPRESSION__MSG, indexedExpression));
-    infoResult.addLine(CliStrings.format(CliStrings.DEFINE_INDEX__REGIONPATH__MSG, regionPath));
-    result = ResultBuilder.buildResult(infoResult);
-
-    return result;
-  }
-
-  @CliCommand(value = CliStrings.CREATE_DEFINED_INDEXES, help = CliStrings.CREATE_DEFINED__HELP)
-  @CliMetaData(relatedTopic = {CliStrings.TOPIC_GEODE_REGION, CliStrings.TOPIC_GEODE_DATA})
-  @ResourceOperation(resource = Resource.CLUSTER, operation = Operation.MANAGE,
-      target = Target.QUERY)
-  // TODO : Add optionContext for indexName
-  public Result createDefinedIndexes(
-
-      @CliOption(key = {CliStrings.MEMBER, CliStrings.MEMBERS},
-          optionContext = ConverterHint.MEMBERIDNAME,
-          help = CliStrings.CREATE_DEFINED_INDEXES__MEMBER__HELP) final String[] memberNameOrID,
-
-      @CliOption(key = {CliStrings.GROUP, CliStrings.GROUPS},
-          optionContext = ConverterHint.MEMBERGROUP,
-          help = CliStrings.CREATE_DEFINED_INDEXES__GROUP__HELP) final String[] group) {
-
-    Result result;
-    AtomicReference<XmlEntity> xmlEntity = new AtomicReference<>();
-
-    if (indexDefinitions.isEmpty()) {
-      final InfoResultData infoResult = ResultBuilder.createInfoResultData();
-      infoResult.addLine(CliStrings.DEFINE_INDEX__FAILURE__MSG);
-      return ResultBuilder.buildResult(infoResult);
-    }
-
-    try {
-      final Set<DistributedMember> targetMembers = CliUtil.findMembers(group, memberNameOrID);
-
-      if (targetMembers.isEmpty()) {
-        return ResultBuilder.createUserErrorResult(CliStrings.NO_MEMBERS_FOUND_MESSAGE);
-      }
-
-      final Cache cache = CacheFactory.getAnyInstance();
-      final ResultCollector<?, ?> rc =
-          CliUtil.executeFunction(createDefinedIndexesFunction, indexDefinitions, targetMembers);
-
-      final List<Object> funcResults = (List<Object>) rc.getResult();
-      final Set<String> successfulMembers = new TreeSet<>();
-      final Map<String, Set<String>> indexOpFailMap = new HashMap<>();
-
-      for (final Object funcResult : funcResults) {
-        if (funcResult instanceof CliFunctionResult) {
-          final CliFunctionResult cliFunctionResult = (CliFunctionResult) funcResult;
-
-          if (cliFunctionResult.isSuccessful()) {
-            successfulMembers.add(cliFunctionResult.getMemberIdOrName());
-
-            if (xmlEntity.get() == null) {
-              xmlEntity.set(cliFunctionResult.getXmlEntity());
-            }
-          } else {
-            final String exceptionMessage = cliFunctionResult.getMessage();
-            Set<String> failedMembers = indexOpFailMap.get(exceptionMessage);
-
-            if (failedMembers == null) {
-              failedMembers = new TreeSet<>();
-            }
-            failedMembers.add(cliFunctionResult.getMemberIdOrName());
-            indexOpFailMap.put(exceptionMessage, failedMembers);
-          }
-        }
-      }
-
-      if (!successfulMembers.isEmpty()) {
-        final InfoResultData infoResult = ResultBuilder.createInfoResultData();
-        infoResult.addLine(CliStrings.CREATE_DEFINED_INDEXES__SUCCESS__MSG);
-
-        int num = 0;
-
-        for (final String memberId : successfulMembers) {
-          ++num;
-          infoResult.addLine(CliStrings
-              .format(CliStrings.CREATE_DEFINED_INDEXES__NUMBER__AND__MEMBER, num, memberId));
-        }
-        result = ResultBuilder.buildResult(infoResult);
-
-      } else {
-        // Group members by the exception thrown.
-        final ErrorResultData erd = ResultBuilder.createErrorResultData();
-
-        final Set<String> exceptionMessages = indexOpFailMap.keySet();
-
-        for (final String exceptionMessage : exceptionMessages) {
-          erd.addLine(exceptionMessage);
-          erd.addLine(CliStrings.CREATE_INDEX__EXCEPTION__OCCURRED__ON);
-          final Set<String> memberIds = indexOpFailMap.get(exceptionMessage);
-
-          int num = 0;
-          for (final String memberId : memberIds) {
-            ++num;
-            erd.addLine(CliStrings.format(CliStrings.CREATE_DEFINED_INDEXES__NUMBER__AND__MEMBER,
-                num, memberId));
-          }
-        }
-        result = ResultBuilder.buildResult(erd);
-      }
-    } catch (Exception e) {
-      result = ResultBuilder.createGemFireErrorResult(e.getMessage());
-    }
-
-    if (xmlEntity.get() != null) {
-      persistClusterConfiguration(result,
-          () -> getSharedConfiguration().addXmlEntity(xmlEntity.get(), group));
-    }
-    return result;
-  }
-
-  @CliCommand(value = CliStrings.CLEAR_DEFINED_INDEXES, help = CliStrings.CLEAR_DEFINED__HELP)
-  @CliMetaData(relatedTopic = {CliStrings.TOPIC_GEODE_REGION, CliStrings.TOPIC_GEODE_DATA})
-  @ResourceOperation(resource = Resource.CLUSTER, operation = Operation.MANAGE,
-      target = Target.QUERY)
-  // TODO : Add optionContext for indexName
-  public Result clearDefinedIndexes() {
-    indexDefinitions.clear();
-    final InfoResultData infoResult = ResultBuilder.createInfoResultData();
-    infoResult.addLine(CliStrings.CLEAR_DEFINED_INDEX__SUCCESS__MSG);
-    return ResultBuilder.buildResult(infoResult);
-  }
-
-  protected static class IndexStatisticsDetailsAdapter {
-
-    private final IndexStatisticsDetails indexStatisticsDetails;
-
-    protected IndexStatisticsDetailsAdapter(final IndexStatisticsDetails indexStatisticsDetails) {
-      this.indexStatisticsDetails = indexStatisticsDetails;
-    }
-
-    public IndexStatisticsDetails getIndexStatisticsDetails() {
-      return indexStatisticsDetails;
-    }
-
-    public String getNumberOfKeys() {
-      return getIndexStatisticsDetails() != null
-          ? StringUtils.defaultString(getIndexStatisticsDetails().getNumberOfKeys()) : "";
-    }
-
-    public String getNumberOfUpdates() {
-      return getIndexStatisticsDetails() != null
-          ? StringUtils.defaultString(getIndexStatisticsDetails().getNumberOfUpdates()) : "";
-    }
-
-    public String getNumberOfValues() {
-      return getIndexStatisticsDetails() != null
-          ? StringUtils.defaultString(getIndexStatisticsDetails().getNumberOfValues()) : "";
-    }
-
-    public String getTotalUpdateTime() {
-      return getIndexStatisticsDetails() != null
-          ? StringUtils.defaultString(getIndexStatisticsDetails().getTotalUpdateTime()) : "";
-    }
-
-    public String getTotalUses() {
-      return getIndexStatisticsDetails() != null
-          ? StringUtils.defaultString(getIndexStatisticsDetails().getTotalUses()) : "";
-    }
-  }
-
-}

http://git-wip-us.apache.org/repos/asf/geode/blob/0dc67f0e/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/IndexDefinition.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/IndexDefinition.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/IndexDefinition.java
new file mode 100644
index 0000000..2cf9f83
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/IndexDefinition.java
@@ -0,0 +1,27 @@
+/*
+ * 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.geode.management.internal.cli.commands;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.apache.geode.management.internal.cli.domain.IndexInfo;
+
+class IndexDefinition {
+  static final Set<IndexInfo> indexDefinitions =
+      Collections.synchronizedSet(new HashSet<IndexInfo>());
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/0dc67f0e/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/ListIndexCommand.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/ListIndexCommand.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/ListIndexCommand.java
new file mode 100644
index 0000000..847426c
--- /dev/null
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/ListIndexCommand.java
@@ -0,0 +1,158 @@
+/*
+ * 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.geode.management.internal.cli.commands;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+import org.springframework.shell.core.annotation.CliCommand;
+import org.springframework.shell.core.annotation.CliOption;
+
+import org.apache.geode.SystemFailure;
+import org.apache.geode.cache.execute.Execution;
+import org.apache.geode.cache.execute.FunctionInvocationTargetException;
+import org.apache.geode.cache.execute.ResultCollector;
+import org.apache.geode.internal.cache.execute.AbstractExecution;
+import org.apache.geode.internal.lang.StringUtils;
+import org.apache.geode.management.cli.CliMetaData;
+import org.apache.geode.management.cli.Result;
+import org.apache.geode.management.internal.cli.domain.IndexDetails;
+import org.apache.geode.management.internal.cli.domain.IndexDetails.IndexStatisticsDetails;
+import org.apache.geode.management.internal.cli.functions.ListIndexFunction;
+import org.apache.geode.management.internal.cli.i18n.CliStrings;
+import org.apache.geode.management.internal.cli.result.ResultBuilder;
+import org.apache.geode.management.internal.cli.result.TabularResultData;
+import org.apache.geode.management.internal.security.ResourceOperation;
+import org.apache.geode.security.ResourcePermission;
+
+public class ListIndexCommand implements GfshCommand {
+  @CliCommand(value = CliStrings.LIST_INDEX, help = CliStrings.LIST_INDEX__HELP)
+  @CliMetaData(relatedTopic = {CliStrings.TOPIC_GEODE_REGION, CliStrings.TOPIC_GEODE_DATA})
+  @ResourceOperation(resource = ResourcePermission.Resource.CLUSTER,
+      operation = ResourcePermission.Operation.READ, target = ResourcePermission.Target.QUERY)
+  public Result listIndex(@CliOption(key = CliStrings.LIST_INDEX__STATS,
+      specifiedDefaultValue = "true", unspecifiedDefaultValue = "false",
+      help = CliStrings.LIST_INDEX__STATS__HELP) final boolean showStats) {
+    try {
+      return toTabularResult(getIndexListing(), showStats);
+    } catch (FunctionInvocationTargetException ignore) {
+      return ResultBuilder.createGemFireErrorResult(
+          CliStrings.format(CliStrings.COULD_NOT_EXECUTE_COMMAND_TRY_AGAIN, CliStrings.LIST_INDEX));
+    } catch (VirtualMachineError e) {
+      SystemFailure.initiateFailure(e);
+      throw e;
+    } catch (Throwable t) {
+      SystemFailure.checkFailure();
+      getCache().getLogger().error(t);
+      return ResultBuilder.createGemFireErrorResult(
+          String.format(CliStrings.LIST_INDEX__ERROR_MESSAGE, toString(t, isDebugging())));
+    }
+  }
+
+  private Result toTabularResult(final List<IndexDetails> indexDetailsList,
+      final boolean showStats) {
+    if (!indexDetailsList.isEmpty()) {
+      final TabularResultData indexData = ResultBuilder.createTabularResultData();
+
+      for (final IndexDetails indexDetails : indexDetailsList) {
+        indexData.accumulate("Member Name",
+            StringUtils.defaultString(indexDetails.getMemberName()));
+        indexData.accumulate("Member ID", indexDetails.getMemberId());
+        indexData.accumulate("Region Path", indexDetails.getRegionPath());
+        indexData.accumulate("Name", indexDetails.getIndexName());
+        indexData.accumulate("Type", StringUtils.defaultString(indexDetails.getIndexType()));
+        indexData.accumulate("Indexed Expression", indexDetails.getIndexedExpression());
+        indexData.accumulate("From Clause", indexDetails.getFromClause());
+
+        if (showStats) {
+          final IndexStatisticsDetailsAdapter adapter =
+              new IndexStatisticsDetailsAdapter(indexDetails.getIndexStatisticsDetails());
+
+          indexData.accumulate("Uses", adapter.getTotalUses());
+          indexData.accumulate("Updates", adapter.getNumberOfUpdates());
+          indexData.accumulate("Update Time", adapter.getTotalUpdateTime());
+          indexData.accumulate("Keys", adapter.getNumberOfKeys());
+          indexData.accumulate("Values", adapter.getNumberOfValues());
+        }
+      }
+
+      return ResultBuilder.buildResult(indexData);
+    } else {
+      return ResultBuilder.createInfoResult(CliStrings.LIST_INDEX__INDEXES_NOT_FOUND_MESSAGE);
+    }
+  }
+
+  List<IndexDetails> getIndexListing() {
+    final Execution functionExecutor = getMembersFunctionExecutor(getMembers(getCache()));
+
+    if (functionExecutor instanceof AbstractExecution) {
+      ((AbstractExecution) functionExecutor).setIgnoreDepartedMembers(true);
+    }
+
+    final ResultCollector<?, ?> resultsCollector =
+        functionExecutor.execute(new ListIndexFunction());
+    final List<?> results = (List<?>) resultsCollector.getResult();
+    final List<IndexDetails> indexDetailsList = new ArrayList<>(results.size());
+
+    for (Object result : results) {
+      if (result instanceof Set) { // ignore FunctionInvocationTargetExceptions and other Exceptions
+        indexDetailsList.addAll((Set<IndexDetails>) result);
+      }
+    }
+    Collections.sort(indexDetailsList);
+    return indexDetailsList;
+  }
+
+  protected static class IndexStatisticsDetailsAdapter {
+
+    private final IndexStatisticsDetails indexStatisticsDetails;
+
+    protected IndexStatisticsDetailsAdapter(final IndexStatisticsDetails indexStatisticsDetails) {
+      this.indexStatisticsDetails = indexStatisticsDetails;
+    }
+
+    public IndexStatisticsDetails getIndexStatisticsDetails() {
+      return indexStatisticsDetails;
+    }
+
+    public String getNumberOfKeys() {
+      return getIndexStatisticsDetails() != null
+          ? StringUtils.defaultString(getIndexStatisticsDetails().getNumberOfKeys()) : "";
+    }
+
+    public String getNumberOfUpdates() {
+      return getIndexStatisticsDetails() != null
+          ? StringUtils.defaultString(getIndexStatisticsDetails().getNumberOfUpdates()) : "";
+    }
+
+    public String getNumberOfValues() {
+      return getIndexStatisticsDetails() != null
+          ? StringUtils.defaultString(getIndexStatisticsDetails().getNumberOfValues()) : "";
+    }
+
+    public String getTotalUpdateTime() {
+      return getIndexStatisticsDetails() != null
+          ? StringUtils.defaultString(getIndexStatisticsDetails().getTotalUpdateTime()) : "";
+    }
+
+    public String getTotalUses() {
+      return getIndexStatisticsDetails() != null
+          ? StringUtils.defaultString(getIndexStatisticsDetails().getTotalUses()) : "";
+    }
+  }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/0dc67f0e/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/CreateDefinedIndexesFunction.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/CreateDefinedIndexesFunction.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/CreateDefinedIndexesFunction.java
index 742840c..47cdb27 100644
--- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/CreateDefinedIndexesFunction.java
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/CreateDefinedIndexesFunction.java
@@ -14,7 +14,6 @@
  */
 package org.apache.geode.management.internal.cli.functions;
 
-import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -38,7 +37,7 @@ public class CreateDefinedIndexesFunction extends FunctionAdapter implements Int
   public void execute(FunctionContext context) {
     String memberId = null;
     List<Index> indexes = null;
-    Cache cache = null;
+    Cache cache;
     try {
       cache = CacheFactory.getAnyInstance();
       memberId = cache.getDistributedSystem().getDistributedMember().getId();

http://git-wip-us.apache.org/repos/asf/geode/blob/0dc67f0e/geode-core/src/main/java/org/apache/geode/management/internal/web/controllers/IndexCommandsController.java
----------------------------------------------------------------------
diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/web/controllers/IndexCommandsController.java b/geode-core/src/main/java/org/apache/geode/management/internal/web/controllers/IndexCommandsController.java
index 296156f..09d7f9a 100644
--- a/geode-core/src/main/java/org/apache/geode/management/internal/web/controllers/IndexCommandsController.java
+++ b/geode-core/src/main/java/org/apache/geode/management/internal/web/controllers/IndexCommandsController.java
@@ -14,9 +14,6 @@
  */
 package org.apache.geode.management.internal.web.controllers;
 
-import org.apache.geode.management.internal.cli.i18n.CliStrings;
-import org.apache.geode.management.internal.cli.util.CommandStringBuilder;
-
 import org.springframework.stereotype.Controller;
 import org.springframework.web.bind.annotation.PathVariable;
 import org.springframework.web.bind.annotation.RequestMapping;
@@ -24,11 +21,19 @@ import org.springframework.web.bind.annotation.RequestMethod;
 import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.ResponseBody;
 
+import org.apache.geode.management.internal.cli.i18n.CliStrings;
+import org.apache.geode.management.internal.cli.util.CommandStringBuilder;
+
 /**
  * The IndexCommandsController class implements the REST API calls for the Gfsh Index commands.
  * </p>
  * 
- * @see org.apache.geode.management.internal.cli.commands.IndexCommands
+ * @see org.apache.geode.management.internal.cli.commands.ClearDefinedIndexesCommand
+ * @see org.apache.geode.management.internal.cli.commands.CreateDefinedIndexesCommand
+ * @see org.apache.geode.management.internal.cli.commands.CreateIndexCommand
+ * @see org.apache.geode.management.internal.cli.commands.DefineIndexCommand
+ * @see org.apache.geode.management.internal.cli.commands.DestroyIndexCommand
+ * @see org.apache.geode.management.internal.cli.commands.ListIndexCommand
  * @see org.apache.geode.management.internal.cli.util.CommandStringBuilder
  * @see org.apache.geode.management.internal.web.controllers.AbstractCommandsController
  * @see org.springframework.stereotype.Controller

http://git-wip-us.apache.org/repos/asf/geode/blob/0dc67f0e/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/IndexCommandsJUnitTest.java
----------------------------------------------------------------------
diff --git a/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/IndexCommandsJUnitTest.java b/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/IndexCommandsJUnitTest.java
deleted file mode 100644
index 0d1f340..0000000
--- a/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/IndexCommandsJUnitTest.java
+++ /dev/null
@@ -1,223 +0,0 @@
-/*
- * 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.geode.management.internal.cli.commands;
-
-import static org.junit.Assert.*;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import java.util.Set;
-
-import org.jmock.Expectations;
-import org.jmock.Mockery;
-import org.jmock.lib.concurrent.Synchroniser;
-import org.jmock.lib.legacy.ClassImposteriser;
-import org.junit.After;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.experimental.categories.Category;
-
-import org.apache.geode.cache.execute.Execution;
-import org.apache.geode.cache.execute.FunctionInvocationTargetException;
-import org.apache.geode.cache.execute.ResultCollector;
-import org.apache.geode.distributed.DistributedMember;
-import org.apache.geode.internal.cache.InternalCache;
-import org.apache.geode.internal.cache.execute.AbstractExecution;
-import org.apache.geode.internal.util.CollectionUtils;
-import org.apache.geode.management.internal.cli.domain.IndexDetails;
-import org.apache.geode.management.internal.cli.functions.ListIndexFunction;
-import org.apache.geode.test.junit.categories.UnitTest;
-
-/**
- * The IndexCommandsJUnitTest class is a test suite of test cases testing the contract and
- * functionality of the IndexCommands class.
- * </p>
- * 
- * @see org.apache.geode.management.internal.cli.commands.IndexCommands
- * @see org.apache.geode.management.internal.cli.domain.IndexDetails
- * @see org.apache.geode.management.internal.cli.functions.ListIndexFunction
- * @see org.jmock.Expectations
- * @see org.jmock.Mockery
- * @see org.jmock.lib.legacy.ClassImposteriser
- * @see org.junit.Assert
- * @see org.junit.Test
- * @since GemFire 7.0
- */
-@Category(UnitTest.class)
-public class IndexCommandsJUnitTest {
-
-  private Mockery mockContext;
-
-  @Before
-  public void setup() {
-    mockContext = new Mockery() {
-      {
-        setImposteriser(ClassImposteriser.INSTANCE);
-        setThreadingPolicy(new Synchroniser());
-      }
-    };
-  }
-
-  @After
-  public void tearDown() {
-    mockContext.assertIsSatisfied();
-    mockContext = null;
-  }
-
-  private IndexCommands createIndexCommands(final InternalCache cache,
-      final Execution functionExecutor) {
-    return new TestIndexCommands(cache, functionExecutor);
-  }
-
-  private IndexDetails createIndexDetails(final String memberId, final String regionPath,
-      final String indexName) {
-    return new IndexDetails(memberId, regionPath, indexName);
-  }
-
-  @Test
-  public void testGetIndexListing() {
-    final InternalCache mockCache = mockContext.mock(InternalCache.class, "InternalCache");
-
-    final AbstractExecution mockFunctionExecutor =
-        mockContext.mock(AbstractExecution.class, "Function Executor");
-
-    final ResultCollector mockResultCollector =
-        mockContext.mock(ResultCollector.class, "ResultCollector");
-
-    final IndexDetails indexDetails1 = createIndexDetails("memberOne", "/Employees", "empIdIdx");
-    final IndexDetails indexDetails2 =
-        createIndexDetails("memberOne", "/Employees", "empLastNameIdx");
-    final IndexDetails indexDetails3 = createIndexDetails("memberTwo", "/Employees", "empDobIdx");
-
-    final List<IndexDetails> expectedIndexDetails =
-        Arrays.asList(indexDetails1, indexDetails2, indexDetails3);
-
-    final List<Set<IndexDetails>> results = new ArrayList<Set<IndexDetails>>(2);
-
-    results.add(CollectionUtils.asSet(indexDetails2, indexDetails1));
-    results.add(CollectionUtils.asSet(indexDetails3));
-
-    mockContext.checking(new Expectations() {
-      {
-        oneOf(mockFunctionExecutor).setIgnoreDepartedMembers(with(equal(true)));
-        oneOf(mockFunctionExecutor).execute(with(aNonNull(ListIndexFunction.class)));
-        will(returnValue(mockResultCollector));
-        oneOf(mockResultCollector).getResult();
-        will(returnValue(results));
-      }
-    });
-
-    final IndexCommands commands = createIndexCommands(mockCache, mockFunctionExecutor);
-
-    final List<IndexDetails> actualIndexDetails = commands.getIndexListing();
-
-    assertNotNull(actualIndexDetails);
-    assertEquals(expectedIndexDetails, actualIndexDetails);
-  }
-
-  @Test(expected = RuntimeException.class)
-  public void testGetIndexListingThrowsRuntimeException() {
-    final InternalCache mockCache = mockContext.mock(InternalCache.class, "InternalCache");
-
-    final Execution mockFunctionExecutor = mockContext.mock(Execution.class, "Function Executor");
-
-    mockContext.checking(new Expectations() {
-      {
-        oneOf(mockFunctionExecutor).execute(with(aNonNull(ListIndexFunction.class)));
-        will(throwException(new RuntimeException("expected")));
-      }
-    });
-
-    final IndexCommands commands = createIndexCommands(mockCache, mockFunctionExecutor);
-
-    try {
-      commands.getIndexListing();
-    } catch (RuntimeException expected) {
-      assertEquals("expected", expected.getMessage());
-      throw expected;
-    }
-  }
-
-  @Test
-  public void testGetIndexListingReturnsFunctionInvocationTargetExceptionInResults() {
-    final InternalCache mockCache = mockContext.mock(InternalCache.class, "InternalCache");
-
-    final AbstractExecution mockFunctionExecutor =
-        mockContext.mock(AbstractExecution.class, "Function Executor");
-
-    final ResultCollector mockResultCollector =
-        mockContext.mock(ResultCollector.class, "ResultCollector");
-
-    final IndexDetails indexDetails = createIndexDetails("memberOne", "/Employees", "empIdIdx");
-
-    final List<IndexDetails> expectedIndexDetails = Arrays.asList(indexDetails);
-
-    final List<Object> results = new ArrayList<Object>(2);
-
-    results.add(CollectionUtils.asSet(indexDetails));
-    results.add(new FunctionInvocationTargetException("expected"));
-
-    mockContext.checking(new Expectations() {
-      {
-        oneOf(mockFunctionExecutor).setIgnoreDepartedMembers(with(equal(true)));
-        oneOf(mockFunctionExecutor).execute(with(aNonNull(ListIndexFunction.class)));
-        will(returnValue(mockResultCollector));
-        oneOf(mockResultCollector).getResult();
-        will(returnValue(results));
-      }
-    });
-
-    final IndexCommands commands = createIndexCommands(mockCache, mockFunctionExecutor);
-
-    final List<IndexDetails> actualIndexDetails = commands.getIndexListing();
-
-    assertNotNull(actualIndexDetails);
-    assertEquals(expectedIndexDetails, actualIndexDetails);
-  }
-
-  private static class TestIndexCommands extends IndexCommands {
-
-    private final InternalCache cache;
-    private final Execution functionExecutor;
-
-    protected TestIndexCommands(final InternalCache cache, final Execution functionExecutor) {
-      assert cache != null : "The InternalCache cannot be null!";
-      assert functionExecutor != null : "The function executor cannot be null!";
-      this.cache = cache;
-      this.functionExecutor = functionExecutor;
-    }
-
-    @Override
-    public InternalCache getCache() {
-      return this.cache;
-    }
-
-    @Override
-    public Set<DistributedMember> getMembers(final InternalCache cache) {
-      assertSame(getCache(), cache);
-      return Collections.emptySet();
-    }
-
-    @Override
-    public Execution getMembersFunctionExecutor(final Set<DistributedMember> members) {
-      Assert.assertNotNull(members);
-      return functionExecutor;
-    }
-  }
-
-}


Mime
View raw message