

[2019-11-04 08:14:00,000] {"current_month":"4","current_year":"2013","message.id":0}/my/main/path/2013/4/foo.csv
[2019-11-04 08:14:01,000] {"current_month":"4","current_year":"2014","message.id":1}/my/main/path/2014/4/foo.csv
[2019-11-04 08:14:01,000] {"current_month":"8","current_year":"2005","message.id":2}/my/main/path/2005/8/foo.csv
[...]

var counter = 0;
getRandomInt = function(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
};
generateMessage = function() {
var msg = {};
msg.Attributes = {"message.id": counter, "current_month": getRandomInt(1, 12).toString(), "current_year": getRandomInt(2000, 2019).toString()};
msg.Body = "";
counter++;
return msg;
}
$.addTimer("500ms",doTick);
function doTick(ctx) {
$.output(generateMessage());
}
[2019-11-04 08:39:24,000] {"current_month":"4","current_year":"2018","message.id":35}
[2019-11-04 08:39:24,000] {"current_month":"10","current_year":"2011","message.id":36}
[2019-11-04 08:39:25,000] {"current_month":"11","current_year":"2007","message.id":37}
[...]
import re
import json
# RegEx to search for ${<varName>} --> The backslash will be escaped in the configString anyway to prevent Modeler from interpreting it as a substitution parameter
# config: "\${current_month}" will look like this in the api.config variable: "${current_month}"
pattern = re.compile('\$\{[^\}]*\}')
# Function that replaces all variables in "inConfigString" with attribute values of "inMsg"
# If no Message attribute value is provided the default value will be used
# If no default value is provided an Exception will be thrown
# This function returns the result configString
def dynamic_config_string(inConfigString,inMsg):
global pattern
# Find all variables in the inConfigString e.g. ['\${current_month=10}','\${current_year}','\${filename}']
variables = pattern.findall(inConfigString)
for var in variables: # in var you will see e.g. \${current_month=10} or \${current_month}
split=var.strip("$\{}").split("=") # in key you will see e.g. ['current_month','10'] or ['current_month']
# try replacing the variable with the provided inMsg attribute value
try:
value=inMsg.attributes[split[0]]
inConfigString=inConfigString.replace(var,str(value))
# KeyError -> inMsg attribute is not provided
except KeyError:
# try replacing the variable with the provided default value
try:
default=split[1]
inConfigString=inConfigString.replace(var,default)
# IndexError -> Default value is not provided
except IndexError:
raise Exception("Message header '"+split[0]+"' undefined and no default value provided")
return inConfigString
# Wrapper function that replaces all variables in "inConfigDict" with attribute values of "inMsg"
# If no Message attribute value is provided the default value will be used
# If no default value is provided an Exception will be thrown
# This function returns the result configDict
def dynamic_config_dict(inConfigDict,inMsg):
try:
inConfigString=dynamic_config_string(json.dumps(inConfigDict),inMsg)
return json.loads(inConfigString)
except Exception as e:
raise e
def on_input(msg):
path = dynamic_config_string(api.config.path,msg)
msg.body=path
api.send("out",msg)
api.set_port_callback("in",on_input)

[2019-11-04 08:14:00,000] {"current_month":"4","current_year":"2013","message.id":0}/my/main/path/2013/4/foo.csv
[2019-11-04 08:14:01,000] {"current_month":"4","current_year":"2014","message.id":1}/my/main/path/2014/4/foo.csv
[2019-11-04 08:14:01,000] {"current_month":"8","current_year":"2005","message.id":2}/my/main/path/2005/8/foo.csv
[...]def on_input(msg):
path = dynamic_config_string(api.config.path,msg)
msg.body=path
# --> This section is new
resultDict = dynamic_config_dict(json.loads(api.config.metadataObj),msg)
msg.attributes["metadataObj"]=resultDict
# <--
api.send("out",msg){"current_month":"6","current_year":"2007","message.id":21,"metadataObj":{"filename":"foo.csv","month":"6","year":"2007"}}/my/main/path/2007/6/foo.csv{
"properties": {},
"description": "Python Operator Dynamic Path Formatting",
"processes": {
"python3operator1": {
"component": "com.sap.system.python3Operator",
"metadata": {
"label": "Dynamic Path Config",
"x": 350,
"y": 12,
"height": 80,
"width": 120,
"extensible": true,
"config": {
"script": "import re\nimport json\n\n# RegEx to search for ${<varName>} --> The backslash will be escaped in the body string anyway\n# config: \"/my/main/path/\\${current_year}/\\${current_month}/\\${filename}.csv\" will look like this in the api.config variable: \"/my/main/path/${current_year}/${current_month}/${filename}.csv\"\n# If you find a way to read api.config as raw string let me know! \npattern = re.compile('\\$\\{[^\\}]*\\}') \n\n# Function that replaces all variables in \"inConfigString\" with attribute values of \"inMsg\"\n# If no Message attribute value is provided the default value will be used\n# If no default value is provided an Exception will be thrown\n# This function returns the result configString\ndef dynamic_config_string(inConfigString,inMsg):\n global pattern\n # Find all variables in the inConfigString e.g. ['\\${current_month=10}','\\${current_year}','\\${filename}']\n variables = pattern.findall(inConfigString)\n for var in variables: # in var you will see e.g. \\${current_month=10} or \\${current_month}\n split=var.strip(\"$\\{}\").split(\"=\") # in key you will see e.g. ['current_month','10'] or ['current_month']\n # try replacing the variable with the provided inMsg attribute value\n try: \n value=inMsg.attributes[split[0]]\n inConfigString=inConfigString.replace(var,str(value)) \n # KeyError -> inMsg attribute is not provided\n except KeyError:\n # try replacing the variable with the provided default value\n try: \n default=split[1]\n inConfigString=inConfigString.replace(var,default) \n # IndexError -> Default value is not provided\n except IndexError: \n raise Exception(\"Message header '\"+split[0]+\"' undefined and no default value provided\")\n return inConfigString\n\n# Wrapper function that replaces all variables in \"inConfigDict\" with attribute values of \"inMsg\" \n# If no Message attribute value is provided the default value will be used\n# If no default value is provided an Exception will be thrown\n# This function returns the result configDict\ndef dynamic_config_dict(inConfigDict,inMsg):\n try:\n inConfigString=dynamic_config_string(json.dumps(inConfigDict),inMsg)\n return json.loads(inConfigString)\n except Exception as e:\n raise e\n\ndef on_input(msg):\n path = dynamic_config_string(api.config.path,msg)\n msg.body=path\n # --> This section is new\n resultDict = dynamic_config_dict(json.loads(api.config.metadataObj),msg)\n msg.attributes[\"metadataObj\"]=resultDict\n # <--\n api.send(\"out\",msg)\n\napi.set_port_callback(\"in\",on_input)",
"path": "/my/main/path/\\${current_year}/\\${current_month}/\\${filename=foo}.csv",
"metadataObj": "{\n \"year\": \"\\${current_year}\",\n \"month\": \"\\${current_month}\",\n \"filename\": \"\\${filename=foo}.csv\"\n}"
},
"additionalinports": [
{
"name": "in",
"type": "message"
}
],
"additionaloutports": [
{
"name": "out",
"type": "message"
}
]
}
},
"messagegenerator1": {
"component": "com.sap.util.dataMessageGenerator",
"metadata": {
"label": "Message Generator",
"x": 12,
"y": 12,
"height": 80,
"width": 120,
"extensible": true,
"config": {
"script": "var counter = 0;\n\ngetRandomInt = function(min, max) {\n return Math.floor(Math.random() * (max - min + 1)) + min;\n};\n\ngenerateMessage = function() {\n var msg = {};\n msg.Attributes = {\"message.id\": counter, \"current_month\": getRandomInt(1, 12).toString(), \"current_year\": getRandomInt(2000, 2019).toString()};\n msg.Body = \"\";\n \n counter++;\n return msg;\n}\n\n$.addTimer(\"500ms\",doTick);\n\nfunction doTick(ctx) {\n $.output(generateMessage());\n}\n"
}
}
},
"wiretap1": {
"component": "com.sap.util.wiretap",
"metadata": {
"label": "Wiretap",
"x": 181,
"y": 12,
"height": 80,
"width": 120,
"ui": "dynpath",
"config": {}
}
},
"wiretap2": {
"component": "com.sap.util.wiretap",
"metadata": {
"label": "Wiretap",
"x": 519,
"y": 12,
"height": 80,
"width": 120,
"ui": "dynpath",
"config": {}
}
}
},
"groups": [],
"connections": [
{
"metadata": {
"points": "136,52 176,52"
},
"src": {
"port": "output",
"process": "messagegenerator1"
},
"tgt": {
"port": "in",
"process": "wiretap1"
}
},
{
"metadata": {
"points": "305,52 345,52"
},
"src": {
"port": "out",
"process": "wiretap1"
},
"tgt": {
"port": "in",
"process": "python3operator1"
}
},
{
"metadata": {
"points": "474,52 514,52"
},
"src": {
"port": "out",
"process": "python3operator1"
},
"tgt": {
"port": "in",
"process": "wiretap2"
}
}
],
"inports": {},
"outports": {}
}
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
| User | Count |
|---|---|
| 36 | |
| 35 | |
| 29 | |
| 29 | |
| 26 | |
| 26 | |
| 25 | |
| 25 | |
| 23 | |
| 23 |