@@ -319,12 +319,12 @@ private static void printCommandHelp() {
319319 System .out .println (" application/json - subscribe to commands with JSON payload" );
320320 System .out .println (" application/cbor - subscribe to commands with CBOR payload" );
321321 System .out .println (" for any other value, subscribe to a generic topic" );
322- System .out .println (" update-command-execution <executionId> <status> [< reason-code>] [< reason-description>]" );
322+ System .out .println (" update-command-execution <executionId> <status> [reason-code=<value >] [reason-description=<value>] [result=<key>:<value>;<key>:<value >]" );
323323 System .out .println (" updates a command execution with a new status" );
324324 System .out .println (" <status> can be one of the following:" );
325325 System .out .println (" IN_PROGRESS, SUCCEEDED, REJECTED, FAILED, TIMED_OUT" );
326- System .out .println (" < reason-code> and < reason-description> may be optionally provided for" );
327- System .out .println (" the REJECTED, FAILED, or TIMED_OUT statuses \n " );
326+ System .out .println (" reason-code and reason-description may be optionally provided for any status " );
327+ System .out .println (" result is a semicolon-separated list of key:value pairs; if a value is true/false it is treated as boolean, otherwise as string \n " );
328328 System .out .println (" Miscellaneous commands:" );
329329 System .out .println (" list-streams list all open streaming operations" );
330330 System .out .println (" close-stream <streamID>" );
@@ -426,39 +426,87 @@ private static void handleGetCommandExecution(ApplicationContext context, String
426426 GetCommandExecutionRequest getCommandExecutionRequest = GetCommandExecutionRequest .builder ()
427427 .executionId (commandExecutionId )
428428 .targetArn (commandExecutionContext .deviceArn )
429+ .includeResult (true )
429430 .build ();
430431 GetCommandExecutionResponse getCommandExecutionResponse = context .controlPlaneClient .getCommandExecution (getCommandExecutionRequest );
431432 System .out .printf ("Status of command execution '%s' is %s\n " , commandExecutionId , getCommandExecutionResponse .status ());
432433 if (getCommandExecutionResponse .statusReason () != null ) {
433434 System .out .printf (" Reason code: %s\n " , getCommandExecutionResponse .statusReason ().reasonCode ());
434435 System .out .printf (" Reason description: %s\n " , getCommandExecutionResponse .statusReason ().reasonDescription ());
435436 }
437+ if (getCommandExecutionResponse .hasResult ()) {
438+ System .out .println (" Result:" );
439+ getCommandExecutionResponse .result ().forEach ((key , value ) -> {
440+ if (value .b () != null ) {
441+ System .out .printf (" %s: %s (boolean)\n " , key , value .b ());
442+ } else if (value .s () != null ) {
443+ System .out .printf (" %s: %s (string)\n " , key , value .s ());
444+ }
445+ });
446+ }
436447 } catch (Exception ex ) {
437448 handleOperationException ("get-command-execution" , ex , context );
438449 }
439450 }
440451
452+ /* Parses key=value pairs using nibbleNextToken. */
453+ private static Map <String , String > parseKeyValueArgs (String input ) {
454+ Pattern pattern = Pattern .compile ("(\\ S+?)=([^\\ s\" ]*(?:\" [^\" ]*\" [^\\ s\" ]*)*)" );
455+ Matcher matcher = pattern .matcher (input );
456+
457+ Map <String , String > result = new HashMap <>();
458+
459+ while (matcher .find ()) {
460+ String key = matcher .group (1 );
461+ String value = matcher .group (2 );
462+ result .put (key , value );
463+ }
464+
465+ return result ;
466+ }
467+
468+ private static HashMap <String , software .amazon .awssdk .iot .iotcommands .model .CommandExecutionResult > parseResult (String resultStr ) {
469+ HashMap <String , software .amazon .awssdk .iot .iotcommands .model .CommandExecutionResult > result = new HashMap <>();
470+
471+ Pattern pattern = Pattern .compile ("([^;:]*):([^;\" ]*(?:\" [^\" ]*\" [^;\" ]*)*)" );
472+ Matcher matcher = pattern .matcher (resultStr );
473+
474+ while (matcher .find ()) {
475+ String key = matcher .group (1 );
476+ String value = matcher .group (2 ).replaceAll ("^\" |\" $" , "" );
477+
478+ software .amazon .awssdk .iot .iotcommands .model .CommandExecutionResult entry =
479+ new software .amazon .awssdk .iot .iotcommands .model .CommandExecutionResult ();
480+
481+ /* NOTE: CommandExecutionResult also supports binary data via the `Bin` member, which is not demonstrated in this
482+ * sample. */
483+ if (value .equalsIgnoreCase ("true" ) || value .equalsIgnoreCase ("false" )) {
484+ entry .b = Boolean .parseBoolean (value );
485+ } else {
486+ entry .s = value ;
487+ }
488+
489+ result .put (key , entry );
490+ }
491+
492+ return result ;
493+ }
494+
441495 private static void handleUpdateCommandExecution (ApplicationContext context , String arguments ) {
442- String [] argumentSplit = arguments .trim ().split (" " , 4 );
443- if (argumentSplit .length < 2 ) {
496+ String [] parts = arguments .trim ().split (" " , 3 );
497+ if (parts .length < 2 ) {
444498 printCommandHelp ();
445499 return ;
446500 }
447501
448- String commandExecutionId = argumentSplit [0 ];
502+ String commandExecutionId = parts [0 ];
449503 if (!context .activeCommandExecutions .containsKey (commandExecutionId )) {
450504 System .out .printf ("Failed to update command execution status: unknown command execution ID '%s'\n " , commandExecutionId );
451505 return ;
452506 }
453507
454- String statusStr = argumentSplit [1 ];
455-
456- String reasonCode = null ;
457- String reasonDescription = null ;
458- if (argumentSplit .length > 3 ) {
459- reasonCode = argumentSplit [2 ];
460- reasonDescription = argumentSplit [3 ];
461- }
508+ String statusStr = parts [1 ];
509+ Map <String , String > kvArgs = parseKeyValueArgs (parts .length > 2 ? parts [2 ] : "" );
462510
463511 try {
464512 CommandExecutionContext commandExecutionContext = context .activeCommandExecutions .get (commandExecutionId );
@@ -467,10 +515,18 @@ private static void handleUpdateCommandExecution(ApplicationContext context, Str
467515 request .deviceType = commandExecutionContext .deviceType ;
468516 request .deviceId = commandExecutionContext .deviceId ;
469517 request .status = CommandExecutionStatus .valueOf (statusStr );
470- if (reasonCode != null && reasonDescription != null ) {
518+
519+ String reasonCode = kvArgs .get ("reason-code" );
520+ String reasonDescription = kvArgs .get ("reason-description" );
521+ if (reasonCode != null || reasonDescription != null ) {
471522 request .statusReason = new StatusReason ();
472523 request .statusReason .reasonCode = reasonCode ;
473- request .statusReason .reasonDescription = reasonDescription ;
524+ request .statusReason .reasonDescription = reasonDescription .replaceAll ("^\" |\" $" , "" );
525+ }
526+
527+ String resultStr = kvArgs .get ("result" );
528+ if (resultStr != null ) {
529+ request .result = parseResult (resultStr );
474530 }
475531
476532 UpdateCommandExecutionResponse response = context .commandsClient .updateCommandExecution (request ).get ();
0 commit comments