This is an automated email from the ASF dual-hosted git repository. jensdeppe pushed a commit to branch develop in repository https://gitbox.apache.org/repos/asf/geode.git
The following commit(s) were added to refs/heads/develop by this push: new 1e7c05c GEODE-5011: Convert ExecuteFunctionCommand and ExportConfigCommand to use ResultModel (#1901) 1e7c05c is described below commit 1e7c05c1832705d48fd035d180331418b7bb0d81 Author: Jens Deppe <jde...@pivotal.io> AuthorDate: Tue May 8 08:11:02 2018 -0700 GEODE-5011: Convert ExecuteFunctionCommand and ExportConfigCommand to use ResultModel (#1901) --- .../internal/cli/CliAroundInterceptor.java | 5 +- .../cli/commands/ExecuteFunctionCommand.java | 26 ++-- .../internal/cli/commands/ExportConfigCommand.java | 46 +++--- .../ExportImportClusterConfigurationCommands.java | 7 +- .../cli/commands/ExportLogsInterceptor.java | 8 +- .../internal/cli/commands/QueryInterceptor.java | 6 +- .../internal/cli/result/AbstractResultData.java | 12 -- .../internal/cli/result/CompositeResultData.java | 4 +- .../internal/cli/result/LegacyCommandResult.java | 12 +- .../internal/cli/result/ModelCommandResult.java | 7 +- .../management/internal/cli/result/ResultData.java | 12 +- .../cli/result/model/AbstractResultModel.java | 1 + .../internal/cli/result/model/FileResultModel.java | 162 +++++++++++++++++++++ .../internal/cli/result/model/ResultModel.java | 23 +++ .../internal/cli/shell/GfshExecutionStrategy.java | 6 +- .../cli/commands/ExecuteFunctionCommandTest.java | 52 +++++++ .../cli/commands/ExportConfigCommandTest.java | 52 +++++++ .../internal/cli/commands/CommandOverHttpTest.java | 4 +- .../cli/commands/ExportConfigCommandDUnitTest.java | 1 + 19 files changed, 376 insertions(+), 70 deletions(-) diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/CliAroundInterceptor.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/CliAroundInterceptor.java index ccd60a0..59431fe 100644 --- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/CliAroundInterceptor.java +++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/CliAroundInterceptor.java @@ -16,7 +16,7 @@ package org.apache.geode.management.internal.cli; import java.nio.file.Path; -import org.apache.geode.management.cli.Result; +import org.apache.geode.management.internal.cli.result.CommandResult; import org.apache.geode.management.internal.cli.result.ResultBuilder; import org.apache.geode.management.internal.cli.shell.GfshExecutionStrategy; @@ -42,7 +42,8 @@ public interface CliAroundInterceptor { * @param tempFile if the command's isFileDownloadOverHttp is true, the is the File downloaded * after the http response is processed. */ - default Result postExecution(GfshParseResult parseResult, Result commandResult, Path tempFile) { + default CommandResult postExecution(GfshParseResult parseResult, CommandResult commandResult, + Path tempFile) { return commandResult; } diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/ExecuteFunctionCommand.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/ExecuteFunctionCommand.java index 909e053..4611503 100644 --- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/ExecuteFunctionCommand.java +++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/ExecuteFunctionCommand.java @@ -35,15 +35,14 @@ import org.apache.geode.management.internal.cli.GfshParseResult; import org.apache.geode.management.internal.cli.functions.CliFunctionResult; import org.apache.geode.management.internal.cli.functions.UserFunctionExecution; import org.apache.geode.management.internal.cli.i18n.CliStrings; -import org.apache.geode.management.internal.cli.result.CompositeResultData; -import org.apache.geode.management.internal.cli.result.ResultBuilder; -import org.apache.geode.management.internal.cli.result.TabularResultData; +import org.apache.geode.management.internal.cli.result.model.ResultModel; +import org.apache.geode.management.internal.cli.result.model.TabularResultModel; public class ExecuteFunctionCommand extends InternalGfshCommand { @CliCommand(value = CliStrings.EXECUTE_FUNCTION, help = CliStrings.EXECUTE_FUNCTION__HELP) @CliMetaData(relatedTopic = {CliStrings.TOPIC_GEODE_FUNCTION}, interceptor = "org.apache.geode.management.internal.cli.commands.ExecuteFunctionCommand$ExecuteFunctionCommandInterceptor") - public Result executeFunction( + public ResultModel executeFunction( @CliOption(key = CliStrings.EXECUTE_FUNCTION__ID, mandatory = true, help = CliStrings.EXECUTE_FUNCTION__ID__HELP) String functionId, @CliOption(key = {CliStrings.GROUP, CliStrings.GROUPS}, @@ -62,8 +61,8 @@ public class ExecuteFunctionCommand extends InternalGfshCommand { @CliOption(key = CliStrings.EXECUTE_FUNCTION__FILTER, help = CliStrings.EXECUTE_FUNCTION__FILTER__HELP) String filterString) { - CompositeResultData executeFunctionResultTable = ResultBuilder.createCompositeResultData(); - TabularResultData resultTable = executeFunctionResultTable.addSection().addTable("Table1"); + ResultModel resultModel = new ResultModel(); + TabularResultModel resultTable = resultModel.addTable("Table1"); String headerText = "Execution summary"; resultTable.setHeader(headerText); @@ -78,7 +77,7 @@ public class ExecuteFunctionCommand extends InternalGfshCommand { } if (dsMembers.size() == 0) { - return ResultBuilder.createUserErrorResult("No members found."); + return new ResultModel().createError("No members found."); } // Build up our argument list @@ -116,16 +115,16 @@ public class ExecuteFunctionCommand extends InternalGfshCommand { resultTable.accumulate("Member ID/Name", r.getMemberIdOrName()); resultTable.accumulate("Function Execution Result", r.getMessage()); if (!r.isSuccessful()) { - resultTable.setStatus(Result.Status.ERROR); + resultModel.setStatus(Result.Status.ERROR); } } - return ResultBuilder.buildResult(resultTable); + return resultModel; } public static class ExecuteFunctionCommandInterceptor implements CliAroundInterceptor { @Override - public Result preExecution(GfshParseResult parseResult) { + public ResultModel preExecution(GfshParseResult parseResult) { String onRegion = parseResult.getParamValueAsString(CliStrings.EXECUTE_FUNCTION__ONREGION); String onMember = parseResult.getParamValueAsString(CliStrings.MEMBER); String onGroup = parseResult.getParamValueAsString(CliStrings.GROUP); @@ -134,16 +133,17 @@ public class ExecuteFunctionCommand extends InternalGfshCommand { boolean moreThanOne = Stream.of(onRegion, onMember, onGroup).filter(Objects::nonNull).count() > 1; + ResultModel result = new ResultModel(); if (moreThanOne) { - return ResultBuilder.createUserErrorResult(CliStrings.EXECUTE_FUNCTION__MSG__OPTIONS); + return result.createError(CliStrings.EXECUTE_FUNCTION__MSG__OPTIONS); } if (onRegion == null && filter != null) { - return ResultBuilder.createUserErrorResult( + return result.createError( CliStrings.EXECUTE_FUNCTION__MSG__MEMBER_SHOULD_NOT_HAVE_FILTER_FOR_EXECUTION); } - return ResultBuilder.createInfoResult(""); + return result; } } } diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/ExportConfigCommand.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/ExportConfigCommand.java index 81fc924..bb82b3c 100644 --- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/ExportConfigCommand.java +++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/ExportConfigCommand.java @@ -28,15 +28,16 @@ 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.AbstractCliAroundInterceptor; import org.apache.geode.management.internal.cli.CliUtil; import org.apache.geode.management.internal.cli.GfshParseResult; import org.apache.geode.management.internal.cli.functions.CliFunctionResult; import org.apache.geode.management.internal.cli.functions.ExportConfigFunction; 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.cli.result.CommandResult; +import org.apache.geode.management.internal.cli.result.ResultData; +import org.apache.geode.management.internal.cli.result.model.InfoResultModel; +import org.apache.geode.management.internal.cli.result.model.ResultModel; import org.apache.geode.management.internal.cli.shell.Gfsh; import org.apache.geode.management.internal.security.ResourceOperation; import org.apache.geode.security.ResourcePermission; @@ -57,7 +58,7 @@ public class ExportConfigCommand extends InternalGfshCommand { relatedTopic = {CliStrings.TOPIC_GEODE_CONFIG}) @ResourceOperation(resource = ResourcePermission.Resource.CLUSTER, operation = ResourcePermission.Operation.READ) - public Result exportConfig( + public ResultModel exportConfig( @CliOption(key = {CliStrings.MEMBER, CliStrings.MEMBERS}, optionContext = ConverterHint.ALL_MEMBER_IDNAME, help = CliStrings.EXPORT_CONFIG__MEMBER__HELP) String[] member, @@ -66,11 +67,14 @@ public class ExportConfigCommand extends InternalGfshCommand { help = CliStrings.EXPORT_CONFIG__GROUP__HELP) String[] group, @CliOption(key = {CliStrings.EXPORT_CONFIG__DIR}, help = CliStrings.EXPORT_CONFIG__DIR__HELP) String dir) { - InfoResultData infoData = ResultBuilder.createInfoResultData(); + + ResultModel crm = new ResultModel(); + InfoResultModel infoData = crm.addInfo(); Set<DistributedMember> targetMembers = findMembers(group, member); if (targetMembers.isEmpty()) { - return ResultBuilder.createUserErrorResult(CliStrings.NO_MEMBERS_FOUND_MESSAGE); + crm.createError(CliStrings.NO_MEMBERS_FOUND_MESSAGE); + return crm; } ResultCollector<?, ?> rc = @@ -85,13 +89,14 @@ public class ExportConfigCommand extends InternalGfshCommand { String cacheFileName = result.getMemberIdOrName() + "-cache.xml"; String propsFileName = result.getMemberIdOrName() + "-gf.properties"; String[] fileContent = (String[]) result.getSerializables(); - infoData.addAsFile(cacheFileName, fileContent[0], "Downloading Cache XML file: {0}", false); - infoData.addAsFile(propsFileName, fileContent[1], "Downloading properties file: {0}", - false); + crm.addFile(cacheFileName, fileContent[0].getBytes(), ResultData.FILE_TYPE_TEXT, + "Downloading Cache XML file: ", false); + crm.addFile(propsFileName, fileContent[1].getBytes(), ResultData.FILE_TYPE_TEXT, + "Downloading properties file: ", false); } } - return ResultBuilder.buildResult(infoData); + return crm; } /** @@ -101,41 +106,42 @@ public class ExportConfigCommand extends InternalGfshCommand { private String saveDirString; @Override - public Result preExecution(GfshParseResult parseResult) { + public ResultModel preExecution(GfshParseResult parseResult) { String dir = parseResult.getParamValueAsString("dir"); if (StringUtils.isBlank(dir)) { saveDirString = new File(".").getAbsolutePath(); - return ResultBuilder.createInfoResult("OK"); + return new ResultModel(); } File saveDirFile = new File(dir.trim()); if (!saveDirFile.exists() && !saveDirFile.mkdirs()) { - return ResultBuilder.createGemFireErrorResult( - CliStrings.format(CliStrings.EXPORT_CONFIG__MSG__CANNOT_CREATE_DIR, dir)); + return ResultModel + .createError(CliStrings.format(CliStrings.EXPORT_CONFIG__MSG__CANNOT_CREATE_DIR, dir)); } if (!saveDirFile.isDirectory()) { - return ResultBuilder.createGemFireErrorResult( - CliStrings.format(CliStrings.EXPORT_CONFIG__MSG__NOT_A_DIRECTORY, dir)); + return ResultModel + .createError(CliStrings.format(CliStrings.EXPORT_CONFIG__MSG__NOT_A_DIRECTORY, dir)); } try { if (!saveDirFile.canWrite()) { - return ResultBuilder.createGemFireErrorResult(CliStrings.format( + return ResultModel.createError(CliStrings.format( CliStrings.EXPORT_CONFIG__MSG__NOT_WRITEABLE, saveDirFile.getCanonicalPath())); } } catch (IOException ioex) { - return ResultBuilder.createGemFireErrorResult( + return ResultModel.createError( CliStrings.format(CliStrings.EXPORT_CONFIG__MSG__NOT_WRITEABLE, saveDirFile.getName())); } saveDirString = saveDirFile.getAbsolutePath(); - return ResultBuilder.createInfoResult("OK"); + return new ResultModel(); } @Override - public Result postExecution(GfshParseResult parseResult, Result commandResult, Path tempFile) { + public CommandResult postExecution(GfshParseResult parseResult, CommandResult commandResult, + Path tempFile) { if (commandResult.hasIncomingFiles()) { try { commandResult.saveIncomingFiles(saveDirString); diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/ExportImportClusterConfigurationCommands.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/ExportImportClusterConfigurationCommands.java index 162b33d..797d935 100644 --- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/ExportImportClusterConfigurationCommands.java +++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/ExportImportClusterConfigurationCommands.java @@ -48,10 +48,12 @@ import org.apache.geode.management.internal.cli.GfshParseResult; import org.apache.geode.management.internal.cli.functions.CliFunctionResult; import org.apache.geode.management.internal.cli.i18n.CliStrings; import org.apache.geode.management.internal.cli.remote.CommandExecutionContext; +import org.apache.geode.management.internal.cli.result.CommandResult; import org.apache.geode.management.internal.cli.result.ErrorResultData; import org.apache.geode.management.internal.cli.result.FileResult; 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.ResultData; import org.apache.geode.management.internal.cli.shell.Gfsh; import org.apache.geode.management.internal.configuration.domain.Configuration; import org.apache.geode.management.internal.configuration.functions.GetRegionNamesFunction; @@ -105,7 +107,7 @@ public class ExportImportClusterConfigurationCommands extends InternalGfshComman InfoResultData infoData = ResultBuilder.createInfoResultData(); byte[] byteData = FileUtils.readFileToByteArray(zipFile); - infoData.addAsFile(zipFileName, byteData, InfoResultData.FILE_TYPE_BINARY, + infoData.addAsFile(zipFileName, byteData, ResultData.FILE_TYPE_BINARY, CliStrings.EXPORT_SHARED_CONFIG__DOWNLOAD__MSG, false); result = ResultBuilder.buildResult(infoData); } catch (Exception e) { @@ -237,7 +239,8 @@ public class ExportImportClusterConfigurationCommands extends InternalGfshComman } @Override - public Result postExecution(GfshParseResult parseResult, Result commandResult, Path tempFile) { + public CommandResult postExecution(GfshParseResult parseResult, CommandResult commandResult, + Path tempFile) { if (commandResult.hasIncomingFiles()) { try { commandResult.saveIncomingFiles(System.getProperty("user.dir")); diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/ExportLogsInterceptor.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/ExportLogsInterceptor.java index 5f13784..1d2da28 100644 --- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/ExportLogsInterceptor.java +++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/ExportLogsInterceptor.java @@ -30,6 +30,7 @@ import org.apache.geode.management.cli.Result; import org.apache.geode.management.internal.cli.AbstractCliAroundInterceptor; import org.apache.geode.management.internal.cli.GfshParseResult; import org.apache.geode.management.internal.cli.functions.ExportLogsFunction; +import org.apache.geode.management.internal.cli.result.CommandResult; import org.apache.geode.management.internal.cli.result.ResultBuilder; /** @@ -77,7 +78,8 @@ public class ExportLogsInterceptor extends AbstractCliAroundInterceptor { } @Override - public Result postExecution(GfshParseResult parseResult, Result commandResult, Path tempFile) { + public CommandResult postExecution(GfshParseResult parseResult, CommandResult commandResult, + Path tempFile) { // in the command over http case, the command result is in the downloaded temp file if (tempFile != null) { Path dirPath; @@ -92,14 +94,14 @@ public class ExportLogsInterceptor extends AbstractCliAroundInterceptor { try { FileUtils.copyFile(tempFile.toFile(), exportedLogFile); FileUtils.deleteQuietly(tempFile.toFile()); - commandResult = ResultBuilder + commandResult = (CommandResult) ResultBuilder .createInfoResult("Logs exported to: " + exportedLogFile.getAbsolutePath()); } catch (IOException e) { logger.error(e.getMessage(), e); commandResult = ResultBuilder.createGemFireErrorResult(e.getMessage()); } } else if (commandResult.getStatus() == Result.Status.OK) { - commandResult = ResultBuilder.createInfoResult( + commandResult = (CommandResult) ResultBuilder.createInfoResult( "Logs exported to the connected member's file system: " + commandResult.nextLine()); } return commandResult; diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/QueryInterceptor.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/QueryInterceptor.java index 53f4ad9..e9f8ce2 100644 --- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/QueryInterceptor.java +++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/QueryInterceptor.java @@ -50,15 +50,15 @@ public class QueryInterceptor extends AbstractCliAroundInterceptor { } @Override - public Result postExecution(GfshParseResult parseResult, Result result, Path tempFile) { + public CommandResult postExecution(GfshParseResult parseResult, CommandResult result, + Path tempFile) { File outputFile = getOutputFile(parseResult); if (outputFile == null) { return result; } - CommandResult commandResult = (CommandResult) result; - CompositeResultData resultData = (CompositeResultData) commandResult.getResultData(); + CompositeResultData resultData = (CompositeResultData) result.getResultData(); CompositeResultData.SectionResultData sectionResultData = resultData.retrieveSectionByIndex(0); String limit = sectionResultData.retrieveString("Limit"); diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/result/AbstractResultData.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/result/AbstractResultData.java index c19b569..fd3c636 100644 --- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/result/AbstractResultData.java +++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/result/AbstractResultData.java @@ -39,18 +39,6 @@ import org.apache.geode.management.internal.cli.shell.Gfsh; * @since GemFire 7.0 */ public abstract class AbstractResultData implements ResultData { - public static final String SECTION_DATA_ACCESSOR = "__sections__"; - public static final String TABLE_DATA_ACCESSOR = "__tables__"; - public static final String BYTE_DATA_ACCESSOR = "__bytes__"; - - public static final int FILE_TYPE_BINARY = 0; - public static final int FILE_TYPE_TEXT = 1; - private static final String FILE_NAME_FIELD = "fileName"; - private static final String FILE_TYPE_FIELD = "fileType"; - private static final String FILE_DATA_FIELD = "fileData"; - private static final String DATA_FIELD = "data"; - private static final String DATA_LENGTH_FIELD = "dataLength"; - private static final String FILE_MESSAGE = "fileMessage"; protected GfJsonObject gfJsonObject; protected GfJsonObject contentObject; diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/result/CompositeResultData.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/result/CompositeResultData.java index b947621..3b73f52 100644 --- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/result/CompositeResultData.java +++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/result/CompositeResultData.java @@ -93,7 +93,7 @@ public class CompositeResultData extends AbstractResultData { int i = 0; for (Iterator<String> iterator = contentObject.keys(); iterator.hasNext();) { String key = iterator.next(); - if (key.startsWith(CompositeResultData.SECTION_DATA_ACCESSOR)) { + if (key.startsWith(ResultData.SECTION_DATA_ACCESSOR)) { if (i == index) { sectionToRetrieve = new SectionResultData(contentObject.getJSONObject(key)); break; @@ -204,7 +204,7 @@ public class CompositeResultData extends AbstractResultData { int i = 0; for (Iterator<String> iterator = sectionGfJsonObject.keys(); iterator.hasNext();) { String key = iterator.next(); - if (key.startsWith(CompositeResultData.TABLE_DATA_ACCESSOR)) { + if (key.startsWith(ResultData.TABLE_DATA_ACCESSOR)) { if (i == index) { tabularResultData = new TabularResultData(sectionGfJsonObject.getJSONObject(key)); break; diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/result/LegacyCommandResult.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/result/LegacyCommandResult.java index a56fe67..353e7e0 100644 --- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/result/LegacyCommandResult.java +++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/result/LegacyCommandResult.java @@ -183,7 +183,7 @@ public class LegacyCommandResult implements CommandResult { for (Iterator<String> it = content.keys(); it.hasNext();) { String key = it.next(); - if (key.startsWith(CompositeResultData.SECTION_DATA_ACCESSOR)) { + if (key.startsWith(ResultData.SECTION_DATA_ACCESSOR)) { GfJsonObject subSection = content.getJSONObject(key); buildSection(resultTable, null, subSection, 0); } else if (key.equals(CompositeResultData.SEPARATOR)) { @@ -218,7 +218,7 @@ public class LegacyCommandResult implements CommandResult { while (keys.hasNext()) { String key = keys.next(); Object object = section.get(key); - if (key.startsWith(CompositeResultData.TABLE_DATA_ACCESSOR)) { + if (key.startsWith(ResultData.TABLE_DATA_ACCESSOR)) { GfJsonObject tableObject = section.getJSONObject(key); addHeaderInTable(table, tableObject); @@ -273,7 +273,7 @@ public class LegacyCommandResult implements CommandResult { // build Table Header first for (int i = 0; i < numOfColumns; i++) { Object object = columnNames.get(i); - if (AbstractResultData.BYTE_DATA_ACCESSOR.equals(object)) { + if (ResultData.BYTE_DATA_ACCESSOR.equals(object)) { // skip file data if any continue; } @@ -284,7 +284,7 @@ public class LegacyCommandResult implements CommandResult { Row[] dataRows = null; for (int i = 0; i < numOfColumns; i++) { Object object = columnNames.get(i); - if (AbstractResultData.BYTE_DATA_ACCESSOR.equals(object)) { + if (ResultData.BYTE_DATA_ACCESSOR.equals(object)) { // skip file data if any continue; } @@ -320,7 +320,7 @@ public class LegacyCommandResult implements CommandResult { try { GfJsonObject content = getContent(); if (content != null) { - fileDataArray = content.getJSONArray(CompositeResultData.BYTE_DATA_ACCESSOR); + fileDataArray = content.getJSONArray(ResultData.BYTE_DATA_ACCESSOR); } } catch (GfJsonException e) { e.printStackTrace(); @@ -339,7 +339,7 @@ public class LegacyCommandResult implements CommandResult { try { GfJsonObject content = getContent(); if (content != null) { - GfJsonArray bytesArray = content.getJSONArray(CompositeResultData.BYTE_DATA_ACCESSOR); + GfJsonArray bytesArray = content.getJSONArray(ResultData.BYTE_DATA_ACCESSOR); AbstractResultData.readFileDataAndDump(bytesArray, directory); } else { throw new RuntimeException("No associated files to save .. "); diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/result/ModelCommandResult.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/result/ModelCommandResult.java index 092c3b2..0824910 100644 --- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/result/ModelCommandResult.java +++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/result/ModelCommandResult.java @@ -27,6 +27,7 @@ import org.apache.geode.management.internal.cli.GfshParser; import org.apache.geode.management.internal.cli.json.GfJsonObject; import org.apache.geode.management.internal.cli.result.model.AbstractResultModel; import org.apache.geode.management.internal.cli.result.model.DataResultModel; +import org.apache.geode.management.internal.cli.result.model.FileResultModel; import org.apache.geode.management.internal.cli.result.model.InfoResultModel; import org.apache.geode.management.internal.cli.result.model.ResultModel; import org.apache.geode.management.internal.cli.result.model.TabularResultModel; @@ -72,7 +73,7 @@ public class ModelCommandResult implements CommandResult { @Override public boolean hasIncomingFiles() { - return false; + return result.getFiles().size() > 0; } @Override @@ -82,7 +83,9 @@ public class ModelCommandResult implements CommandResult { @Override public void saveIncomingFiles(String directory) throws IOException { - + for (FileResultModel file : result.getFiles().values()) { + file.writeFile(directory); + } } @Override diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/result/ResultData.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/result/ResultData.java index a4ca7eb..6b2656a 100644 --- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/result/ResultData.java +++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/result/ResultData.java @@ -25,12 +25,22 @@ public interface ResultData { String RESULT_CONTENT = "content"; String RESULT_FOOTER = "footer"; - String TYPE_COMPOSITE = "composite"; String TYPE_ERROR = "error"; String TYPE_INFO = "info"; String TYPE_TABULAR = "table"; + String SECTION_DATA_ACCESSOR = "__sections__"; + String TABLE_DATA_ACCESSOR = "__tables__"; + String BYTE_DATA_ACCESSOR = "__bytes__"; + int FILE_TYPE_BINARY = 0; + int FILE_TYPE_TEXT = 1; + String FILE_NAME_FIELD = "fileName"; + String FILE_TYPE_FIELD = "fileType"; + String FILE_DATA_FIELD = "fileData"; + String DATA_LENGTH_FIELD = "dataLength"; + String FILE_MESSAGE = "fileMessage"; + String getHeader(); String getFooter(); diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/result/model/AbstractResultModel.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/result/model/AbstractResultModel.java index aee54aa..709a481 100644 --- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/result/model/AbstractResultModel.java +++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/result/model/AbstractResultModel.java @@ -50,4 +50,5 @@ public abstract class AbstractResultModel { public void setFooter(String footer) { this.footer = footer; } + } diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/result/model/FileResultModel.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/result/model/FileResultModel.java new file mode 100644 index 0000000..0712a14 --- /dev/null +++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/result/model/FileResultModel.java @@ -0,0 +1,162 @@ +/* + * 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.result.model; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileOutputStream; +import java.io.FileWriter; +import java.io.IOException; +import java.text.MessageFormat; + +import org.apache.geode.management.internal.cli.i18n.CliStrings; +import org.apache.geode.management.internal.cli.result.ResultData; +import org.apache.geode.management.internal.cli.shell.Gfsh; + +public class FileResultModel { + + private String filename; + private int type; + private String message; + private byte[] data; + private int length; + + public FileResultModel() {} + + public FileResultModel(String fileName, byte[] data, int fileType, String message) { + this.filename = fileName; + this.data = data; + this.length = data.length; + this.type = fileType; + this.message = message; + } + + public String getFilename() { + return filename; + } + + public void setFilename(String filename) { + this.filename = filename; + } + + public int getType() { + return type; + } + + public void setType(int type) { + this.type = type; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public byte[] getData() { + return data; + } + + public void setData(byte[] data) { + this.data = data; + } + + public int getLength() { + return length; + } + + public void setLength(int length) { + this.length = length; + } + + public void writeFile(String directory) throws IOException { + String options = "(y/N)"; + + File fileToDumpData = new File(filename); + if (!fileToDumpData.isAbsolute()) { + if (directory == null || directory.isEmpty()) { + directory = System.getProperty("user.dir", "."); + } + fileToDumpData = new File(directory, filename); + } + + File parentDirectory = fileToDumpData.getParentFile(); + if (parentDirectory != null) { + parentDirectory.mkdirs(); + } + Gfsh gfsh = Gfsh.getCurrentInstance(); + if (fileToDumpData.exists()) { + String fileExistsMessage = + CliStrings.format(CliStrings.ABSTRACTRESULTDATA__MSG__FILE_WITH_NAME_0_EXISTS_IN_1, + filename, fileToDumpData.getParent(), options); + if (gfsh != null && !gfsh.isQuietMode()) { + fileExistsMessage = fileExistsMessage + " Overwrite? " + options + " : "; + String interaction = gfsh.interact(fileExistsMessage); + if (!"y".equalsIgnoreCase(interaction.trim())) { + // do not save file & continue + return; + } + } else { + throw new IOException(fileExistsMessage); + } + } else if (!parentDirectory.exists()) { + handleCondition(CliStrings.format( + CliStrings.ABSTRACTRESULTDATA__MSG__PARENT_DIRECTORY_OF_0_DOES_NOT_EXIST, + fileToDumpData.getAbsolutePath())); + return; + } else if (!parentDirectory.canWrite()) { + handleCondition(CliStrings.format( + CliStrings.ABSTRACTRESULTDATA__MSG__PARENT_DIRECTORY_OF_0_IS_NOT_WRITABLE, + fileToDumpData.getAbsolutePath())); + return; + } else if (!parentDirectory.isDirectory()) { + handleCondition( + CliStrings.format(CliStrings.ABSTRACTRESULTDATA__MSG__PARENT_OF_0_IS_NOT_DIRECTORY, + fileToDumpData.getAbsolutePath())); + return; + } + if (type == ResultData.FILE_TYPE_TEXT) { + FileWriter fw = new FileWriter(fileToDumpData); + BufferedWriter bw = new BufferedWriter(fw); + bw.write(new String(data)); + bw.flush(); + fw.flush(); + fw.close(); + } else if (type == ResultData.FILE_TYPE_BINARY) { + FileOutputStream fos = new FileOutputStream(fileToDumpData); + fos.write(data); + fos.flush(); + fos.close(); + } + if (message != null && !message.isEmpty()) { + if (gfsh != null) { + Gfsh.println(MessageFormat.format(message, fileToDumpData.getAbsolutePath())); + } + } + } + + private void handleCondition(String message) throws IOException { + Gfsh gfsh = Gfsh.getCurrentInstance(); + // null check required in GfshVM too to avoid test issues + if (gfsh != null && !gfsh.isQuietMode()) { + gfsh.logWarning(message, null); + } else { + throw new IOException(message); + } + } +} diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/result/model/ResultModel.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/result/model/ResultModel.java index a132ac9..7097958 100644 --- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/result/model/ResultModel.java +++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/result/model/ResultModel.java @@ -15,6 +15,9 @@ package org.apache.geode.management.internal.cli.result.model; +import static org.apache.geode.management.internal.cli.result.AbstractResultData.FILE_TYPE_BINARY; +import static org.apache.geode.management.internal.cli.result.AbstractResultData.FILE_TYPE_TEXT; + import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.LinkedHashMap; @@ -49,12 +52,14 @@ import org.apache.geode.management.internal.cli.functions.CliFunctionResult; * */ public class ResultModel { + private String header; private String footer; private Map<String, AbstractResultModel> sections = new LinkedHashMap<>(); private int sectionCount = 0; private Result.Status status = Result.Status.OK; private Object configObject; + private Map<String, FileResultModel> files = new LinkedHashMap<>(); @JsonIgnore public Object getConfigObject() { @@ -113,6 +118,24 @@ public class ResultModel { this.sections = content; } + public Map<String, FileResultModel> getFiles() { + return files; + } + + public void setFiles(Map<String, FileResultModel> files) { + this.files = files; + } + + public void addFile(String fileName, byte[] data, int fileType, String message, + boolean addTimestampToName) { + if (fileType != FILE_TYPE_BINARY && fileType != FILE_TYPE_TEXT) { + throw new IllegalArgumentException("Unsupported file type is specified."); + } + + FileResultModel fileModel = new FileResultModel(fileName, data, fileType, message + fileName); + files.put(fileName, fileModel); + } + public InfoResultModel addInfo() { return addInfo(Integer.toString(sectionCount++)); } diff --git a/geode-core/src/main/java/org/apache/geode/management/internal/cli/shell/GfshExecutionStrategy.java b/geode-core/src/main/java/org/apache/geode/management/internal/cli/shell/GfshExecutionStrategy.java index 7402c24..7b7dedc 100755 --- a/geode-core/src/main/java/org/apache/geode/management/internal/cli/shell/GfshExecutionStrategy.java +++ b/geode-core/src/main/java/org/apache/geode/management/internal/cli/shell/GfshExecutionStrategy.java @@ -38,6 +38,7 @@ import org.apache.geode.management.internal.cli.GfshParseResult; import org.apache.geode.management.internal.cli.LogWrapper; import org.apache.geode.management.internal.cli.i18n.CliStrings; import org.apache.geode.management.internal.cli.remote.CommandExecutor; +import org.apache.geode.management.internal.cli.result.CommandResult; import org.apache.geode.management.internal.cli.result.FileResult; import org.apache.geode.management.internal.cli.result.ModelCommandResult; import org.apache.geode.management.internal.cli.result.ResultBuilder; @@ -144,7 +145,7 @@ public class GfshExecutionStrategy implements ExecutionStrategy { * @throws IllegalStateException if gfsh doesn't have an active connection. */ private Result executeOnRemote(GfshParseResult parseResult) { - Result commandResult = null; + CommandResult commandResult = null; Object response = null; Path tempFile = null; @@ -250,7 +251,8 @@ public class GfshExecutionStrategy implements ExecutionStrategy { // 3. Post Remote Execution if (interceptor != null) { - Result postExecResult = interceptor.postExecution(parseResult, commandResult, tempFile); + CommandResult postExecResult = + interceptor.postExecution(parseResult, commandResult, tempFile); if (postExecResult != null) { if (Status.ERROR.equals(postExecResult.getStatus())) { if (logWrapper.infoEnabled()) { diff --git a/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/ExecuteFunctionCommandTest.java b/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/ExecuteFunctionCommandTest.java new file mode 100644 index 0000000..6ff375e --- /dev/null +++ b/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/ExecuteFunctionCommandTest.java @@ -0,0 +1,52 @@ +/* + * 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.mockito.Mockito.spy; + +import org.junit.Before; +import org.junit.ClassRule; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +import org.apache.geode.test.junit.categories.UnitTest; +import org.apache.geode.test.junit.rules.GfshParserRule; + +@Category(UnitTest.class) +public class ExecuteFunctionCommandTest { + + @ClassRule + public static GfshParserRule gfsh = new GfshParserRule(); + + private ExecuteFunctionCommand command; + + @Before + public void before() throws Exception { + command = spy(ExecuteFunctionCommand.class); + } + + @Test + public void conflictingExecutionLocations() { + gfsh.executeAndAssertThat(command, "execute function --id=foo --region=bar --member=baz") + .statusIsError().containsOutput("Provide Only one of region/member/groups"); + } + + @Test + public void filterWithoutRegion() { + gfsh.executeAndAssertThat(command, "execute function --id=foo --filter=bar").statusIsError() + .containsOutput("Filters for executing on member or group is not supported"); + } +} diff --git a/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/ExportConfigCommandTest.java b/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/ExportConfigCommandTest.java new file mode 100644 index 0000000..abc21c3 --- /dev/null +++ b/geode-core/src/test/java/org/apache/geode/management/internal/cli/commands/ExportConfigCommandTest.java @@ -0,0 +1,52 @@ +/* + * 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.mockito.Mockito.spy; + +import org.junit.Before; +import org.junit.ClassRule; +import org.junit.Rule; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.rules.TemporaryFolder; + +import org.apache.geode.test.junit.categories.UnitTest; +import org.apache.geode.test.junit.rules.GfshParserRule; + +@Category(UnitTest.class) +public class ExportConfigCommandTest { + + @ClassRule + public static GfshParserRule gfsh = new GfshParserRule(); + + @Rule + public TemporaryFolder temp = new TemporaryFolder(); + + private ExportConfigCommand command; + + @Before + public void before() throws Exception { + command = spy(ExportConfigCommand.class); + } + + @Test + public void incorrectDirectoryShowsError() throws Exception { + String wrongDir = temp.newFile().getAbsolutePath(); + gfsh.executeAndAssertThat(command, "export config --dir=" + wrongDir).statusIsError() + .containsOutput(wrongDir + " is not a directory"); + } +} diff --git a/geode-web/src/test/java/org/apache/geode/management/internal/cli/commands/CommandOverHttpTest.java b/geode-web/src/test/java/org/apache/geode/management/internal/cli/commands/CommandOverHttpTest.java index 9ed1321..c890476 100644 --- a/geode-web/src/test/java/org/apache/geode/management/internal/cli/commands/CommandOverHttpTest.java +++ b/geode-web/src/test/java/org/apache/geode/management/internal/cli/commands/CommandOverHttpTest.java @@ -84,7 +84,7 @@ public class CommandOverHttpTest { public void exportConfig() throws Exception { String dir = temporaryFolder.getRoot().getAbsolutePath(); gfshRule.executeAndAssertThat("export config --dir=" + dir).statusIsSuccess() - .containsOutput("Downloading Cache XML file: " + dir + "/server-cache.xml") - .containsOutput("Downloading properties file: " + dir + "/server-gf.properties"); + .containsOutput("Downloading Cache XML file: server-cache.xml") + .containsOutput("Downloading properties file: server-gf.properties"); } } diff --git a/geode-web/src/test/java/org/apache/geode/management/internal/cli/commands/ExportConfigCommandDUnitTest.java b/geode-web/src/test/java/org/apache/geode/management/internal/cli/commands/ExportConfigCommandDUnitTest.java index 4a44fcb..763af13 100644 --- a/geode-web/src/test/java/org/apache/geode/management/internal/cli/commands/ExportConfigCommandDUnitTest.java +++ b/geode-web/src/test/java/org/apache/geode/management/internal/cli/commands/ExportConfigCommandDUnitTest.java @@ -39,6 +39,7 @@ import org.apache.geode.test.junit.rules.GfshCommandRule; @Category(DistributedTest.class) @RunWith(JUnitParamsRunner.class) public class ExportConfigCommandDUnitTest { + @Rule public ClusterStartupRule startupRule = new ClusterStartupRule().withLogFile(); -- To stop receiving notification emails like this one, please contact jensde...@apache.org.