Return-Path: X-Original-To: archive-asf-public-internal@cust-asf2.ponee.io Delivered-To: archive-asf-public-internal@cust-asf2.ponee.io Received: from cust-asf.ponee.io (cust-asf.ponee.io [163.172.22.183]) by cust-asf2.ponee.io (Postfix) with ESMTP id DDE33200CF8 for ; Thu, 31 Aug 2017 03:26:11 +0200 (CEST) Received: by cust-asf.ponee.io (Postfix) id DC4B816A565; Thu, 31 Aug 2017 01:26:11 +0000 (UTC) Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by cust-asf.ponee.io (Postfix) with SMTP id B603C16A560 for ; Thu, 31 Aug 2017 03:26:09 +0200 (CEST) Received: (qmail 34253 invoked by uid 500); 31 Aug 2017 01:26:08 -0000 Mailing-List: contact commits-help@geode.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@geode.apache.org Delivered-To: mailing list commits@geode.apache.org Received: (qmail 30908 invoked by uid 99); 31 Aug 2017 01:25:43 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 31 Aug 2017 01:25:43 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id 1511EF55A4; Thu, 31 Aug 2017 01:25:38 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: dschneider@apache.org To: commits@geode.apache.org Date: Thu, 31 Aug 2017 01:25:53 -0000 Message-Id: <01d5f5508e074a5a96f4a3e982be6558@git.apache.org> In-Reply-To: <4e343206aca34d2495b7c292e7787abc@git.apache.org> References: <4e343206aca34d2495b7c292e7787abc@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: [16/47] geode git commit: GEODE-3436: Restore refactoring of IndexCommands archived-at: Thu, 31 Aug 2017 01:26:12 -0000 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 Authored: Mon Aug 7 12:35:14 2017 -0700 Committer: Jinmei Liao 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 = 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 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 funcResults = (List) rc.getResult(); + final Set successfulMembers = new TreeSet<>(); + final Map> 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 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 exceptionMessages = indexOpFailMap.keySet(); + + for (final String exceptionMessage : exceptionMessages) { + erd.addLine(exceptionMessage); + erd.addLine(CliStrings.CREATE_INDEX__EXCEPTION__OCCURRED__ON); + final Set 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 = 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 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 funcResults = (List) rc.getResult(); + final Set successfulMembers = new TreeSet<>(); + final Map> 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 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 exceptionMessages = indexOpFailMap.keySet(); + + for (final String exceptionMessage : exceptionMessages) { + erd.addLine(exceptionMessage); + erd.addLine(CliStrings.CREATE_INDEX__EXCEPTION__OCCURRED__ON); + final Set 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 targetMembers = CliUtil.findMembers(group, memberNameOrID); + + if (targetMembers.isEmpty()) { + return ResultBuilder.createUserErrorResult(CliStrings.NO_MEMBERS_FOUND_MESSAGE); + } + + ResultCollector rc = CliUtil.executeFunction(destroyIndexFunction, indexInfo, targetMembers); + List funcResults = (List) rc.getResult(); + + Set successfulMembers = new TreeSet<>(); + Map> indexOpFailMap = new HashMap<>(); + + AtomicReference 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 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 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 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 indexDefinitions = - Collections.synchronizedSet(new HashSet()); - - @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 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 indexDetailsList = new ArrayList<>(results.size()); - - for (Object result : results) { - if (result instanceof Set) { // ignore FunctionInvocationTargetExceptions and other Exceptions - indexDetailsList.addAll((Set) result); - } - } - - Collections.sort(indexDetailsList); - - return indexDetailsList; - } - - protected Result toTabularResult(final List 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 = 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 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 funcResults = (List) rc.getResult(); - final Set successfulMembers = new TreeSet<>(); - final Map> 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 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 exceptionMessages = indexOpFailMap.keySet(); - - for (final String exceptionMessage : exceptionMessages) { - erd.addLine(exceptionMessage); - erd.addLine(CliStrings.CREATE_INDEX__EXCEPTION__OCCURRED__ON); - final Set 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 targetMembers = CliUtil.findMembers(group, memberNameOrID); - - if (targetMembers.isEmpty()) { - return ResultBuilder.createUserErrorResult(CliStrings.NO_MEMBERS_FOUND_MESSAGE); - } - - ResultCollector rc = CliUtil.executeFunction(destroyIndexFunction, indexInfo, targetMembers); - List funcResults = (List) rc.getResult(); - - Set successfulMembers = new TreeSet<>(); - Map> indexOpFailMap = new HashMap<>(); - - AtomicReference 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 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 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 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 = new AtomicReference<>(); - - if (indexDefinitions.isEmpty()) { - final InfoResultData infoResult = ResultBuilder.createInfoResultData(); - infoResult.addLine(CliStrings.DEFINE_INDEX__FAILURE__MSG); - return ResultBuilder.buildResult(infoResult); - } - - try { - final Set 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 funcResults = (List) rc.getResult(); - final Set successfulMembers = new TreeSet<>(); - final Map> 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 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 exceptionMessages = indexOpFailMap.keySet(); - - for (final String exceptionMessage : exceptionMessages) { - erd.addLine(exceptionMessage); - erd.addLine(CliStrings.CREATE_INDEX__EXCEPTION__OCCURRED__ON); - final Set 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 indexDefinitions = + Collections.synchronizedSet(new HashSet()); +} 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 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 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 indexDetailsList = new ArrayList<>(results.size()); + + for (Object result : results) { + if (result instanceof Set) { // ignore FunctionInvocationTargetExceptions and other Exceptions + indexDetailsList.addAll((Set) 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 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. *

* - * @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. - *

- * - * @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 expectedIndexDetails = - Arrays.asList(indexDetails1, indexDetails2, indexDetails3); - - final List> results = new ArrayList>(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 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 expectedIndexDetails = Arrays.asList(indexDetails); - - final List results = new ArrayList(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 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 getMembers(final InternalCache cache) { - assertSame(getCache(), cache); - return Collections.emptySet(); - } - - @Override - public Execution getMembersFunctionExecutor(final Set members) { - Assert.assertNotNull(members); - return functionExecutor; - } - } - -}