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 85169200B3B for ; Mon, 11 Jul 2016 21:12:13 +0200 (CEST) Received: by cust-asf.ponee.io (Postfix) id 83889160A78; Mon, 11 Jul 2016 19:12:13 +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 362C4160A5E for ; Mon, 11 Jul 2016 21:12:11 +0200 (CEST) Received: (qmail 16471 invoked by uid 500); 11 Jul 2016 19:12:10 -0000 Mailing-List: contact commits-help@geode.incubator.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@geode.incubator.apache.org Delivered-To: mailing list commits@geode.incubator.apache.org Received: (qmail 16462 invoked by uid 99); 11 Jul 2016 19:12:10 -0000 Received: from pnap-us-west-generic-nat.apache.org (HELO spamd2-us-west.apache.org) (209.188.14.142) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 11 Jul 2016 19:12:10 +0000 Received: from localhost (localhost [127.0.0.1]) by spamd2-us-west.apache.org (ASF Mail Server at spamd2-us-west.apache.org) with ESMTP id D28321A032A for ; Mon, 11 Jul 2016 19:12:09 +0000 (UTC) X-Virus-Scanned: Debian amavisd-new at spamd2-us-west.apache.org X-Spam-Flag: NO X-Spam-Score: -4.646 X-Spam-Level: X-Spam-Status: No, score=-4.646 tagged_above=-999 required=6.31 tests=[KAM_ASCII_DIVIDERS=0.8, KAM_LAZY_DOMAIN_SECURITY=1, RCVD_IN_DNSWL_HI=-5, RCVD_IN_MSPIKE_H3=-0.01, RCVD_IN_MSPIKE_WL=-0.01, RP_MATCHES_RCVD=-1.426] autolearn=disabled Received: from mx1-lw-us.apache.org ([10.40.0.8]) by localhost (spamd2-us-west.apache.org [10.40.0.9]) (amavisd-new, port 10024) with ESMTP id fs8f_1WxE_IM for ; Mon, 11 Jul 2016 19:12:01 +0000 (UTC) Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by mx1-lw-us.apache.org (ASF Mail Server at mx1-lw-us.apache.org) with SMTP id 6682A5FD6C for ; Mon, 11 Jul 2016 19:12:00 +0000 (UTC) Received: (qmail 16160 invoked by uid 99); 11 Jul 2016 19:11:59 -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; Mon, 11 Jul 2016 19:11:59 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id 52AA9DFFF8; Mon, 11 Jul 2016 19:11:59 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: zhouxj@apache.org To: commits@geode.incubator.apache.org Message-Id: <35055730bd2d4360b78143fd9dbfd52e@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: incubator-geode git commit: GEODE-11: GFSH commands for Lucene Date: Mon, 11 Jul 2016 19:11:59 +0000 (UTC) archived-at: Mon, 11 Jul 2016 19:12:13 -0000 Repository: incubator-geode Updated Branches: refs/heads/develop 48f6e6ec5 -> 82adda1cf GEODE-11: GFSH commands for Lucene Signed-off-by: Aparna Dharmakkan GEODE-11: Implementing GFSH command for listing lucene indexes. Added the LuceneIndexCommands class that implements the list lucene index functionality in GFSH and the LuceneListIndexFunction class that gets the information about lucene indexes from the cache. Also added a test to verify this functionality. The org.springframework.shell.core.CommandMarker file is required to register the lucene commands in GFSH. Signed-off-by: Gester Zhou GEODE-11: Adding JUnit test for LuceneIndexCommands Added a JUnit test for getIndexListing() Signed-off-by: Gester Zhou Adding a unit test for list lucene indexes gfsh command Signed-off-by: Gester Zhou GEODE-11 Adding lucene create index gfsh command Added lucene create index command and dunit tests. Signed-off-by: Aparna Dharmakkan GEODE-11: Create lucene index gfsh command Added a GFSH command to create a lucene index. Added DUnit and JUnit tests. Also added JUnit test for LucenListIndexFunction. Made changes according to review comments. Signed-off-by: Gester Zhou GEODE-1652: merge pull request 190, fix the conflicts This closes #190 Project: http://git-wip-us.apache.org/repos/asf/incubator-geode/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-geode/commit/82adda1c Tree: http://git-wip-us.apache.org/repos/asf/incubator-geode/tree/82adda1c Diff: http://git-wip-us.apache.org/repos/asf/incubator-geode/diff/82adda1c Branch: refs/heads/develop Commit: 82adda1cf7eb55d39c29f99d06d73f9d9ad7b0dc Parents: 48f6e6e Author: Dan Smith Authored: Fri Jul 1 10:45:04 2016 -0700 Committer: zhouxh Committed: Mon Jul 11 12:09:31 2016 -0700 ---------------------------------------------------------------------- .../management/internal/cli/CliUtil.java | 32 +++ .../cli/functions/RegionCreateFunction.java | 53 +--- .../lucene/internal/cli/LuceneCliStrings.java | 48 ++++ .../internal/cli/LuceneIndexCommands.java | 249 +++++++++++++++++++ .../lucene/internal/cli/LuceneIndexDetails.java | 107 ++++++++ .../lucene/internal/cli/LuceneIndexInfo.java | 59 +++++ .../functions/LuceneCreateIndexFunction.java | 106 ++++++++ .../cli/functions/LuceneListIndexFunction.java | 66 +++++ ...org.springframework.shell.core.CommandMarker | 2 + .../cli/LuceneIndexCommandsDUnitTest.java | 197 +++++++++++++++ .../cli/LuceneIndexCommandsJUnitTest.java | 185 ++++++++++++++ .../LuceneCreateIndexFunctionJUnitTest.java | 126 ++++++++++ .../LuceneListIndexFunctionJUnitTest.java | 102 ++++++++ 13 files changed, 1289 insertions(+), 43 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/82adda1c/geode-core/src/main/java/com/gemstone/gemfire/management/internal/cli/CliUtil.java ---------------------------------------------------------------------- diff --git a/geode-core/src/main/java/com/gemstone/gemfire/management/internal/cli/CliUtil.java b/geode-core/src/main/java/com/gemstone/gemfire/management/internal/cli/CliUtil.java index 30ae97b..94dee73 100755 --- a/geode-core/src/main/java/com/gemstone/gemfire/management/internal/cli/CliUtil.java +++ b/geode-core/src/main/java/com/gemstone/gemfire/management/internal/cli/CliUtil.java @@ -359,6 +359,38 @@ public class CliUtil { return stackAsString; } + @SuppressWarnings("unchecked") + public static Class forName(String classToLoadName, String neededFor) { + Class loadedClass = null; + try { + // Set Constraints + ClassPathLoader classPathLoader = ClassPathLoader.getLatest(); + if (classToLoadName != null && !classToLoadName.isEmpty()) { + loadedClass = (Class) classPathLoader.forName(classToLoadName); + } + } catch (ClassNotFoundException | NoClassDefFoundError e) { + throw new RuntimeException(CliStrings.format(CliStrings.CREATE_REGION__MSG__COULDNOT_FIND_CLASS_0_SPECIFIED_FOR_1, new Object[] {classToLoadName, neededFor}), e); + } + catch (ClassCastException e) { + throw new RuntimeException(CliStrings.format(CliStrings.CREATE_REGION__MSG__CLASS_SPECIFIED_FOR_0_SPECIFIED_FOR_1_IS_NOT_OF_EXPECTED_TYPE, new Object[] {classToLoadName, neededFor}), e); + } + + return loadedClass; + } + + public static K newInstance(Class klass, String neededFor) { + K instance = null; + try { + instance = klass.newInstance(); + } catch (InstantiationException e) { + throw new RuntimeException(CliStrings.format(CliStrings.CREATE_REGION__MSG__COULDNOT_INSTANTIATE_CLASS_0_SPECIFIED_FOR_1, new Object[] {klass, neededFor}), e); + } catch (IllegalAccessException e) { + throw new RuntimeException(CliStrings.format(CliStrings.CREATE_REGION__MSG__COULDNOT_ACCESS_CLASS_0_SPECIFIED_FOR_1, new Object[] {klass, neededFor}), e); + } + + return instance; + } + static class CustomFileFilter implements FileFilter { private String extensionWithDot; http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/82adda1c/geode-core/src/main/java/com/gemstone/gemfire/management/internal/cli/functions/RegionCreateFunction.java ---------------------------------------------------------------------- diff --git a/geode-core/src/main/java/com/gemstone/gemfire/management/internal/cli/functions/RegionCreateFunction.java b/geode-core/src/main/java/com/gemstone/gemfire/management/internal/cli/functions/RegionCreateFunction.java index 7e060c2..48c0876 100644 --- a/geode-core/src/main/java/com/gemstone/gemfire/management/internal/cli/functions/RegionCreateFunction.java +++ b/geode-core/src/main/java/com/gemstone/gemfire/management/internal/cli/functions/RegionCreateFunction.java @@ -37,7 +37,6 @@ import com.gemstone.gemfire.cache.execute.FunctionAdapter; import com.gemstone.gemfire.cache.execute.FunctionContext; import com.gemstone.gemfire.cache.execute.ResultSender; import com.gemstone.gemfire.compression.Compressor; -import com.gemstone.gemfire.internal.ClassPathLoader; import com.gemstone.gemfire.internal.InternalEntity; import com.gemstone.gemfire.internal.cache.xmlcache.CacheXml; import com.gemstone.gemfire.internal.i18n.LocalizedStrings; @@ -205,12 +204,12 @@ public class RegionCreateFunction extends FunctionAdapter implements InternalEnt final String keyConstraint = regionCreateArgs.getKeyConstraint(); final String valueConstraint = regionCreateArgs.getValueConstraint(); if (keyConstraint != null && !keyConstraint.isEmpty()) { - Class keyConstraintClass = forName(keyConstraint, CliStrings.CREATE_REGION__KEYCONSTRAINT); + Class keyConstraintClass = CliUtil.forName(keyConstraint, CliStrings.CREATE_REGION__KEYCONSTRAINT); factory.setKeyConstraint(keyConstraintClass); } if (valueConstraint != null && !valueConstraint.isEmpty()) { - Class valueConstraintClass = forName(valueConstraint, CliStrings.CREATE_REGION__VALUECONSTRAINT); + Class valueConstraintClass = CliUtil.forName(valueConstraint, CliStrings.CREATE_REGION__VALUECONSTRAINT); factory.setValueConstraint(valueConstraintClass); } @@ -296,27 +295,27 @@ public class RegionCreateFunction extends FunctionAdapter implements InternalEnt final Set cacheListeners = regionCreateArgs.getCacheListeners(); if (cacheListeners != null && !cacheListeners.isEmpty()) { for (String cacheListener : cacheListeners) { - Class> cacheListenerKlass = forName(cacheListener, CliStrings.CREATE_REGION__CACHELISTENER); - factory.addCacheListener(newInstance(cacheListenerKlass, CliStrings.CREATE_REGION__CACHELISTENER)); + Class> cacheListenerKlass = CliUtil.forName(cacheListener, CliStrings.CREATE_REGION__CACHELISTENER); + factory.addCacheListener(CliUtil.newInstance(cacheListenerKlass, CliStrings.CREATE_REGION__CACHELISTENER)); } } // Compression provider if(regionCreateArgs.isSetCompressor()) { - Class compressorKlass = forName(regionCreateArgs.getCompressor(), CliStrings.CREATE_REGION__COMPRESSOR); - factory.setCompressor(newInstance(compressorKlass, CliStrings.CREATE_REGION__COMPRESSOR)); + Class compressorKlass = CliUtil.forName(regionCreateArgs.getCompressor(), CliStrings.CREATE_REGION__COMPRESSOR); + factory.setCompressor(CliUtil.newInstance(compressorKlass, CliStrings.CREATE_REGION__COMPRESSOR)); } final String cacheLoader = regionCreateArgs.getCacheLoader(); if (cacheLoader != null) { - Class> cacheLoaderKlass = forName(cacheLoader, CliStrings.CREATE_REGION__CACHELOADER); - factory.setCacheLoader(newInstance(cacheLoaderKlass, CliStrings.CREATE_REGION__CACHELOADER)); + Class> cacheLoaderKlass = CliUtil.forName(cacheLoader, CliStrings.CREATE_REGION__CACHELOADER); + factory.setCacheLoader(CliUtil.newInstance(cacheLoaderKlass, CliStrings.CREATE_REGION__CACHELOADER)); } final String cacheWriter = regionCreateArgs.getCacheWriter(); if (cacheWriter != null) { - Class> cacheWriterKlass = forName(cacheWriter, CliStrings.CREATE_REGION__CACHEWRITER); - factory.setCacheWriter(newInstance(cacheWriterKlass, CliStrings.CREATE_REGION__CACHEWRITER)); + Class> cacheWriterKlass = CliUtil.forName(cacheWriter, CliStrings.CREATE_REGION__CACHEWRITER); + factory.setCacheWriter(CliUtil.newInstance(cacheWriterKlass, CliStrings.CREATE_REGION__CACHEWRITER)); } String regionName = regionPathData.getName(); @@ -376,38 +375,6 @@ public class RegionCreateFunction extends FunctionAdapter implements InternalEnt return prAttrFactory.create(); } - @SuppressWarnings("unchecked") - private static Class forName(String classToLoadName, String neededFor) { - Class loadedClass = null; - try { - // Set Constraints - ClassPathLoader classPathLoader = ClassPathLoader.getLatest(); - if (classToLoadName != null && !classToLoadName.isEmpty()) { - loadedClass = (Class) classPathLoader.forName(classToLoadName); - } - } catch (ClassNotFoundException | NoClassDefFoundError e) { - throw new RuntimeException(CliStrings.format(CliStrings.CREATE_REGION__MSG__COULDNOT_FIND_CLASS_0_SPECIFIED_FOR_1, new Object[] {classToLoadName, neededFor}), e); - } - catch (ClassCastException e) { - throw new RuntimeException(CliStrings.format(CliStrings.CREATE_REGION__MSG__CLASS_SPECIFIED_FOR_0_SPECIFIED_FOR_1_IS_NOT_OF_EXPECTED_TYPE, new Object[] {classToLoadName, neededFor}), e); - } - - return loadedClass; - } - - private static K newInstance(Class klass, String neededFor) { - K instance = null; - try { - instance = klass.newInstance(); - } catch (InstantiationException e) { - throw new RuntimeException(CliStrings.format(CliStrings.CREATE_REGION__MSG__COULDNOT_INSTANTIATE_CLASS_0_SPECIFIED_FOR_1, new Object[] {klass, neededFor}), e); - } catch (IllegalAccessException e) { - throw new RuntimeException(CliStrings.format(CliStrings.CREATE_REGION__MSG__COULDNOT_ACCESS_CLASS_0_SPECIFIED_FOR_1, new Object[] {klass, neededFor}), e); - } - - return instance; - } - @Override public String getId() { return ID; http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/82adda1c/geode-lucene/src/main/java/com/gemstone/gemfire/cache/lucene/internal/cli/LuceneCliStrings.java ---------------------------------------------------------------------- diff --git a/geode-lucene/src/main/java/com/gemstone/gemfire/cache/lucene/internal/cli/LuceneCliStrings.java b/geode-lucene/src/main/java/com/gemstone/gemfire/cache/lucene/internal/cli/LuceneCliStrings.java new file mode 100644 index 0000000..3248e75 --- /dev/null +++ b/geode-lucene/src/main/java/com/gemstone/gemfire/cache/lucene/internal/cli/LuceneCliStrings.java @@ -0,0 +1,48 @@ +/* + * 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 com.gemstone.gemfire.cache.lucene.internal.cli; + +public class LuceneCliStrings { + //List Lucene Index commands + public static final String LUCENE_LIST_INDEX = "list lucene index"; + public static final String LUCENE_LIST_INDEX__HELP = "Display the list of lucene indexes created for all members."; + public static final String LUCENE_LIST_INDEX__ERROR_MESSAGE = "An error occurred while collecting all lucene index information across the Geode cluster: %1$s"; + public static final String LUCENE_LIST_INDEX__INDEXES_NOT_FOUND_MESSAGE = "No lucene indexes Found"; + + public static final String LUCENE_CREATE_INDEX = "create lucene index"; + public static final String LUCENE_CREATE_INDEX__HELP = "Create a lucene index that can be used to execute queries."; + public static final String LUCENE_CREATE_INDEX__NAME = "name"; + public static final String LUCENE_CREATE_INDEX__NAME__HELP = "Name of the lucene index to create."; + public static final String LUCENE_CREATE_INDEX__REGION = "region"; + public static final String LUCENE_CREATE_INDEX__REGION_HELP = "Name/Path of the region where the lucene index is created on."; + public static final String LUCENE_CREATE_INDEX__FIELD = "field"; + public static final String LUCENE_CREATE_INDEX__FIELD_HELP = "fields on the region values which are stored in the lucene index."; + public static final String LUCENE_CREATE_INDEX__ANALYZER = "analyzer"; + public static final String LUCENE_CREATE_INDEX__ANALYZER_HELP = "Type of the analyzer for each field."; + public static final String LUCENE_CREATE_INDEX__GROUP = "group"; + public static final String LUCENE_CREATE_INDEX__GROUP__HELP = "Group of members in which the lucene index will be created."; + + public static final String CREATE_INDEX__SUCCESS__MSG = "Index successfully created with following details"; + public static final String CREATE_INDEX__FAILURE__MSG = "Failed to create index \"{0}\" due to following reasons"; + public static final String CREATE_INDEX__NAME__MSG = "Name : {0}"; + public static final String CREATE_INDEX__REGIONPATH__MSG = "RegionPath : {0}"; + public static final String CREATE_INDEX__MEMBER__MSG = "Members which contain the index"; + public static final String CREATE_INDEX__NUMBER__AND__MEMBER = "{0}. {1}"; + public static final String CREATE_INDEX__EXCEPTION__OCCURRED__ON = "Occurred on following members"; +} http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/82adda1c/geode-lucene/src/main/java/com/gemstone/gemfire/cache/lucene/internal/cli/LuceneIndexCommands.java ---------------------------------------------------------------------- diff --git a/geode-lucene/src/main/java/com/gemstone/gemfire/cache/lucene/internal/cli/LuceneIndexCommands.java b/geode-lucene/src/main/java/com/gemstone/gemfire/cache/lucene/internal/cli/LuceneIndexCommands.java new file mode 100755 index 0000000..796d9f7 --- /dev/null +++ b/geode-lucene/src/main/java/com/gemstone/gemfire/cache/lucene/internal/cli/LuceneIndexCommands.java @@ -0,0 +1,249 @@ +/* + * 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 com.gemstone.gemfire.cache.lucene.internal.cli; + +import static com.gemstone.gemfire.cache.operations.OperationContext.*; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; +import java.util.stream.Collectors; + +import com.gemstone.gemfire.SystemFailure; +import com.gemstone.gemfire.cache.Cache; +import com.gemstone.gemfire.cache.CacheFactory; +import com.gemstone.gemfire.cache.execute.Execution; +import com.gemstone.gemfire.cache.execute.FunctionInvocationTargetException; +import com.gemstone.gemfire.cache.execute.ResultCollector; +import com.gemstone.gemfire.cache.lucene.internal.cli.functions.LuceneCreateIndexFunction; +import com.gemstone.gemfire.cache.lucene.internal.cli.functions.LuceneListIndexFunction; +import com.gemstone.gemfire.distributed.DistributedMember; +import com.gemstone.gemfire.internal.cache.execute.AbstractExecution; +import com.gemstone.gemfire.internal.security.GeodeSecurityUtil; +import com.gemstone.gemfire.management.cli.CliMetaData; +import com.gemstone.gemfire.management.cli.ConverterHint; +import com.gemstone.gemfire.management.cli.Result; +import com.gemstone.gemfire.management.internal.cli.CliUtil; +import com.gemstone.gemfire.management.internal.cli.commands.AbstractCommandsSupport; + +import com.gemstone.gemfire.management.internal.cli.domain.IndexInfo; +import com.gemstone.gemfire.management.internal.cli.functions.CliFunctionResult; +import com.gemstone.gemfire.management.internal.cli.i18n.CliStrings; +import com.gemstone.gemfire.management.internal.cli.result.CommandResultException; +import com.gemstone.gemfire.management.internal.cli.result.ErrorResultData; +import com.gemstone.gemfire.management.internal.cli.result.InfoResultData; +import com.gemstone.gemfire.management.internal.cli.result.ResultBuilder; +import com.gemstone.gemfire.management.internal.cli.result.TabularResultData; +import com.gemstone.gemfire.management.internal.configuration.SharedConfigurationWriter; +import com.gemstone.gemfire.management.internal.configuration.domain.XmlEntity; +import com.gemstone.gemfire.management.internal.security.ResourceOperation; +import com.gemstone.gemfire.security.GeodePermission.Operation; +import com.gemstone.gemfire.security.GeodePermission.Resource; + +import org.springframework.shell.core.annotation.CliCommand; +import org.springframework.shell.core.annotation.CliOption; + +/** + * The LuceneIndexCommands class encapsulates all Geode shell (Gfsh) commands related to Lucene indexes defined in Geode. + *

+ * @see AbstractCommandsSupport + * @see LuceneIndexDetails + * @see LuceneListIndexFunction + */ +@SuppressWarnings("unused") +public class LuceneIndexCommands extends AbstractCommandsSupport { + + private static final LuceneCreateIndexFunction createIndexFunction = new LuceneCreateIndexFunction(); + + @CliCommand(value = LuceneCliStrings.LUCENE_LIST_INDEX, help = LuceneCliStrings.LUCENE_LIST_INDEX__HELP) + @CliMetaData(shellOnly = false, relatedTopic={CliStrings.TOPIC_GEODE_REGION, CliStrings.TOPIC_GEODE_DATA }) + @ResourceOperation(resource = Resource.CLUSTER, operation = Operation.READ) + public Result listIndex() { + try { + return toTabularResult(getIndexListing()); + } + catch (FunctionInvocationTargetException ignore) { + return ResultBuilder.createGemFireErrorResult(CliStrings.format(CliStrings.COULD_NOT_EXECUTE_COMMAND_TRY_AGAIN, + LuceneCliStrings.LUCENE_LIST_INDEX)); + } + catch (VirtualMachineError e) { + SystemFailure.initiateFailure(e); + throw e; + } + catch (Throwable t) { + SystemFailure.checkFailure(); + getCache().getLogger().error(t); + return ResultBuilder.createGemFireErrorResult(String.format(LuceneCliStrings.LUCENE_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 LuceneListIndexFunction()); + final List> results = (List>) resultsCollector.getResult(); + + return results.stream() + .flatMap(set -> set.stream()) + .sorted() + .collect(Collectors.toList()); + } + + protected Result toTabularResult(final List indexDetailsList) { + if (!indexDetailsList.isEmpty()) { + final TabularResultData indexData = ResultBuilder.createTabularResultData(); + + for (final LuceneIndexDetails indexDetails : indexDetailsList) { + indexData.accumulate("Index Name", indexDetails.getIndexName()); + indexData.accumulate("Region Path", indexDetails.getRegionPath()); + indexData.accumulate("Indexed Fields", indexDetails.getSearchableFieldNamesString()); + indexData.accumulate("Field Analyzer", indexDetails.getFieldAnalyzersString()); + } + return ResultBuilder.buildResult(indexData); + } + else { + return ResultBuilder.createInfoResult(LuceneCliStrings.LUCENE_LIST_INDEX__INDEXES_NOT_FOUND_MESSAGE); + } + } + + @CliCommand(value = LuceneCliStrings.LUCENE_CREATE_INDEX, help = LuceneCliStrings.LUCENE_CREATE_INDEX__HELP) + @CliMetaData(shellOnly = false, relatedTopic={CliStrings.TOPIC_GEODE_REGION, CliStrings.TOPIC_GEODE_DATA }, writesToSharedConfiguration=true) + //TODO : Add optionContext for indexName + public Result createIndex( + @CliOption(key = LuceneCliStrings.LUCENE_CREATE_INDEX__NAME, + mandatory=true, + help = LuceneCliStrings.LUCENE_CREATE_INDEX__NAME__HELP) final String indexName, + + @CliOption (key = LuceneCliStrings.LUCENE_CREATE_INDEX__REGION, + mandatory = true, + optionContext = ConverterHint.REGIONPATH, + help = LuceneCliStrings.LUCENE_CREATE_INDEX__REGION_HELP) final String regionPath, + + @CliOption(key = LuceneCliStrings.LUCENE_CREATE_INDEX__FIELD, + mandatory = true, + help = LuceneCliStrings.LUCENE_CREATE_INDEX__FIELD_HELP) + @CliMetaData (valueSeparator = ",") final String[] fields, + + @CliOption(key = LuceneCliStrings.LUCENE_CREATE_INDEX__ANALYZER, + mandatory = false, + unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE, + help = LuceneCliStrings.LUCENE_CREATE_INDEX__ANALYZER_HELP) + @CliMetaData (valueSeparator = ",") final String[] analyzers, + + @CliOption (key = LuceneCliStrings.LUCENE_CREATE_INDEX__GROUP, + optionContext = ConverterHint.MEMBERGROUP, + unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE, + help = LuceneCliStrings.LUCENE_CREATE_INDEX__GROUP__HELP) + @CliMetaData (valueSeparator = ",") final String[] groups) { + + Result result = null; + XmlEntity xmlEntity = null; + + GeodeSecurityUtil.authorizeRegionManage(regionPath); + try { + final Cache cache = getCache(); + LuceneIndexInfo indexInfo = new LuceneIndexInfo(indexName, regionPath, fields, analyzers); + final ResultCollector rc = this.createIndexOnGroups(groups, indexInfo); + final List funcResults = (List) rc.getResult(); + + final Set successfulMembers = new TreeSet(); + final Map> indexOpFailMap = new HashMap>(); + + for (final CliFunctionResult cliFunctionResult : funcResults) { + + if (cliFunctionResult.isSuccessful()) { + successfulMembers.add(cliFunctionResult.getMemberIdOrName()); + + if (xmlEntity == null) { + xmlEntity = 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(LuceneCliStrings.CREATE_INDEX__SUCCESS__MSG); + infoResult.addLine(CliStrings.format(LuceneCliStrings.CREATE_INDEX__NAME__MSG, indexName)); + infoResult.addLine(CliStrings.format(LuceneCliStrings.CREATE_INDEX__REGIONPATH__MSG, regionPath)); + infoResult.addLine(LuceneCliStrings.CREATE_INDEX__MEMBER__MSG); + + int num = 0; + + for (final String memberId : successfulMembers) { + ++num; + infoResult.addLine(CliStrings.format(LuceneCliStrings.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(LuceneCliStrings.CREATE_INDEX__FAILURE__MSG, indexName)); + + final Set exceptionMessages = indexOpFailMap.keySet(); + + for (final String exceptionMessage : exceptionMessages) { + erd.addLine(exceptionMessage); + erd.addLine(LuceneCliStrings.CREATE_INDEX__EXCEPTION__OCCURRED__ON); + final Set memberIds = indexOpFailMap.get(exceptionMessage); + + int num = 0; + for (final String memberId : memberIds) { + ++num; + erd.addLine(CliStrings.format(LuceneCliStrings.CREATE_INDEX__NUMBER__AND__MEMBER, num, memberId)); + } + } + result = ResultBuilder.buildResult(erd); + } + } catch (CommandResultException crex) { + result = crex.getResult(); + } catch (Exception e) { + result = ResultBuilder.createGemFireErrorResult(e.getMessage()); + } +// TODO - store in cluster config +// if (xmlEntity != null) { +// result.setCommandPersisted((new SharedConfigurationWriter()).addXmlEntity(xmlEntity, groups)); +// } + + return result; + } + + protected ResultCollector createIndexOnGroups( String[] groups, final LuceneIndexInfo indexInfo) throws CommandResultException { + final Set targetMembers = CliUtil.findAllMatchingMembers(groups, null); + return CliUtil.executeFunction(createIndexFunction, indexInfo, targetMembers); + } +} http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/82adda1c/geode-lucene/src/main/java/com/gemstone/gemfire/cache/lucene/internal/cli/LuceneIndexDetails.java ---------------------------------------------------------------------- diff --git a/geode-lucene/src/main/java/com/gemstone/gemfire/cache/lucene/internal/cli/LuceneIndexDetails.java b/geode-lucene/src/main/java/com/gemstone/gemfire/cache/lucene/internal/cli/LuceneIndexDetails.java new file mode 100644 index 0000000..c967530 --- /dev/null +++ b/geode-lucene/src/main/java/com/gemstone/gemfire/cache/lucene/internal/cli/LuceneIndexDetails.java @@ -0,0 +1,107 @@ +/* + * 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 com.gemstone.gemfire.cache.lucene.internal.cli; + +import java.io.Serializable; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; +import com.gemstone.gemfire.cache.lucene.internal.LuceneIndexImpl; + +import org.apache.lucene.analysis.Analyzer; + +public class LuceneIndexDetails implements Comparable, Serializable { + private static final long serialVersionUID = 1L; + + private final String indexName; + private final String regionPath; + private final String[] searchableFieldNames; + private final Map fieldAnalyzers; + + public LuceneIndexDetails(final String indexName, final String regionPath, final String[] searchableFieldNames, Map fieldAnalyzers) { + this.indexName = indexName; + this.regionPath = regionPath; + this.searchableFieldNames = searchableFieldNames; + this.fieldAnalyzers = getAnalyzerStrings(fieldAnalyzers); + } + + public LuceneIndexDetails(LuceneIndexImpl index) { + this(index.getName(), index.getRegionPath(), index.getFieldNames(), index.getFieldAnalyzers()); + } + + private Map getAnalyzerStrings(Map fieldAnalyzers) { + if(fieldAnalyzers == null) { + return Collections.emptyMap(); + } + + Map results = new HashMap<>(); + + for (Entry entry : fieldAnalyzers.entrySet()) { + final Analyzer analyzer = entry.getValue(); + if(analyzer != null) { + results.put(entry.getKey(), analyzer.getClass().getSimpleName()); + } + } + return results; + } + + public String getSearchableFieldNamesString() { + return Arrays.asList(searchableFieldNames).toString(); + } + + + public String getFieldAnalyzersString() { + return fieldAnalyzers.toString(); + } + + @Override + public String toString() { + final StringBuffer buffer = new StringBuffer(); + buffer.append("{\n\tIndex Name = "+indexName); + buffer.append(",\tRegion Path = "+regionPath); + buffer.append(",\tIndexed Fields = "+getSearchableFieldNamesString()); + buffer.append(",\tField Analyzer = "+getFieldAnalyzersString()); + buffer.append("\n}\n"); + return buffer.toString(); + } + + + public String getIndexName() { + return indexName; + } + + public String getRegionPath() { + return regionPath; + } + + public String[] getSearchableFieldNames() { + return searchableFieldNames; + } + + private static > int compare(final T obj1, final T obj2) { + return (obj1 == null && obj2 == null ? 0 : (obj1 == null ? 1 : (obj2 == null ? -1 : obj1.compareTo(obj2)))); + } + + @Override + public int compareTo(final LuceneIndexDetails indexDetails) { + int comparisonValue = compare(getIndexName(), indexDetails.getIndexName()); + return (comparisonValue != 0 ? comparisonValue : compare(getRegionPath(), indexDetails.getRegionPath())); + } + +} http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/82adda1c/geode-lucene/src/main/java/com/gemstone/gemfire/cache/lucene/internal/cli/LuceneIndexInfo.java ---------------------------------------------------------------------- diff --git a/geode-lucene/src/main/java/com/gemstone/gemfire/cache/lucene/internal/cli/LuceneIndexInfo.java b/geode-lucene/src/main/java/com/gemstone/gemfire/cache/lucene/internal/cli/LuceneIndexInfo.java new file mode 100644 index 0000000..76b7b60 --- /dev/null +++ b/geode-lucene/src/main/java/com/gemstone/gemfire/cache/lucene/internal/cli/LuceneIndexInfo.java @@ -0,0 +1,59 @@ +/* + * 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 com.gemstone.gemfire.cache.lucene.internal.cli; + +import java.io.Serializable; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; +import com.gemstone.gemfire.cache.lucene.internal.LuceneIndexImpl; + +import org.apache.lucene.analysis.Analyzer; + +public class LuceneIndexInfo implements Serializable { + private static final long serialVersionUID = 1L; + + private final String indexName; + private final String regionPath; + private final String[] searchableFieldNames; + private final String[] fieldAnalyzers; + + public LuceneIndexInfo(final String indexName, final String regionPath, final String[] searchableFieldNames, String[] fieldAnalyzers) { + this.indexName = indexName; + this.regionPath = regionPath; + this.searchableFieldNames = searchableFieldNames; + this.fieldAnalyzers = fieldAnalyzers; + } + + public String getIndexName() { + return indexName; + } + + public String getRegionPath() { + return regionPath; + } + + public String[] getSearchableFieldNames() { + return searchableFieldNames; + } + + public String[] getFieldAnalyzers() { + return fieldAnalyzers; + } +} http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/82adda1c/geode-lucene/src/main/java/com/gemstone/gemfire/cache/lucene/internal/cli/functions/LuceneCreateIndexFunction.java ---------------------------------------------------------------------- diff --git a/geode-lucene/src/main/java/com/gemstone/gemfire/cache/lucene/internal/cli/functions/LuceneCreateIndexFunction.java b/geode-lucene/src/main/java/com/gemstone/gemfire/cache/lucene/internal/cli/functions/LuceneCreateIndexFunction.java new file mode 100644 index 0000000..d943fbc --- /dev/null +++ b/geode-lucene/src/main/java/com/gemstone/gemfire/cache/lucene/internal/cli/functions/LuceneCreateIndexFunction.java @@ -0,0 +1,106 @@ +/* + * 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 com.gemstone.gemfire.cache.lucene.internal.cli.functions; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import com.gemstone.gemfire.cache.Cache; +import com.gemstone.gemfire.cache.CacheFactory; +import com.gemstone.gemfire.cache.execute.FunctionAdapter; +import com.gemstone.gemfire.cache.execute.FunctionContext; +import com.gemstone.gemfire.cache.lucene.LuceneIndex; +import com.gemstone.gemfire.cache.lucene.LuceneService; +import com.gemstone.gemfire.cache.lucene.LuceneServiceProvider; +import com.gemstone.gemfire.cache.lucene.internal.LuceneIndexImpl; +import com.gemstone.gemfire.cache.lucene.internal.cli.LuceneCliStrings; +import com.gemstone.gemfire.cache.lucene.internal.cli.LuceneIndexDetails; +import com.gemstone.gemfire.cache.lucene.internal.cli.LuceneIndexInfo; +import com.gemstone.gemfire.internal.InternalEntity; +import com.gemstone.gemfire.management.internal.cli.CliUtil; +import com.gemstone.gemfire.management.internal.cli.functions.CliFunctionResult; +import com.gemstone.gemfire.management.internal.cli.i18n.CliStrings; +import com.gemstone.gemfire.management.internal.configuration.domain.XmlEntity; + +import org.apache.lucene.analysis.Analyzer; + + +/** + * The LuceneCreateIndexFunction class is a function used to create Lucene indexes. + *

+ * @see Cache + * @see com.gemstone.gemfire.cache.execute.Function + * @see FunctionAdapter + * @see FunctionContext + * @see InternalEntity + * @see LuceneIndexDetails + */ +@SuppressWarnings("unused") +public class LuceneCreateIndexFunction extends FunctionAdapter implements InternalEntity { + + protected Cache getCache() { + return CacheFactory.getAnyInstance(); + } + + public String getId() { + return LuceneListIndexFunction.class.getName(); + } + + public void execute(final FunctionContext context) { + String memberId = null; + try { + final LuceneIndexInfo indexInfo = (LuceneIndexInfo) context.getArguments(); + final Cache cache = getCache(); + memberId = cache.getDistributedSystem().getDistributedMember().getId(); + LuceneService service = LuceneServiceProvider.get(cache); + + String[] fields = indexInfo.getSearchableFieldNames(); + String[] analyzerName = indexInfo.getFieldAnalyzers(); + + if (analyzerName == null || analyzerName.length == 0) { + service.createIndex(indexInfo.getIndexName(), indexInfo.getRegionPath(), fields); + } + else { + Map fieldAnalyzer = new HashMap<>(); + for (int i = 0; i < fields.length; i++) { + Analyzer analyzer = toAnalyzer(analyzerName[i]); + fieldAnalyzer.put(fields[i], analyzer); + } + service.createIndex(indexInfo.getIndexName(), indexInfo.getRegionPath(), fieldAnalyzer); + } + + //TODO - update cluster configuration by returning a valid XmlEntity + XmlEntity xmlEntity = null; + context.getResultSender().lastResult(new CliFunctionResult(memberId, xmlEntity)); + } + catch (Exception e) { + String exceptionMessage = CliStrings.format(CliStrings.EXCEPTION_CLASS_AND_MESSAGE, e.getClass().getName(), + e.getMessage()); + context.getResultSender().lastResult(new CliFunctionResult(memberId, e, e.getMessage())); + } + } + + private Analyzer toAnalyzer(final String className) + { + Class clazz = CliUtil.forName(className, LuceneCliStrings.LUCENE_CREATE_INDEX__ANALYZER); + return CliUtil.newInstance(clazz, LuceneCliStrings.LUCENE_CREATE_INDEX__ANALYZER); + } + +} http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/82adda1c/geode-lucene/src/main/java/com/gemstone/gemfire/cache/lucene/internal/cli/functions/LuceneListIndexFunction.java ---------------------------------------------------------------------- diff --git a/geode-lucene/src/main/java/com/gemstone/gemfire/cache/lucene/internal/cli/functions/LuceneListIndexFunction.java b/geode-lucene/src/main/java/com/gemstone/gemfire/cache/lucene/internal/cli/functions/LuceneListIndexFunction.java new file mode 100755 index 0000000..4460d57 --- /dev/null +++ b/geode-lucene/src/main/java/com/gemstone/gemfire/cache/lucene/internal/cli/functions/LuceneListIndexFunction.java @@ -0,0 +1,66 @@ +/* + * 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 com.gemstone.gemfire.cache.lucene.internal.cli.functions; + +import java.util.HashSet; +import java.util.Set; + +import com.gemstone.gemfire.cache.Cache; +import com.gemstone.gemfire.cache.CacheFactory; +import com.gemstone.gemfire.cache.execute.FunctionAdapter; +import com.gemstone.gemfire.cache.execute.FunctionContext; +import com.gemstone.gemfire.cache.lucene.LuceneIndex; +import com.gemstone.gemfire.cache.lucene.LuceneService; +import com.gemstone.gemfire.cache.lucene.LuceneServiceProvider; +import com.gemstone.gemfire.cache.lucene.internal.LuceneIndexImpl; +import com.gemstone.gemfire.cache.lucene.internal.cli.LuceneIndexDetails; +import com.gemstone.gemfire.internal.InternalEntity; + +/** + * The LuceneListIndexFunction class is a function used to collect the information on all lucene indexes in + * the entire Cache. + *

+ * @see Cache + * @see com.gemstone.gemfire.cache.execute.Function + * @see FunctionAdapter + * @see FunctionContext + * @see InternalEntity + * @see LuceneIndexDetails + */ +@SuppressWarnings("unused") +public class LuceneListIndexFunction extends FunctionAdapter implements InternalEntity { + + protected Cache getCache() { + return CacheFactory.getAnyInstance(); + } + + public String getId() { + return LuceneListIndexFunction.class.getName(); + } + + public void execute(final FunctionContext context) { + final Set indexDetailsSet = new HashSet<>(); + final Cache cache = getCache(); + LuceneService service = LuceneServiceProvider.get(cache); + for (LuceneIndex index : service.getAllIndexes()) { + indexDetailsSet.add(new LuceneIndexDetails((LuceneIndexImpl) index)); + } + context.getResultSender().lastResult(indexDetailsSet); + } + +} http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/82adda1c/geode-lucene/src/main/resources/META-INF/services/org.springframework.shell.core.CommandMarker ---------------------------------------------------------------------- diff --git a/geode-lucene/src/main/resources/META-INF/services/org.springframework.shell.core.CommandMarker b/geode-lucene/src/main/resources/META-INF/services/org.springframework.shell.core.CommandMarker new file mode 100644 index 0000000..5d37d35 --- /dev/null +++ b/geode-lucene/src/main/resources/META-INF/services/org.springframework.shell.core.CommandMarker @@ -0,0 +1,2 @@ +# Lucene Extensions command +com.gemstone.gemfire.cache.lucene.internal.cli.LuceneIndexCommands \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/82adda1c/geode-lucene/src/test/java/com/gemstone/gemfire/cache/lucene/internal/cli/LuceneIndexCommandsDUnitTest.java ---------------------------------------------------------------------- diff --git a/geode-lucene/src/test/java/com/gemstone/gemfire/cache/lucene/internal/cli/LuceneIndexCommandsDUnitTest.java b/geode-lucene/src/test/java/com/gemstone/gemfire/cache/lucene/internal/cli/LuceneIndexCommandsDUnitTest.java new file mode 100755 index 0000000..2647bcc --- /dev/null +++ b/geode-lucene/src/test/java/com/gemstone/gemfire/cache/lucene/internal/cli/LuceneIndexCommandsDUnitTest.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 com.gemstone.gemfire.cache.lucene.internal.cli; + +import com.gemstone.gemfire.cache.*; +import com.gemstone.gemfire.cache.lucene.LuceneIndex; +import com.gemstone.gemfire.cache.lucene.LuceneService; +import com.gemstone.gemfire.cache.lucene.LuceneServiceProvider; +import com.gemstone.gemfire.distributed.ConfigurationProperties; +import com.gemstone.gemfire.management.cli.Result.Status; +import com.gemstone.gemfire.management.internal.cli.CommandManager; +import com.gemstone.gemfire.management.internal.cli.commands.CliCommandTestBase; +import com.gemstone.gemfire.management.internal.cli.result.CommandResult; +import com.gemstone.gemfire.management.internal.cli.util.CommandStringBuilder; +import com.gemstone.gemfire.test.dunit.*; +import com.gemstone.gemfire.test.junit.categories.DistributedTest; +import com.sun.org.apache.regexp.internal.RE; + +import org.apache.lucene.analysis.Analyzer; +import org.apache.lucene.analysis.core.KeywordAnalyzer; +import org.apache.lucene.analysis.standard.StandardAnalyzer; +import org.junit.Before; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +import static com.gemstone.gemfire.cache.lucene.test.LuceneTestUtilities.*; +import static com.gemstone.gemfire.test.dunit.Assert.*; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.stream.Collectors; + +@Category(DistributedTest.class) +public class LuceneIndexCommandsDUnitTest extends CliCommandTestBase { + + @Before + public void createJMXManager() { + disconnectAllFromDS(); + setUpJmxManagerOnVm0ThenConnect(null); + } + + @Test + public void listIndexShouldReturnExistingIndex() throws Exception { + final VM vm1 = Host.getHost(0).getVM(1); + + createIndex(vm1); + CommandManager.getInstance().add(LuceneIndexCommands.class.newInstance()); + + CommandStringBuilder csb = new CommandStringBuilder(LuceneCliStrings.LUCENE_LIST_INDEX); + String resultAsString = executeCommandAndLogResult(csb); + assertTrue(resultAsString.contains(INDEX_NAME)); + } + + @Test + public void createIndexShouldCreateANewIndex() throws Exception { + final VM vm1 = Host.getHost(0).getVM(1); + vm1.invoke(() -> {getCache();}); + + CommandManager.getInstance().add(LuceneIndexCommands.class.newInstance()); + + CommandStringBuilder csb = new CommandStringBuilder(LuceneCliStrings.LUCENE_CREATE_INDEX); + csb.addOption(LuceneCliStrings.LUCENE_CREATE_INDEX__NAME,INDEX_NAME); + csb.addOption(LuceneCliStrings.LUCENE_CREATE_INDEX__REGION,REGION_NAME); + csb.addOption(LuceneCliStrings.LUCENE_CREATE_INDEX__FIELD,"field1,field2,field3"); + + String resultAsString = executeCommandAndLogResult(csb); + + vm1.invoke(() -> { + LuceneService luceneService = LuceneServiceProvider.get(getCache()); + createRegion(); + final LuceneIndex index = luceneService.getIndex(INDEX_NAME, REGION_NAME); + assertArrayEquals(new String[] {"field1", "field2", "field3"}, index.getFieldNames()); + }); + } + + @Test + public void createIndexWithAnalyzersShouldCreateANewIndex() throws Exception { + final VM vm1 = Host.getHost(0).getVM(1); + vm1.invoke(() -> {getCache();}); + + CommandManager.getInstance().add(LuceneIndexCommands.class.newInstance()); + + List analyzerNames = new ArrayList<>(); + analyzerNames.add(StandardAnalyzer.class.getCanonicalName()); + analyzerNames.add(KeywordAnalyzer.class.getCanonicalName()); + analyzerNames.add(StandardAnalyzer.class.getCanonicalName()); + + + CommandStringBuilder csb = new CommandStringBuilder(LuceneCliStrings.LUCENE_CREATE_INDEX); + csb.addOption(LuceneCliStrings.LUCENE_CREATE_INDEX__NAME,INDEX_NAME); + csb.addOption(LuceneCliStrings.LUCENE_CREATE_INDEX__REGION,REGION_NAME); + csb.addOption(LuceneCliStrings.LUCENE_CREATE_INDEX__FIELD,"field1,field2,field3"); + csb.addOption(LuceneCliStrings.LUCENE_CREATE_INDEX__ANALYZER,String.join(",",analyzerNames)); + + String resultAsString = executeCommandAndLogResult(csb); + + vm1.invoke(() -> { + LuceneService luceneService = LuceneServiceProvider.get(getCache()); + createRegion(); + final LuceneIndex index = luceneService.getIndex(INDEX_NAME, REGION_NAME); + final Map fieldAnalyzers = index.getFieldAnalyzers(); + assertEquals(StandardAnalyzer.class, fieldAnalyzers.get("field1").getClass()); + assertEquals(KeywordAnalyzer.class, fieldAnalyzers.get("field2").getClass()); + assertEquals(StandardAnalyzer.class, fieldAnalyzers.get("field3").getClass()); + }); + } + + @Test + public void createIndexOnGroupShouldCreateANewIndexOnGroup() throws Exception { + final VM vm1 = Host.getHost(0).getVM(1); + final VM vm2 = Host.getHost(0).getVM(2); + vm1.invoke(() -> { + getCache(); + }); + vm2.invoke(() -> { + Properties props = new Properties(); + props.setProperty(ConfigurationProperties.GROUPS, "group1"); + getSystem(props); + getCache(); + }); + + + CommandManager.getInstance().add(LuceneIndexCommands.class.newInstance()); + + CommandStringBuilder csb = new CommandStringBuilder(LuceneCliStrings.LUCENE_CREATE_INDEX); + csb.addOption(LuceneCliStrings.LUCENE_CREATE_INDEX__NAME,INDEX_NAME); + csb.addOption(LuceneCliStrings.LUCENE_CREATE_INDEX__REGION,REGION_NAME); + csb.addOption(LuceneCliStrings.LUCENE_CREATE_INDEX__FIELD,"field1,field2,field3"); + csb.addOption(LuceneCliStrings.LUCENE_CREATE_INDEX__GROUP,"group1"); + String resultAsString = executeCommandAndLogResult(csb); + + vm2.invoke(() -> { + LuceneService luceneService = LuceneServiceProvider.get(getCache()); + createRegion(); + final LuceneIndex index = luceneService.getIndex(INDEX_NAME, REGION_NAME); + assertArrayEquals(new String[] {"field1", "field2", "field3"}, index.getFieldNames()); + }); + + vm1.invoke(() -> { + LuceneService luceneService = LuceneServiceProvider.get(getCache()); + try { + createRegion(); + fail("Should have thrown an exception due to the missing index"); + } catch(IllegalStateException expected) { + + } + }); + } + + private void createRegion() { + getCache().createRegionFactory(RegionShortcut.PARTITION).create(REGION_NAME); + } + + private String executeCommandAndLogResult(final CommandStringBuilder csb) { + String commandString = csb.toString(); + writeToLog("Command String :\n ", commandString); + CommandResult commandResult = executeCommand(commandString); + String resultAsString = commandResultToString(commandResult); + writeToLog("Result String :\n ", resultAsString); + assertEquals("Command failed\n" + resultAsString, Status.OK, commandResult.getStatus()); + return resultAsString; + } + + private void createIndex(final VM vm1) { + vm1.invoke(() -> { + LuceneService luceneService = LuceneServiceProvider.get(getCache()); + Map fieldAnalyzers = new HashMap(); + fieldAnalyzers.put("field1", new StandardAnalyzer()); + fieldAnalyzers.put("field2", new KeywordAnalyzer()); + fieldAnalyzers.put("field3", null); + luceneService.createIndex(INDEX_NAME, REGION_NAME, fieldAnalyzers); + createRegion(); + }); + } + + private void writeToLog(String text, String resultAsString) { + System.out.println(text + ": " + getTestMethodName() + " : "); + System.out.println(text + ":" + resultAsString); + } +} http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/82adda1c/geode-lucene/src/test/java/com/gemstone/gemfire/cache/lucene/internal/cli/LuceneIndexCommandsJUnitTest.java ---------------------------------------------------------------------- diff --git a/geode-lucene/src/test/java/com/gemstone/gemfire/cache/lucene/internal/cli/LuceneIndexCommandsJUnitTest.java b/geode-lucene/src/test/java/com/gemstone/gemfire/cache/lucene/internal/cli/LuceneIndexCommandsJUnitTest.java new file mode 100644 index 0000000..0ebfa10 --- /dev/null +++ b/geode-lucene/src/test/java/com/gemstone/gemfire/cache/lucene/internal/cli/LuceneIndexCommandsJUnitTest.java @@ -0,0 +1,185 @@ +/* + * 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 com.gemstone.gemfire.cache.lucene.internal.cli; +import static com.gemstone.gemfire.internal.lang.StringUtils.trim; +import static org.junit.Assert.*; +import static org.mockito.Matchers.isA; +import static org.mockito.Mockito.*; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.lucene.analysis.Analyzer; +import org.apache.lucene.analysis.core.KeywordAnalyzer; +import org.apache.lucene.analysis.standard.StandardAnalyzer; +import org.junit.Assert; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +import com.gemstone.gemfire.cache.Cache; +import com.gemstone.gemfire.cache.execute.Execution; +import com.gemstone.gemfire.cache.execute.ResultCollector; +import com.gemstone.gemfire.cache.lucene.internal.cli.functions.LuceneListIndexFunction; +import com.gemstone.gemfire.distributed.DistributedMember; +import com.gemstone.gemfire.internal.cache.execute.AbstractExecution; +import com.gemstone.gemfire.internal.util.CollectionUtils; +import com.gemstone.gemfire.management.cli.Result; +import com.gemstone.gemfire.management.cli.Result.Status; +import com.gemstone.gemfire.management.internal.cli.functions.CliFunctionResult; +import com.gemstone.gemfire.management.internal.cli.i18n.CliStrings; +import com.gemstone.gemfire.management.internal.cli.result.CommandResult; +import com.gemstone.gemfire.management.internal.cli.result.CommandResultException; +import com.gemstone.gemfire.management.internal.cli.result.InfoResultData; +import com.gemstone.gemfire.management.internal.cli.result.ResultBuilder; +import com.gemstone.gemfire.management.internal.cli.result.TabularResultData; +import com.gemstone.gemfire.test.junit.categories.UnitTest; + +/** + * The LuceneIndexCommandsJUnitTest class is a test suite of test cases testing the contract and functionality of the + * LuceneIndexCommands class. + *

+ * @see LuceneIndexCommands + * @see LuceneIndexDetails + * @see com.gemstone.gemfire.cache.lucene.internal.cli.functions.LuceneListIndexFunction + * @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 LuceneIndexCommandsJUnitTest { + + private LuceneIndexCommands createIndexCommands(final Cache cache, final Execution functionExecutor) { + return new LuceneTestIndexCommands(cache, functionExecutor); + } + + private LuceneIndexDetails createIndexDetails(final String indexName, final String regionPath, final String[] searchableFields, final Map fieldAnalyzers) { + return new LuceneIndexDetails(indexName, regionPath, searchableFields, fieldAnalyzers); + } + + @Test + public void testListIndex() { + + final Cache mockCache = mock(Cache.class, "Cache"); + final AbstractExecution mockFunctionExecutor = mock(AbstractExecution.class, "Function Executor"); + final ResultCollector mockResultCollector = mock(ResultCollector.class, "ResultCollector"); + + String[] searchableFields={"field1","field2","field3"}; + Map fieldAnalyzers = new HashMap<>(); + fieldAnalyzers.put("field1", new StandardAnalyzer()); + fieldAnalyzers.put("field2", new KeywordAnalyzer()); + fieldAnalyzers.put("field3", null); + final LuceneIndexDetails indexDetails1 = createIndexDetails("memberFive", "/Employees", searchableFields, fieldAnalyzers); + final LuceneIndexDetails indexDetails2 = createIndexDetails("memberSix", "/Employees", searchableFields, fieldAnalyzers); + final LuceneIndexDetails indexDetails3 = createIndexDetails("memberTen", "/Employees", searchableFields, fieldAnalyzers); + + + final List expectedIndexDetails = new ArrayList<>(3); + expectedIndexDetails.add(indexDetails1); + expectedIndexDetails.add(indexDetails2); + expectedIndexDetails.add(indexDetails3); + + final List> results = new ArrayList>(); + + results.add(CollectionUtils.asSet(indexDetails2, indexDetails1,indexDetails3)); + + + when(mockFunctionExecutor.execute(isA(LuceneListIndexFunction.class))) + .thenReturn(mockResultCollector); + when(mockResultCollector.getResult()) + .thenReturn(results); + + final LuceneIndexCommands commands = createIndexCommands(mockCache, mockFunctionExecutor); + + CommandResult result = (CommandResult) commands.listIndex(); + TabularResultData data = (TabularResultData) result.getResultData(); + assertEquals(Arrays.asList("memberFive", "memberSix", "memberTen"), data.retrieveAllValues("Index Name")); + assertEquals(Arrays.asList("/Employees", "/Employees", "/Employees"), data.retrieveAllValues("Region Path")); + assertEquals(Arrays.asList("[field1, field2, field3]", "[field1, field2, field3]", "[field1, field2, field3]"), data.retrieveAllValues("Indexed Fields")); + assertEquals(Arrays.asList("{field1=StandardAnalyzer, field2=KeywordAnalyzer}", "{field1=StandardAnalyzer, field2=KeywordAnalyzer}", "{field1=StandardAnalyzer, field2=KeywordAnalyzer}"), data.retrieveAllValues("Field Analyzer")); + } + + @Test + public void testCreateIndex() throws CommandResultException { + final Cache mockCache=mock(Cache.class); + final ResultCollector mockResultCollector = mock(ResultCollector.class); + final LuceneIndexCommands commands=spy(createIndexCommands(mockCache,null)); + final String memberId="member1"; + final List cliFunctionResults=new ArrayList<>(); + cliFunctionResults.add(new CliFunctionResult(memberId,true,"Index Created")); + + doReturn(mockResultCollector).when(commands).createIndexOnGroups(any(),any(LuceneIndexInfo.class)); + doReturn(cliFunctionResults).when(mockResultCollector).getResult(); + + String indexName ="index"; + String regionPath="regionPath"; + String[] searchableFields={"field1","field2","field3"}; + String[] fieldAnalyzers = { StandardAnalyzer.class.getCanonicalName(), KeywordAnalyzer.class.getCanonicalName(), StandardAnalyzer.class.getCanonicalName()}; + + Result actualResult=commands.createIndex(indexName,regionPath,searchableFields,fieldAnalyzers,null); + Result expectedResult = buildResult(indexName, regionPath, memberId); + assertEquals(Status.OK,actualResult.getStatus()); + assertEquals(expectedResult,actualResult); + } + + private Result buildResult(final String indexName, final String regionPath, final String memberId) { + final InfoResultData infoResult = ResultBuilder.createInfoResultData(); + infoResult.addLine(LuceneCliStrings.CREATE_INDEX__SUCCESS__MSG); + infoResult.addLine(CliStrings.format(LuceneCliStrings.CREATE_INDEX__NAME__MSG, indexName)); + infoResult.addLine(CliStrings.format(LuceneCliStrings.CREATE_INDEX__REGIONPATH__MSG, regionPath)); + infoResult.addLine(LuceneCliStrings.CREATE_INDEX__MEMBER__MSG); + infoResult.addLine(CliStrings.format(LuceneCliStrings.CREATE_INDEX__NUMBER__AND__MEMBER, 1 , memberId)); + return ResultBuilder.buildResult(infoResult); + } + + private static class LuceneTestIndexCommands extends LuceneIndexCommands { + + private final Cache cache; + private final Execution functionExecutor; + + protected LuceneTestIndexCommands(final Cache cache, final Execution functionExecutor) { + assert cache != null : "The Cache cannot be null!"; + this.cache = cache; + this.functionExecutor = functionExecutor; + } + + @Override + protected Cache getCache() { + return this.cache; + } + + @Override + protected Set getMembers(final Cache cache) { + assertSame(getCache(), cache); + return Collections.emptySet(); + } + + @Override + protected Execution getMembersFunctionExecutor(final Set members) { + Assert.assertNotNull(members); + return functionExecutor; + } + } + +} http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/82adda1c/geode-lucene/src/test/java/com/gemstone/gemfire/cache/lucene/internal/cli/functions/LuceneCreateIndexFunctionJUnitTest.java ---------------------------------------------------------------------- diff --git a/geode-lucene/src/test/java/com/gemstone/gemfire/cache/lucene/internal/cli/functions/LuceneCreateIndexFunctionJUnitTest.java b/geode-lucene/src/test/java/com/gemstone/gemfire/cache/lucene/internal/cli/functions/LuceneCreateIndexFunctionJUnitTest.java new file mode 100644 index 0000000..b81cad7 --- /dev/null +++ b/geode-lucene/src/test/java/com/gemstone/gemfire/cache/lucene/internal/cli/functions/LuceneCreateIndexFunctionJUnitTest.java @@ -0,0 +1,126 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.gemstone.gemfire.cache.lucene.internal.cli.functions; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.*; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.lucene.analysis.Analyzer; +import org.apache.lucene.analysis.core.KeywordAnalyzer; +import org.apache.lucene.analysis.standard.StandardAnalyzer; +import org.junit.Before; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.mockito.ArgumentCaptor; +import com.gemstone.gemfire.cache.execute.FunctionContext; +import com.gemstone.gemfire.cache.execute.ResultSender; +import com.gemstone.gemfire.cache.lucene.internal.InternalLuceneService; +import com.gemstone.gemfire.cache.lucene.internal.cli.LuceneIndexInfo; +import com.gemstone.gemfire.distributed.DistributedSystem; +import com.gemstone.gemfire.internal.cache.GemFireCacheImpl; +import com.gemstone.gemfire.management.internal.cli.functions.CliFunctionResult; +import com.gemstone.gemfire.management.internal.configuration.domain.XmlEntity; +import com.gemstone.gemfire.test.fake.Fakes; +import com.gemstone.gemfire.test.junit.categories.UnitTest; + +@Category(UnitTest.class) + +public class LuceneCreateIndexFunctionJUnitTest { + + private InternalLuceneService service; + private GemFireCacheImpl cache; + String member; + FunctionContext context; + ResultSender resultSender; + CliFunctionResult expectedResult; + + @Before + public void prepare() { + cache = Fakes.cache(); + DistributedSystem ds = Fakes.distributedSystem(); + member = ds.getDistributedMember().getId(); + service = mock(InternalLuceneService.class); + when(cache.getService(InternalLuceneService.class)).thenReturn(service); + doNothing().when(service).createIndex(anyString(), anyString(), anyMap()); + + context = mock(FunctionContext.class); + resultSender = mock(ResultSender.class); + when(context.getResultSender()).thenReturn(resultSender); + + XmlEntity xmlEntity = null; + expectedResult = new CliFunctionResult(member, xmlEntity); + } + + @Test + @SuppressWarnings("unchecked") + public void testExecuteWithAnalyzer() throws Throwable { + List analyzerNames = new ArrayList<>(); + analyzerNames.add(StandardAnalyzer.class.getCanonicalName()); + analyzerNames.add(KeywordAnalyzer.class.getCanonicalName()); + analyzerNames.add(StandardAnalyzer.class.getCanonicalName()); + String [] analyzers = new String[3]; + analyzerNames.toArray(analyzers); + LuceneIndexInfo indexInfo = new LuceneIndexInfo("index1", "/region1", + new String[] {"field1", "field2", "field3"}, analyzers); + when(context.getArguments()).thenReturn(indexInfo); + + LuceneCreateIndexFunction function = new LuceneCreateIndexFunction(); + function = spy(function); + doReturn(cache).when(function).getCache(); + function.execute(context); + + ArgumentCaptor analyzersCaptor = ArgumentCaptor.forClass(Map.class); + verify(service).createIndex(eq("index1"), eq("/region1"), analyzersCaptor.capture()); + Map analyzerPerField = analyzersCaptor.getValue(); + assertEquals(3, analyzerPerField.size()); + assertTrue(analyzerPerField.get("field1") instanceof StandardAnalyzer); + assertTrue(analyzerPerField.get("field2") instanceof KeywordAnalyzer); + assertTrue(analyzerPerField.get("field3") instanceof StandardAnalyzer); + + ArgumentCaptor resultCaptor = ArgumentCaptor.forClass(Set.class); + verify(resultSender).lastResult(resultCaptor.capture()); + CliFunctionResult result = (CliFunctionResult)resultCaptor.getValue(); + + assertEquals(expectedResult, result); + } + + @Test + @SuppressWarnings("unchecked") + public void testExecuteWithoutAnalyzer() throws Throwable { + String fields[] = new String[] {"field1", "field2", "field3"}; + LuceneIndexInfo indexInfo = new LuceneIndexInfo("index1", "/region1", fields, null); + when(context.getArguments()).thenReturn(indexInfo); + + LuceneCreateIndexFunction function = new LuceneCreateIndexFunction(); + function = spy(function); + doReturn(cache).when(function).getCache(); + function.execute(context); + + verify(service).createIndex(eq("index1"), eq("/region1"), eq("field1"), eq("field2"), eq("field3")); + + ArgumentCaptor resultCaptor = ArgumentCaptor.forClass(Set.class); + verify(resultSender).lastResult(resultCaptor.capture()); + CliFunctionResult result = (CliFunctionResult)resultCaptor.getValue(); + + assertEquals(expectedResult, result); + } +} http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/82adda1c/geode-lucene/src/test/java/com/gemstone/gemfire/cache/lucene/internal/cli/functions/LuceneListIndexFunctionJUnitTest.java ---------------------------------------------------------------------- diff --git a/geode-lucene/src/test/java/com/gemstone/gemfire/cache/lucene/internal/cli/functions/LuceneListIndexFunctionJUnitTest.java b/geode-lucene/src/test/java/com/gemstone/gemfire/cache/lucene/internal/cli/functions/LuceneListIndexFunctionJUnitTest.java new file mode 100644 index 0000000..cb22cf8 --- /dev/null +++ b/geode-lucene/src/test/java/com/gemstone/gemfire/cache/lucene/internal/cli/functions/LuceneListIndexFunctionJUnitTest.java @@ -0,0 +1,102 @@ +/* + * 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 com.gemstone.gemfire.cache.lucene.internal.cli.functions; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.*; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; + +import org.apache.lucene.analysis.Analyzer; +import org.apache.lucene.analysis.core.KeywordAnalyzer; +import org.apache.lucene.analysis.standard.StandardAnalyzer; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.mockito.ArgumentCaptor; +import org.mockito.Mockito; + +import com.gemstone.gemfire.cache.execute.FunctionContext; +import com.gemstone.gemfire.cache.execute.ResultSender; +import com.gemstone.gemfire.cache.lucene.LuceneIndex; +import com.gemstone.gemfire.cache.lucene.internal.InternalLuceneService; +import com.gemstone.gemfire.cache.lucene.internal.LuceneIndexImpl; +import com.gemstone.gemfire.cache.lucene.internal.cli.LuceneIndexDetails; +import com.gemstone.gemfire.internal.cache.GemFireCacheImpl; +import com.gemstone.gemfire.test.fake.Fakes; +import com.gemstone.gemfire.test.junit.categories.UnitTest; + +@Category(UnitTest.class) + +public class LuceneListIndexFunctionJUnitTest { + + @Test + @SuppressWarnings("unchecked") + public void testExecute() throws Throwable { + GemFireCacheImpl cache = Fakes.cache(); + InternalLuceneService service = mock(InternalLuceneService.class); + when(cache.getService(InternalLuceneService.class)).thenReturn(service); + + FunctionContext context = mock(FunctionContext.class); + ResultSender resultSender = mock(ResultSender.class); + when(context.getResultSender()).thenReturn(resultSender); + + LuceneIndexImpl index1 = getMockLuceneIndex("index1"); + LuceneIndexImpl index2 = getMockLuceneIndex("index2"); + + TreeSet expectedResult = new TreeSet(); + expectedResult.add(new LuceneIndexDetails(index1)); + expectedResult.add(new LuceneIndexDetails(index2)); + + ArrayList allIndexes = new ArrayList(); + allIndexes.add(index1); + allIndexes.add(index2); + when(service.getAllIndexes()).thenReturn(allIndexes); + + LuceneListIndexFunction function = new LuceneListIndexFunction(); + function = spy(function); + Mockito.doReturn(cache).when(function).getCache(); + function.execute(context); + + ArgumentCaptor resultCaptor = ArgumentCaptor.forClass(Set.class); + verify(resultSender).lastResult(resultCaptor.capture()); + Set result = resultCaptor.getValue(); + + assertEquals(2, result.size()); + assertEquals(expectedResult, result); + } + + private LuceneIndexImpl getMockLuceneIndex(final String indexName) + { + String[] searchableFields={"field1","field2"}; + Map fieldAnalyzers = new HashMap<>(); + fieldAnalyzers.put("field1", new StandardAnalyzer()); + fieldAnalyzers.put("field2", new KeywordAnalyzer()); + + LuceneIndexImpl index = mock(LuceneIndexImpl.class); + when(index.getName()).thenReturn(indexName); + when(index.getRegionPath()).thenReturn("/region"); + when(index.getFieldNames()).thenReturn(searchableFields); + when(index.getFieldAnalyzers()).thenReturn(fieldAnalyzers); + return index; + } + +}