Repository: geode
Updated Branches:
  refs/heads/feature/GEODE-2267 450516464 -> 112f26699


GEODE-2418: enable gfsh to download file from http connection


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

Branch: refs/heads/feature/GEODE-2267
Commit: 4a700206973e72099550aefbf89e3f29f52daf54
Parents: 4505164
Author: Jinmei Liao <[email protected]>
Authored: Tue Feb 21 15:54:12 2017 -0800
Committer: Jinmei Liao <[email protected]>
Committed: Wed Feb 22 09:14:50 2017 -0800

----------------------------------------------------------------------
 .../geode/management/cli/CliMetaData.java       |   8 ++
 .../cli/AbstractCliAroundInterceptor.java       |   4 +-
 .../internal/cli/CliAroundInterceptor.java      |  29 ++++-
 .../management/internal/cli/CommandRequest.java |  15 ++-
 .../cli/commands/MiscellaneousCommands.java     | 126 ++++++++++++-------
 .../cli/functions/ExportLogsFunction.java       |   7 +-
 .../internal/cli/i18n/CliStrings.java           |  30 ++++-
 .../cli/shell/GfshExecutionStrategy.java        |  62 +++++----
 .../cli/util/ExportLogsCacheWriter.java         |  10 +-
 .../MiscellaneousCommandsController.java        |  41 ++++--
 .../web/shell/AbstractHttpOperationInvoker.java |  42 ++++---
 .../web/shell/RestHttpOperationInvoker.java     |  35 +++---
 .../web/shell/SimpleHttpOperationInvoker.java   |  12 +-
 .../dunit/rules/GfshShellConnectionRule.java    |  26 ++--
 .../cli/commands/ExportLogsOverHttpDunit.java   | 113 +++++++++++++++++
 .../RestHttpOperationInvokerJUnitTest.java      |  46 +++----
 .../SimpleHttpOperationInvokerJUnitTest.java    |  18 +--
 17 files changed, 437 insertions(+), 187 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/geode/blob/4a700206/geode-core/src/main/java/org/apache/geode/management/cli/CliMetaData.java
----------------------------------------------------------------------
diff --git 
a/geode-core/src/main/java/org/apache/geode/management/cli/CliMetaData.java 
b/geode-core/src/main/java/org/apache/geode/management/cli/CliMetaData.java
index a20fba5..dc7d741 100644
--- a/geode-core/src/main/java/org/apache/geode/management/cli/CliMetaData.java
+++ b/geode-core/src/main/java/org/apache/geode/management/cli/CliMetaData.java
@@ -44,6 +44,14 @@ public @interface CliMetaData {
   boolean shellOnly() default false;
 
   /**
+   * Indicates when executed over http, is this command downloading files from 
the member.
+   * When this is set to true, the RestHttpOperationInvoker will use an 
extractor to extract
+   * the inputstream in the response to a temporary file and it's up to your 
command's interceptor's
+   * postExecution to use that temp file to fit your need.
+   **/
+  boolean isFileDownloadOverHttp() default false;
+
+  /**
    * Indicates that the effect of the command is persisted or the commands 
affects the persistent
    * configuration
    */

http://git-wip-us.apache.org/repos/asf/geode/blob/4a700206/geode-core/src/main/java/org/apache/geode/management/internal/cli/AbstractCliAroundInterceptor.java
----------------------------------------------------------------------
diff --git 
a/geode-core/src/main/java/org/apache/geode/management/internal/cli/AbstractCliAroundInterceptor.java
 
b/geode-core/src/main/java/org/apache/geode/management/internal/cli/AbstractCliAroundInterceptor.java
index de24727..3e1357d 100644
--- 
a/geode-core/src/main/java/org/apache/geode/management/internal/cli/AbstractCliAroundInterceptor.java
+++ 
b/geode-core/src/main/java/org/apache/geode/management/internal/cli/AbstractCliAroundInterceptor.java
@@ -14,10 +14,10 @@
  */
 package org.apache.geode.management.internal.cli;
 
-import java.io.IOException;
-
 import org.apache.geode.management.internal.cli.shell.Gfsh;
 
+import java.io.IOException;
+
 /**
  * Semi-complete implementation of {@link CliAroundInterceptor} for 
convenience for implementors.
  * 

http://git-wip-us.apache.org/repos/asf/geode/blob/4a700206/geode-core/src/main/java/org/apache/geode/management/internal/cli/CliAroundInterceptor.java
----------------------------------------------------------------------
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 11d74c1..2eeebb5 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
@@ -15,8 +15,11 @@
 package org.apache.geode.management.internal.cli;
 
 import org.apache.geode.management.cli.Result;
+import org.apache.geode.management.internal.cli.result.ResultBuilder;
 import org.apache.geode.management.internal.cli.shell.GfshExecutionStrategy;
 
+import java.nio.file.Path;
+
 /**
  * Interceptor interface which {@link GfshExecutionStrategy} can use to 
intercept before & after
  * actual command execution.
@@ -26,8 +29,30 @@ import 
org.apache.geode.management.internal.cli.shell.GfshExecutionStrategy;
  */
 public interface CliAroundInterceptor {
 
-  public Result preExecution(GfshParseResult parseResult);
+  /**
+   * called by the OperationInvoker before the command is executed
+   * @param parseResult
+   * @return
+   */
+  default public Result preExecution(GfshParseResult parseResult) {
+    return ResultBuilder.createInfoResult("");
+  }
+
+  @Deprecated
+  default public Result postExecution(GfshParseResult parseResult, Result 
commandResult){
+    return commandResult;
+  }
 
-  public Result postExecution(GfshParseResult parseResult, Result 
commandResult);
+  /**
+   * called by the OperationInvoker after the command is executed
+   * @param parseResult
+   * @param commandResult
+   * @param tempFile: if the command's isFileDownloadOverHttp is true, the is 
the File downloaded
+   * after the http response is processed.
+   * @return
+   */
+  default public Result postExecution(GfshParseResult parseResult, Result 
commandResult, Path tempFile) {
+    return postExecution(parseResult, commandResult);
+  }
 
 }

http://git-wip-us.apache.org/repos/asf/geode/blob/4a700206/geode-core/src/main/java/org/apache/geode/management/internal/cli/CommandRequest.java
----------------------------------------------------------------------
diff --git 
a/geode-core/src/main/java/org/apache/geode/management/internal/cli/CommandRequest.java
 
b/geode-core/src/main/java/org/apache/geode/management/internal/cli/CommandRequest.java
index b0242c9..a135340 100644
--- 
a/geode-core/src/main/java/org/apache/geode/management/internal/cli/CommandRequest.java
+++ 
b/geode-core/src/main/java/org/apache/geode/management/internal/cli/CommandRequest.java
@@ -14,12 +14,13 @@
  */
 package org.apache.geode.management.internal.cli;
 
+import org.apache.geode.internal.lang.StringUtils;
+import org.apache.geode.management.cli.CliMetaData;
+
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
 
-import org.apache.geode.internal.lang.StringUtils;
-
 /**
  * The CommandRequest class encapsulates information pertaining to the command 
the user entered in
  * Gfsh.
@@ -39,6 +40,7 @@ public class CommandRequest {
 
   private final Map<String, String> customParameters = new HashMap<String, 
String>();
   private final Map<String, String> env;
+  private boolean downloadFile = false;
 
   private String customInput;
 
@@ -65,6 +67,11 @@ public class CommandRequest {
     this.env = env;
     this.fileData = fileData;
     this.parseResult = parseResult;
+
+    CliMetaData metaData = 
parseResult.getMethod().getDeclaredAnnotation(CliMetaData.class);
+    if(metaData.isFileDownloadOverHttp()){
+      downloadFile = true;
+    }
   }
 
   public String getName() {
@@ -88,6 +95,10 @@ public class CommandRequest {
     return customInput;
   }
 
+  public boolean isDownloadFile(){
+    return downloadFile;
+  }
+
   public void setCustomInput(final String input) {
     this.customInput = input;
   }

http://git-wip-us.apache.org/repos/asf/geode/blob/4a700206/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/MiscellaneousCommands.java
----------------------------------------------------------------------
diff --git 
a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/MiscellaneousCommands.java
 
b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/MiscellaneousCommands.java
index e720d09..1da3d68 100644
--- 
a/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/MiscellaneousCommands.java
+++ 
b/geode-core/src/main/java/org/apache/geode/management/internal/cli/commands/MiscellaneousCommands.java
@@ -14,42 +14,8 @@
  */
 package org.apache.geode.management.internal.cli.commands;
 
-import java.io.BufferedInputStream;
-import java.io.BufferedReader;
-import java.io.ByteArrayInputStream;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.OutputStream;
-import java.io.PrintWriter;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.text.MessageFormat;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-import java.util.concurrent.Callable;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.Future;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-import java.util.zip.DataFormatException;
-import java.util.zip.GZIPInputStream;
-import javax.management.ObjectName;
-
 import org.apache.commons.io.FileUtils;
+import org.apache.commons.lang.StringUtils;
 import org.apache.geode.LogWriter;
 import org.apache.geode.cache.Cache;
 import org.apache.geode.cache.CacheFactory;
@@ -108,19 +74,49 @@ import 
org.apache.geode.management.internal.cli.result.ResultData;
 import org.apache.geode.management.internal.cli.result.ResultDataException;
 import org.apache.geode.management.internal.cli.result.TabularResultData;
 import org.apache.geode.management.internal.cli.shell.Gfsh;
-import org.apache.geode.management.internal.cli.util.MergeLogs;
 import org.apache.geode.management.internal.cli.util.ExportLogsCacheWriter;
 import org.apache.geode.management.internal.configuration.utils.ZipUtils;
 import org.apache.geode.management.internal.security.ResourceOperation;
 import org.apache.geode.security.ResourcePermission.Operation;
 import org.apache.geode.security.ResourcePermission.Resource;
-
 import org.apache.logging.log4j.Logger;
 import org.springframework.shell.core.CommandMarker;
 import org.springframework.shell.core.annotation.CliAvailabilityIndicator;
 import org.springframework.shell.core.annotation.CliCommand;
 import org.springframework.shell.core.annotation.CliOption;
 
+import java.io.BufferedInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.zip.DataFormatException;
+import java.util.zip.GZIPInputStream;
+import javax.management.ObjectName;
+
 /**
  * @since GemFire 7.0
  */
@@ -129,6 +125,7 @@ public class MiscellaneousCommands implements CommandMarker 
{
   public final static String FORMAT = "yyyy/MM/dd/HH/mm/ss/SSS/z";
   public final static String ONLY_DATE_FORMAT = "yyyy/MM/dd";
   public final static String DEFAULT_TIME_OUT = "10";
+  private static Logger logger = LogService.getLogger();
 
   private final GetStackTracesFunction getStackTracesFunction = new 
GetStackTracesFunction();
 
@@ -139,8 +136,6 @@ public class MiscellaneousCommands implements CommandMarker 
{
 
   public void shutdownNode(final long timeout, final Set<DistributedMember> 
includeMembers)
       throws TimeoutException, InterruptedException, ExecutionException {
-    Cache cache = CacheFactory.getAnyInstance();
-    LogWriter logger = cache.getLogger();
     ExecutorService exec = Executors.newSingleThreadExecutor();
     try {
       final Function shutDownFunction = new ShutDownFunction();
@@ -691,11 +686,13 @@ public class MiscellaneousCommands implements 
CommandMarker {
 
   @CliCommand(value = CliStrings.EXPORT_LOGS, help = 
CliStrings.EXPORT_LOGS__HELP)
   @CliMetaData(shellOnly = false,
+      isFileDownloadOverHttp = true,
+      interceptor = 
"org.apache.geode.management.internal.cli.commands.MiscellaneousCommands$ExportLogsInterceptor",
       relatedTopic = {CliStrings.TOPIC_GEODE_SERVER, 
CliStrings.TOPIC_GEODE_DEBUG_UTIL})
   @ResourceOperation(resource = Resource.CLUSTER, operation = Operation.READ)
   public Result exportLogs(
       @CliOption(key = CliStrings.EXPORT_LOGS__DIR, help = 
CliStrings.EXPORT_LOGS__DIR__HELP,
-          mandatory = true) String dirName,
+          mandatory = false) String dirName,
       @CliOption(key = CliStrings.EXPORT_LOGS__GROUP,
           unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE,
           optionContext = ConverterHint.MEMBERGROUP,
@@ -719,12 +716,11 @@ public class MiscellaneousCommands implements 
CommandMarker {
           unspecifiedDefaultValue = CliMetaData.ANNOTATION_NULL_VALUE,
           help = CliStrings.EXPORT_LOGS__ENDTIME__HELP) String end) {
     Result result = null;
-    Logger logger = LogService.getLogger();
-
     try {
       GemFireCacheImpl cache = GemFireCacheImpl.getInstance();
 
-      Set<DistributedMember> targetMembers = 
CliUtil.findMembersIncludingLocators(groups, memberIds);
+      Set<DistributedMember> targetMembers =
+          CliUtil.findMembersIncludingLocators(groups, memberIds);
 
 
       Map<String, Path> zipFilesFromMembers = new HashMap<>();
@@ -736,7 +732,8 @@ public class MiscellaneousCommands implements CommandMarker 
{
 
         cacheWriter.startFile(server.getName());
 
-        CliUtil.executeFunction(new ExportLogsFunction(),
+        CliUtil
+            .executeFunction(new ExportLogsFunction(),
                 new ExportLogsFunction.Args(start, end, logLevel, 
onlyLogLevel), server)
             .getResult();
         Path zipFile = cacheWriter.endFile();
@@ -756,12 +753,13 @@ public class MiscellaneousCommands implements 
CommandMarker {
       }
 
       Path workingDir = Paths.get(System.getProperty("user.dir"));
-      Path exportedLogsZipFile = workingDir.resolve("exportedLogs[" + 
System.currentTimeMillis() + "].zip").toAbsolutePath();
+      Path exportedLogsZipFile = workingDir
+          .resolve("exportedLogs_" + System.currentTimeMillis() + 
".zip").toAbsolutePath();
 
       logger.info("Zipping into: " + exportedLogsZipFile.toString());
       ZipUtils.zipDirectory(exportedLogsDir, exportedLogsZipFile);
       FileUtils.deleteDirectory(tempDir.toFile());
-      result = ResultBuilder.createInfoResult("File exported to: " + 
exportedLogsZipFile.toString());
+      result = ResultBuilder.createInfoResult(exportedLogsZipFile.toString());
     } catch (Exception ex) {
       ex.printStackTrace();
       logger.error(ex, ex);
@@ -774,7 +772,40 @@ public class MiscellaneousCommands implements 
CommandMarker {
     return result;
   }
 
-
+  /**
+   * after the export logs, will need to copy the tempFile to the desired 
location
+   * and delete the temp file.
+   */
+  public static class ExportLogsInterceptor extends 
AbstractCliAroundInterceptor {
+    @Override
+    public Result postExecution(GfshParseResult parseResult, Result 
commandResult, Path tempFile) {
+      // in the command over http case, the command result is in the 
downloaded temp file
+      if(tempFile!=null){
+        Path dirPath;
+        String dirName = parseResult.getParamValueStrings().get("dir");
+        if(StringUtils.isBlank(dirName)){
+          dirPath = Paths.get(System.getProperty("user.dir"));
+        }
+        else{
+          dirPath = Paths.get(dirName);
+        }
+        String fileName = "exportedLogs_"+System.currentTimeMillis()+".zip";
+        File exportedLogFile = dirPath.resolve(fileName).toFile();
+        try {
+          FileUtils.copyFile(tempFile.toFile(), exportedLogFile);
+          FileUtils.deleteQuietly(tempFile.toFile());
+          commandResult = ResultBuilder.createInfoResult("Logs exported to: 
"+exportedLogFile.getAbsolutePath());
+        } catch (IOException e) {
+          logger.error(e.getMessage(), e);
+          commandResult = 
ResultBuilder.createGemFireErrorResult(e.getMessage());
+        }
+      }
+      else{
+        commandResult = ResultBuilder.createInfoResult("Logs exported to the 
connected locator's file system: " + commandResult.nextLine());
+      }
+      return commandResult;
+    }
+  }
 
   /****
    * Current implementation supports writing it to a file and returning the 
location of the file
@@ -1005,6 +1036,7 @@ public class MiscellaneousCommands implements 
CommandMarker {
         result = 
ResultBuilder.buildResult(getSystemWideMetrics(export_to_report_to, 
categories));
       }
     } catch (Exception e) {
+      logger.error(e.getMessage(), e);
       return ResultBuilder.createGemFireErrorResult("#SB" + 
CliUtil.stackTraceAsString(e));
     }
     return result;

http://git-wip-us.apache.org/repos/asf/geode/blob/4a700206/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/ExportLogsFunction.java
----------------------------------------------------------------------
diff --git 
a/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/ExportLogsFunction.java
 
b/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/ExportLogsFunction.java
index 1dc89e9..560e8aa 100644
--- 
a/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/ExportLogsFunction.java
+++ 
b/geode-core/src/main/java/org/apache/geode/management/internal/cli/functions/ExportLogsFunction.java
@@ -17,7 +17,6 @@
 package org.apache.geode.management.internal.cli.functions;
 
 import static java.util.stream.Collectors.toSet;
-import static 
org.apache.geode.distributed.internal.DistributionManager.LOCATOR_DM_TYPE;
 
 import org.apache.geode.cache.AttributesFactory;
 import org.apache.geode.cache.DataPolicy;
@@ -99,10 +98,6 @@ public class ExportLogsFunction implements Function, 
InternalEntity {
     }
   }
 
-  protected static boolean isLocator(GemFireCacheImpl cache) {
-    return cache.getMyId().getVmKind() == LOCATOR_DM_TYPE;
-  }
-
   public static Region createOrGetExistingExportLogsRegion(boolean 
isInitiatingMember)
       throws IOException, ClassNotFoundException {
     GemFireCacheImpl cache = GemFireCacheImpl.getInstance();
@@ -134,7 +129,7 @@ public class ExportLogsFunction implements Function, 
InternalEntity {
       return;
     }
 
-      exportLogsRegion.destroyRegion();
+    exportLogsRegion.destroyRegion();
 
   }
 

http://git-wip-us.apache.org/repos/asf/geode/blob/4a700206/geode-core/src/main/java/org/apache/geode/management/internal/cli/i18n/CliStrings.java
----------------------------------------------------------------------
diff --git 
a/geode-core/src/main/java/org/apache/geode/management/internal/cli/i18n/CliStrings.java
 
b/geode-core/src/main/java/org/apache/geode/management/internal/cli/i18n/CliStrings.java
index c536e8e..cfba6d3 100644
--- 
a/geode-core/src/main/java/org/apache/geode/management/internal/cli/i18n/CliStrings.java
+++ 
b/geode-core/src/main/java/org/apache/geode/management/internal/cli/i18n/CliStrings.java
@@ -14,18 +14,38 @@
  */
 package org.apache.geode.management.internal.cli.i18n;
 
-import static org.apache.geode.distributed.ConfigurationProperties.*;
-
-import java.text.MessageFormat;
+import static 
org.apache.geode.distributed.ConfigurationProperties.ARCHIVE_DISK_SPACE_LIMIT;
+import static 
org.apache.geode.distributed.ConfigurationProperties.ARCHIVE_FILE_SIZE_LIMIT;
+import static 
org.apache.geode.distributed.ConfigurationProperties.CACHE_XML_FILE;
+import static 
org.apache.geode.distributed.ConfigurationProperties.DURABLE_CLIENT_ID;
+import static 
org.apache.geode.distributed.ConfigurationProperties.ENABLE_CLUSTER_CONFIGURATION;
+import static 
org.apache.geode.distributed.ConfigurationProperties.ENABLE_TIME_STATISTICS;
+import static org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER;
+import static org.apache.geode.distributed.ConfigurationProperties.LOCATORS;
+import static 
org.apache.geode.distributed.ConfigurationProperties.LOG_DISK_SPACE_LIMIT;
+import static 
org.apache.geode.distributed.ConfigurationProperties.LOG_FILE_SIZE_LIMIT;
+import static org.apache.geode.distributed.ConfigurationProperties.LOG_LEVEL;
+import static 
org.apache.geode.distributed.ConfigurationProperties.MCAST_ADDRESS;
+import static org.apache.geode.distributed.ConfigurationProperties.MCAST_PORT;
+import static 
org.apache.geode.distributed.ConfigurationProperties.MEMCACHED_BIND_ADDRESS;
+import static 
org.apache.geode.distributed.ConfigurationProperties.MEMCACHED_PORT;
+import static 
org.apache.geode.distributed.ConfigurationProperties.MEMCACHED_PROTOCOL;
+import static 
org.apache.geode.distributed.ConfigurationProperties.SERVER_BIND_ADDRESS;
+import static 
org.apache.geode.distributed.ConfigurationProperties.SOCKET_BUFFER_SIZE;
+import static 
org.apache.geode.distributed.ConfigurationProperties.STATISTIC_ARCHIVE_FILE;
+import static 
org.apache.geode.distributed.ConfigurationProperties.STATISTIC_SAMPLE_RATE;
+import static 
org.apache.geode.distributed.ConfigurationProperties.USE_CLUSTER_CONFIGURATION;
 
 import org.apache.geode.cache.PartitionAttributesFactory;
 import org.apache.geode.cache.server.CacheServer;
 import org.apache.geode.distributed.ConfigurationProperties;
-import org.apache.geode.distributed.internal.DistributionConfig;
 import org.apache.geode.distributed.internal.ClusterConfigurationService;
+import org.apache.geode.distributed.internal.DistributionConfig;
 import org.apache.geode.internal.cache.xmlcache.CacheXml;
 import org.apache.geode.management.internal.cli.shell.Gfsh;
 
+import java.text.MessageFormat;
+
 /**
  * - * Contains 'String' constants used as key to the Localized strings to be 
used in classes under
  * <code>org.apache.geode.management.internal.cli</code> for Command Line 
Interface (CLI). NOTES: 1.
@@ -1371,7 +1391,7 @@ public class CliStrings {
   public static final String EXPORT_LOGS__HELP = "Export the log files for a 
member or members.";
   public static final String EXPORT_LOGS__DIR = "dir";
   public static final String EXPORT_LOGS__DIR__HELP =
-      "Directory to which log files will be written.";
+      "Local directory to which log files will be written. This is only used 
when you are exporting logs using http connection. If no specified, user.dir 
will be used.";
   public static final String EXPORT_LOGS__MEMBER = "member";
   public static final String EXPORT_LOGS__MEMBER__HELP =
       "Name/Id of the member whose log files will be exported.";

http://git-wip-us.apache.org/repos/asf/geode/blob/4a700206/geode-core/src/main/java/org/apache/geode/management/internal/cli/shell/GfshExecutionStrategy.java
----------------------------------------------------------------------
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 b53c53f..02744e5 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
@@ -14,10 +14,7 @@
  */
 package org.apache.geode.management.internal.cli.shell;
 
-import static 
org.apache.geode.management.internal.cli.multistep.CLIMultiStepHelper.*;
-
-import java.lang.reflect.Method;
-import java.util.Map;
+import static 
org.apache.geode.management.internal.cli.multistep.CLIMultiStepHelper.execCLISteps;
 
 import org.apache.geode.internal.ClassPathLoader;
 import org.apache.geode.management.cli.CliMetaData;
@@ -35,13 +32,16 @@ import 
org.apache.geode.management.internal.cli.multistep.MultiStepCommand;
 import org.apache.geode.management.internal.cli.result.FileResult;
 import org.apache.geode.management.internal.cli.result.ResultBuilder;
 import org.apache.geode.security.NotAuthorizedException;
-
 import org.springframework.shell.core.ExecutionStrategy;
 import org.springframework.shell.core.Shell;
 import org.springframework.shell.event.ParseResult;
 import org.springframework.util.Assert;
 import org.springframework.util.ReflectionUtils;
 
+import java.lang.reflect.Method;
+import java.nio.file.Path;
+import java.util.Map;
+
 /**
  * Defines the {@link ExecutionStrategy} for commands that are executed in 
GemFire SHell (gfsh).
  * 
@@ -235,10 +235,14 @@ public class GfshExecutionStrategy implements 
ExecutionStrategy {
     try {
       response = shell.getOperationInvoker()
           .processCommand(new CommandRequest(parseResult, env, fileData));
+
     } catch (NotAuthorizedException e) {
       return ResultBuilder
           .createGemFireUnAuthorizedErrorResult("Unauthorized. Reason : " + 
e.getMessage());
-    } finally {
+    } catch (Exception e){
+      e.printStackTrace();
+    }
+    finally {
       env.clear();
     }
 
@@ -250,33 +254,39 @@ public class GfshExecutionStrategy implements 
ExecutionStrategy {
               + "Please check manager logs for error.");
     }
 
-    if (logWrapper.fineEnabled()) {
-      logWrapper.fine("Received response :: " + response);
-    }
-    CommandResponse commandResponse =
-        CommandResponseBuilder.prepareCommandResponseFromJson((String) 
response);
+    // the response could be a string which is a json respresentation of the 
CommandResult object
+    // it can also be a Path to a temp file downloaded from the rest http 
request
+    if(response instanceof String) {
+      CommandResponse commandResponse =
+          CommandResponseBuilder.prepareCommandResponseFromJson((String) 
response);
 
-    if (commandResponse.isFailedToPersist()) {
-      
shell.printAsSevere(CliStrings.SHARED_CONFIGURATION_FAILED_TO_PERSIST_COMMAND_CHANGES);
-      
logWrapper.severe(CliStrings.SHARED_CONFIGURATION_FAILED_TO_PERSIST_COMMAND_CHANGES);
+      if (commandResponse.isFailedToPersist()) {
+        
shell.printAsSevere(CliStrings.SHARED_CONFIGURATION_FAILED_TO_PERSIST_COMMAND_CHANGES);
+        
logWrapper.severe(CliStrings.SHARED_CONFIGURATION_FAILED_TO_PERSIST_COMMAND_CHANGES);
+      }
+
+      String debugInfo = commandResponse.getDebugInfo();
+      if (debugInfo != null && !debugInfo.trim().isEmpty()) {
+        // TODO - Abhishek When debug is ON, log response in gfsh logs
+        // TODO - Abhishek handle \n better. Is it coming from GemFire 
formatter
+        debugInfo = debugInfo.replaceAll("\n\n\n", "\n");
+        debugInfo = debugInfo.replaceAll("\n\n", "\n");
+        debugInfo =
+            debugInfo.replaceAll("\n", "\n[From Manager : " + 
commandResponse.getSender() + "]");
+        debugInfo = "[From Manager : " + commandResponse.getSender() + "]" + 
debugInfo;
+        LogWrapper.getInstance().info(debugInfo);
+      }
+      commandResult = ResultBuilder.fromJson((String) response);
     }
 
-    String debugInfo = commandResponse.getDebugInfo();
-    if (debugInfo != null && !debugInfo.trim().isEmpty()) {
-      // TODO - Abhishek When debug is ON, log response in gfsh logs
-      // TODO - Abhishek handle \n better. Is it coming from GemFire formatter
-      debugInfo = debugInfo.replaceAll("\n\n\n", "\n");
-      debugInfo = debugInfo.replaceAll("\n\n", "\n");
-      debugInfo =
-          debugInfo.replaceAll("\n", "\n[From Manager : " + 
commandResponse.getSender() + "]");
-      debugInfo = "[From Manager : " + commandResponse.getSender() + "]" + 
debugInfo;
-      LogWrapper.getInstance().info(debugInfo);
+    Path tempFile = null;
+    if(response instanceof Path){
+      tempFile = (Path)response;
     }
-    commandResult = ResultBuilder.fromJson((String) response);
 
     // 3. Post Remote Execution
     if (interceptor != null) {
-      Result postExecResult = interceptor.postExecution(parseResult, 
commandResult);
+      Result postExecResult = interceptor.postExecution(parseResult, 
commandResult, tempFile);
       if (postExecResult != null) {
         if (Status.ERROR.equals(postExecResult.getStatus())) {
           if (logWrapper.infoEnabled()) {

http://git-wip-us.apache.org/repos/asf/geode/blob/4a700206/geode-core/src/main/java/org/apache/geode/management/internal/cli/util/ExportLogsCacheWriter.java
----------------------------------------------------------------------
diff --git 
a/geode-core/src/main/java/org/apache/geode/management/internal/cli/util/ExportLogsCacheWriter.java
 
b/geode-core/src/main/java/org/apache/geode/management/internal/cli/util/ExportLogsCacheWriter.java
index a8b7225..178bb4a 100644
--- 
a/geode-core/src/main/java/org/apache/geode/management/internal/cli/util/ExportLogsCacheWriter.java
+++ 
b/geode-core/src/main/java/org/apache/geode/management/internal/cli/util/ExportLogsCacheWriter.java
@@ -22,15 +22,11 @@ import org.apache.geode.cache.EntryEvent;
 import org.apache.geode.cache.util.CacheWriterAdapter;
 
 import java.io.BufferedOutputStream;
-import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
-import java.io.OutputStream;
 import java.io.Serializable;
 import java.nio.file.Files;
 import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.Map;
 
 public class ExportLogsCacheWriter extends CacheWriterAdapter implements 
Serializable {
   private Path currentFile;
@@ -38,11 +34,9 @@ public class ExportLogsCacheWriter extends 
CacheWriterAdapter implements Seriali
 
   @Override
   public void beforeCreate(EntryEvent event) throws CacheWriterException {
-    if (currentFile.getFileName().endsWith("server-2.zip")) {
-      System.out.println("We got data from server 2");
-    }
     if (currentOutputStream == null) {
-      throw new IllegalStateException("No outputStream is open.  You must call 
startFile before sending data.");
+      throw new IllegalStateException(
+          "No outputStream is open.  You must call startFile before sending 
data.");
     }
 
     try {

http://git-wip-us.apache.org/repos/asf/geode/blob/4a700206/geode-core/src/main/java/org/apache/geode/management/internal/web/controllers/MiscellaneousCommandsController.java
----------------------------------------------------------------------
diff --git 
a/geode-core/src/main/java/org/apache/geode/management/internal/web/controllers/MiscellaneousCommandsController.java
 
b/geode-core/src/main/java/org/apache/geode/management/internal/web/controllers/MiscellaneousCommandsController.java
index ac912c8..28cc658 100644
--- 
a/geode-core/src/main/java/org/apache/geode/management/internal/web/controllers/MiscellaneousCommandsController.java
+++ 
b/geode-core/src/main/java/org/apache/geode/management/internal/web/controllers/MiscellaneousCommandsController.java
@@ -14,11 +14,13 @@
  */
 package org.apache.geode.management.internal.web.controllers;
 
-import java.util.concurrent.Callable;
-
 import org.apache.geode.internal.lang.StringUtils;
 import org.apache.geode.management.internal.cli.i18n.CliStrings;
+import org.apache.geode.management.internal.cli.result.ResultBuilder;
 import org.apache.geode.management.internal.cli.util.CommandStringBuilder;
+import org.springframework.core.io.InputStreamResource;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpStatus;
 import org.springframework.http.ResponseEntity;
 import org.springframework.stereotype.Controller;
 import org.springframework.web.bind.annotation.PathVariable;
@@ -27,6 +29,9 @@ import org.springframework.web.bind.annotation.RequestMethod;
 import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.ResponseBody;
 
+import java.io.File;
+import java.io.FileInputStream;
+
 /**
  * The MiscellaneousCommandsController class implements GemFire Management 
REST API web service
  * endpoints for the Gfsh Miscellaneous Commands.
@@ -48,21 +53,19 @@ import org.springframework.web.bind.annotation.ResponseBody;
 public class MiscellaneousCommandsController extends 
AbstractCommandsController {
 
   @RequestMapping(method = RequestMethod.GET, value = "/logs")
-  public Callable<ResponseEntity<String>> exportLogs(
-      @RequestParam(CliStrings.EXPORT_LOGS__DIR) final String directory,
-      @RequestParam(value = CliStrings.EXPORT_LOGS__GROUP, required = false) 
final String[] groups,
-      @RequestParam(value = CliStrings.EXPORT_LOGS__MEMBER,
+  public ResponseEntity<InputStreamResource> exportLogs(@RequestParam(value = 
CliStrings.EXPORT_LOGS__DIR, required = false) final String directory,
+                                                        @RequestParam(value = 
CliStrings.EXPORT_LOGS__GROUP, required = false) final String[] groups,
+                                                        @RequestParam(value = 
CliStrings.EXPORT_LOGS__MEMBER,
           required = false) final String memberNameId,
-      @RequestParam(value = CliStrings.EXPORT_LOGS__LOGLEVEL,
+                                                        @RequestParam(value = 
CliStrings.EXPORT_LOGS__LOGLEVEL,
           required = false) final String logLevel,
-      @RequestParam(value = CliStrings.EXPORT_LOGS__UPTO_LOGLEVEL,
+                                                        @RequestParam(value = 
CliStrings.EXPORT_LOGS__UPTO_LOGLEVEL,
           defaultValue = "false") final Boolean onlyLogLevel,
-      @RequestParam(value = CliStrings.EXPORT_LOGS__MERGELOG,
+                                                        @RequestParam(value = 
CliStrings.EXPORT_LOGS__MERGELOG,
           defaultValue = "false") final Boolean mergeLog,
-      @RequestParam(value = CliStrings.EXPORT_LOGS__STARTTIME,
+                                                        @RequestParam(value = 
CliStrings.EXPORT_LOGS__STARTTIME,
           required = false) final String startTime,
-      @RequestParam(value = CliStrings.EXPORT_LOGS__ENDTIME,
-          required = false) final String endTime) {
+                                                        @RequestParam(value = 
CliStrings.EXPORT_LOGS__ENDTIME, required = false) final String endTime) {
     final CommandStringBuilder command = new 
CommandStringBuilder(CliStrings.EXPORT_LOGS);
 
     command.addOption(CliStrings.EXPORT_LOGS__DIR, decode(directory));
@@ -93,7 +96,19 @@ public class MiscellaneousCommandsController extends 
AbstractCommandsController
       command.addOption(CliStrings.EXPORT_LOGS__ENDTIME, endTime);
     }
 
-    return getProcessCommandCallable(command.toString());
+    // the result is json string from CommandResult
+    String result =  processCommand(command.toString());
+
+    // parse the result to get the file path
+    String filePath = ResultBuilder.fromJson(result).nextLine().trim();
+
+    HttpHeaders respHeaders = new HttpHeaders();
+    try {
+      InputStreamResource isr = new InputStreamResource(new 
FileInputStream(new File(filePath)));
+      return new ResponseEntity<InputStreamResource>(isr, respHeaders, 
HttpStatus.OK);
+    } catch (Exception ex) {
+      throw new RuntimeException("IOError writing file to output stream", ex);
+    }
   }
 
   // TODO determine whether Async functionality is required

http://git-wip-us.apache.org/repos/asf/geode/blob/4a700206/geode-core/src/main/java/org/apache/geode/management/internal/web/shell/AbstractHttpOperationInvoker.java
----------------------------------------------------------------------
diff --git 
a/geode-core/src/main/java/org/apache/geode/management/internal/web/shell/AbstractHttpOperationInvoker.java
 
b/geode-core/src/main/java/org/apache/geode/management/internal/web/shell/AbstractHttpOperationInvoker.java
index fa05248..2a409cc 100644
--- 
a/geode-core/src/main/java/org/apache/geode/management/internal/web/shell/AbstractHttpOperationInvoker.java
+++ 
b/geode-core/src/main/java/org/apache/geode/management/internal/web/shell/AbstractHttpOperationInvoker.java
@@ -15,6 +15,7 @@
 
 package org.apache.geode.management.internal.web.shell;
 
+import org.apache.commons.io.FileUtils;
 import org.apache.geode.internal.GemFireVersion;
 import org.apache.geode.internal.lang.StringUtils;
 import org.apache.geode.internal.logging.LogService;
@@ -41,14 +42,18 @@ import org.springframework.http.client.ClientHttpResponse;
 import org.springframework.http.client.SimpleClientHttpRequestFactory;
 import org.springframework.http.converter.HttpMessageConverter;
 import 
org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
+import org.springframework.web.client.RequestCallback;
 import org.springframework.web.client.ResourceAccessException;
 import org.springframework.web.client.ResponseErrorHandler;
+import org.springframework.web.client.ResponseExtractor;
 import org.springframework.web.client.RestTemplate;
 
 import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.InputStreamReader;
 import java.net.URI;
+import java.nio.file.Files;
+import java.nio.file.Path;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.Iterator;
@@ -583,7 +588,7 @@ public abstract class AbstractHttpOperationInvoker 
implements HttpOperationInvok
    * @see org.apache.geode.management.internal.web.http.ClientHttpRequest
    * @see org.springframework.http.ResponseEntity
    */
-  protected <T> ResponseEntity<T> send(final ClientHttpRequest request,
+  protected <T> T send(final ClientHttpRequest request,
       final Class<T> responseType) {
     return send(request, responseType, Collections.<String, Object>emptyMap());
   }
@@ -603,10 +608,9 @@ public abstract class AbstractHttpOperationInvoker 
implements HttpOperationInvok
    * @see org.springframework.web.client.RestTemplate#exchange(java.net.URI,
    *      org.springframework.http.HttpMethod, 
org.springframework.http.HttpEntity, Class)
    */
-  protected <T> ResponseEntity<T> send(final ClientHttpRequest request, final 
Class<T> responseType,
+  protected <T> T send(final ClientHttpRequest request, final Class<T> 
responseType,
       final Map<String, ?> uriVariables) {
     final URI url = request.getURL(uriVariables);
-
     if (isDebugEnabled()) {
       printInfo("Link: %1$s", request.getLink().toHttpRequestLine());
       printInfo("HTTP URL: %1$s", url);
@@ -626,7 +630,24 @@ public abstract class AbstractHttpOperationInvoker 
implements HttpOperationInvok
       printInfo("HTTP response body: ", response.getBody());
     }
 
-    return response;
+    return response.getBody();
+  }
+
+  protected Path downloadResponseToTempFile(ClientHttpRequest request, 
Map<String, ?> uriVariables){
+    final URI url = request.getURL(uriVariables);
+    // Optional Accept header
+    RequestCallback requestCallback = r -> 
r.getHeaders().setAccept(Arrays.asList(MediaType.APPLICATION_OCTET_STREAM));
+
+    // Streams the response instead of loading it all in memory
+    ResponseExtractor<Path> responseExtractor = resp -> {
+      Path tempFile = Files.createTempFile("fileDownload", "");
+      if(tempFile.toFile().exists()){
+        FileUtils.deleteQuietly(tempFile.toFile());
+      }
+      Files.copy(resp.getBody(), tempFile);
+      return tempFile;
+    };
+    return getRestTemplate().execute(url, 
org.springframework.http.HttpMethod.GET, requestCallback, responseExtractor);
   }
 
   /**
@@ -680,10 +701,8 @@ public abstract class AbstractHttpOperationInvoker 
implements HttpOperationInvok
       request.addParameterValues("resourceName", resourceName);
       request.addParameterValues("attributeName", attributeName);
 
-      final ResponseEntity<byte[]> response = send(request, byte[].class);
-
       try {
-        return IOUtils.deserializeObject(response.getBody());
+        return IOUtils.deserializeObject(send(request, byte[].class));
       } catch (IOException e) {
         throw new MBeanAccessException(String.format(
             "De-serializing the result of accessing attribute (%1$s) on MBean 
(%2$s) failed!",
@@ -785,10 +804,8 @@ public abstract class AbstractHttpOperationInvoker 
implements HttpOperationInvok
       request.addParameterValues("parameters", params); // TODO may need to 
convert method parameter
                                                         // arguments
 
-      final ResponseEntity<byte[]> response = send(request, byte[].class);
-
       try {
-        return IOUtils.deserializeObject(response.getBody());
+        return IOUtils.deserializeObject(send(request, byte[].class));
       } catch (IOException e) {
         throw new MBeanAccessException(String.format(
             "De-serializing the result from invoking operation (%1$s) on MBean 
(%2$s) failed!",
@@ -831,11 +848,8 @@ public abstract class AbstractHttpOperationInvoker 
implements HttpOperationInvok
       final ClientHttpRequest request = createHttpRequest(link);
 
       request.setContent(new QueryParameterSource(objectName, 
queryExpression));
-
-      final ResponseEntity<byte[]> response = send(request, byte[].class);
-
       try {
-        return (Set<ObjectName>) IOUtils.deserializeObject(response.getBody());
+        return (Set<ObjectName>) IOUtils.deserializeObject(send(request, 
byte[].class));
       } catch (Exception e) {
         throw new MBeanAccessException(String.format(
             "An error occurred while querying for MBean names using ObjectName 
pattern (%1$s) and Query expression (%2$s)!",

http://git-wip-us.apache.org/repos/asf/geode/blob/4a700206/geode-core/src/main/java/org/apache/geode/management/internal/web/shell/RestHttpOperationInvoker.java
----------------------------------------------------------------------
diff --git 
a/geode-core/src/main/java/org/apache/geode/management/internal/web/shell/RestHttpOperationInvoker.java
 
b/geode-core/src/main/java/org/apache/geode/management/internal/web/shell/RestHttpOperationInvoker.java
index 82b2b1f..cb0f082 100644
--- 
a/geode-core/src/main/java/org/apache/geode/management/internal/web/shell/RestHttpOperationInvoker.java
+++ 
b/geode-core/src/main/java/org/apache/geode/management/internal/web/shell/RestHttpOperationInvoker.java
@@ -15,14 +15,6 @@
 
 package org.apache.geode.management.internal.web.shell;
 
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-
 import org.apache.geode.internal.lang.Filter;
 import org.apache.geode.internal.lang.Initable;
 import org.apache.geode.internal.lang.StringUtils;
@@ -36,15 +28,21 @@ import 
org.apache.geode.management.internal.web.domain.LinkIndex;
 import org.apache.geode.management.internal.web.http.ClientHttpRequest;
 import org.apache.geode.management.internal.web.http.HttpHeader;
 import org.apache.geode.management.internal.web.util.ConvertUtils;
-
 import org.apache.logging.log4j.Logger;
 import org.springframework.http.HttpMethod;
 import org.springframework.http.HttpStatus;
-import org.springframework.http.ResponseEntity;
 import org.springframework.http.client.ClientHttpResponse;
 import org.springframework.web.client.ResourceAccessException;
 import org.springframework.web.util.UriTemplate;
 
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
 /**
  * The RestHttpOperationInvoker class is an implementation of the 
OperationInvoker interface that
  * translates (adapts) GemFire shell command invocations into HTTP requests to 
a corresponding REST
@@ -376,7 +374,8 @@ public class RestHttpOperationInvoker extends 
AbstractHttpOperationInvoker imple
    * (execution).
    * 
    * @param command the command requested/entered by the user to be processed.
-   * @return the result of the command execution.
+   * @return either a json string of the CommandResult or a Path to a temp 
file if the response is a
+   *        InputStream
    * @see 
#createHttpRequest(org.apache.geode.management.internal.cli.CommandRequest)
    * @see 
#handleResourceAccessException(org.springframework.web.client.ResourceAccessException)
    * @see #isConnected()
@@ -388,15 +387,19 @@ public class RestHttpOperationInvoker extends 
AbstractHttpOperationInvoker imple
    * @see org.springframework.http.ResponseEntity
    */
   @Override
-  public String processCommand(final CommandRequest command) {
+  public Object processCommand(final CommandRequest command) {
     assertState(isConnected(),
         "Gfsh must be connected to the GemFire Manager in order to process 
commands remotely!");
 
+    Object result = null;
     try {
-      ResponseEntity<String> response =
-          send(createHttpRequest(command), String.class, 
command.getParameters());
-
-      return response.getBody();
+      if(command.isDownloadFile()){
+        result = downloadResponseToTempFile(createHttpRequest(command), 
command.getParameters());
+      }
+      else{
+        result = send(createHttpRequest(command), String.class, 
command.getParameters());
+      }
+      return result;
     } catch (RestApiCallForCommandNotFoundException e) {
       return simpleProcessCommand(command, e);
     } catch (ResourceAccessException e) {

http://git-wip-us.apache.org/repos/asf/geode/blob/4a700206/geode-core/src/main/java/org/apache/geode/management/internal/web/shell/SimpleHttpOperationInvoker.java
----------------------------------------------------------------------
diff --git 
a/geode-core/src/main/java/org/apache/geode/management/internal/web/shell/SimpleHttpOperationInvoker.java
 
b/geode-core/src/main/java/org/apache/geode/management/internal/web/shell/SimpleHttpOperationInvoker.java
index dcda27b..d11d824 100644
--- 
a/geode-core/src/main/java/org/apache/geode/management/internal/web/shell/SimpleHttpOperationInvoker.java
+++ 
b/geode-core/src/main/java/org/apache/geode/management/internal/web/shell/SimpleHttpOperationInvoker.java
@@ -15,19 +15,17 @@
 
 package org.apache.geode.management.internal.web.shell;
 
-import java.net.URI;
-import java.util.Map;
-
 import org.apache.geode.management.internal.cli.CommandRequest;
 import org.apache.geode.management.internal.cli.shell.Gfsh;
 import org.apache.geode.management.internal.web.domain.Link;
 import org.apache.geode.management.internal.web.http.ClientHttpRequest;
 import org.apache.geode.management.internal.web.http.HttpMethod;
-
-import org.springframework.http.ResponseEntity;
 import org.springframework.web.client.ResourceAccessException;
 import org.springframework.web.util.UriComponentsBuilder;
 
+import java.net.URI;
+import java.util.Map;
+
 /**
  * The SimpleHttpOperationInvoker class is an implementation of the 
OperationInvoker interface that
  * issues commands to the GemFire Manager via HTTP. The 
SimpleHttpOperationInvoker uses a single URL
@@ -156,9 +154,7 @@ public class SimpleHttpOperationInvoker extends 
AbstractHttpOperationInvoker {
         "Gfsh must be connected to the GemFire Manager in order to process 
commands remotely!");
 
     try {
-      final ResponseEntity<String> response = send(createHttpRequest(command), 
String.class);
-
-      return response.getBody();
+      return send(createHttpRequest(command), String.class);
     } catch (ResourceAccessException e) {
       return handleResourceAccessException(e);
     }

http://git-wip-us.apache.org/repos/asf/geode/blob/4a700206/geode-core/src/test/java/org/apache/geode/test/dunit/rules/GfshShellConnectionRule.java
----------------------------------------------------------------------
diff --git 
a/geode-core/src/test/java/org/apache/geode/test/dunit/rules/GfshShellConnectionRule.java
 
b/geode-core/src/test/java/org/apache/geode/test/dunit/rules/GfshShellConnectionRule.java
index 93572fe..c3310d5 100644
--- 
a/geode-core/src/test/java/org/apache/geode/test/dunit/rules/GfshShellConnectionRule.java
+++ 
b/geode-core/src/test/java/org/apache/geode/test/dunit/rules/GfshShellConnectionRule.java
@@ -16,6 +16,7 @@ package org.apache.geode.test.dunit.rules;
 
 import static org.assertj.core.api.Assertions.assertThat;
 
+import org.apache.geode.internal.lang.StringUtils;
 import org.apache.geode.management.cli.Result;
 import org.apache.geode.management.internal.cli.CliUtil;
 import org.apache.geode.management.internal.cli.HeadlessGfsh;
@@ -23,6 +24,7 @@ import 
org.apache.geode.management.internal.cli.i18n.CliStrings;
 import org.apache.geode.management.internal.cli.result.CommandResult;
 import org.apache.geode.management.internal.cli.util.CommandStringBuilder;
 import org.apache.geode.test.junit.rules.DescribedExternalResource;
+import org.json.JSONArray;
 import org.junit.runner.Description;
 
 /**
@@ -89,6 +91,11 @@ public class GfshShellConnectionRule extends 
DescribedExternalResource {
     assertThat(this.connected).isTrue();
   }
 
+  public void connectAndVerify(int port, PortType type, String... options) 
throws Exception {
+    connect(port, type, options);
+    assertThat(this.connected).isTrue();
+  }
+
   public void connect(int port, PortType type, String... options) throws 
Exception {
     CliUtil.isGfshVM = true;
     final CommandStringBuilder connectCommand = new 
CommandStringBuilder(CliStrings.CONNECT);
@@ -157,19 +164,24 @@ public class GfshShellConnectionRule extends 
DescribedExternalResource {
   public CommandResult executeCommand(String command) throws Exception {
     gfsh.executeCommand(command);
     CommandResult result = (CommandResult) gfsh.getResult();
-    System.out.println("Command Result: \n" + gfsh.outputString);
+    if(StringUtils.isBlank(gfsh.outputString)){
+       JSONArray messages = ((JSONArray)result.getContent().get("message"));
+       for(int i=0; i< messages.length(); i++){
+         gfsh.outputString += messages.getString(i)+"\n";
+       }
+    }
+    System.out.println("Command result: \n" + gfsh.outputString);
     return result;
   }
 
+  public String getGfshOutput(){
+    return gfsh.outputString;
+  }
+
 
   public CommandResult executeAndVerifyCommand(String command) throws 
Exception {
     CommandResult result = executeCommand(command);
-
-    if (result.getStatus() != Result.Status.OK) {
-      System.out.println("broken");
-    }
-    assertThat(result.getStatus()).describedAs(result.getContent().toString())
-        .isEqualTo(Result.Status.OK);
+    assertThat(result.getStatus()).isEqualTo(Result.Status.OK);
     return result;
   }
 

http://git-wip-us.apache.org/repos/asf/geode/blob/4a700206/geode-web/src/test/java/org/apache/geode/management/internal/cli/commands/ExportLogsOverHttpDunit.java
----------------------------------------------------------------------
diff --git 
a/geode-web/src/test/java/org/apache/geode/management/internal/cli/commands/ExportLogsOverHttpDunit.java
 
b/geode-web/src/test/java/org/apache/geode/management/internal/cli/commands/ExportLogsOverHttpDunit.java
new file mode 100644
index 0000000..a45d9ef
--- /dev/null
+++ 
b/geode-web/src/test/java/org/apache/geode/management/internal/cli/commands/ExportLogsOverHttpDunit.java
@@ -0,0 +1,113 @@
+/*
+ * 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.apache.geode.distributed.ConfigurationProperties.HTTP_SERVICE_BIND_ADDRESS;
+import static 
org.apache.geode.distributed.ConfigurationProperties.HTTP_SERVICE_PORT;
+import static 
org.apache.geode.distributed.ConfigurationProperties.JMX_MANAGER_PORT;
+import static org.assertj.core.api.Assertions.assertThat;
+
+import org.apache.geode.internal.AvailablePortHelper;
+import org.apache.geode.test.dunit.rules.GfshShellConnectionRule;
+import org.apache.geode.test.dunit.rules.Locator;
+import org.apache.geode.test.dunit.rules.LocatorServerStartupRule;
+import org.apache.geode.test.junit.categories.DistributedTest;
+import org.junit.BeforeClass;
+import org.junit.ClassRule;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.junit.rules.TemporaryFolder;
+
+import java.io.File;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Properties;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+@Category(DistributedTest.class)
+public class ExportLogsOverHttpDunit {
+
+  @Rule
+  public TemporaryFolder temporaryFolder = new TemporaryFolder();
+
+  @ClassRule
+  public static LocatorServerStartupRule lsRule = new 
LocatorServerStartupRule();
+
+  @ClassRule
+  public static GfshShellConnectionRule gfshConnector = new 
GfshShellConnectionRule();
+
+  private static int jmxPort, httpPort;
+  private static Properties locatorProperties;
+  private static Set<String> expectedZipEntries = new HashSet<>();
+
+  @BeforeClass
+  public static void beforeClass() throws Exception {
+    int[] ports = AvailablePortHelper.getRandomAvailableTCPPorts(2);
+    httpPort = ports[0];
+    jmxPort = ports[1];
+    locatorProperties = new Properties();
+    locatorProperties.setProperty(HTTP_SERVICE_BIND_ADDRESS, "localhost");
+    locatorProperties.setProperty(HTTP_SERVICE_PORT, httpPort + "");
+    locatorProperties.setProperty(JMX_MANAGER_PORT, jmxPort + "");
+
+    // start the locator in vm0 and then connect to it over http
+    Locator locator = lsRule.startLocatorVM(0, locatorProperties);
+    lsRule.startServerVM(1, locator.getPort());
+    gfshConnector.connectAndVerify(httpPort, 
GfshShellConnectionRule.PortType.http);
+
+    String[] expectedLogs = {"locator-0/locator-0.log", 
"server-1/server-1.log"};
+    expectedZipEntries = 
Arrays.stream(expectedLogs).collect(Collectors.toSet());
+  }
+
+  @Test
+  public void testExportWithNoDir() throws Exception {
+    // export the logs
+    gfshConnector.executeCommand("export logs");
+    // verify that the message contains a path to the user.dir
+    String message = gfshConnector.getGfshOutput();
+    assertThat(message).contains("Logs exported to: ");
+    assertThat(message).contains(System.getProperty("user.dir"));
+
+    String zipPath = message.replaceAll("Logs exported to: ", "").trim();
+    verifyZipContent(zipPath);
+  }
+
+  @Test
+  public void testExportWithDir() throws Exception {
+    File dir = temporaryFolder.newFolder();
+    // export the logs
+    gfshConnector.executeCommand("export logs --dir="+dir.getAbsolutePath());
+    // verify that the message contains a path to the user.dir
+    String message = gfshConnector.getGfshOutput();
+    assertThat(message).contains("Logs exported to: ");
+    assertThat(message).contains(dir.getAbsolutePath());
+
+    String zipPath = message.replaceAll("Logs exported to: ", "").trim();
+    verifyZipContent(zipPath);
+  }
+
+  private void verifyZipContent(String zipPath) throws Exception{
+    Set<String> actualZipEnries =
+        new 
ZipFile(zipPath).stream().map(ZipEntry::getName).collect(Collectors.toSet());
+
+    assertThat(actualZipEnries).isEqualTo(expectedZipEntries);
+
+  }
+}

http://git-wip-us.apache.org/repos/asf/geode/blob/4a700206/geode-web/src/test/java/org/apache/geode/management/internal/web/shell/RestHttpOperationInvokerJUnitTest.java
----------------------------------------------------------------------
diff --git 
a/geode-web/src/test/java/org/apache/geode/management/internal/web/shell/RestHttpOperationInvokerJUnitTest.java
 
b/geode-web/src/test/java/org/apache/geode/management/internal/web/shell/RestHttpOperationInvokerJUnitTest.java
index 808c78f..912e16a 100644
--- 
a/geode-web/src/test/java/org/apache/geode/management/internal/web/shell/RestHttpOperationInvokerJUnitTest.java
+++ 
b/geode-web/src/test/java/org/apache/geode/management/internal/web/shell/RestHttpOperationInvokerJUnitTest.java
@@ -14,22 +14,12 @@
  */
 package org.apache.geode.management.internal.web.shell;
 
-import static org.junit.Assert.*;
-
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.TreeMap;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.experimental.categories.Category;
-import org.springframework.core.io.Resource;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.ResponseEntity;
-import org.springframework.web.client.ResourceAccessException;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
 
 import org.apache.geode.internal.lang.StringUtils;
 import org.apache.geode.management.internal.cli.CommandRequest;
@@ -39,6 +29,18 @@ import 
org.apache.geode.management.internal.web.domain.LinkIndex;
 import org.apache.geode.management.internal.web.http.ClientHttpRequest;
 import org.apache.geode.management.internal.web.http.HttpMethod;
 import org.apache.geode.test.junit.categories.UnitTest;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.springframework.core.io.Resource;
+import org.springframework.web.client.ResourceAccessException;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
 
 /**
  * The RestHttpOperationInvokerJUnitTest class is a test suite of test cases 
testing the contract
@@ -315,13 +317,13 @@ public class RestHttpOperationInvokerJUnitTest extends 
AbstractWebTestCase {
 
       @Override
       @SuppressWarnings("unchecked")
-      protected <T> ResponseEntity<T> send(final ClientHttpRequest request,
+      protected <T> T send(final ClientHttpRequest request,
           final Class<T> responseType, final Map<String, ?> uriVariables) {
-        return new ResponseEntity(expectedResult, HttpStatus.OK);
+        return (T) expectedResult;
       }
     };
 
-    final String actualResult = operationInvoker.processCommand(
+    final Object actualResult = operationInvoker.processCommand(
         createCommandRequest("list-libraries", Collections.<String, 
String>emptyMap()));
 
     assertEquals(expectedResult, actualResult);
@@ -351,7 +353,7 @@ public class RestHttpOperationInvokerJUnitTest extends 
AbstractWebTestCase {
       protected void printWarning(final String message, final Object... args) 
{}
     };
 
-    final String actualResult = operationInvoker.processCommand(
+    final Object actualResult = operationInvoker.processCommand(
         createCommandRequest("get resource", Collections.<String, 
String>emptyMap()));
 
     assertEquals(expectedResult, actualResult);
@@ -371,7 +373,7 @@ public class RestHttpOperationInvokerJUnitTest extends 
AbstractWebTestCase {
       protected void printWarning(final String message, final Object... args) 
{}
 
       @Override
-      protected <T> ResponseEntity<T> send(final ClientHttpRequest request,
+      protected <T> T send(final ClientHttpRequest request,
           final Class<T> responseType, final Map<String, ?> uriVariables) {
         throw new ResourceAccessException("test");
       }
@@ -389,7 +391,7 @@ public class RestHttpOperationInvokerJUnitTest extends 
AbstractWebTestCase {
             + "Please try reconnecting or see the GemFire Manager's log file 
for further details.",
         operationInvoker.getBaseUrl(), "test");
 
-    final String actualResult = operationInvoker.processCommand(
+    final Object actualResult = operationInvoker.processCommand(
         createCommandRequest("list-libraries", Collections.<String, 
String>emptyMap()));
 
     assertFalse(operationInvoker.isConnected());

http://git-wip-us.apache.org/repos/asf/geode/blob/4a700206/geode-web/src/test/java/org/apache/geode/management/internal/web/shell/SimpleHttpOperationInvokerJUnitTest.java
----------------------------------------------------------------------
diff --git 
a/geode-web/src/test/java/org/apache/geode/management/internal/web/shell/SimpleHttpOperationInvokerJUnitTest.java
 
b/geode-web/src/test/java/org/apache/geode/management/internal/web/shell/SimpleHttpOperationInvokerJUnitTest.java
index 8afbcf6..ae19afa 100644
--- 
a/geode-web/src/test/java/org/apache/geode/management/internal/web/shell/SimpleHttpOperationInvokerJUnitTest.java
+++ 
b/geode-web/src/test/java/org/apache/geode/management/internal/web/shell/SimpleHttpOperationInvokerJUnitTest.java
@@ -14,9 +14,10 @@
  */
 package org.apache.geode.management.internal.web.shell;
 
-import static org.junit.Assert.*;
-
-import java.util.Collections;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
 
 import org.apache.geode.management.internal.cli.CommandRequest;
 import org.apache.geode.management.internal.web.AbstractWebTestCase;
@@ -25,15 +26,14 @@ import 
org.apache.geode.management.internal.web.http.ClientHttpRequest;
 import org.apache.geode.management.internal.web.http.HttpHeader;
 import org.apache.geode.management.internal.web.http.HttpMethod;
 import org.apache.geode.test.junit.categories.UnitTest;
-
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.experimental.categories.Category;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.ResponseEntity;
 import org.springframework.web.client.ResourceAccessException;
 
+import java.util.Collections;
+
 /**
  * The SimpleHttpOperationInvokerJUnitTest class is a test suite of test cases 
testing the contract
  * and functionality of the SimpleHttpOperationInvoker class.
@@ -128,9 +128,9 @@ public class SimpleHttpOperationInvokerJUnitTest extends 
AbstractWebTestCase {
 
       @Override
       @SuppressWarnings("unchecked")
-      protected <T> ResponseEntity<T> send(final ClientHttpRequest request,
+      protected <T> T send(final ClientHttpRequest request,
           final Class<T> responseType) {
-        return new ResponseEntity(expectedResult, HttpStatus.OK);
+        return (T) expectedResult;
       }
     };
 
@@ -151,7 +151,7 @@ public class SimpleHttpOperationInvokerJUnitTest extends 
AbstractWebTestCase {
       }
 
       @Override
-      protected <T> ResponseEntity<T> send(final ClientHttpRequest request,
+      protected <T> T send(final ClientHttpRequest request,
           final Class<T> responseType) {
         throw new ResourceAccessException("test");
       }

Reply via email to