diff --git a/nebula-logger/core/main/logger-engine/classes/CallableLogger.cls b/nebula-logger/core/main/logger-engine/classes/CallableLogger.cls index 15622bade..4662c5c4a 100644 --- a/nebula-logger/core/main/logger-engine/classes/CallableLogger.cls +++ b/nebula-logger/core/main/logger-engine/classes/CallableLogger.cls @@ -29,6 +29,7 @@ global without sharing class CallableLogger implements System.Callable { private static final String OMNISTUDIO_ARGUMENT_OUTPUT = 'output'; private static final String OMNISTUDIO_ARGUMENT_OPTIONS = 'options'; private static final String OUTPUT_ARGUMENT_CALL_ERROR_MESSAGE = 'errorMessage'; + private static final String OUTPUT_ARGUMENT_CALL_ERROR_TYPE = 'errorType'; private static final String OUTPUT_ARGUMENT_CALL_IS_SUCCESS = 'isSuccess'; /** @@ -39,33 +40,26 @@ global without sharing class CallableLogger implements System.Callable { */ global Object call(String action, Map arguments) { arguments = arguments ?? new Map(); - arguments.remove(null); - CallableHandler handler; - Map input; - Map output; - // if (isOmniStudioCall(arguments)) { - if (arguments.containsKey(OMNISTUDIO_ARGUMENT_INPUT) || arguments.containsKey(OMNISTUDIO_ARGUMENT_OUTPUT)) { - handler = new OmniStudioCallableHandler(); - input = (Map) arguments.get(OMNISTUDIO_ARGUMENT_INPUT); - output = (Map) arguments.get(OMNISTUDIO_ARGUMENT_OUTPUT); - } else { - handler = new StandardCallableHandler(); - input = arguments; - output = new Map(); + // Relevant OmniStudio docs for using the Callable interface: https://help.salesforce.com/s/articleView?id=sf.os_callable_implementations.htm&type=5 + Map input = (Map) arguments.get(OMNISTUDIO_ARGUMENT_INPUT) ?? arguments; + Map output = (Map) arguments.get(OMNISTUDIO_ARGUMENT_OUTPUT) ?? new Map(); +// System.Assert.fail(input.toString()); + try { + output.put(OUTPUT_ARGUMENT_CALL_IS_SUCCESS, true); + new CallableHandler().handleCall(action, input, output); + } catch(System.Exception thrownException) { + output.put(OUTPUT_ARGUMENT_CALL_IS_SUCCESS, false); + output.put(OUTPUT_ARGUMENT_CALL_ERROR_MESSAGE, thrownException.getMessage()); + output.put(OUTPUT_ARGUMENT_CALL_ERROR_TYPE, thrownException.getTypeName()); } - handler.handleCall(action, input, output); - return output; } @SuppressWarnings('PMD.ApexDoc') - private abstract class CallableHandler { - public virtual void handleCall(String action, Map input, Map output) { - Boolean isSuccess = true; - String errorMessage; - + private class CallableHandler { + public void handleCall(String action, Map input, Map output) { switch on action { // Methods for transaction IDs / parent transaction IDs when 'getTransactionId' { @@ -87,103 +81,56 @@ global without sharing class CallableLogger implements System.Callable { when 'endScenario' { Logger.endScenario((String) input.get(ARGUMENT_SCENARIO)); } + // Methods for adding & saving log entries + when 'newEntry' { + this.newEntry(input); + output.put(OUTPUT_ARGUMENT_CALL_IS_SUCCESS, true); + } + when 'saveLog' { + this.saveLog(input); + output.put(OUTPUT_ARGUMENT_CALL_IS_SUCCESS, true); + } when else { - isSuccess = false; - errorMessage = 'Unknown action: ' + action; + throw new System.IllegalArgumentException('Unknown action: ' + action); } } - - output.put(OUTPUT_ARGUMENT_CALL_IS_SUCCESS, isSuccess); - if (String.isNotBlank(errorMessage)) { - output.put(OUTPUT_ARGUMENT_CALL_ERROR_MESSAGE, errorMessage); - } } - protected LogEntryEventBuilder newEntry(Map arguments) { - // The value of loggingLevel could be either a string name or enum value, - // so coerce it to a string for consistency - String loggingLevelName = '' + arguments.get(ARGUMENT_LOGGING_LEVEL); + private void newEntry(Map input) { + // The value of loggingLevel could be either a string name or an enum value from System.LoggingLevel, + // so always first convert it to a string for consistency + String loggingLevelName = input.get(ARGUMENT_LOGGING_LEVEL)?.toString(); System.LoggingLevel loggingLevel = Logger.getLoggingLevel(loggingLevelName); - String message = (String) arguments.get(ARGUMENT_MESSAGE); + String message = (String) input.get(ARGUMENT_MESSAGE); LogEntryEventBuilder logEntryEventBuilder = Logger.newEntry(loggingLevel, message); - if (arguments.containsKey(ARGUMENT_EXCEPTION)) { - logEntryEventBuilder.setExceptionDetails((System.Exception) arguments.get(ARGUMENT_EXCEPTION)); + if (input.containsKey(ARGUMENT_EXCEPTION)) { + logEntryEventBuilder.setExceptionDetails((System.Exception) input.get(ARGUMENT_EXCEPTION)); } - if (arguments.containsKey(ARGUMENT_RECORD_ID)) { - logEntryEventBuilder.setRecord((String) arguments.get(ARGUMENT_RECORD_ID)); + if (input.containsKey(ARGUMENT_RECORD_ID)) { + logEntryEventBuilder.setRecord((String) input.get(ARGUMENT_RECORD_ID)); } - if (arguments.containsKey(ARGUMENT_RECORD)) { - logEntryEventBuilder.setRecord((SObject) arguments.get(ARGUMENT_RECORD)); + if (input.containsKey(ARGUMENT_RECORD)) { + logEntryEventBuilder.setRecord((SObject) input.get(ARGUMENT_RECORD)); } - if (arguments.containsKey(ARGUMENT_RECORD_LIST)) { - logEntryEventBuilder.setRecord((List) arguments.get(ARGUMENT_RECORD_LIST)); + if (input.containsKey(ARGUMENT_RECORD_LIST)) { + logEntryEventBuilder.setRecord((List) input.get(ARGUMENT_RECORD_LIST)); } - if (arguments.containsKey(ARGUMENT_RECORD_MAP)) { - logEntryEventBuilder.setRecord((Map) arguments.get(ARGUMENT_RECORD_MAP)); + if (input.containsKey(ARGUMENT_RECORD_MAP)) { + logEntryEventBuilder.setRecord((Map) input.get(ARGUMENT_RECORD_MAP)); } - if (arguments.containsKey(ARGUMENT_TAGS)) { - logEntryEventBuilder.addTags((List) arguments.get(ARGUMENT_TAGS)); + if (input.containsKey(ARGUMENT_TAGS)) { + logEntryEventBuilder.addTags((List) input.get(ARGUMENT_TAGS)); } - - return logEntryEventBuilder; } - protected void saveLog(Map arguments) { - String saveMethodName = ((String) arguments.get(ARGUMENT_SAVE_METHOD_NAME)) ?? Logger.getUserSettings().DefaultSaveMethod__c; + private void saveLog(Map input) { + // The value of saveMethodName could be either a string name or an enum value from Logger.SaveMethod, + // so always first convert it to a string for consistency + // System.Assert.fail(input.toString()); + String saveMethodName = input.get(ARGUMENT_SAVE_METHOD_NAME)?.toString() ?? Logger.getUserSettings().DefaultSaveMethod__c; Logger.saveLog(saveMethodName); } } - - // Handler used when Apex developers/ISVs/package creators are directly creating - // interacting with `CallableLogger` (i.e., anyone not using this for OmniStudio) - @SuppressWarnings('PMD.ApexDoc') - private class StandardCallableHandler extends CallableHandler { - public override void handleCall(String action, Map input, Map output) { - switch on action { - // Methods for adding entries & saving - when 'newEntry' { - this.newEntry(input); - output.put(OUTPUT_ARGUMENT_CALL_IS_SUCCESS, true); - } - when 'saveLog' { - this.saveLog(input); - output.put(OUTPUT_ARGUMENT_CALL_IS_SUCCESS, true); - } - when else { - super.handleCall(action, input, output); - } - } - } - } - - // Handler used when OmniStudio designers & developers are using `CallableLogger` for logging in OmniStudio - @SuppressWarnings('PMD.ApexDoc') - private class OmniStudioCallableHandler extends CallableHandler { - public override void handleCall(String action, Map input, Map output) { - switch on action { - // TODO revisit if using 'addnewentry' and ''addnewentry' is the best approach for OmniStudio: - // - For omniscripts, there's no state, so calling saveLog() doesn't make sense - // - For integration procedures, there IS state, so devs may want to call newEntry() and saveLog() - when 'addNewEntry' { - this.newEntry(input); - output.put(OUTPUT_ARGUMENT_CALL_IS_SUCCESS, true); - } - when 'saveNewEntry' { - this.newEntry(input); - Logger.saveLog(); - output.put(OUTPUT_ARGUMENT_CALL_IS_SUCCESS, true); - } - when else { - super.handleCall(action, input, output); - } - } - } - } - - // OmniStudio / OmniScript docs https://help.salesforce.com/s/articleView?id=sf.os_callable_implementations.htm&type=5 - private Boolean isOmniStudioCall(Map arguments) { - return arguments.containsKey(OMNISTUDIO_ARGUMENT_INPUT) || arguments.containsKey(OMNISTUDIO_ARGUMENT_OUTPUT); - } } diff --git a/nebula-logger/core/tests/logger-engine/classes/CallableLogger_Tests.cls b/nebula-logger/core/tests/logger-engine/classes/CallableLogger_Tests.cls index fafda3206..ab729b386 100644 --- a/nebula-logger/core/tests/logger-engine/classes/CallableLogger_Tests.cls +++ b/nebula-logger/core/tests/logger-engine/classes/CallableLogger_Tests.cls @@ -13,9 +13,10 @@ private class CallableLogger_Tests { System.Callable callableLoggerInstance = (System.Callable) System.Type.forName('CallableLogger').newInstance(); Map returnedOutput = (Map) callableLoggerInstance.call(fakeActionName, null); - System.Assert.areEqual(2, returnedOutput.size()); + System.Assert.areEqual(3, returnedOutput.size()); System.Assert.areEqual(false, returnedOutput.get('isSuccess'), 'Expected isSuccess == false. Output received: ' + returnedOutput); System.Assert.areEqual('Unknown action: ' + fakeActionName, returnedOutput.get('errorMessage')); + System.Assert.areEqual(System.IllegalArgumentException.class.getName(), returnedOutput.get('errorType')); } @IsTest @@ -26,9 +27,10 @@ private class CallableLogger_Tests { System.Callable callableLoggerInstance = (System.Callable) System.Type.forName('CallableLogger').newInstance(); callableLoggerInstance.call(fakeActionName, new Map{ 'output' => omnistudioOutput }); - System.Assert.areEqual(2, omnistudioOutput.size()); + System.Assert.areEqual(3, omnistudioOutput.size()); System.Assert.areEqual(false, omnistudioOutput.get('isSuccess'), 'Expected isSuccess == false. Output received: ' + omnistudioOutput); System.Assert.areEqual('Unknown action: ' + fakeActionName, omnistudioOutput.get('errorMessage')); + System.Assert.areEqual(System.IllegalArgumentException.class.getName(), omnistudioOutput.get('errorType')); } @IsTest @@ -41,9 +43,10 @@ private class CallableLogger_Tests { System.Callable callableLoggerInstance = (System.Callable) System.Type.forName('CallableLogger').newInstance(); Map returnedOutput = (Map) callableLoggerInstance.call(incorrectlyCasedActionName, null); - System.Assert.areEqual(2, returnedOutput.size()); + System.Assert.areEqual(3, returnedOutput.size()); System.Assert.areEqual(false, returnedOutput.get('isSuccess'), 'Expected isSuccess == false. Output received: ' + returnedOutput); System.Assert.areEqual('Unknown action: ' + incorrectlyCasedActionName, returnedOutput.get('errorMessage')); + System.Assert.areEqual(System.IllegalArgumentException.class.getName(), returnedOutput.get('errorType')); } @IsTest @@ -401,7 +404,7 @@ private class CallableLogger_Tests { Map omnistudioOutput = new Map(); System.Callable callableLoggerInstance = (System.Callable) System.Type.forName('CallableLogger').newInstance(); - callableLoggerInstance.call('saveLog', new Map{ 'output' => omnistudioOutput }); + callableLoggerInstance.call('saveLog', new Map{ 'output' => omnistudioOutput }); System.Assert.areEqual(1, omnistudioOutput.size(), omnistudioOutput.toString()); System.Assert.areEqual(true, omnistudioOutput.get('isSuccess'), 'Expected isSuccess == true. Output received: ' + omnistudioOutput); @@ -416,7 +419,10 @@ private class CallableLogger_Tests { String targetSaveMethodName = Logger.SaveMethod.SYNCHRONOUS_DML.name(); System.Callable callableLoggerInstance = (System.Callable) System.Type.forName('CallableLogger').newInstance(); - Map returnedOutput = (Map) callableLoggerInstance.call('saveLog', new Map{ 'saveMethodName' => targetSaveMethodName }); + Map returnedOutput = (Map) callableLoggerInstance.call( + 'saveLog', + new Map{ 'saveMethodName' => targetSaveMethodName } + ); System.Assert.areEqual(1, returnedOutput.size()); System.Assert.areEqual(true, returnedOutput.get('isSuccess'), 'Expected isSuccess == true. Output received: ' + returnedOutput); @@ -432,7 +438,10 @@ private class CallableLogger_Tests { String targetSaveMethodName = Logger.SaveMethod.SYNCHRONOUS_DML.name(); System.Callable callableLoggerInstance = (System.Callable) System.Type.forName('CallableLogger').newInstance(); - Map returnedOutput = (Map) callableLoggerInstance.call('saveLog', new Map{ 'saveMethodName' => targetSaveMethodName }); + Map returnedOutput = (Map) callableLoggerInstance.call( + 'saveLog', + new Map{ 'saveMethodName' => targetSaveMethodName } + ); System.Assert.areEqual(1, returnedOutput.size()); System.Assert.areEqual(true, returnedOutput.get('isSuccess'), 'Expected isSuccess == true. Output received: ' + returnedOutput);