the purpose of this document is to explain how to develop with the runtime. The target audience are the developers.
This section focus on the development part, to create a new collection of connector/worker. The developer can choose two different pattern:
- connector
- worker
The connector pattern embed the Connector SDK
In the next part of the documentation, we use the term of Runner. A Runner is a Connector or a Worker.
What is the difference between a Worker
and a Connector
?
Actually, a Connector
is used behind the scene for the Worker
implementation.
For the concept point of view, a Connector
is reusable and generic, where a Worker
is more specific to your company.
This is why all component you can find on the community hub are connector.
The second technical difference is on the structure. A Connector take as Input a class, where all parameters are a member of the class.
A Worker
access a list of variables.
A Connector has then three class:
- the function, where the core of the code is located
- an Input class
- an Output class
Keep in mind at any time you can move from a Worker structure to a Connector structure. The Cherry runtime execute both components
without distinction. The runtime call it a Runner
To take advantage of the different tool, two abstract class are present in the library:
-
The
AbstractConnector
implement the interfaceOutboundConnectorFunction
. -
The
AbstractWorker
is the second abstract class.
This part works for connector and worker.
Give a list of Input that your connector / worker expect. Each parameter has:
- a name (message)
- a label (Message to log). This label is visible in the Element Template for example
- a type. Multiple getter are available to access variables
- a scope: OPTIONAL, MANDATORY
- a description
Arrays.asList(
RunnerParameter.getInstance("message", "Message to log", String.class, RunnerParameter.Level.OPTIONAL, "Message to log, to ensure the worker was called"),
RunnerParameter.getInstance("delay", "Delay in ms", Long.class, RunnerParameter.Level.OPTIONAL, "Delay to sleep, in milliseconds")
),
This information build the documentation and the Element-Template
A parameter has multiple decorators. These are used to generate a rich Element-Template.
setVisibleInTemplate() A Mandatory parameter is visible every time. An Optional parameter has a checkbox. The designer has to select the checkbox to be able to give the value. With this decoration, the optional parameter is visible at any time.
getAccessAllVariables()
A connector/worker accesses a list of predefined variables.
You may need to have dynamic access: a variable is a prefix (designer says "_green"), and the connector/worker will access the temparature_green
variable.
When a parameter adds this decorator, then all variables in the process instance will be fetched to the connector/worker.
addCondition() To condition the visibility of a parameter by another parameter. Let's say that you have a parameter COUNTRY and a parameter STATE. You want to show the parameter STATE only when COUNTRY equals USA or BRAZIL. Then, on the parameter STATE, add
.addCondition("COUNTRY", Arrays.asList("USA", "BRAZIL"));
addChoice() A parameter can be a list of choice, and the designer will choose one in the dropdown. Add all choice via this decorator
.addChoice("USA", "United State Of America")
.addChoice("Brazil", "Brazil")
.addChoice("FR", "France")
Give the list of BPMN Errors that the connector/worker can throw. This list will be available in the documentation.
The Element-Template will contain the FEEL expression to transform a ConnectorException
to a BPMN Error.
Without this list, all ConnectorException
will be transformed into a Fail.
Output follow the same rule as the input
The worker has only one class, and get directly the information from the context.
Declare in the constructor the different input.
(see src/main/java/io/camunda/cherry/embeddedrunner/ping/worker/PingWorker.java
)
@Component
public class PingWorker extends AbstractWorker implements IntruntimeRunner {
public PingWorker() {
super("c-ping",
Arrays.asList(
RunnerParameter.getInstance(INPUT_MESSAGE,
"Message",
String.class,
RunnerParameter.Level.OPTIONAL,
"Message to log"),
RunnerParameter.getInstance(INPUT_DELAY,
"Delay",
Long.class,
RunnerParameter.Level.OPTIONAL,
"Delay to sleep")),
Collections.singletonList(
RunnerParameter.getInstance(OUTPUT_TIMESTAMP,
"Time stamp",
String.class,
RunnerParameter.Level.REQUIRED,
"Produce a timestamp")),
Collections.emptyList());
}
In the execution, you can access parameters via the different getInput...Value()
methods
String message = getInputStringValue(INPUT_MESSAGE, null, activatedJob);
Long delay = getInputLongValue(INPUT_DELAY, null, activatedJob);
The declaration in the connector is different. The Input is an object. Second, a notation @OutboundConnector
must be declared.
In the annotation, you must give the different inputVariables. These variables are defined in the InputObject, and the name of the variable in the notation and the name in the object must be identical
The recommendation is to declare a constant for each Input to ensure consistency. Attention, the value in the constant must be the exact name as the variable name.
public class PingConnectorInput extends AbstractConnectorInput {
// see
// https://docs.camunda.io/docs/components/integration-runtime/connectors/custom-built-connectors/connector-sdk/#validation
@NotEmpty
protected final static String INPUT_MESSAGE="message";
private String message;
protected final static String INPUT_DELAY="delay";
private int delay;
protected final static String INPUT_THROWERRORPLEASE="throwErrorPlease";
private boolean throwErrorPlease;
Then the value can be used in the declaration
@Component
@OutboundConnector(name = PingConnector.TYPE_PINGCONNECTOR,
inputVariables = { PingConnectorInput.INPUT_MESSAGE,
PingConnectorInput.INPUT_DELAY,
PingConnectorInput.INPUT_THROWERRORPLEASE },
type = PingConnector.TYPE_PINGCONNECTOR)
public class PingConnector extends AbstractConnector implements OutboundConnectorFunction
In the constructor, reference the Input class and the Output class. The Cherry runtime will introspect these class to create the documentation and the Element-template
public PingConnector() {
super(TYPE_PINGCONNECTOR,
PingConnectorInput.class,
PingConnectorOutput.class,
Collections.singletonList(new BpmnError(ERROR_BAD_WEATHER, "Why this is a bad weather?")));
Doing this way, the Cherry runtime will not find the documentation to build the documentation or the Element-template.
Do do that, the Input object need to extend the AbstractConnectorInput
class
public class PingConnectorInput extends AbstractConnectorInput {
and override a getInputParameters
method
@Override
public List<RunnerParameter> getInputParameters() {
return Arrays.asList(
RunnerParameter.getInstance("message", "Message", String.class, RunnerParameter.Level.OPTIONAL, "Message to log"),
RunnerParameter.getInstance("delay", "Delay", Long.class, RunnerParameter.Level.OPTIONAL, "Delay to sleep"),
RunnerParameter.getInstance("throwErrorPlease", "Throw ControllerPage Please", Boolean.class,
RunnerParameter.Level.OPTIONAL, "If true, then the connector throw an error"));
}
Same with the Output object
public class PingConnectorOutput extends AbstractConnectorOutput {
and
@Override
public List<RunnerParameter> getOutputParameters() {
return Arrays.asList(
RunnerParameter.getInstance("timeStampMS", "Time stamp", Long.class, RunnerParameter.Level.REQUIRED,
"Produce a timestamp"),
RunnerParameter.getInstance("ipAddress", "Ip Address", String.class, RunnerParameter.Level.REQUIRED,
"Returm the IpAddress"),
RunnerParameter.getInstance("parameters", "Parameters", Map.class, RunnerParameter.Level.REQUIRED,
"Returm parameters"));
}
The output of your connector may be
- a list of parameters. Then you can match one parameter by one in the Element-template, in multiple variables. Or if you don't want a result, just do not match it.
- an object saved in one process variable
This is the default behavior.
Just reference the Output object.
public class PingObjectConnectorOutput {
private final Long internalTimeStampMS;
private final String internalIpAddress;
public PingObjectConnectorOutput(long currentTimestamp, String ipAddress) {
super();
this.internalTimeStampMS = currentTimestamp;
this.internalIpAddress = ipAddress;
}
/* Return an objet, getter can be regular */
public long getTimeStampMS() {
return internalTimeStampMS;
}
/* Return an objet, getter can be regular */
public String getIpAddress() {
return internalIpAddress;
}
}
In multiple output parameters
Then, you have to specify the list of outputs in the method getOutputParameters()
and
You must create a getter for each member, starting with a lower case
For example, for the object
private long internalTimeStampMS;
the method must be
public long gettimeStampMS() {
if the time does not start by a lower case, then Zeebe will not find the value and can't do the correct mapping.
public class PingConnectorOutput extends AbstractConnectorOutput {
private long internalTimeStampMS;
private String internalIpAddress;
private Map<String, Object> parameters;
public PingConnectorOutput() {
super();
}
public PingConnectorOutput(long currentTimestamp, String ipAddress, Map<String, Object> parameters) {
super();
this.internalTimeStampMS = currentTimestamp;
this.internalIpAddress = ipAddress;
this.parameters = parameters;
}
@Override
public List<RunnerParameter> getOutputParameters() {
return Arrays.asList(
RunnerParameter.getInstance("timeStampMS", "Time stamp", Long.class, RunnerParameter.Level.REQUIRED,"Produce a timestamp"),
RunnerParameter.getInstance("ipAddress", "Ip Address", String.class, RunnerParameter.Level.REQUIRED,"Returm the IpAddress"),
RunnerParameter.getInstance("parameters", "Parameters", Map.class, RunnerParameter.Level.REQUIRED,"Returm parameters"));
}
/* The getter must start by a lower case */
public long gettimeStampMS() {
return internalTimeStampMS;
}
/* The getter must start by a lower case */
public String getipAddress() {
return internalIpAddress;
}
public Map<String, Object> getparameters() {
return parameters;
}
}
You can override different method:
@Override
public String getName() {
return "MyConnector";
}
@Override
public String getLabel() {
return "My First Connector";
}
@Override
public String getDescription() {
return "Verify that the connector is visible in the Modeler via the template, and is executed correctly.";
}
@Override
public String getLogo() {
return WORKERLOGO;
}
private static final String WORKERLOGO = "data:image/svg+xml,%3C?xml version='1.0' encoding='UTF-8' standalone='no'?%3E%3Csvg xmlns:dc='http://purl.org/dc/elements/1.1/' xmlns:cc='http://creativecommons.org/ns%23' xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns%23' xmlns:svg='http://www.w3.org/2000/svg' xmlns='http://www.w3.org/2000/svg' version='1.1' id='Capa_1' x='0px' y='0px' viewBox='0 0 18 18' xml:space='preserve' width='18' height='18'%3E%3Cmetadata id='metadata55'%3E%3Crdf:RDF%3E%3Ccc:Work rdf:about=''%3E%3Cdc:format%3Eimage/svg+xml%3C/dc:format%3E%3Cdc:type rdf:resource='http://purl.org/dc/dcmitype/StillImage' /%3E%3Cdc:title%3E%3C/dc:title%3E%3C/cc:Work%3E%3C/rdf:RDF%3E%3C/metadata%3E%3Cdefs id='defs53' /%3E%3Cg id='g18' transform='scale(0.3)'%3E %3Cpath d='M 30,0 C 13.458,0 0,13.458 0,30 0,46.542 13.458,60 30,60 46.542,60 60,46.542 60,30 60,13.458 46.542,0 30,0 Z m 0,58 C 14.561,58 2,45.439 2,30 2,14.561 14.561,2 30,2 45.439,2 58,14.561 58,30 58,45.439 45.439,58 30,58 Z' id='path2' /%3E %3Cpath d='M 23.165,8.459 C 23.702,8.329 24.033,7.789 23.904,7.253 23.775,6.716 23.234,6.387 22.698,6.514 18.763,7.46 15.176,9.469 12.322,12.323 9.468,15.177 7.46,18.764 6.514,22.698 c -0.129,0.536 0.202,1.076 0.739,1.206 0.078,0.019 0.157,0.027 0.234,0.027 0.451,0 0.861,-0.308 0.972,-0.767 0.859,-3.575 2.685,-6.836 5.277,-9.429 2.592,-2.593 5.854,-4.417 9.429,-5.276 z' id='path4' /%3E %3Cpath d='m 52.747,36.096 c -0.538,-0.129 -1.077,0.201 -1.206,0.739 -0.859,3.575 -2.685,6.836 -5.277,9.429 -2.592,2.593 -5.854,4.418 -9.43,5.277 -0.537,0.13 -0.868,0.67 -0.739,1.206 0.11,0.459 0.521,0.767 0.972,0.767 0.077,0 0.156,-0.009 0.234,-0.027 3.936,-0.946 7.523,-2.955 10.377,-5.809 2.854,-2.854 4.862,-6.441 5.809,-10.376 0.128,-0.536 -0.203,-1.076 -0.74,-1.206 z' id='path6' /%3E %3Cpath d='m 24.452,13.286 c 0.538,-0.125 0.873,-0.663 0.747,-1.2 -0.125,-0.538 -0.665,-0.878 -1.2,-0.747 -3.09,0.72 -5.904,2.282 -8.141,4.52 -2.237,2.236 -3.8,5.051 -4.52,8.141 -0.126,0.537 0.209,1.075 0.747,1.2 0.076,0.019 0.152,0.026 0.228,0.026 0.454,0 0.865,-0.312 0.973,-0.773 0.635,-2.725 2.014,-5.207 3.986,-7.18 1.972,-1.973 4.456,-3.352 7.18,-3.987 z' id='path8' /%3E %3Cpath d='m 48.661,36.001 c 0.126,-0.537 -0.209,-1.075 -0.747,-1.2 -0.538,-0.133 -1.075,0.209 -1.2,0.747 -0.635,2.725 -2.014,5.207 -3.986,7.18 -1.972,1.973 -4.455,3.352 -7.18,3.986 -0.538,0.125 -0.873,0.663 -0.747,1.2 0.107,0.462 0.519,0.773 0.973,0.773 0.075,0 0.151,-0.008 0.228,-0.026 3.09,-0.72 5.904,-2.282 8.141,-4.52 2.236,-2.236 3.798,-5.05 4.518,-8.14 z' id='path10' /%3E %3Cpath d='m 26.495,16.925 c -0.119,-0.541 -0.653,-0.879 -1.19,-0.763 -4.557,0.997 -8.146,4.586 -9.143,9.143 -0.118,0.539 0.224,1.072 0.763,1.19 0.072,0.016 0.144,0.023 0.215,0.023 0.46,0 0.873,-0.318 0.976,-0.786 0.831,-3.796 3.821,-6.786 7.617,-7.617 0.538,-0.118 0.88,-0.651 0.762,-1.19 z' id='path12' /%3E %3Cpath d='m 43.838,34.695 c 0.118,-0.539 -0.224,-1.072 -0.763,-1.19 -0.54,-0.118 -1.072,0.222 -1.19,0.763 -0.831,3.796 -3.821,6.786 -7.617,7.617 -0.539,0.118 -0.881,0.651 -0.763,1.19 0.103,0.468 0.516,0.786 0.976,0.786 0.071,0 0.143,-0.008 0.215,-0.023 4.556,-0.997 8.145,-4.586 9.142,-9.143 z' id='path14' /%3E %3Cpath d='m 38.08,30 c 0,-4.455 -3.625,-8.08 -8.08,-8.08 -4.455,0 -8.08,3.625 -8.08,8.08 0,4.455 3.625,8.08 8.08,8.08 4.455,0 8.08,-3.625 8.08,-8.08 z M 30,36.08 c -3.353,0 -6.08,-2.728 -6.08,-6.08 0,-3.352 2.728,-6.08 6.08,-6.08 3.352,0 6.08,2.728 6.08,6.08 0,3.352 -2.727,6.08 -6.08,6.08 z' id='path16' /%3E%3C/g%3E%3Cg id='g20'%3E%3C/g%3E%3Cg id='g22'%3E%3C/g%3E%3Cg id='g24'%3E%3C/g%3E%3Cg id='g26'%3E%3C/g%3E%3Cg id='g28'%3E%3C/g%3E%3Cg id='g30'%3E%3C/g%3E%3Cg id='g32'%3E%3C/g%3E%3Cg id='g34'%3E%3C/g%3E%3Cg id='g36'%3E%3C/g%3E%3Cg id='g38'%3E%3C/g%3E%3Cg id='g40'%3E%3C/g%3E%3Cg id='g42'%3E%3C/g%3E%3Cg id='g44'%3E%3C/g%3E%3Cg id='g46'%3E%3C/g%3E%3Cg id='g48'%3E%3C/g%3E%3Cg id='g85' transform='matrix(1.1259408,0,0,1.1259408,33.760593,8.6647721)'%3E%3Cpath d='m -15.969199,-1.3973349 c -0.04428,0.56592004 -0.49572,0.83754004 -0.58752,0.88722004 -0.4887,0.26676 -1.31112,0.17388 -1.70856,-0.38556 -0.21924,-0.30780004 -0.3294,-0.79758004 -0.1161,-1.13670004 l 0.0027,-0.0054 c 0.07668,-0.12474 0.25434,-0.33534 0.58212,-0.34236 h 0.01188 c 0.11718,0 0.25218,0.03564 0.37152,0.06696 0.0837,0.02214 0.15606,0.04104 0.21006,0.04482 0.03402,0.00216 0.08262,-0.00648 0.14418,-0.01728 0.18414,-0.0324 0.4914,-0.0864 0.76032,0.10368 0.36612,0.2597403 0.33156,0.76356 0.3294,0.78462 z' id='path57' style='fill:%23aa0000;fill-opacity:1;stroke-width:0.3' /%3E%3Cpath d='m -18.207499,-2.3007546 c -0.1053,0.07452 -0.17496,0.16686 -0.21708,0.2349 l -0.0027,0.00432 c -0.10908,0.17388 -0.13932,0.37584 -0.1188,0.57348 -0.0022,0.00108 -0.0043,0.00216 -0.0059,0.00378 -0.40014,0.3267 -0.85212,0.24246 -1.02762,0.19116 l -0.01026,-0.0027 c -0.5589,-0.13932 -1.11078,-0.74304 -1.00926,-1.38618 0.05616,-0.35424 0.324,-0.7614 0.72792,-0.85428 0.06966,-0.0162 0.43362,-0.0837 0.7263,0.16146 0.08964,0.0756 0.15606,0.1857601 0.21438,0.28296 0.04158,0.0702 0.07776,0.13014 0.11718,0.16956 0.02538,0.02538 0.06966,0.05022 0.12582,0.08208 0.1647,0.09234 0.4131,0.2322001 0.4779,0.53352 5.4e-4,0.00216 0.0011,0.00432 0.0022,0.00594 z' id='path59' style='fill:%23aa0000;fill-opacity:1;stroke-width:0.3' /%3E%3Cpath d='m -17.110219,-2.3309949 c -0.03186,0.0054 -0.05994,0.00918 -0.07992,0.00918 -0.0032,0 -0.0065,-5.4e-4 -0.0092,-5.4e-4 -0.01512,-0.00108 -0.03294,-0.00324 -0.05184,-0.00702 0.16578,-0.42336 0.23436,-1.10052 -0.34182,-1.95804 -0.0011,-0.00216 -0.0027,-0.00378 -0.0049,-0.0054 0.03348,-0.13284 0.04482,-0.22572 0.04752,-0.2484 0.0016,-0.01512 -0.0092,-0.02808 -0.02376,-0.0297 -0.01512,-0.00216 -0.02808,0.00918 -0.0297,0.02376 -0.0065,0.05778 -0.07128,0.5788801 -0.4347,1.0416602 -0.22734,0.28944 -0.58536,0.5049 -0.70902,0.56646 -0.01134,-0.00756 -0.02106,-0.01512 -0.02754,-0.0216 -0.01782,-0.01782 -0.0351,-0.04104 -0.05292,-0.06858 0.01026,-0.0054 0.02106,-0.01134 0.0324,-0.01728 0.12906,-0.06912 0.34506,-0.1841401 0.60858,-0.4600801 0.31158,-0.32616 0.37098,-0.82566 0.2835,-0.96174 -0.04212,-0.06588 -0.10962,-0.07236 -0.16362,-0.07722 -0.07074,-0.00594 -0.1134,-0.01026 -0.12096,-0.10638 -0.007,-0.0837 0.0324,-0.15768 0.1107,-0.20736 0.1053,-0.0675 0.29376,-0.0891 0.47628,0.01458 0.11394,0.06426 0.11286,0.17388 0.11232,0.27972 -5.4e-4,0.07074 -0.0011,0.1377 0.03402,0.18576 l 0.01512,0.02052 c 0.0864,0.1171801 0.28836,0.3904201 0.40932,0.86724 0.12906,0.5102999 0.007,0.9752399 -0.07992,1.1604599 z' id='path61' style='fill:%23502d16;fill-opacity:1;stroke-width:0.3' /%3E%3Cpath d='m -18.698899,-4.5455348 c -0.0043,0.00216 -0.0086,0.00324 -0.01296,0.00324 -0.0097,0 -0.0189,-0.0054 -0.02376,-0.01404 -5.4e-4,-5.4e-4 -0.03834,-0.06804 -0.10638,-0.13014 -0.01134,-0.00972 -0.01188,-0.027 -0.0022,-0.0378 0.01026,-0.01134 0.027,-0.01188 0.03834,-0.00216 0.07506,0.06804 0.11556,0.14094 0.11718,0.14418 0.0076,0.01296 0.0027,0.02916 -0.01026,0.03672 z' id='path63' style='stroke-width:0.3' /%3E%3Cpath d='m -18.644359,-4.0309149 c -0.05616,0.06642 -0.08532,0.0783 -0.1296,0.09612 l -0.01404,0.00594 c -0.0032,0.00162 -0.007,0.00216 -0.01026,0.00216 -0.0108,0 -0.02052,-0.00648 -0.02484,-0.01674 -0.0059,-0.0135 5.4e-4,-0.0297 0.01458,-0.0351 l 0.01404,-0.00594 c 0.0405,-0.01674 0.06102,-0.02538 0.10908,-0.081 0.0097,-0.01188 0.027,-0.01296 0.03834,-0.00324 0.01134,0.00972 0.01242,0.02646 0.0027,0.0378 z' id='path65' style='stroke-width:0.3' /%3E%3Cpath d='m -17.948839,-4.4391548 c -0.01404,-0.02214 -0.0324,-0.03402 -0.05292,-0.0405 -0.07182,0.09666 -0.32454,0.243 -0.57834,0.243 -0.0675,0 -0.13554,-0.01026 -0.1998,-0.03456 -0.1728,-0.06588 -0.29106,-0.15768 -0.40554,-0.24624 -0.09072,-0.07074 -0.17658,-0.13716 -0.28134,-0.18252 -0.01404,-0.00648 -0.01998,-0.02214 -0.01404,-0.03564 0.0059,-0.01404 0.0216,-0.01998 0.03564,-0.01404 0.1107,0.0486 0.19926,0.11664 0.29268,0.18954 0.11124,0.0864 0.2268,0.1755 0.3915,0.23814 0.16794,0.06372 0.3564,0.02214 0.4995,-0.04212 -0.06156,-0.19008 -0.45954,-0.76842 -1.11564,-0.6210001 -0.10152,0.02268 -0.19008,0.04374 -0.26784,0.0621 -0.3294,0.07722 -0.47034,0.11016 -0.61668,0.07128 0.0135,0.06804 0.04914,0.12582 0.10584,0.17226 0.1134,0.09126 0.2781,0.11394 0.3564,0.11502 -0.03996,-0.04536 -0.08262,-0.07452 -0.135,-0.09288 -0.01404,-0.00486 -0.0216,-0.01998 -0.01674,-0.03402 0.0049,-0.01458 0.02052,-0.0216 0.03456,-0.01674 0.1701,0.05994 0.2484,0.21222 0.37476,0.5227201 0.1323,0.32508 0.59508,0.62802 0.97038,0.5157 0.38232,-0.11448 0.37584,-0.51732 0.3753,-0.52164 0,-0.0108 0.0065,-0.02106 0.0162,-0.02538 0.02538,-0.01134 0.15552,-0.07074 0.24732,-0.15714 0.0016,-0.00162 0.0032,-0.0027 0.0049,-0.0027 v -5.4e-4 c -0.0043,-0.02646 -0.01188,-0.04752 -0.02106,-0.0621 m -0.89532,-0.2851201 c 0.01026,-0.01134 0.027,-0.01188 0.03834,-0.00216 0.07506,0.06804 0.11556,0.14094 0.11718,0.14418 0.0076,0.01296 0.0027,0.02916 -0.01026,0.03672 -0.0043,0.00216 -0.0086,0.00324 -0.01296,0.00324 -0.0097,0 -0.0189,-0.0054 -0.02376,-0.01404 -5.4e-4,-5.4e-4 -0.03834,-0.06804 -0.10638,-0.13014 -0.01134,-0.00972 -0.01188,-0.027 -0.0022,-0.0378 m -0.45468,0.36774 c -0.0011,0 -0.01674,0.0027 -0.04752,0.0027 -0.0243,0 -0.05724,-0.00162 -0.09936,-0.00702 -0.01512,-0.00162 -0.02538,-0.01512 -0.02322,-0.03024 0.0016,-0.01458 0.01512,-0.02484 0.03024,-0.02322 0.08748,0.01134 0.13014,0.00486 0.13068,0.00486 0.01458,-0.0027 0.02862,0.00702 0.03078,0.02214 0.0027,0.01458 -0.007,0.02808 -0.0216,0.03078 m 0.65448,0.32562 c -0.05616,0.06642 -0.08532,0.0783 -0.1296,0.09612 l -0.01404,0.00594 c -0.0032,0.00162 -0.007,0.00216 -0.01026,0.00216 -0.0108,0 -0.02052,-0.00648 -0.02484,-0.01674 -0.0059,-0.0135 5.4e-4,-0.0297 0.01458,-0.0351 l 0.01404,-0.00594 c 0.0405,-0.01674 0.06102,-0.02538 0.10908,-0.081 0.0097,-0.01188 0.027,-0.01296 0.03834,-0.00324 0.01134,0.00972 0.01242,0.02646 0.0027,0.0378 z' id='path67' style='fill:%23008000;fill-opacity:1;stroke-width:0.3' /%3E%3Cpath d='m -19.277239,-4.3873149 c 0.0027,0.01458 -0.007,0.02808 -0.0216,0.03078 -0.0011,0 -0.01674,0.0027 -0.04752,0.0027 -0.0243,0 -0.05724,-0.00162 -0.09936,-0.00702 -0.01512,-0.00162 -0.02538,-0.01512 -0.02322,-0.03024 0.0016,-0.01458 0.01512,-0.02484 0.03024,-0.02322 0.08748,0.01134 0.13014,0.00486 0.13068,0.00486 0.01458,-0.0027 0.02862,0.00702 0.03078,0.02214 z' id='path69' style='stroke-width:0.3' /%3E%3C/g%3E%3C/svg%3E";
@Override
public String getLogo() {
return WORKERLOGO;
}
The logo must be an SVG image.
Then here you are: the execute method!
To simplify the implementation, a set of getter() is provided to access any input.
public String getInputStringValue(String parameterName, String defaultValue, final ActivatedJob activatedJob) {
public Double getInputDoubleValue(String parameterName, Double defaultValue, final ActivatedJob activatedJob) {
@Override
public void execute(final JobClient jobClient, final ActivatedJob activatedJob, ContextExecution contextExecution) {
String message = getInputStringValue("message", null, activatedJob);
Long delay = getInputLongValue("delay", null, activatedJob);
...
setOutputValue("timestamp", formattedDate, contextExecution);
}
You have different method to access the input, in the correct class. To produce the result, use a setOutput method. This method verify that you respect the Output contract.
Camunda 8 does not propose any solution to manipulate files.
In a connector/worker, a file can be manipulated. For example, OfficeToPdf needs an MS Office or an Open Office document as input and will produce a PDF document as a result.
Cherry uses the Zeebe Cherry File Storage library.
The StorageDefinition concept specifies how to access files (same concept as a JDBC URL). Then the Runner LoadFileFromDisk required a storage definition and produced a "fileLoaded" as output. Note: the storage definition is the way to access where files are stored, not the file itself.
When you want to save a file for the first time, you need to specify the location. This is the Storage definition. Cherry uses this storage definition to do the job. A process variable is then calculated to access the file.
You can access the method set and easily access the file.
setOutputFileVariableValue("MyFile", storageDefinition, fileVariable, contextExecution);
To access the file, use the method.
FileVariable fileVariable = getInputFileVariableValue("MyFile", activatedJob);
Cherry will do the job to load the file where it is.
Note: the Cherry runtime contains embedded connectors loadFile
and saveFile
to load and save files using the storage definition.
Existing storage definitions are (refer to the library to have the complete list of storage):
- JSON: files are stored as JSON, as a process variable. This is simple, but if your file is significant, not very efficient. The file is encoded in base 64, which implies a 20 to 40% overload, and the file is stored in the C8 engine, which may cause some overlap.
Example with LoadFileFromDisk:
storageDefinition: JSON
fileLoaded contains JSON information with the file
{"name": "...", "mimeType": "application/txt", value="..."}
- FOLDER:. The file is stored in a folder with a unique name to avoid any collision.
Example with LoadFileFromDisk:
storageDefinition: FOLDER:/c8/fileprocess
fileLoaded contains
"contractMay_554343435533.docx"
Note: the folder is accessible by Runners. If you run multiple Cherry applications on different hosts, the folder must be visible to all applications.
- TEMPFOLDER, the temporary folder on the host, is used to store the file with a unique name to avoid any collision
Example with LoadFileFromDisk:
storageDefinition: TEMPFOLDER
fileLoaded contains
"contractMay_554343435533.docx"
This file is visible in the temporary folder on the host.
Note: the temporary folder is accessible only on one host, and each host has a different temporary folder. This implies your Runners run only on the same host, not in a cluster.
Start the Cherry runtime. Your connector appears in the dashboard, and the Element Template file can be downloaded.
You can download the complete collection to save for the desktop Modeler.
Or you can access the definition of one connector/worker to create a connector template in the Web Modeler. One connector template must be created one by one.
You have an external connector, and when you will upload it in Cherry runtime, you want to take advantages of all functions, displaying it with logo, display the list of Inputs, Outputs, BPMNError.
You want to generate the element-template by the Cherry runtime, with advance controles.
It is possible to do that without embedded any Cherry Library. You will just need to add some methods in your connector, then the runtime will be able to access it.
For example, the Cherry runtime will try to access a method getLogo()
to read the logo.
To be sure to not miss any function, check interfaces CherryConnector, CherryInput, CherryOutput stored
under io.camunda.connector.cherrytemplate
. Copy the package in your connector, and follow the README.MD