diff --git a/pom.xml b/pom.xml
index e969093..88bbdb1 100644
--- a/pom.xml
+++ b/pom.xml
@@ -10,7 +10,7 @@
ep.asyncapi.tool.sap.is
ep-asyncapi-sap-is-converter
- 1.0.4
+ 1.0.5
ep-asyncapi-sap-is-converter
ep-asyncapi-sap-is-converter
@@ -67,7 +67,7 @@
com.solace.ep.codegen
solace-ep-codegen
- 1.1.0
+ 1.1.1
diff --git a/src/main/java/ep/asyncapi/tool/sap/is/converter/service/EpActionsService.java b/src/main/java/ep/asyncapi/tool/sap/is/converter/service/EpActionsService.java
index e5221c4..04dcd3e 100644
--- a/src/main/java/ep/asyncapi/tool/sap/is/converter/service/EpActionsService.java
+++ b/src/main/java/ep/asyncapi/tool/sap/is/converter/service/EpActionsService.java
@@ -155,7 +155,7 @@ public byte[] generateISWorkflowArtefactForAppVersion(final ApiClient apiClient,
//resources/scenarios/integrationflow
sapIFlowConverter.createIntegrationFlowFiles(integrationFlowSubDirectory, mapMuleDoc);
//resources/script/
- sapIFlowConverter.createDynamicTopicScriptFiles(scriptSubDirectory);
+ sapIFlowConverter.createDynamicTopicScriptFiles(scriptSubDirectory, mapMuleDoc);
//create zip file
final File zipFile = createZipFile(mainDirectory);
diff --git a/src/main/java/ep/asyncapi/tool/sap/is/converter/service/converter/SapIFlowConverter.java b/src/main/java/ep/asyncapi/tool/sap/is/converter/service/converter/SapIFlowConverter.java
index 4400b95..62ddc3a 100644
--- a/src/main/java/ep/asyncapi/tool/sap/is/converter/service/converter/SapIFlowConverter.java
+++ b/src/main/java/ep/asyncapi/tool/sap/is/converter/service/converter/SapIFlowConverter.java
@@ -3,6 +3,7 @@
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.solace.ep.codegen.internal.model.MapMuleDoc;
+import com.solace.ep.codegen.internal.model.MapSubFlowEgress;
import com.solace.ep.codegen.internal.model.SchemaInstance;
import com.solace.ep.codegen.sap.iflow.SapIFlowGenerator;
@@ -353,14 +354,74 @@ private String generateProjectFileContent(final String asyncAPITitle) {
}
}
- public void createDynamicTopicScriptFiles(final File scriptSubDirectory) {
+ /**
+ * This method will create script files:
+ * - composeTopic.groovy (static)
+ * - topicParameters.groovy -- generated dynamically with topic parameters in code, one script function per event
+ * @param scriptSubDirectory
+ * @param mapMuleDoc
+ */
+ public void createDynamicTopicScriptFiles(final File scriptSubDirectory, MapMuleDoc mapMuleDoc) {
try {
final InputStream composeTopicScriptInputStream = SapIFlowConverter.class.getResourceAsStream(SapIflorConverterConstants.RESOURCES_SCRIPT_COMPOSE_TOPIC_FILE_PATH);
- // final InputStream extractFieldScriptInputStream = SapIFlowConverter.class.getResourceAsStream(SapIflorConverterConstants.RESOURCES_SCRIPT_EXTRACT_FIELD_FILE_PATH);
File composeTopicScriptFile = new File(scriptSubDirectory, "composeTopic.groovy");
- // File extractFieldScriptFile = new File(scriptSubDirectory, "extractField.groovy");
FileUtils.copyInputStreamToFile(composeTopicScriptInputStream, composeTopicScriptFile);
- // FileUtils.copyInputStreamToFile(extractFieldScriptInputStream, extractFieldScriptFile);
+
+ if (mapMuleDoc.getMapEgressSubFlows().isEmpty()) {
+ return;
+ } else {
+ int count = 0;
+ for (MapSubFlowEgress pub : mapMuleDoc.getMapEgressSubFlows() ) {
+ if (pub.getSetVariables().size() > 0) {
+ count++;
+ }
+ }
+ if (count == 0) {
+ return;
+ }
+ }
+
+ File topicParametersScriptFile = new File(scriptSubDirectory, "topicParameters.groovy");
+ FileUtils.writeStringToFile(topicParametersScriptFile, SapIflorConverterConstants.TOPIC_PARAMETERS_GROOVY_HEADER, "UTF-8", false );
+ int outputChannel = 0; // , functionCount = 0;
+ for ( MapSubFlowEgress pub : mapMuleDoc.getMapEgressSubFlows() ) {
+ if ( pub.getSetVariables().size() == 0 ) {
+ outputChannel++;
+ continue;
+ }
+ if ( pub.isPublishToQueue() ) {
+ outputChannel++;
+ continue;
+ }
+ String topicParametersGroovyFx = SapIflorConverterConstants.TOPIC_PARAMETERS_GROOVY_FX;
+ topicParametersGroovyFx = topicParametersGroovyFx.replace(
+ SapIflorConverterConstants.TP_TOKEN_EVENT_NAME,
+ pub.getMessageName() != null ? pub.getMessageName() : "UNKNOWN"
+ );
+ topicParametersGroovyFx = topicParametersGroovyFx.replace(
+ SapIflorConverterConstants.TP_TOKEN_TOPIC_ADDRESS_PATTERN,
+ pub.getPublishAddress() != null ? pub.getPublishAddress() : "UNKNOWN"
+ );
+ topicParametersGroovyFx = topicParametersGroovyFx.replace(
+ SapIflorConverterConstants.TP_TOKEN_FX_INSTANCE,
+ Integer.toString(outputChannel++)
+ );
+ StringBuilder varsList = new StringBuilder();
+ StringBuilder jsonPath = new StringBuilder();
+ StringBuilder setValue = new StringBuilder();
+ int varIndex = 1;
+ for( Map.Entry var : pub.getSetVariables().entrySet() ) {
+ final String topicVar = var.getKey();
+ varsList.append(String.format(SapIflorConverterConstants.TOPIC_PARAMETERS_VAR_LIST_PATTERN, topicVar));
+ jsonPath.append(String.format(SapIflorConverterConstants.TOPIC_PARAMETERS_JSON_PATH_PATTERN, topicVar, varIndex));
+ setValue.append(String.format(SapIflorConverterConstants.TOPIC_PARAMETERS_SET_VALUE_PATTERN, topicVar, varIndex));
+ varIndex++;
+ }
+ topicParametersGroovyFx = topicParametersGroovyFx.replace(SapIflorConverterConstants.TP_TOKEN_TOPIC_VARS_LIST, varsList.toString());
+ topicParametersGroovyFx = topicParametersGroovyFx.replace(SapIflorConverterConstants.TP_TOKEN_VARS_JSON_PATH, jsonPath.toString());
+ topicParametersGroovyFx = topicParametersGroovyFx.replace(SapIflorConverterConstants.TP_TOKEN_VARS_SET_VALUE, setValue.toString());
+ FileUtils.writeStringToFile(topicParametersScriptFile, topicParametersGroovyFx, "UTF-8", true);
+ };
} catch (IOException ioException) {
log.error("Error encountered in SapIFlowConverter.createDynamicTopicScriptFiles", ioException);
}
diff --git a/src/main/java/ep/asyncapi/tool/sap/is/converter/service/converter/SapIflorConverterConstants.java b/src/main/java/ep/asyncapi/tool/sap/is/converter/service/converter/SapIflorConverterConstants.java
index efcf2b8..dba6d32 100644
--- a/src/main/java/ep/asyncapi/tool/sap/is/converter/service/converter/SapIflorConverterConstants.java
+++ b/src/main/java/ep/asyncapi/tool/sap/is/converter/service/converter/SapIflorConverterConstants.java
@@ -20,4 +20,61 @@ public class SapIflorConverterConstants {
RESOURCES_MAPPING_SOURCE_TO_DESTINATIONFORMAT_TEMPLATE = "/static/iflowdocument-template/src/main/resources/mapping/sourceToDestinationFormatMmap.xml",
RESOURCES_SCRIPT_COMPOSE_TOPIC_FILE_PATH = "/static/iflowdocument-template/src/main/resources/script/composeTopic.groovy",
RESOURCES_SCRIPT_EXTRACT_FIELD_FILE_PATH = "/static/iflowdocument-template/src/main/resources/script/extractField.groovy";
+
+ public static final String
+ TOPIC_PARAMETERS_GROOVY_HEADER =
+ "/**\n" + //
+ " * topicParameters.groovy\n" + //
+ " * ----------------------\n" + //
+ " * EDIT this script to define sources for published topic variables\n" + //
+ " * - One function is generated per event type published to Event Mesh\n" + //
+ " * - Define entry for variable source as JSON Path (payload) or Set Value (explicit)\n" + //
+ " * - The JSON Path will be evaluated first, the Set Value can be used as a default\n" + //
+ " * if the field specified in JSON Path is not found in the payload\n" + //
+ " **/\n" + //
+ "import com.sap.gateway.ip.core.customdev.util.Message;\n" + //
+ "\n" + //
+ "TV_JSON_PATH_PROPERTY = \"__topicVarsJsonPath__\";\n" + //
+ "TV_SET_VALUE_PROPERTY = \"__topicVarsSetValue__\";\n" + //
+ "\n",
+ TOPIC_PARAMETERS_GROOVY_FX =
+ "/**\n" + //
+ " * Define Topic Variables for Event:\n" + //
+ " * >>$$__EVENT_NAME__$$<<\n" + //
+ " *\n" + //
+ " * Topic Address Pattern:\n" + //
+ " * >>$$__TOPIC_ADDRESS_PATTERN__$$<<\n" + //
+ " *\n" + //
+ " * Topic Variables:\n" + //
+ ">>$$__TOPIC_VARS_LIST__$$<<\n" + //
+ " **/\n" + //
+ "def Message defineTopicParams_>>$$__FX_INSTANCE__$$<<(Message message) {\n" + //
+ "\n" + //
+ " def topicVarsJsonPath = [:]; // Map of topicVariables -> JSON path locations\n" + //
+ " def topicVarsSetValue = [:]; // Map of topicVariables -> Explicit values\n" + //
+ "\n" + //
+ " // Uncomment property value to set JSON Path location in payload\n" + //
+ " // DO NOT use $. prefix for JSON Path specification\n" + //
+ ">>$$__TOPIC_VARS_JSON_PATH__$$<<\n" + //
+ "\n" + //
+ " // Uncomment property entry below to set a topic value directly\n" + //
+ ">>$$__TOPIC_VARS_SET_VALUE__$$<<\n" + //
+ "\n" + //
+ " message.setProperty(TV_JSON_PATH_PROPERTY, topicVarsJsonPath);\n" + //
+ " message.setProperty(TV_SET_VALUE_PROPERTY, topicVarsSetValue);\n" + //
+ "\n" + //
+ " return message;\n" + //
+ "}\n" + //
+ "\n",
+ TOPIC_PARAMETERS_JSON_PATH_PATTERN = " // topicVarsJsonPath.%s = \"payload.field%d\"\n",
+ TOPIC_PARAMETERS_SET_VALUE_PATTERN = " // topicVarsSetValue.%s = \"VALUE%d\"\n",
+ TOPIC_PARAMETERS_VAR_LIST_PATTERN = " * - %s\n";
+
+ public static String
+ TP_TOKEN_EVENT_NAME = ">>$$__EVENT_NAME__$$<<",
+ TP_TOKEN_TOPIC_ADDRESS_PATTERN = ">>$$__TOPIC_ADDRESS_PATTERN__$$<<",
+ TP_TOKEN_TOPIC_VARS_LIST = ">>$$__TOPIC_VARS_LIST__$$<<\n",
+ TP_TOKEN_FX_INSTANCE = ">>$$__FX_INSTANCE__$$<<",
+ TP_TOKEN_VARS_JSON_PATH = ">>$$__TOPIC_VARS_JSON_PATH__$$<<\n",
+ TP_TOKEN_VARS_SET_VALUE = ">>$$__TOPIC_VARS_SET_VALUE__$$<<\n";
}
diff --git a/src/main/resources/static/iflowdocument-template/src/main/resources/script/composeTopic.groovy b/src/main/resources/static/iflowdocument-template/src/main/resources/script/composeTopic.groovy
index f64a756..e8226f6 100644
--- a/src/main/resources/static/iflowdocument-template/src/main/resources/script/composeTopic.groovy
+++ b/src/main/resources/static/iflowdocument-template/src/main/resources/script/composeTopic.groovy
@@ -1,62 +1,78 @@
-/*
-This script will build a topic string with variable elements by extracting
-values from a JSON message body
-- If there are no variable elements in the topic string then then the set value will be passed on
-- If there is no composedTopic pattern then the script will do nothing
-*/
+/**
+ * composeTopic.groovy
+ * -------------------
+ * This script will build a topic string with variable elements by extracting
+ * values from a JSON message body OR by replacing variables with explicit values
+ * - In general, this script should not require editing
+ * - This script relies on existing message properties:
+ * - composedTopic -- Topic pattern with variables enclosed in braces: {var}
+ * - __topicVarsJsonPath__ -- Map of variable names -> JSON path of value
+ * - __topicVarsSetValue__ -- Map of variable names -> explicit values
+**/
import com.sap.gateway.ip.core.customdev.util.Message;
-import java.util.HashMap;
import groovy.json.JsonSlurper;
-def Message processData(Message message) {
- final GP_TOPICEXP = 'gpath_topicexp_';
- final GP_TOPICVAL = 'gpath_topicval_';
- final GP_COMPOSED_PATTERN = "gpath_composedTopicPattern";
- final COMPOSED_TOPIC = "composedTopic";
-
+def Message composeTopic(Message message) {
+ final COMPOSED_TOPIC_PROPERTY = 'composedTopic';
+ final TV_JSON_PATH_PROPERTY = '__topicVarsJsonPath__';
+ final TV_SET_VALUE_PROPERTY = '__topicVarsSetValue__';
+
def properties = message.getProperties();
- def topicValProperties = new HashMap();
-
+
try {
- def composedTopicString = properties.get(GP_COMPOSED_PATTERN);
- if (composedTopicString == null || composedTopicString.length() == 0) {
- // This could be an error, or the topic may be set directly on the publisher
- // (bypass composed topic logic)
+ def composedTopicPattern = properties.get(COMPOSED_TOPIC_PROPERTY);
+
+ // No topic pattern, nothing to do
+ if (!composedTopicPattern || composedTopicPattern.isEmpty()) {
+ // TODO - Error condition?
return message;
}
- if (!composedTopicString.contains("{")) {
- // Debug log, static topic detected
- message.setProperty(COMPOSED_TOPIC, composedTopicString);
+ // No variables in topic pattern, nothing to do
+ if (!composedTopicPattern.contains('{')) {
return message;
}
- // Extract dynamic topic values from message body
- final js = new groovy.json.JsonSlurper();
- final request = js.parseText(message.getBody(java.lang.String) as String);
- properties.each { prop, texp ->
- if (prop.startsWith(GP_TOPICEXP)) {
- def varval = groovy.util.Eval.x(request, 'x.' + texp);
- topicValProperties.put(GP_TOPICVAL + prop.replace(GP_TOPICEXP, ""), varval.toString());
- } else if (prop.startsWith(GP_TOPICVAL)) {
- topicValProperties.put(prop, texp.toString());
+ def tvJsonPath = properties.get(TV_JSON_PATH_PROPERTY)
+ def tvSetValue = properties.get(TV_SET_VALUE_PROPERTY)
+
+ // Special properties with variable content not present, nothing to do
+ if (!tvJsonPath && !tvSetValue) {
+ return message;
+ } else if (tvJsonPath.size() == 0 && tvSetValue.size() == 0) {
+ return message;
+ }
+
+ def composedTopicString = composedTopicPattern
+
+ // Set topic variables from payload
+ if (tvJsonPath && tvJsonPath.size() > 0) {
+ final js = new groovy.json.JsonSlurper()
+ final request = js.parseText(message.getBody(java.lang.String) as String)
+ tvJsonPath.each { entry ->
+ def varName = "{$entry.key}"
+ def varValue = groovy.util.Eval.x(request, 'x.' + entry.value)
+ if (varName && varValue) {
+ composedTopicString = composedTopicString.replace(varName, varValue)
+ }
}
}
-
- // Add Extracted values to message properties
- topicValProperties.each { key, value ->
- def varName = "{" + key.replace(GP_TOPICVAL, "") + "}";
- def varVal = value;
- if (varVal == null || varVal.isEmpty()) {
- varVal = "NULL";
+
+ // Set topic variables directly
+ if (tvSetValue) {
+ tvSetValue.each{ entry ->
+ def varName = "{$entry.key}"
+ def varValue = entry.value
+ if (varName && varValue) {
+ composedTopicString = composedTopicString.replace(varName, varValue)
+ }
}
- composedTopicString = composedTopicString.replace(varName, varVal);
}
-
+
// Set the composed topic to expected property
- message.setProperty(COMPOSED_TOPIC, composedTopicString);
+ message.setProperty(COMPOSED_TOPIC_PROPERTY, composedTopicString);
} catch (Exception ex) {
- message.setProperty('gpath_error', ex.getMessage());
+ message.setProperty('composedTopic_error', ex.getMessage());
}
return message;
}
\ No newline at end of file