I have a quite large project, where almost all tasks have the same connector applied to them. I've been trying to find a way to move the core functionality of these connector (which is a Groovy script) into a separate Groovy Script file so if I had to change something, I would only have to change the external script file instead of updating each connector one by one for hundreds of tasks. But there is just one problem: I can't for the love of God extract the variables in a dynamic way. I'm not entirely sure how the variables provided to the script (like activityId, processId, or custom variables) work, but it seems to me that unless the connector script contains a direct reference for that variable, then the variable won't become accessible. It's not contained in the Binding, I can't interpolate, or even eval them, they simply don't exist within the script's context unless directly referenced. The only way I can pass the variables to the external script is by referencing each one of them directly in the script, after which they become accessible. But that won't do for me, because it is possible that I'll need to introduce new variables down the line, and if I can't dynamically pass them as well, then I'll have to update every single connector every time a new variable is introduced. I'm at a loss here, how could I possibly pass the variables accessible inside the connector script without having to explicitly name them?
Hi RiSza,
you have several options.
the first one is to extract your connector call to a call activity, using a contract so you can pass all required data to your connector, but shared data stills remains in one single place
an other option is to add a "all parameter" Map<String,Serializable> extra parameter input to your connector. Since it has no access to Groovy script, just add a global "allParam" function to get them and pass to your connector input. this way you keep also a single place ot truth with your data, but of course your connector implementation should be aware of this and may be updated to consume all new parameters
regards,
L.
Hi,
extracting common logic is a good idea !
What about using method parameters to retrieve the context ?
public class CustomBusinessLogic {
APIAccessor apiAccessor
publlic CustomBusinessLogic (APIAccessor apiAccessor){
this.apiAccessor = apiAccessor
}
public void doSomething(long processInstanceId, BusinessObject myBusinessVaraible ){
// DO YOUR THINGS
}
public String doSomethingElse(String aStringVariableValue){
// DO YOUR THINGS
}
}
And then call your method in your process like this:
new CustomBusinessLogic (apiAccessor).doSomething(processInstanceId, myBusinessVaraible)
or
return new CustomBusinessLogic (apiAccessor).doSomethingElse(aStringVariable)
To be even cleaner, I suggest externalizing this logic in a specific dependency (developing the logic aside using maven or gradle and build a jar that can be imported in your project). This will give you access to all standard tooling for unit testing and so on.
HTH
Romain
Extracting the connector call to a call activity won't do, we're talking about hundreds if not thousands of connector calls here (every human task has the same functionality attached to it).
The other solution, I don't fully understand. What do you mean about an "input" to the connector? As far as I'm aware, there is no input you can explicitly add to a connector, it uses whatever is accessible in the context. Could you elaborate on this one, please?
Extracting the connector call to a call activity won't do, we're talking about hundreds if not thousands of connector calls here (every human task has the same functionality attached to it).
The other solution, I don't fully understand. What do you mean about an "input" to the connector? As far as I'm aware, there is no input you can explicitly add to a connector, it uses whatever is accessible in the context. Could you elaborate on this one, please?
the idea is to pass a single connector input, including all required data, instead of passing each one, as detailled by @romain’s answer thus you don’t need to review all your connector config, since they will all use the same content
But how do I specify the content of this input in a way that it will automatically include newly created variables without updating the connector itself?
The problem is that I'm still stuck having to explicitly pass these parameters (or call these methods) from the connector itself, which means I'll have to update every single connector every time something changes. For example, let's see that my external logic handles the following variables:
- processInstanceId
- processDefinitionId
- activityInstanceId
- myCustomId
All is fine, everything is working. But then the design changes, and so does the data structure, and I'll have to handle a brand new variable, too:
- myCustomUuid
How do I ensure that my external logic will receive this new variable without having to update over a thousand connectors? Your solution would require me to create a new method in my external script, and then update every connector to call it. That is extremely cumbersome. My approach was that the external script provides a function that specifies what parameters it requests from the connector, but I can't address these variables dynamically at all. They are simply not provided to the connector unless explicitly referenced from code. Neither string interpolation or evaluate() succeeds in dynamically addressing the variables, which means that I'm stuck updating every connector when a new variable is introduced.
You mayuse the apiAccessor
to retrieve process/activity variables dynamically:
public void printContext(long processInstanceId, long activityInstanceId) {
def activityVariables = apiAccessor.processAPI.getActivityDataInstances(activityInstanceId, 0, 999)
println activityVariables.collect{ "${it.name}=${it.value}" }
if(activityInstanceId == null) {
def processVariables = apiAccessor.processAPI.getProcessDataInstances(processInstanceId, 0, 999)
println activityVariables.collect{ "${it.name}=${it.value}" }
}
}
However this won’t work Business variables.