diff --git a/pom.xml b/pom.xml
index 2e7492b..53edb5b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -12,7 +12,15 @@
17
${java.version}
${java.version}
- 8.1.0
+
+ 8.1.4
+
+
+ 0.3.0
+
+ 0.2.2
+ 0.2.2
+
5.9.1
2.0.3
2.7.4
@@ -66,25 +74,21 @@
io.camunda.connector
connector-core
- 0.2.0
-
-
- io.camunda.connector
- connector-runtime-job-worker
- 0.2.2
+ ${connector-core.version}
+ provided
+
+
+
io.camunda.connector
connector-validation
- 0.2.2
-
-
-
- jakarta.validation
- jakarta.validation-api
- 3.0.2
+ ${connector-validation.version}
+ provided
+
+
com.fasterxml.jackson.datatype
@@ -147,7 +151,7 @@
io.zeebe
zeebe-worker-java-testutils
- 8.0.0
+ 8.1.3
test
diff --git a/src/main/java/io/camunda/cherry/admin/RunnerInformation.java b/src/main/java/io/camunda/cherry/admin/RunnerInformation.java
index 2dfbbfc..620e199 100644
--- a/src/main/java/io/camunda/cherry/admin/RunnerInformation.java
+++ b/src/main/java/io/camunda/cherry/admin/RunnerInformation.java
@@ -1,6 +1,6 @@
/* ******************************************************************** */
/* */
-/* WorkerInformation */
+/* RunnerInformation */
/* */
/* Collect worker information from a worker. */
/* This class works as a facade. It's easy then to get the JSON */
@@ -110,7 +110,8 @@ public void setDisplayLogo(boolean displayLogo) {
* @return the list of errors
*/
public String getDefinitionErrors() {
- return String.join(", ", runner.getDefinitionErrors());
+ return String.join(", ", runner.checkValidDefinition());
+
}
public enum TYPE_RUNNER {WORKER, CONNECTOR}
diff --git a/src/main/java/io/camunda/cherry/admin/RunnerRestController.java b/src/main/java/io/camunda/cherry/admin/RunnerRestController.java
index 593c3ff..15413e2 100644
--- a/src/main/java/io/camunda/cherry/admin/RunnerRestController.java
+++ b/src/main/java/io/camunda/cherry/admin/RunnerRestController.java
@@ -116,7 +116,7 @@ public RunnerInformation stopWorker(@RequestParam(name = "name") String runnerNa
RunnerInformation runnerInfo = RunnerInformation.getRunnerInformation(runner);
return completeRunnerInformation(runnerInfo, false, false, null);
} catch (CherryJobRunnerFactory.OperationException e) {
- if (e.exceptionCode.equals(CherryJobRunnerFactory.WORKER_NOT_FOUND))
+ if (CherryJobRunnerFactory.RUNNER_NOT_FOUND.equals(e.getExceptionCode()))
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "WorkerName [" + runnerName + "] not found");
throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, "WorkerName [" + runnerName + "] error " + e);
}
@@ -138,7 +138,7 @@ public RunnerInformation startWorker(@RequestParam(name = "name") String runnerN
RunnerInformation runnerInfo = RunnerInformation.getRunnerInformation(runner);
return completeRunnerInformation(runnerInfo, false, false, null);
} catch (CherryJobRunnerFactory.OperationException e) {
- if (e.exceptionCode.equals(CherryJobRunnerFactory.WORKER_NOT_FOUND))
+ if (CherryJobRunnerFactory.RUNNER_NOT_FOUND.equals(e.getExceptionCode()))
throw new ResponseStatusException(HttpStatus.NOT_FOUND, "WorkerName [" + runnerName + "] not found");
throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, "WorkerName [" + runnerName + "] error " + e);
}
diff --git a/src/main/java/io/camunda/cherry/definition/AbstractConnectorInput.java b/src/main/java/io/camunda/cherry/definition/AbstractConnectorInput.java
index af4efaa..c8cceab 100644
--- a/src/main/java/io/camunda/cherry/definition/AbstractConnectorInput.java
+++ b/src/main/java/io/camunda/cherry/definition/AbstractConnectorInput.java
@@ -22,4 +22,15 @@ public List getInputParameters() {
return Collections.emptyList();
}
+ /**
+ * Create the list and give a class.
+ * If the Cherry input connector is created from a basic connector, give the Input connector.
+ * The Cherry will be able to verify the list againts the Input: all fields are declared? All RunnerParameters exists as a member in the class?
+ */
+ public record InputParametersInfo (List listRunners, Class inputClass){}
+
+ public InputParametersInfo getInputParametersInfo() {
+ return new InputParametersInfo(Collections.emptyList(), null);
+ }
+
}
diff --git a/src/main/java/io/camunda/cherry/definition/AbstractRunner.java b/src/main/java/io/camunda/cherry/definition/AbstractRunner.java
index 9c0ac6d..39e6e08 100644
--- a/src/main/java/io/camunda/cherry/definition/AbstractRunner.java
+++ b/src/main/java/io/camunda/cherry/definition/AbstractRunner.java
@@ -25,10 +25,12 @@
import org.springframework.beans.factory.annotation.Autowired;
import java.io.File;
+import java.lang.reflect.Field;
import java.time.Duration;
import java.util.*;
import java.util.function.Predicate;
import java.util.stream.Collectors;
+import java.util.stream.Stream;
public abstract class AbstractRunner {
@@ -688,7 +690,7 @@ private boolean containsKeyInJob(String parameterName, final ActivatedJob activa
*
* @param parameterName parameter to get the value
* @param activatedJob activated job
- * @return
+ * @return an object
*/
protected Object getValueFromJob(String parameterName, final ActivatedJob activatedJob) {
if (activatedJob.getVariablesAsMap().containsKey(parameterName))
@@ -739,17 +741,6 @@ public List getListBpmnErrors() {
return listBpmnErrors;
}
- /**
- * Check parameters. If something is not correct in the definition, then throw an error
- *
- * @return a list of errors
- */
- public List getDefinitionErrors() {
- List listOfErrors = new ArrayList<>();
- listOfErrors.addAll(checkListParameters(listInput));
- listOfErrors.addAll(checkListParameters(listOutput));
- return listOfErrors;
- }
/**
* Return the list of variable to fetch if this is possible, else null.
* To calculate the list:
@@ -825,7 +816,7 @@ public String getDescription() {
* Image must be a string like
* "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='18' height='18.0' viewBox='0 0 18 18.0' %3E%3Cg id='XMLID_238_'%3E %3Cpath id='XMLID_239_' d='m 14.708846 10.342394 c -1.122852 0.0,-2.528071 0.195852,-2.987768 0.264774 C 9.818362 8.6202,9.277026 7.4907875,9.155265 7.189665 C 9.320285 6.765678,9.894426 5.155026,9.976007 3.0864196 C 10.016246 2.0507226,9.797459 1.2768387,9.325568 .... -0.00373,0.03951 0.00969,0.0425 0.030567 z'/%3E%3C/svg%3E";
*
- * @return
+ * @return the logo
*/
public String getLogo() {
return logo;
@@ -856,10 +847,51 @@ private boolean isStringEmpty(String value) {
*
* @return
*/
- public boolean isValidDefinition() {
- return (getIdentification().isEmpty());
+ public List checkValidDefinition() {
+ List listOfErrors= new ArrayList<>();
+ if (getIdentification().isEmpty())
+ listOfErrors.add("No identification");
+
+ if (this instanceof AbstractConnector) {
+ AbstractConnectorInput.InputParametersInfo parameterInfo=((AbstractConnector) this).getAbstractConnectorInput().getInputParametersInfo();
+ if (parameterInfo!=null && ! parameterInfo.listRunners().isEmpty() && parameterInfo.inputClass()!=null)
+ listOfErrors.addAll(confrontParameterWithClass( parameterInfo.inputClass(), parameterInfo.listRunners()));
+ }
+
+ listOfErrors.addAll(checkListParameters(listInput));
+ listOfErrors.addAll(checkListParameters(listOutput));
+
+ return listOfErrors;
}
+ /**
+ * Confront a list of RunnerParameter with a class.
+ * @param clazz class to confront
+ * @param parameters list of Runner.
+ * @return empty is every thing is OK, else an analysis
+ */
+ private List confrontParameterWithClass(Class clazz, List parameters) {
+ List listOfErrors= new ArrayList<>();
+
+ Field[] fields = clazz.getDeclaredFields();
+ // All fields are part of parameters?
+ for (Field field: fields) {
+ long number = parameters.stream().filter(t -> t.getName().equals(field.getName())).count();
+ if (number != 1)
+ listOfErrors.add("Class Field[" + field.getName() + "] is not part of parameters");
+ }
+
+ // All parameters must be part of the fields
+ for (RunnerParameter parameter : parameters) {
+ if (parameter.getName().equals("*"))
+ continue;
+ long number = Stream.of(fields).filter(t -> t.getName().equals(parameter.getName())).count();
+ if (number != 1)
+ listOfErrors.add("Parameter[" + parameter.getName() + "] is not part of fields in the class");
+ }
+
+ return listOfErrors;
+ }
private List checkListParameters(List listParameters) {
diff --git a/src/main/java/io/camunda/cherry/ping/PingConnectorInput.java b/src/main/java/io/camunda/cherry/ping/PingConnectorInput.java
index 559d466..7b976ad 100644
--- a/src/main/java/io/camunda/cherry/ping/PingConnectorInput.java
+++ b/src/main/java/io/camunda/cherry/ping/PingConnectorInput.java
@@ -6,7 +6,8 @@
import java.util.Arrays;
import java.util.List;
-import jakarta.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotEmpty;
+
public class PingConnectorInput extends AbstractConnectorInput {
diff --git a/src/main/java/io/camunda/cherry/runtime/CherryJobRunnerFactory.java b/src/main/java/io/camunda/cherry/runtime/CherryJobRunnerFactory.java
index 9da51f0..7738ad7 100644
--- a/src/main/java/io/camunda/cherry/runtime/CherryJobRunnerFactory.java
+++ b/src/main/java/io/camunda/cherry/runtime/CherryJobRunnerFactory.java
@@ -6,7 +6,7 @@
/* ******************************************************************** */
package io.camunda.cherry.runtime;
-import io.camunda.connector.runtime.jobworker.api.outbound.ConnectorJobHandler;
+import io.camunda.connector.runtime.util.outbound.ConnectorJobHandler;
import io.camunda.zeebe.client.api.worker.JobWorker;
import io.camunda.zeebe.client.api.worker.JobWorkerBuilderStep1;
import io.camunda.cherry.definition.AbstractConnector;
@@ -26,7 +26,7 @@
@Service
public class CherryJobRunnerFactory {
- public static final String WORKER_NOT_FOUND = "WorkerNotFound";
+ public static final String RUNNER_NOT_FOUND = "WorkerNotFound";
public static final String UNKNOWN_WORKER_CLASS = "UnknownWorkerClass";
public static final String WORKER_INVALID_DEFINITION = "WORKER_INVALID_DEFINITION";
@@ -56,9 +56,9 @@ public void startAll() {
for (AbstractRunner runner : listRunners) {
- String errors = String.join(", ", runner.getDefinitionErrors());
- if (!errors.isEmpty()) {
- logger.error("Runner [" + runner.getIdentification() + "] can't start, errors " + errors);
+ List listOfErrors = runner.checkValidDefinition();
+ if (!listOfErrors.isEmpty()) {
+ logger.error("Runner [" + runner.getIdentification() + "] can't start, errors " + String.join(", ",listOfErrors));
continue;
}
@@ -83,11 +83,9 @@ public void stopAll() {
if (running.runner != null) {
try {
stopRunner(running.runner.getIdentification());
- } catch (OperationException e) {
- logger.error("Error on worker [" + running.runner.getIdentification() + "]");
} catch (Exception e) {
- logger.error("Error on worker [" + running.runner.getIdentification() + "]");
+ logger.error("Error on runner [" + running.runner.getIdentification() + "] : "+e);
}
}
}
@@ -104,12 +102,12 @@ public void stopAll() {
public boolean stopRunner(String runnerName) throws OperationException {
for (Running running : listRunnerRunning) {
if (running.runner().getIdentification().equals(runnerName)) {
- closeJobWorker(running.containerJobWorker.jobWorker);
- running.containerJobWorker.jobWorker = null;
+ closeJobWorker(running.containerJobWorker.getJobWorker());
+ running.containerJobWorker.setJobWorker(null);
return true;
}
}
- throw new OperationException(WORKER_NOT_FOUND, "Worker not found");
+ throw new OperationException(RUNNER_NOT_FOUND, "Runner not found");
}
/**
@@ -117,32 +115,34 @@ public boolean stopRunner(String runnerName) throws OperationException {
*
* @param runnerName name of the runner (connector/worker)
* @return true if the runner started
- * @throws Exception
+ * @throws OperationException runner can't start
*/
public boolean startRunner(String runnerName) throws OperationException {
for (Running running : listRunnerRunning) {
if (running.runner().getIdentification().equals(runnerName)) {
- if (!running.runner.isValidDefinition())
+ List listOfErrors= running.runner.checkValidDefinition();
+ if (! listOfErrors.isEmpty())
throw new OperationException(WORKER_INVALID_DEFINITION, "Worker has error in the definition : "
- + String.join(";", running.runner.getDefinitionErrors()));
+ + String.join(";", listOfErrors));
- closeJobWorker(running.containerJobWorker.jobWorker);
- running.containerJobWorker.jobWorker = null;
+ closeJobWorker(running.containerJobWorker.getJobWorker());
+ running.containerJobWorker.setJobWorker( null);
JobWorkerBuilderStep1.JobWorkerBuilderStep3 jobWorkerBuild = createJobWorker(running.runner);
- running.containerJobWorker.jobWorker = jobWorkerBuild.open();
+ running.containerJobWorker.setJobWorker( jobWorkerBuild.open());
return true;
}
}
- throw new OperationException(WORKER_NOT_FOUND, "Worker not found");
+ throw new OperationException(RUNNER_NOT_FOUND, "Worker not found");
}
public boolean isRunnerActive(String runnerName) throws OperationException {
for (Running running : listRunnerRunning) {
if (running.runner().getIdentification().equals(runnerName)) {
- return running.containerJobWorker.jobWorker != null;
+
+ return running.containerJobWorker.getJobWorker() != null;
}
}
- throw new OperationException(WORKER_NOT_FOUND, "Worker not found");
+ throw new OperationException(RUNNER_NOT_FOUND, "Worker not found");
}
@@ -202,11 +202,19 @@ else if (runner instanceof AbstractConnector abstractConnector)
* Not possible to restart a jobWorker: must be created again !
*/
private static class ContainerJobWorker {
- public JobWorker jobWorker;
+ private JobWorker jobWorker;
public ContainerJobWorker(JobWorker jobWorker) {
this.jobWorker = jobWorker;
}
+
+ public JobWorker getJobWorker() {
+ return jobWorker;
+ }
+
+ public void setJobWorker(JobWorker jobWorker) {
+ this.jobWorker = jobWorker;
+ }
}
record Running(AbstractRunner runner, ContainerJobWorker containerJobWorker) {
@@ -216,13 +224,22 @@ record Running(AbstractRunner runner, ContainerJobWorker containerJobWorker) {
/**
* Declare an exception on an operation
*/
- public class OperationException extends Exception {
- public String exceptionCode;
- public String explanation;
+ public static class OperationException extends Exception {
+ private final String exceptionCode;
+ private final String explanation;
OperationException(String exceptionCode, String explanation) {
this.exceptionCode = exceptionCode;
this.explanation = explanation;
}
+
+ public String getExceptionCode() {
+ return exceptionCode;
+ }
+
+ public String getExplanation() {
+ return explanation;
+ }
+
}
}
diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties
index 73ba891..2299e89 100644
--- a/src/main/resources/application.properties
+++ b/src/main/resources/application.properties
@@ -1,13 +1,14 @@
# use a OnPremise Zeebe engine
-# zeebe.client.broker.gateway-address=127.0.0.1:26500
+zeebe.client.broker.gateway-address=127.0.0.1:26500
# zeebe.client.broker.gateway-address=host.docker.internal:26500
-# zeebe.client.security.plaintext=true
+zeebe.client.security.plaintext=true
# use a cloud Zeebe engine
-zeebe.client.cloud.region=bru-2
-zeebe.client.cloud.clusterId=f867aa3d-5ee7-4324-96e8-21f557f104af
-zeebe.client.cloud.clientId=si71NBAWtUlREmfKja5oQC3M.WsT~sHa
-zeebe.client.cloud.clientSecret=pCTITndkvyNsaSkfJ-ji5w38vaP19QAXWURM3UVC1.J.eVyxa44uITFv3_c8iFi2
+# zeebe.client.cloud.region=bru-2
+# zeebe.client.cloud.clusterId=f867aa3d-5ee7-4324-96e8-21f557f104af
+# zeebe.client.cloud.clientId=si71NBAWtUlREmfKja5oQC3M.WsT~sHa
+# zeebe.client.cloud.clientSecret=pCTITndkvyNsaSkfJ-ji5w38vaP19QAXWURM3UVC1.J.eVyxa44uITFv3_c8iFi2
+
zeebe.client.worker.maxJobsActive=32
diff --git a/src/test/resources/connectorworker/connectorworker.bpmn b/src/test/resources/connectorworker/PingConnectorWorker.bpmn
similarity index 99%
rename from src/test/resources/connectorworker/connectorworker.bpmn
rename to src/test/resources/connectorworker/PingConnectorWorker.bpmn
index 53f9294..9e4b9ee 100644
--- a/src/test/resources/connectorworker/connectorworker.bpmn
+++ b/src/test/resources/connectorworker/PingConnectorWorker.bpmn
@@ -1,6 +1,6 @@
-
+
Flow_00mgsl9
@@ -85,24 +85,24 @@
-
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
+
+
@@ -150,4 +150,4 @@
-
+
\ No newline at end of file
diff --git a/src/test/resources/files/Cherry.jpg b/src/test/resources/files/Cherry.jpg
new file mode 100644
index 0000000..ffc7a67
Binary files /dev/null and b/src/test/resources/files/Cherry.jpg differ