From 581a9023117ebb38200568adf8ddd1ba84c6fbbd Mon Sep 17 00:00:00 2001 From: Pierre-yves-monnet Date: Wed, 27 Nov 2024 20:38:31 -0800 Subject: [PATCH] with UnitTest implementation --- README.md | 29 +- doc/scenarioreference/C8CrawlUrl.bpmn | 570 +++++ doc/unittestscenario/SendUnitTestCommand.rest | 21 + .../resources/ScoreAcceptanceScn.json | 94 + pom.xml | 2 +- .../org/camunda/automator/AutomatorAPI.java | 238 +- .../automator/AutomatorApplication.java | 10 +- .../org/camunda/automator/AutomatorCLI.java | 438 ++-- .../org/camunda/automator/AutomatorRest.java | 271 +++ .../automator/bpmnengine/BpmnEngine.java | 483 ++-- .../BpmnEngineConfigurationInstance.java | 90 +- .../bpmnengine/BpmnEngineFactory.java | 76 +- .../camunda7/BpmnEngineCamunda7.java | 1029 ++++---- ...kCompleteJobExceptionHandlingStrategy.java | 32 +- ...hmarkStartPiExceptionHandlingStrategy.java | 38 +- .../camunda8/BpmnEngineCamunda8.java | 2079 ++++++++--------- .../camunda8/StatisticsCollector.java | 52 +- .../refactoring/RefactoredCommandWrapper.java | 122 +- .../bpmnengine/dummy/BpmnEngineDummy.java | 288 +-- .../configuration/BpmnEngineList.java | 1086 +++++---- .../ConfigurationServersEngine.java | 156 +- .../configuration/ConfigurationStartup.java | 260 +-- .../automator/content/ContentManager.java | 104 + .../content/ContentRestController.java | 40 + .../automator/definition/Scenario.java | 352 ++- .../definition/ScenarioDeployment.java | 30 +- .../definition/ScenarioExecution.java | 258 +- .../definition/ScenarioFlowControl.java | 76 +- .../automator/definition/ScenarioStep.java | 543 +++-- .../automator/definition/ScenarioTool.java | 40 +- .../definition/ScenarioVerification.java | 99 +- .../definition/ScenarioVerificationBasic.java | 2 +- .../ScenarioVerificationPerformance.java | 62 + .../definition/ScenarioVerificationTask.java | 66 +- .../ScenarioVerificationVariable.java | 18 +- .../definition/ScenarioWarmingUp.java | 34 +- .../automator/engine/AutomatorException.java | 38 +- .../automator/engine/RunParameters.java | 484 ++-- .../camunda/automator/engine/RunResult.java | 690 +++--- .../camunda/automator/engine/RunScenario.java | 423 ++-- .../automator/engine/RunZeebeOperation.java | 48 +- .../automator/engine/SchedulerExecution.java | 32 +- .../flow/CreateProcessInstanceThread.java | 362 +-- .../engine/flow/FixedBackoffSupplier.java | 16 +- .../automator/engine/flow/RunObjectives.java | 508 ++-- .../engine/flow/RunScenarioFlowBasic.java | 104 +- .../flow/RunScenarioFlowServiceTask.java | 428 ++-- .../flow/RunScenarioFlowStartEvent.java | 330 +-- .../engine/flow/RunScenarioFlowUserTask.java | 214 +- .../engine/flow/RunScenarioFlows.java | 704 +++--- .../engine/flow/RunScenarioWarmingUp.java | 556 ++--- .../engine/unit/RunScenarioUnit.java | 356 +-- .../unit/RunScenarioUnitServiceTask.java | 118 +- .../unit/RunScenarioUnitStartEvent.java | 64 +- .../engine/unit/RunScenarioUnitUserTask.java | 122 +- .../engine/unit/RunScenarioVerification.java | 264 ++- .../automator/services/AutomatorStartup.java | 435 ++-- .../automator/services/ServiceAccess.java | 30 +- .../services/ServiceDataOperation.java | 64 +- .../services/dataoperation/DataOperation.java | 92 +- .../DataOperationGenerateList.java | 64 +- .../DataOperationGenerateUniqueID.java | 62 +- .../dataoperation/DataOperationLoadFile.java | 70 +- .../DataOperationStringToDate.java | 106 +- src/main/resources/application.yaml | 5 +- 65 files changed, 8640 insertions(+), 7337 deletions(-) create mode 100644 doc/scenarioreference/C8CrawlUrl.bpmn create mode 100644 doc/unittestscenario/SendUnitTestCommand.rest create mode 100644 doc/unittestscenario/resources/ScoreAcceptanceScn.json create mode 100644 src/main/java/org/camunda/automator/AutomatorRest.java create mode 100644 src/main/java/org/camunda/automator/content/ContentManager.java create mode 100644 src/main/java/org/camunda/automator/content/ContentRestController.java create mode 100644 src/main/java/org/camunda/automator/definition/ScenarioVerificationPerformance.java diff --git a/README.md b/README.md index fbd8f57..62e0765 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,7 @@ What Process-Automator do: Process-Automator do not * Execute service task in unit-scenario -* It is not expected to throw a BPMN Message in the flow: Process-Automator piloted a real system. +* It is not expected to catch a BPMN Message in the flow: Process-Automator piloted a real system. ## Requirement @@ -70,7 +70,6 @@ A scenario can be executed on a Camunda 7 or a Camunda 8 server. Process-Automat ## Different usages - ### Unit test and regression, unit performance test (unit-scenario) The unit scenario describes one process instance execution. Creation and user tasks are described. @@ -94,6 +93,32 @@ Visit [Load Test Scenario](doc/loadtestscenario/README.md) and the [Load test Tu ## Scenario +Process-Execution-Automator execute a scenario. + +A scenario define +* a list of robots. A robot + * Create process instances, + * Execute service task, + * Execute user tasks +* some objectives + * How many process instance must be created + * How many service task has to be executed + * Time to execute a section in the process +* a warm up section + +Due to the “backoff strategy”, workers need to be wake up + +Robots can be registered in the same pod +![C8CrawlUrl.png](doc/scenarioreference/C8CrawlUrl.png) + +Or multiple pods can be defined. Each pod run the process-execution-automator on the same scenario, but limit which robots are executed +![C8CrawlUrl-multiple-pods.png](doc/scenarioreference/C8CrawlUrl-multiple-pods.png) + + +For unit testing, the execution is different. The pod is started, but don't start immediately the scenario. + + + This section references all the information to build a scenario. Visit [Scenario reference](doc/scenarioreference/README.md) diff --git a/doc/scenarioreference/C8CrawlUrl.bpmn b/doc/scenarioreference/C8CrawlUrl.bpmn new file mode 100644 index 0000000..5d946a7 --- /dev/null +++ b/doc/scenarioreference/C8CrawlUrl.bpmn @@ -0,0 +1,570 @@ + + + + + + + + + + + + + + + + + + + + + + Flow_17n6ju8 + + + + + + Flow_17n6ju8 + Flow_03a245y + + + Flow_191cul5 + + + Flow_03a245y + Flow_191cul5 + + + + + + + Flow_0ue17j2 + + + + + Flow_06qswzj + + + + + + Flow_0ue17j2 + Flow_1dpfwyb + + + + + + Flow_0zrd1qi + Flow_0zhmx9x + + + + + + Flow_0zhmx9x + Flow_11raeuz + Flow_1llqly1 + + + + + + Flow_1llqly1 + Flow_06qswzj + + + + + + Flow_1dpfwyb + Flow_0zrd1qi + Flow_0af83lu + + + + =urlNotFound + + + Flow_124nqht + + + + Flow_0af83lu + Flow_0x26tsm + + + Flow_0x26tsm + Flow_124nqht + Flow_15yyn2a + + + + =processAcceptable + + + + + + Flow_15yyn2a + Flow_11raeuz + + + + 0 s + + + + 10 s + + + + + + 1 s + + + 1 s + + + 5 s + + + + + + + + + Flow_1q4xt3v + + PT20M + + + + Flow_1q4xt3v + + + + + Loop 20 + + + 2 s + + + 400PI/mn + + + + + + + + + DataObjectReference_16o9ddc + + + + + DataObjectReference_16o9ddc + + + + + DataObjectReference_16o9ddc + + + + + DataObjectReference_16o9ddc + + + + + DataObjectReference_16o9ddc + + + + + DataObjectReference_16o9ddc + + + + + DataObjectReference_16o9ddc + + + + + DataObjectReference_16o9ddc + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/unittestscenario/SendUnitTestCommand.rest b/doc/unittestscenario/SendUnitTestCommand.rest new file mode 100644 index 0000000..a41ae51 --- /dev/null +++ b/doc/unittestscenario/SendUnitTestCommand.rest @@ -0,0 +1,21 @@ +### POST Request +POST http://localhost:8381/api/unittest/run?name=ScoreAcceptanceScn&server=Camunda8Ruby&wait=false +Content-Type: application/json + +{ +} + + +### POST Request +GET http://localhost:8381/api/unittest/get?id=1732767184446 +Content-Type: application/json + +{ +} + +### GET LIST +GET http://localhost:8381/api/unittest/list +Content-Type: application/json + +{ +} diff --git a/doc/unittestscenario/resources/ScoreAcceptanceScn.json b/doc/unittestscenario/resources/ScoreAcceptanceScn.json new file mode 100644 index 0000000..cdd80e7 --- /dev/null +++ b/doc/unittestscenario/resources/ScoreAcceptanceScn.json @@ -0,0 +1,94 @@ +{ + "name": "ScoreAcceptance", + "processId": "ScoreAcceptance", + "serverType": "Camunda_8", + "typeScenario": "UNIT", + "executions": [ + { + "name": "ScoreAccepted", + "steps": [ + { + "type": "STARTEVENT", + "taskId": "ScoreApplication", + "processId": "ScoreAcceptance", + "variables": { + "score": 245 + } + } + ], + "verifications": { + "activities": [ + { + "type": "ActGetScore", + "taskId": "ActGetScore" + }, + { + "description": "we accepted the application with this amount", + "type": "TASK", + "taskId": "ActSendAcceptation" + }, + { + "type": "ENDEVENT", + "taskId": "EndAccepted" + } + ], + "variables": [ + { + "description": "we accepted the application with this amount", + "name": "accepted", + "value": true + } + ], + "performances": [ + { + "description": "From get Score to the End Event, less than 200 ms", + "fromFlowNode": "ActGetScore", + "fromMarker": "begin", + "toFlowNode": "EndAccepted", + "toMarker": "end", + "duration": "PT0.2S" + }, + { + "description": "GetScore must be performed in less than 100 ms", + "fromFlowNode": "ActGetScore", + "fromMarker": "begin", + "toFlowNode": "ActGetScore", + "toMarker": "end", + "duration": "PT0.1S" + } + ] + } + }, + { + "name": "ScoreRejected", + "steps": [ + { + "type": "STARTEVENT", + "taskId": "ScoreApplication", + "processId": "ScoreAcceptance", + "variables": { + "score": 67 + } + } + ], + "verifications": { + "activities": [ + { + "type": "TASK", + "taskId": "ActSendRejection" + }, + { + "type": "ENDEVENT", + "taskId": "EndRejected" + } + ], + "variables": [ + { + "name": "accepted", + "value": false + } + ] + } + } + ] +} \ No newline at end of file diff --git a/pom.xml b/pom.xml index 8be44aa..3a78b70 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ org.camunda.community.automator process-execution-automator - 1.7.1 + 1.8.0 diff --git a/src/main/java/org/camunda/automator/AutomatorAPI.java b/src/main/java/org/camunda/automator/AutomatorAPI.java index e4f7da0..7683984 100644 --- a/src/main/java/org/camunda/automator/AutomatorAPI.java +++ b/src/main/java/org/camunda/automator/AutomatorAPI.java @@ -25,129 +25,129 @@ @Component public class AutomatorAPI { - static Logger logger = LoggerFactory.getLogger(AutomatorAPI.class); - - @Autowired - ServiceAccess serviceAccess; - - /** - * Create an empty scenario. - * The scenario can be created from scratch by the caller - * - * @return the scenario - * see scenario class to create from scratch a scenario - */ - public Scenario createScenario() { - return new Scenario(); - } - - /** - * Load the scenario from a file - * - * @param scenarioFile file to read the scenario - * @return the scenario - * @throws AutomatorException if scenario can't be read - */ - public Scenario loadFromFile(File scenarioFile) throws AutomatorException { - return Scenario.createFromFile(scenarioFile); - } - - /** - * Create from an input Stream. - * - * @param scenarioInputStream inputStream - * @param origin origin of inputStream - * @return scenario - * @throws AutomatorException if scenario can't be read - */ - public Scenario loadFromInputStream(InputStream scenarioInputStream, String origin) throws AutomatorException { - return Scenario.createFromInputStream(scenarioInputStream, origin); - } - - /** - * Search the engine from the scenario - * - * @param scenario scenario - * @param bpmnEngineList different engine configuration - * @return the engine, null if no engine exist, an exception if the connection is not possible - */ - public BpmnEngine getBpmnEngineFromScenario(Scenario scenario, BpmnEngineList bpmnEngineList) - throws AutomatorException { - try { - - if (scenario.getServerName() != null) { - return getBpmnEngine(bpmnEngineList.getByServerName(scenario.getServerName()), true); - } - - return null; - } catch (AutomatorException e) { - logger.error("Can't connect the engine for the scenario [{}] serverName[{}]: {}", scenario.getName(), - scenario.getServerName(), e.getMessage()); - throw e; + static Logger logger = LoggerFactory.getLogger(AutomatorAPI.class); + + @Autowired + ServiceAccess serviceAccess; + + /** + * Create an empty scenario. + * The scenario can be created from scratch by the caller + * + * @return the scenario + * see scenario class to create from scratch a scenario + */ + public Scenario createScenario() { + return new Scenario(); } - } - - /** - * Execute a scenario - * - * @param bpmnEngine Access the Camunda engine. if null, then the value in the scenario are used - * @param runParameters parameters use to run the scenario - * @param scenario the scenario to execute - */ - public RunResult executeScenario(BpmnEngine bpmnEngine, RunParameters runParameters, Scenario scenario) { - RunScenario runScenario = null; - - try { - runScenario = new RunScenario(scenario, bpmnEngine, runParameters, serviceAccess); - } catch (Exception e) { - RunResult result = new RunResult(runScenario); - result.addError(null, "Initialization error"); - return result; + /** + * Load the scenario from a file + * + * @param scenarioFile file to read the scenario + * @return the scenario + * @throws AutomatorException if scenario can't be read + */ + public Scenario loadFromFile(File scenarioFile) throws AutomatorException { + return Scenario.createFromFile(scenarioFile); } - RunResult runResult = new RunResult(runScenario); - runResult.add(runScenario.runScenario()); - - return runResult; - } - - - /* ******************************************************************** */ - /* */ - /* Additional tool */ - /* */ - /* Deploy Process */ - /* Deploy a process in the server */ - /* ******************************************************************** */ - - public BpmnEngine getBpmnEngine(BpmnEngineList.BpmnServerDefinition serverDefinition, boolean logDebug) - throws AutomatorException { - return BpmnEngineFactory.getInstance().getEngineFromConfiguration(serverDefinition, logDebug); - } - - /** - * Deploy a process, bpmEngine is given by the caller - * - * @param bpmnEngine Engine to deploy - * @param runParameters parameters used to deploy the version - * @param scenario scenario - * @return the result object - */ - public RunResult deployProcess(BpmnEngine bpmnEngine, RunParameters runParameters, Scenario scenario) { - RunScenario runScenario = null; - try { - long begin = System.currentTimeMillis(); - runScenario = new RunScenario(scenario, bpmnEngine, runParameters, serviceAccess); - RunResult runResult = new RunResult(runScenario); - runResult.add(runScenario.runDeployment()); - runResult.addTimeExecution(System.currentTimeMillis() - begin); - return runResult; - } catch (Exception e) { - RunResult result = new RunResult(runScenario); - result.addError(null, "Process deployment error error " + e.getMessage()); - return result; + /** + * Create from an input Stream. + * + * @param scenarioInputStream inputStream + * @param origin origin of inputStream + * @return scenario + * @throws AutomatorException if scenario can't be read + */ + public Scenario loadFromInputStream(InputStream scenarioInputStream, String origin) throws AutomatorException { + return Scenario.createFromInputStream(scenarioInputStream, origin); } - } + /** + * Search the engine from the scenario + * + * @param scenario scenario + * @param bpmnEngineList different engine configuration + * @return the engine, null if no engine exist, an exception if the connection is not possible + */ + public BpmnEngine getBpmnEngineFromScenario(Scenario scenario, BpmnEngineList bpmnEngineList) + throws AutomatorException { + try { + + if (scenario.getServerName() != null) { + return getBpmnEngine(bpmnEngineList.getByServerName(scenario.getServerName()), true); + } + + return null; + } catch (AutomatorException e) { + logger.error("Can't connect the engine for the scenario [{}] serverName[{}]: {}", scenario.getName(), + scenario.getServerName(), e.getMessage()); + throw e; + } + + } + + /** + * Execute a scenario + * + * @param bpmnEngine Access the Camunda engine. if null, then the value in the scenario are used + * @param runParameters parameters use to run the scenario + * @param scenario the scenario to execute + */ + public RunResult executeScenario(BpmnEngine bpmnEngine, RunParameters runParameters, Scenario scenario) { + RunScenario runScenario = null; + + try { + runScenario = new RunScenario(scenario, bpmnEngine, runParameters, serviceAccess); + } catch (Exception e) { + RunResult result = new RunResult(runScenario); + result.addError(null, "Initialization error"); + return result; + } + + RunResult runResult = new RunResult(runScenario); + runResult.merge(runScenario.runScenario()); + + return runResult; + } + + + /* ******************************************************************** */ + /* */ + /* Additional tool */ + /* */ + /* Deploy Process */ + /* Deploy a process in the server */ + /* ******************************************************************** */ + + public BpmnEngine getBpmnEngine(BpmnEngineList.BpmnServerDefinition serverDefinition, boolean logDebug) + throws AutomatorException { + return BpmnEngineFactory.getInstance().getEngineFromConfiguration(serverDefinition, logDebug); + } + + /** + * Deploy a process, bpmEngine is given by the caller + * + * @param bpmnEngine Engine to deploy + * @param runParameters parameters used to deploy the version + * @param scenario scenario + * @return the result object + */ + public RunResult deployProcess(BpmnEngine bpmnEngine, RunParameters runParameters, Scenario scenario) { + RunScenario runScenario = null; + try { + long begin = System.currentTimeMillis(); + runScenario = new RunScenario(scenario, bpmnEngine, runParameters, serviceAccess); + RunResult runResult = new RunResult(runScenario); + runResult.merge(runScenario.runDeployment()); + runResult.addTimeExecution(System.currentTimeMillis() - begin); + return runResult; + } catch (Exception e) { + RunResult result = new RunResult(runScenario); + result.addError(null, "Process deployment error error " + e.getMessage()); + return result; + } + + } } diff --git a/src/main/java/org/camunda/automator/AutomatorApplication.java b/src/main/java/org/camunda/automator/AutomatorApplication.java index af39f83..7805309 100644 --- a/src/main/java/org/camunda/automator/AutomatorApplication.java +++ b/src/main/java/org/camunda/automator/AutomatorApplication.java @@ -9,11 +9,11 @@ public class AutomatorApplication { - public static void main(String[] args) { + public static void main(String[] args) { - SpringApplication.run(AutomatorApplication.class, args); - // thanks to Spring, the class AutomatorStartup.init() is active. - } - // https://docs.camunda.io/docs/components/best-practices/development/writing-good-workers/ + SpringApplication.run(AutomatorApplication.class, args); + // thanks to Spring, the class AutomatorStartup.init() is active. + } + // https://docs.camunda.io/docs/components/best-practices/development/writing-good-workers/ } diff --git a/src/main/java/org/camunda/automator/AutomatorCLI.java b/src/main/java/org/camunda/automator/AutomatorCLI.java index 479ac89..257785a 100644 --- a/src/main/java/org/camunda/automator/AutomatorCLI.java +++ b/src/main/java/org/camunda/automator/AutomatorCLI.java @@ -24,230 +24,230 @@ @Component public class AutomatorCLI implements CommandLineRunner { - public static boolean isRunningCLI = false; - static Logger logger = LoggerFactory.getLogger(AutomatorCLI.class); - @Autowired - AutomatorAPI automatorAPI; - @Autowired - BpmnEngineList engineConfiguration; - - @Autowired - ConfigurationStartup configurationStartup; - - public static void main(String[] args) { - isRunningCLI = true; - SpringApplication app = new SpringApplication(AutomatorCLI.class); - app.setBannerMode(Banner.Mode.OFF); - System.exit(SpringApplication.exit(app.run(args))); - } - - /* ******************************************************************** */ - /* */ - /* Usage */ - /* -c, --conf */ - /* configuration file contains connection to engine */ - /* */ - /* -e, --engine ConnectionUrlString */ - /* CAMUNDA7; */ - /* CAMUNDA8;CLOUD;;;; */ - /* CAMUNDA8;LOCAL;; */ - /* */ - /* -d, --debug */ - /* logs all steps */ - /* -n, --numberofexecution <number> */ - /* override the number of execution for the scenario */ - /* -r, --recursive */ - /* all *.json in the folder and sub-folder are monitored and executed*/ - /* */ - /* run <scenarioFile> */ - /* */ - /* ******************************************************************** */ - - private static void printUsage() { - logOutLn("Usage: <option> <action> <parameter>"); - logOutLn(" -s, --server <serverName>"); - logOutLn(" Which server to use in the configuration"); - logOutLn(" -e, --engine ConnectionUrlString"); - logOutLn(" CAMUNDA7;<URL>"); - logOutLn(" CAMUNDA8;CLOUD;<region>;<clusterId>;<clientIs>;<clientSecret>"); - logOutLn(" CAMUNDA8;LOCAL;<gateway>;<plaintext>"); - logOutLn(" -l, --level <DEBUG|COMPLETE|MONITORING|MAIN|NOTHING>"); - logOutLn(" Define the level of log (MONITORING is the default)"); - logOutLn(" -n, --numberofexecution <number>"); - logOutLn(" override the number of execution for the scenario"); - logOutLn(" -d, --deploy <TRUE|FALSE>"); - logOutLn(" Allow deployment of process is defined in the scenario (default is TRUE)"); - - logOutLn(" -x, --execute"); - logOutLn(" execute the scenario"); - logOutLn(" -v, --verification"); - logOutLn(" verify the scenario"); - logOutLn(" -f, --fullreport"); - logOutLn(" Full report"); - - logOutLn(""); - logOutLn("ACTIONS: "); - logOutLn(" run <scenarioFile>"); - logOutLn(" execute one scenario"); - logOutLn(" recursive <folder>"); - logOutLn(" all *.json in the folder and sub-folder are monitored and executed"); - - } - - private static BpmnEngineList decodeConfiguration(String propertiesFileName) throws Exception { - throw new Exception("Not yet implemented"); - } - - private static List<File> detectRecursiveScenario(File folderRecursive) { - List<File> listFiles = new ArrayList<>(); - for (File file : folderRecursive.listFiles()) { - if (file.isDirectory()) { - listFiles.addAll(detectRecursiveScenario(file)); - } else if (file.getName().endsWith(".json")) { - listFiles.add(file); - } + public static boolean isRunningCLI = false; + static Logger logger = LoggerFactory.getLogger(AutomatorCLI.class); + @Autowired + AutomatorAPI automatorAPI; + @Autowired + BpmnEngineList engineConfiguration; + + @Autowired + ConfigurationStartup configurationStartup; + + public static void main(String[] args) { + isRunningCLI = true; + SpringApplication app = new SpringApplication(AutomatorCLI.class); + app.setBannerMode(Banner.Mode.OFF); + System.exit(SpringApplication.exit(app.run(args))); } - return listFiles; - } - - /** - * To reduce the number of warning - * - * @param message message to log out - */ - private static void logOutLn(String message) { - System.out.println(message); - } - - public void run(String[] args) { - if (!isRunningCLI) - return; - File scenarioFile = null; - File folderRecursive = null; - - RunParameters runParameters = new RunParameters(); - runParameters.setExecution(true) - .setServerName(configurationStartup.getServerName()) - .setLogLevel(configurationStartup.getLogLevelEnum()) - .setCreation(configurationStartup.isPolicyExecutionCreation()) - .setServiceTask(configurationStartup.isPolicyExecutionServiceTask()) - .setUserTask(configurationStartup.isPolicyExecutionUserTask()) - .setWarmingUp(configurationStartup.isPolicyExecutionWarmingUp()) - .setDeploymentProcess(configurationStartup.isPolicyDeployProcess()) - .setDeepTracking(configurationStartup.deepTracking()) - .setStartEventNbThreads(configurationStartup.getStartEventNbThreads()); - List<String> filterService = configurationStartup.getFilterService(); - if (filterService != null) { - runParameters.setFilterExecutionServiceTask(filterService); + + /* ******************************************************************** */ + /* */ + /* Usage */ + /* -c, --conf <file> */ + /* configuration file contains connection to engine */ + /* */ + /* -e, --engine ConnectionUrlString */ + /* CAMUNDA7;<URL> */ + /* CAMUNDA8;CLOUD;<region>;<clusterId>;<clientIs>;<clientSecret> */ + /* CAMUNDA8;LOCAL;<gateway>;<plaintext> */ + /* */ + /* -d, --debug */ + /* logs all steps */ + /* -n, --numberofexecution <number> */ + /* override the number of execution for the scenario */ + /* -r, --recursive */ + /* all *.json in the folder and sub-folder are monitored and executed*/ + /* */ + /* run <scenarioFile> */ + /* */ + /* ******************************************************************** */ + + private static void printUsage() { + logOutLn("Usage: <option> <action> <parameter>"); + logOutLn(" -s, --server <serverName>"); + logOutLn(" Which server to use in the configuration"); + logOutLn(" -e, --engine ConnectionUrlString"); + logOutLn(" CAMUNDA7;<URL>"); + logOutLn(" CAMUNDA8;CLOUD;<region>;<clusterId>;<clientIs>;<clientSecret>"); + logOutLn(" CAMUNDA8;LOCAL;<gateway>;<plaintext>"); + logOutLn(" -l, --level <DEBUG|COMPLETE|MONITORING|MAIN|NOTHING>"); + logOutLn(" Define the level of log (MONITORING is the default)"); + logOutLn(" -n, --numberofexecution <number>"); + logOutLn(" override the number of execution for the scenario"); + logOutLn(" -d, --deploy <TRUE|FALSE>"); + logOutLn(" Allow deployment of process is defined in the scenario (default is TRUE)"); + + logOutLn(" -x, --execute"); + logOutLn(" execute the scenario"); + logOutLn(" -v, --verification"); + logOutLn(" verify the scenario"); + logOutLn(" -f, --fullreport"); + logOutLn(" Full report"); + + logOutLn(""); + logOutLn("ACTIONS: "); + logOutLn(" run <scenarioFile>"); + logOutLn(" execute one scenario"); + logOutLn(" recursive <folder>"); + logOutLn(" all *.json in the folder and sub-folder are monitored and executed"); + } - Integer overrideNumberOfExecution = null; - int i = 0; - ACTION action = null; - String serverName = null; - try { - while (i < args.length) { - if ("-h".equals(args[i]) || "--help".equals(args[i])) { - printUsage(); - return; - } else if ("-s".equals(args[i]) || "--server".equals(args[i])) { - if (args.length < i + 1) - throw new AutomatorException("Bad usage : -c <ServerName>"); - serverName = args[i + 1]; - i++; - } else if ("-e".equals(args[i]) || "--engine".equals(args[i])) { - if (args.length < i + 1) - throw new AutomatorException("Bad usage : -e <ConnectionUrlString>"); - engineConfiguration = decodeConfiguration(args[i + 1]); - i++; - } else if ("-l".equals(args[i]) || "--level".equals(args[i])) { - if (args.length < i + 1) - throw new AutomatorException("Bad usage : -l <DEBUG|MONITORING|MAIN|NOTHING>"); - runParameters.setLogLevel(RunParameters.LOGLEVEL.valueOf(args[i + 1])); - i++; - } else if ("-n".equals(args[i]) || "--numberofexecution".equals(args[i])) { - if (args.length < i + 1) - throw new AutomatorException("Bad usage : n <numberofexecution>"); - overrideNumberOfExecution = Integer.parseInt(args[i + 1]); - i++; - } else if ("-d".equals(args[i]) || "--deploy".equals(args[i])) { - if (args.length < i + 1) - throw new AutomatorException("Bad usage : -d TRUE|FALSE"); - runParameters.setDeploymentProcess("TRUE".equalsIgnoreCase(args[i + 1])); - i++; - } else if ("-x".equals(args[i]) || "--execute".equals(args[i])) { - runParameters.setExecution(true); - } else if ("-v".equals(args[i]) || "--verification".equals(args[i])) { - runParameters.setVerification(true); - } else if ("-f".equals(args[i]) || "--fullreport".equals(args[i])) { - runParameters.setFullDetailsSynthesis(true); - } else if ("run".equals(args[i])) { - if (args.length < i + 1) - throw new AutomatorException("Bad usage : run <scenarioFile>"); - action = ACTION.RUN; - scenarioFile = new File(args[i + 1]); - i++; - } else if ("recursive".equals(args[i])) { - if (args.length < i + 1) - throw new AutomatorException("Bad usage : recursive <folder>"); - action = ACTION.RECURSIVE; - folderRecursive = new File(args[i + 1]); - i++; - } else { - printUsage(); - throw new AutomatorException("Bad usage : unknown parameters [" + args[i] + "]"); - } - i++; - } - - if (action == null) { - throw new AutomatorException("Bad usage : missing action (" + ACTION.RUN + ")"); - } - if (!runParameters.isExecution() && !runParameters.isVerification()) { - runParameters.setExecution(true); // default - } - - // get the correct server configuration - BpmnEngineList.BpmnServerDefinition serverDefinition = null; - - serverDefinition = engineConfiguration.getByServerName(serverName); - if (serverDefinition == null) { - throw new AutomatorException("Check configuration: Server name (from parameter)[" + serverName - + "] does not exist in the list of servers in application.yaml file"); - } - - long beginTime = System.currentTimeMillis(); - BpmnEngine bpmnEngine = automatorAPI.getBpmnEngine(serverDefinition, true); - - switch (action) { - case RUN -> { - Scenario scenario = automatorAPI.loadFromFile(scenarioFile); - BpmnEngine bpmnEngineScenario = automatorAPI.getBpmnEngine(serverDefinition, true); - - // execution - RunResult scenarioExecutionResult = automatorAPI.executeScenario( - bpmnEngineScenario == null ? bpmnEngine : bpmnEngineScenario, runParameters, scenario); - - logger.info(scenarioExecutionResult.getSynthesis(runParameters.isFullDetailsSynthesis())); - } - case RECURSIVE -> { - List<File> listScenario = detectRecursiveScenario(folderRecursive); - for (File scenarioFileIndex : listScenario) { - Scenario scenario = automatorAPI.loadFromFile(scenarioFileIndex); - BpmnEngine bpmnEngineScenario = automatorAPI.getBpmnEngine(serverDefinition, true); - RunResult scenarioExecutionResult = automatorAPI.executeScenario( - bpmnEngineScenario == null ? bpmnEngine : bpmnEngineScenario, runParameters, scenario); - - logger.info(scenarioExecutionResult.getSynthesis(false)); + + private static BpmnEngineList decodeConfiguration(String propertiesFileName) throws Exception { + throw new Exception("Not yet implemented"); + } + + private static List<File> detectRecursiveScenario(File folderRecursive) { + List<File> listFiles = new ArrayList<>(); + for (File file : folderRecursive.listFiles()) { + if (file.isDirectory()) { + listFiles.addAll(detectRecursiveScenario(file)); + } else if (file.getName().endsWith(".json")) { + listFiles.add(file); + } } - } - } - logger.info("That's all folks! " + (System.currentTimeMillis() - beginTime) + " ms."); + return listFiles; + } - } catch (Exception e) { - logger.error("Error during execution " + e); + /** + * To reduce the number of warning + * + * @param message message to log out + */ + private static void logOutLn(String message) { + System.out.println(message); } - } + public void run(String[] args) { + if (!isRunningCLI) + return; + File scenarioFile = null; + File folderRecursive = null; + + RunParameters runParameters = new RunParameters(); + runParameters.setExecution(true) + .setServerName(configurationStartup.getServerName()) + .setLogLevel(configurationStartup.getLogLevelEnum()) + .setCreation(configurationStartup.isPolicyExecutionCreation()) + .setServiceTask(configurationStartup.isPolicyExecutionServiceTask()) + .setUserTask(configurationStartup.isPolicyExecutionUserTask()) + .setWarmingUp(configurationStartup.isPolicyExecutionWarmingUp()) + .setDeploymentProcess(configurationStartup.isPolicyDeployProcess()) + .setDeepTracking(configurationStartup.deepTracking()) + .setStartEventNbThreads(configurationStartup.getStartEventNbThreads()); + List<String> filterService = configurationStartup.getFilterService(); + if (filterService != null) { + runParameters.setFilterExecutionServiceTask(filterService); + } + Integer overrideNumberOfExecution = null; + int i = 0; + ACTION action = null; + String serverName = null; + try { + while (i < args.length) { + if ("-h".equals(args[i]) || "--help".equals(args[i])) { + printUsage(); + return; + } else if ("-s".equals(args[i]) || "--server".equals(args[i])) { + if (args.length < i + 1) + throw new AutomatorException("Bad usage : -c <ServerName>"); + serverName = args[i + 1]; + i++; + } else if ("-e".equals(args[i]) || "--engine".equals(args[i])) { + if (args.length < i + 1) + throw new AutomatorException("Bad usage : -e <ConnectionUrlString>"); + engineConfiguration = decodeConfiguration(args[i + 1]); + i++; + } else if ("-l".equals(args[i]) || "--level".equals(args[i])) { + if (args.length < i + 1) + throw new AutomatorException("Bad usage : -l <DEBUG|MONITORING|MAIN|NOTHING>"); + runParameters.setLogLevel(RunParameters.LOGLEVEL.valueOf(args[i + 1])); + i++; + } else if ("-n".equals(args[i]) || "--numberofexecution".equals(args[i])) { + if (args.length < i + 1) + throw new AutomatorException("Bad usage : n <numberofexecution>"); + overrideNumberOfExecution = Integer.parseInt(args[i + 1]); + i++; + } else if ("-d".equals(args[i]) || "--deploy".equals(args[i])) { + if (args.length < i + 1) + throw new AutomatorException("Bad usage : -d TRUE|FALSE"); + runParameters.setDeploymentProcess("TRUE".equalsIgnoreCase(args[i + 1])); + i++; + } else if ("-x".equals(args[i]) || "--execute".equals(args[i])) { + runParameters.setExecution(true); + } else if ("-v".equals(args[i]) || "--verification".equals(args[i])) { + runParameters.setVerification(true); + } else if ("-f".equals(args[i]) || "--fullreport".equals(args[i])) { + runParameters.setFullDetailsSynthesis(true); + } else if ("run".equals(args[i])) { + if (args.length < i + 1) + throw new AutomatorException("Bad usage : run <scenarioFile>"); + action = ACTION.RUN; + scenarioFile = new File(args[i + 1]); + i++; + } else if ("recursive".equals(args[i])) { + if (args.length < i + 1) + throw new AutomatorException("Bad usage : recursive <folder>"); + action = ACTION.RECURSIVE; + folderRecursive = new File(args[i + 1]); + i++; + } else { + printUsage(); + throw new AutomatorException("Bad usage : unknown parameters [" + args[i] + "]"); + } + i++; + } + + if (action == null) { + throw new AutomatorException("Bad usage : missing action (" + ACTION.RUN + ")"); + } + if (!runParameters.isExecution() && !runParameters.isVerification()) { + runParameters.setExecution(true); // default + } + + // get the correct server configuration + BpmnEngineList.BpmnServerDefinition serverDefinition = null; + + serverDefinition = engineConfiguration.getByServerName(serverName); + if (serverDefinition == null) { + throw new AutomatorException("Check configuration: Server name (from parameter)[" + serverName + + "] does not exist in the list of servers in application.yaml file"); + } + + long beginTime = System.currentTimeMillis(); + BpmnEngine bpmnEngine = automatorAPI.getBpmnEngine(serverDefinition, true); + + switch (action) { + case RUN -> { + Scenario scenario = automatorAPI.loadFromFile(scenarioFile); + BpmnEngine bpmnEngineScenario = automatorAPI.getBpmnEngine(serverDefinition, true); + + // execution + RunResult scenarioExecutionResult = automatorAPI.executeScenario( + bpmnEngineScenario == null ? bpmnEngine : bpmnEngineScenario, runParameters, scenario); + + logger.info(scenarioExecutionResult.getSynthesis(runParameters.isFullDetailsSynthesis())); + } + case RECURSIVE -> { + List<File> listScenario = detectRecursiveScenario(folderRecursive); + for (File scenarioFileIndex : listScenario) { + Scenario scenario = automatorAPI.loadFromFile(scenarioFileIndex); + BpmnEngine bpmnEngineScenario = automatorAPI.getBpmnEngine(serverDefinition, true); + RunResult scenarioExecutionResult = automatorAPI.executeScenario( + bpmnEngineScenario == null ? bpmnEngine : bpmnEngineScenario, runParameters, scenario); + + logger.info(scenarioExecutionResult.getSynthesis(false)); + } + } + } + logger.info("That's all folks! " + (System.currentTimeMillis() - beginTime) + " ms."); + + } catch (Exception e) { + logger.error("Error during execution " + e); + } + + } - public enum ACTION {RUN, RECURSIVE, VERIFY, RUNVERIFY, RECURSIVVERIFY} + public enum ACTION {RUN, RECURSIVE, VERIFY, RUNVERIFY, RECURSIVVERIFY} } diff --git a/src/main/java/org/camunda/automator/AutomatorRest.java b/src/main/java/org/camunda/automator/AutomatorRest.java new file mode 100644 index 0000000..a1b62a2 --- /dev/null +++ b/src/main/java/org/camunda/automator/AutomatorRest.java @@ -0,0 +1,271 @@ +package org.camunda.automator; + +import org.camunda.automator.bpmnengine.BpmnEngine; +import org.camunda.automator.configuration.BpmnEngineList; +import org.camunda.automator.configuration.ConfigurationStartup; +import org.camunda.automator.content.ContentManager; +import org.camunda.automator.definition.Scenario; +import org.camunda.automator.engine.AutomatorException; +import org.camunda.automator.engine.RunParameters; +import org.camunda.automator.engine.RunResult; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import java.io.File; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@RestController +public class AutomatorRest { + public static final String JSON_SCENARIO_NAME = "scenarioName"; + public static final String JSON_SERVER_NAME = "serverName"; + public static final String JSON_ID = "id"; + public static final String JSON_STATUS = "status"; + public static final String JSON_GENERAL_STATUS = "generalStatus"; + public static final String JSON_NAME = "name"; + public static final String JSON_DETAIL = "detail"; + public static final String JSON_MESSAGE = "message"; + public static final String JSON_INFO = "info"; + private static final Logger logger = LoggerFactory.getLogger(ContentManager.class.getName()); + private final ConfigurationStartup configurationStartup; + private final ContentManager contentManager; + private final AutomatorAPI automatorAPI; + BpmnEngineList engineConfiguration; + HashMap<String, Map<String, Object>> cacheExecution = new HashMap<>(); + + public AutomatorRest(ConfigurationStartup configurationStartup, ContentManager contentManager, AutomatorAPI automatorAPI, BpmnEngineList engineConfiguration) { + this.configurationStartup = configurationStartup; + this.contentManager = contentManager; + this.automatorAPI = automatorAPI; + this.engineConfiguration = engineConfiguration; + } + + @PostMapping(value = "/api/unittest/run", produces = "application/json") + public Map<String, Object> runUnitTest(@RequestParam(name = "name") String scenarioName, @RequestParam(name = "server", required = false) String serverName, @RequestParam(name = "wait", required = false) Boolean wait) { + + Map<String, Object> resultMap = new HashMap<>(); + resultMap.put("senarioName", scenarioName); + + String unitTestId = String.valueOf(System.currentTimeMillis()); + resultMap.put("id", unitTestId); + + if (Boolean.TRUE.equals(wait)) { + startTest(scenarioName, serverName, unitTestId); + resultMap = cacheExecution.get(unitTestId); + return resultMap; + + } else { + Thread thread = new Thread(() -> startTest(scenarioName, serverName, unitTestId)); + thread.start(); + } + + return resultMap; + } + + @GetMapping(value = "/api/unittest/get", produces = "application/json") + public Map<String, Object> getUnitTest(@RequestParam(name = "id") String unitTestId) { + Map<String, Object> resultTest = cacheExecution.get(unitTestId); + if (resultTest != null) { + return resultTest; + } else { + return Map.of("status", "NOTEXIST"); + } + } + + @GetMapping(value = "/api/unittest/list", produces = "application/json") + public List<Map<String, Object>> getListUnitTest() { + List<Map<String, Object>> listUnitTest = new ArrayList<>(); + for (Map.Entry entryTest : cacheExecution.entrySet()) { + if (entryTest.getValue() instanceof Map<?, ?> resultMap) { + listUnitTest.add(Map.of("id", entryTest.getKey(), + JSON_SCENARIO_NAME, getSecureValue(resultMap.get(JSON_SCENARIO_NAME)))); + } else { + listUnitTest.add(Map.of(JSON_ID, entryTest.getKey(), + JSON_SCENARIO_NAME, "")); + } + } + return listUnitTest; + } + + + /** + * Start a test + */ + private void startTest(String scenarioName, String serverName, String unitTestId) { + Map<String, Object> resultMap = new HashMap<>(); + cacheExecution.put(unitTestId, resultMap); + + RunParameters runParameters = new RunParameters(); + runParameters.setExecution(true) + .setServerName(serverName == null || scenarioName.isEmpty() ? configurationStartup.getServerName() : serverName) + .setLogLevel(configurationStartup.getLogLevelEnum()); + resultMap.put(JSON_ID, unitTestId); + resultMap.put(JSON_SERVER_NAME, runParameters.getServerName()); + resultMap.put(JSON_SCENARIO_NAME, scenarioName); + + logger.info( + "Unit Test parameters serverName[{}] ", + runParameters.getServerName()); + + // now proceed the scenario + try { + Scenario scenario = null; + File scenarioFile = contentManager.getFromName(scenarioName); + try { + scenario = automatorAPI.loadFromFile(scenarioFile); + } catch (Exception e) { + logger.error("Error during accessing InputStream from File [{}]: {}", scenarioFile.getAbsolutePath(), + e.getMessage()); + } + if (scenario == null) { + resultMap.put(JSON_STATUS, "NOTEXIST"); + return; + } + + logger.info("Start scenario [{}] on (1)ScenarioServerName[{}] (2)ConfigurationServerName[{}]", + scenario.getName(), scenario.getServerName(), runParameters.getServerName()); + + // BpmnEngine: find the correct one referenced in the scenario + String message = ""; + BpmnEngine bpmnEngine = connectToEngine(scenario, runParameters, resultMap); + if (bpmnEngine == null) { + logger.error("Scenario [{}] file[{}] Server {} No BPM ENGINE running.", scenario.getName(), + scenario.getName(), message); + return; + } + + bpmnEngine.turnHighFlowMode(true); + logger.info("Scenario [{}] file[{}] use BpmnEngine {}", scenario.getName(), scenario.getName(), + bpmnEngine.getSignature()); + RunResult scenarioExecutionResult = automatorAPI.executeScenario(bpmnEngine, runParameters, scenario); + logger.info("AutomatorRest: end scenario [{}] in {} ms", scenario.getName(), + scenarioExecutionResult.getTimeExecution()); + bpmnEngine.turnHighFlowMode(false); + resultMap.put(JSON_STATUS, "EXECUTED"); + resultMap.putAll(resultToJson(scenarioExecutionResult)); + + } catch (Exception e) { + logger.error("During execute unit Test", e.getMessage()); + resultMap.put("error", e.getMessage()); + } + } + + /** + * @param runResult + * @return + */ + private Map<String, Object> resultToJson(RunResult runResult) { + Map<String, Object> resultMap = new HashMap<>(); + + resultMap.put(JSON_GENERAL_STATUS, runResult.isSuccess() ? StatusTest.SUCCESS : StatusTest.FAIL); + List<Map<String, Object>> listVerificationsJson = new ArrayList<>(); + for (RunResult runResultUnit : runResult.getListRunResults()) { + if (runResultUnit.getScnExecution() == null) { + continue; + } + Map<String, Object> recordResult = new HashMap<>(); + listVerificationsJson.add(recordResult); + recordResult.put(JSON_NAME, runResultUnit.getScnExecution().getName()); + recordResult.put(JSON_STATUS, runResultUnit.isSuccess() ? StatusTest.SUCCESS : StatusTest.FAIL); + recordResult.put(JSON_DETAIL, runResultUnit.getListVerifications().stream() + .map(t -> { // + return Map.of(JSON_STATUS, t.isSuccess ? StatusTest.SUCCESS : StatusTest.FAIL, // + JSON_MESSAGE, getSecureValue(t.message), // + JSON_INFO, getSecureValue(t.verification.getSynthesis())); + })// + .toList()); + } + resultMap.put("tests", listVerificationsJson); + return resultMap; + } + + private Map<String, Object> completeMessage(Map<String, Object> result, StatusTest status, String complement) { + result.put("status", status.toString()); + result.put("complement", complement); + return result; + } + + /** + * Connect to the BPM Engine + * + * @param scenario scenario to use to connect + * @param runParameters + * @param result + * @return + */ + private BpmnEngine connectToEngine(Scenario scenario, RunParameters runParameters, Map<String, Object> result) { + BpmnEngine bpmnEngine = null; + boolean pleaseTryAgain; + int countEngineIsNotReady = 0; + String message = ""; + + do { + pleaseTryAgain = false; + countEngineIsNotReady++; + try { + if (scenario.getServerName() != null && !scenario.getServerName().isEmpty()) { + message += "ScenarioServerName[" + scenario.getServerName() + "];"; + bpmnEngine = automatorAPI.getBpmnEngineFromScenario(scenario, engineConfiguration); + } else { + if (runParameters.getServerName() == null) { + result = completeMessage(result, StatusTest.ENGINE_NOT_EXIST, "Engine [" + runParameters.getServerName() + "] does not exist in the list"); + return null; + } + + + message += "ConfigurationServerName[" + runParameters.getServerName() + "];"; + BpmnEngineList.BpmnServerDefinition serverDefinition = engineConfiguration.getByServerName( + runParameters.getServerName()); + if (serverDefinition == null) { + result = completeMessage(result, StatusTest.ENGINE_NOT_EXIST, "Engine [" + runParameters.getServerName() + "] does not exist in the list"); + return null; + } + + if (runParameters.showLevelMonitoring()) { + logger.info("Run scenario with Server {}", serverDefinition.getSynthesis()); + } + bpmnEngine = automatorAPI.getBpmnEngine(serverDefinition, true); + } + if (runParameters.showLevelDashboard()) { + logger.info("Scenario [{}] Connect to BpmnEngine {}", scenario.getName(), message); + } + + if (!bpmnEngine.isReady()) { + bpmnEngine.connection(); + } + } catch (AutomatorException e) { + pleaseTryAgain = true; + message += "EXCEPT " + e.getMessage(); + } + if (pleaseTryAgain && countEngineIsNotReady < 10) { + logger.info( + "Scenario [{}] file[{}] No BPM ENGINE running [{}] tentative:{}/10. Sleep 30s. Scenario reference serverName[{}]", + message, countEngineIsNotReady, scenario.getName(), scenario.getName(), scenario.getServerName()); + try { + Thread.sleep(((long) 1000) * 30); + } catch (InterruptedException e) { + // nothing to do + } + } + } while (pleaseTryAgain && countEngineIsNotReady < 10); + return bpmnEngine; + } + + /** + * Return "" if info is null: in a Map.of(), a null pointer return an exception + * + * @param info value to return + * @return info or "" + */ + private Object getSecureValue(Object info) { + return info == null ? "" : info; + } + + public enum StatusTest {SCENARIO_NOT_EXIST, ENGINE_NOT_EXIST, SUCCESS, FAIL} +} diff --git a/src/main/java/org/camunda/automator/bpmnengine/BpmnEngine.java b/src/main/java/org/camunda/automator/bpmnengine/BpmnEngine.java index c0cedd6..1ccc67c 100644 --- a/src/main/java/org/camunda/automator/bpmnengine/BpmnEngine.java +++ b/src/main/java/org/camunda/automator/bpmnengine/BpmnEngine.java @@ -11,254 +11,257 @@ import java.io.File; import java.time.Duration; +import java.util.Date; import java.util.List; import java.util.Map; public interface BpmnEngine { - /** - * init the engine. This method will - * - * @throws Exception in case of error - */ - void init(); - - void connection() throws AutomatorException; - - void disconnection() throws AutomatorException; - - /** - * Engine is ready. If not, a connection() method must be call - * - * @return true if the engine is ready - */ - boolean isReady(); - - /* ******************************************************************** */ - /* */ - /* Manage process instance */ - /* */ - /* ******************************************************************** */ - void turnHighFlowMode(boolean hightFlowMode); - - /** - * @param processId Process ID (BPMN ID : ExpenseNode) - * @param starterEventId BPMN ID (startEvent) - * @param variables List of variables to create the process instance - * @return a processInstanceId - * @throws AutomatorException in case of error - */ - String createProcessInstance(String processId, String starterEventId, Map<String, Object> variables) - throws AutomatorException; - - /** - * we finish with this processinstanceid, engine can clean it - * - * @param processInstanceId Process instance Id to clean - * @param cleanAll if true, the process instance must be clean. - * @throws AutomatorException in case of error - */ - void endProcessInstance(String processInstanceId, boolean cleanAll) throws AutomatorException; - - - /* ******************************************************************** */ - /* */ - /* User task */ - /* */ - /* ******************************************************************** */ - - /** - * @param processInstanceId Process Instance Id - * @param userTaskId BPMN Id (Review) - * @param maxResult maximum result to return. - * @return list of taskId - * @throws AutomatorException in case of error - */ - List<String> searchUserTasksByProcessInstance(String processInstanceId, String userTaskId, int maxResult) - throws AutomatorException; - - /** - * Return a list of task - * - * @param userTaskId userTaskId - * @param maxResult maxResult returned - * @return list of TaskId - * @throws AutomatorException in case of error - */ - List<String> searchUserTasks(String userTaskId, int maxResult) throws AutomatorException; - - /** - * @param userTaskId BPMN Id (Review) - * @param userId User id who executes the task - * @param variables variable to update - * @throws AutomatorException in case of error - */ - void executeUserTask(String userTaskId, String userId, Map<String, Object> variables) throws AutomatorException; - - - /* ******************************************************************** */ - /* */ - /* Service tasks */ - /* */ - /* ******************************************************************** */ - - /** - * @param workerId workerId - * @param topic topic to register - * @param streamEnabled true if the stream enable is open - * @param lockTime lock time for the job - * @param jobHandler C7: must implement ExternalTaskHandler. C8: must implement JobHandler - * @param backoffSupplier backOffStrategy - * @return list of Service Task - */ - RegisteredTask registerServiceTask(String workerId, - String topic, - boolean streamEnabled, - Duration lockTime, - Object jobHandler, - FixedBackoffSupplier backoffSupplier); - - /** - * @param processInstanceId process instance ID - * @param serviceTaskId BPMN IP (Review) - * @param topic topic to search to execute the service task - * @param maxResult maximum result - * @return list of taskId - * @throws AutomatorException in case of error - */ - List<String> searchServiceTasks(String processInstanceId, String serviceTaskId, String topic, int maxResult) - throws AutomatorException; - - /** - * Execute a service task - * - * @param serviceTaskId BPMN ID (Review) - * @param workerId Worker who execute the task - * @param variables variable to updates - * @throws AutomatorException in case of error - */ - void executeServiceTask(String serviceTaskId, String workerId, Map<String, Object> variables) - throws AutomatorException; - - /** - * Search task. - * - * @param processInstanceId filter on the processInstanceId. may be null - * @param taskId filter on the taskId - * @param maxResult maximum Result - * @return List of task description - * @throws AutomatorException in case of error - */ - List<TaskDescription> searchTasksByProcessInstanceId(String processInstanceId, String taskId, int maxResult) - throws AutomatorException; - - /* ******************************************************************** */ - /* */ - /* Generic tasks */ - /* */ - /* ******************************************************************** */ - - /** - * Search process instance by a variable content - * - * @param processId BPMN Process ID - * @param filterVariables Variable name - * @param maxResult maxResult - * @return list of ProcessInstance which match the filter - * @throws AutomatorException in case of error - */ - List<ProcessDescription> searchProcessInstanceByVariable(String processId, - Map<String, Object> filterVariables, - int maxResult) throws AutomatorException; - - /** - * Get variables of a process instanceId - * - * @param processInstanceId the process instance ID - * @return variables attached to the process instance ID - * @throws AutomatorException in case of error - */ - Map<String, Object> getVariables(String processInstanceId) throws AutomatorException; - - /* ******************************************************************** */ - /* */ - /* CountInformation */ - /* */ - /* ******************************************************************** */ - long countNumberOfProcessInstancesCreated(String processId, DateFilter startDate, DateFilter endDate) - throws AutomatorException; - - long countNumberOfProcessInstancesEnded(String processId, DateFilter startDate, DateFilter endDate) - throws AutomatorException; - - long countNumberOfTasks(String processId, String taskId) throws AutomatorException; - - /** - * Deploy a BPMN file (may contains multiple processes) - * - * @param processFile process to deploy - * @param policy policy to deploy the process - * @return the deploymentId - * @throws AutomatorException in case of error - */ - String deployBpmn(File processFile, ScenarioDeployment.Policy policy) throws AutomatorException; - - /* ******************************************************************** */ - /* */ - /* Deployment */ - /* */ - /* ******************************************************************** */ - - BpmnEngineList.CamundaEngine getTypeCamundaEngine(); - - - /* ******************************************************************** */ - /* */ - /* get server definition */ - /* */ - /* ******************************************************************** */ - - /** - * return the signature of the engine, to log it for example - * - * @return signature of the engine - */ - String getSignature(); - - int getWorkerExecutionThreads(); - - class RegisteredTask { - public TopicSubscription topicSubscription; - public JobWorker jobWorker; - - public boolean isNull() { - return topicSubscription == null && jobWorker == null; + /** + * init the engine. This method will + * + * @throws Exception in case of error + */ + void init(); + + void connection() throws AutomatorException; + + void disconnection() throws AutomatorException; + + /** + * Engine is ready. If not, a connection() method must be call + * + * @return true if the engine is ready + */ + boolean isReady(); + + /* ******************************************************************** */ + /* */ + /* Manage process instance */ + /* */ + /* ******************************************************************** */ + void turnHighFlowMode(boolean hightFlowMode); + + /** + * @param processId Process ID (BPMN ID : ExpenseNode) + * @param starterEventId BPMN ID (startEvent) + * @param variables List of variables to create the process instance + * @return a processInstanceId + * @throws AutomatorException in case of error + */ + String createProcessInstance(String processId, String starterEventId, Map<String, Object> variables) + throws AutomatorException; + + /** + * we finish with this processinstanceid, engine can clean it + * + * @param processInstanceId Process instance Id to clean + * @param cleanAll if true, the process instance must be clean. + * @throws AutomatorException in case of error + */ + void endProcessInstance(String processInstanceId, boolean cleanAll) throws AutomatorException; + + + /* ******************************************************************** */ + /* */ + /* User task */ + /* */ + /* ******************************************************************** */ + + /** + * @param processInstanceId Process Instance Id + * @param filterTaskId If not null, list if filtered to return only this task + * @param maxResult maximum result to return. + * @return list of taskId + * @throws AutomatorException in case of error + */ + List<String> searchUserTasksByProcessInstance(String processInstanceId, String filterTaskId, int maxResult) + throws AutomatorException; + + /** + * Return a list of task + * + * @param userTaskId userTaskId + * @param maxResult maxResult returned + * @return list of TaskId + * @throws AutomatorException in case of error + */ + List<String> searchUserTasks(String userTaskId, int maxResult) throws AutomatorException; + + /** + * @param userTaskId BPMN Id (Review) + * @param userId User id who executes the task + * @param variables variable to update + * @throws AutomatorException in case of error + */ + void executeUserTask(String userTaskId, String userId, Map<String, Object> variables) throws AutomatorException; + + + /* ******************************************************************** */ + /* */ + /* Service tasks */ + /* */ + /* ******************************************************************** */ + + /** + * @param workerId workerId + * @param topic topic to register + * @param streamEnabled true if the stream enable is open + * @param lockTime lock time for the job + * @param jobHandler C7: must implement ExternalTaskHandler. C8: must implement JobHandler + * @param backoffSupplier backOffStrategy + * @return list of Service Task + */ + RegisteredTask registerServiceTask(String workerId, + String topic, + boolean streamEnabled, + Duration lockTime, + Object jobHandler, + FixedBackoffSupplier backoffSupplier); + + /** + * @param processInstanceId process instance ID + * @param serviceTaskId BPMN IP (Review) + * @param topic topic to search to execute the service task + * @param maxResult maximum result + * @return list of taskId + * @throws AutomatorException in case of error + */ + List<String> searchServiceTasks(String processInstanceId, String serviceTaskId, String topic, int maxResult) + throws AutomatorException; + + /** + * Execute a service task + * + * @param serviceTaskId BPMN ID (Review) + * @param workerId Worker who execute the task + * @param variables variable to updates + * @throws AutomatorException in case of error + */ + void executeServiceTask(String serviceTaskId, String workerId, Map<String, Object> variables) + throws AutomatorException; + + /** + * Search task. + * + * @param processInstanceId filter on the processInstanceId. may be null + * @param taskId filter on the taskId + * @param maxResult maximum Result + * @return List of task description + * @throws AutomatorException in case of error + */ + List<TaskDescription> searchTasksByProcessInstanceId(String processInstanceId, String taskId, int maxResult) + throws AutomatorException; + + /* ******************************************************************** */ + /* */ + /* Generic tasks */ + /* */ + /* ******************************************************************** */ + + /** + * Search process instance by a variable content + * + * @param processId BPMN Process ID + * @param filterVariables Variable name + * @param maxResult maxResult + * @return list of ProcessInstance which match the filter + * @throws AutomatorException in case of error + */ + List<ProcessDescription> searchProcessInstanceByVariable(String processId, + Map<String, Object> filterVariables, + int maxResult) throws AutomatorException; + + /** + * Get variables of a process instanceId + * + * @param processInstanceId the process instance ID + * @return variables attached to the process instance ID + * @throws AutomatorException in case of error + */ + Map<String, Object> getVariables(String processInstanceId) throws AutomatorException; + + /* ******************************************************************** */ + /* */ + /* CountInformation */ + /* */ + /* ******************************************************************** */ + long countNumberOfProcessInstancesCreated(String processId, DateFilter startDate, DateFilter endDate) + throws AutomatorException; + + long countNumberOfProcessInstancesEnded(String processId, DateFilter startDate, DateFilter endDate) + throws AutomatorException; + + long countNumberOfTasks(String processId, String taskId) throws AutomatorException; + + /** + * Deploy a BPMN file (may contains multiple processes) + * + * @param processFile process to deploy + * @param policy policy to deploy the process + * @return the deploymentId + * @throws AutomatorException in case of error + */ + String deployBpmn(File processFile, ScenarioDeployment.Policy policy) throws AutomatorException; + + /* ******************************************************************** */ + /* */ + /* Deployment */ + /* */ + /* ******************************************************************** */ + + BpmnEngineList.CamundaEngine getTypeCamundaEngine(); + + + /* ******************************************************************** */ + /* */ + /* get server definition */ + /* */ + /* ******************************************************************** */ + + /** + * return the signature of the engine, to log it for example + * + * @return signature of the engine + */ + String getSignature(); + + int getWorkerExecutionThreads(); + + class RegisteredTask { + public TopicSubscription topicSubscription; + public JobWorker jobWorker; + + public boolean isNull() { + return topicSubscription == null && jobWorker == null; + } + + public boolean isClosed() { + if (jobWorker != null) + return jobWorker.isClosed(); + return topicSubscription == null; + } + + public void close() { + if (jobWorker != null) + jobWorker.close(); + if (topicSubscription != null) { + topicSubscription.close(); + topicSubscription = null; + } + } } - public boolean isClosed() { - if (jobWorker != null) - return jobWorker.isClosed(); - return topicSubscription == null; + class TaskDescription { + public String processInstanceId; + public String taskId; + public ScenarioStep.Step type; + public boolean isCompleted; + public Date startDate; + public Date endDate; } - public void close() { - if (jobWorker != null) - jobWorker.close(); - if (topicSubscription != null) { - topicSubscription.close(); - topicSubscription = null; - } + class ProcessDescription { + public String processInstanceId; } - } - - class TaskDescription { - public String processInstanceId; - public String taskId; - public ScenarioStep.Step type; - public boolean isCompleted; - } - - class ProcessDescription { - public String processInstanceId; - } } diff --git a/src/main/java/org/camunda/automator/bpmnengine/BpmnEngineConfigurationInstance.java b/src/main/java/org/camunda/automator/bpmnengine/BpmnEngineConfigurationInstance.java index 578fab0..89af914 100644 --- a/src/main/java/org/camunda/automator/bpmnengine/BpmnEngineConfigurationInstance.java +++ b/src/main/java/org/camunda/automator/bpmnengine/BpmnEngineConfigurationInstance.java @@ -7,68 +7,68 @@ */ public class BpmnEngineConfigurationInstance { - public static BpmnEngineList getZeebeSaas(String zeebeGatewayAddress, Boolean zeebePlainText) { - BpmnEngineList bpmEngineConfiguration = new BpmnEngineList(); + public static BpmnEngineList getZeebeSaas(String zeebeGatewayAddress, Boolean zeebePlainText) { + BpmnEngineList bpmEngineConfiguration = new BpmnEngineList(); - BpmnEngineList.BpmnServerDefinition serverDefinition = new BpmnEngineList.BpmnServerDefinition(); - serverDefinition.serverType = BpmnEngineList.CamundaEngine.CAMUNDA_8; - serverDefinition.zeebeGatewayAddress = zeebeGatewayAddress; - serverDefinition.zeebePlainText = zeebePlainText; + BpmnEngineList.BpmnServerDefinition serverDefinition = new BpmnEngineList.BpmnServerDefinition(); + serverDefinition.serverType = BpmnEngineList.CamundaEngine.CAMUNDA_8; + serverDefinition.zeebeGatewayAddress = zeebeGatewayAddress; + serverDefinition.zeebePlainText = zeebePlainText; - bpmEngineConfiguration.addExplicitServer(serverDefinition); - return bpmEngineConfiguration; - } + bpmEngineConfiguration.addExplicitServer(serverDefinition); + return bpmEngineConfiguration; + } - public static BpmnEngineList getCamunda7(String serverUrl) { - BpmnEngineList bpmEngineConfiguration = new BpmnEngineList(); + public static BpmnEngineList getCamunda7(String serverUrl) { + BpmnEngineList bpmEngineConfiguration = new BpmnEngineList(); - BpmnEngineList.BpmnServerDefinition serverDefinition = new BpmnEngineList.BpmnServerDefinition(); - serverDefinition.serverType = BpmnEngineList.CamundaEngine.CAMUNDA_7; - serverDefinition.camunda7ServerUrl = serverUrl; + BpmnEngineList.BpmnServerDefinition serverDefinition = new BpmnEngineList.BpmnServerDefinition(); + serverDefinition.serverType = BpmnEngineList.CamundaEngine.CAMUNDA_7; + serverDefinition.camunda7ServerUrl = serverUrl; - bpmEngineConfiguration.addExplicitServer(serverDefinition); + bpmEngineConfiguration.addExplicitServer(serverDefinition); - return bpmEngineConfiguration; - } + return bpmEngineConfiguration; + } - public static BpmnEngineList getCamunda8(String zeebeGatewayAddress) { - BpmnEngineList bpmEngineConfiguration = new BpmnEngineList(); + public static BpmnEngineList getCamunda8(String zeebeGatewayAddress) { + BpmnEngineList bpmEngineConfiguration = new BpmnEngineList(); - BpmnEngineList.BpmnServerDefinition serverDefinition = new BpmnEngineList.BpmnServerDefinition(); - serverDefinition.serverType = BpmnEngineList.CamundaEngine.CAMUNDA_8; - serverDefinition.zeebeGatewayAddress = zeebeGatewayAddress; + BpmnEngineList.BpmnServerDefinition serverDefinition = new BpmnEngineList.BpmnServerDefinition(); + serverDefinition.serverType = BpmnEngineList.CamundaEngine.CAMUNDA_8; + serverDefinition.zeebeGatewayAddress = zeebeGatewayAddress; - bpmEngineConfiguration.addExplicitServer(serverDefinition); + bpmEngineConfiguration.addExplicitServer(serverDefinition); - return bpmEngineConfiguration; - } + return bpmEngineConfiguration; + } - public static BpmnEngineList getCamundaSaas8(String zeebeCloudRegister, - String zeebeCloudRegion, - String zeebeCloudClusterId, - String zeebeCloudClientId) { - BpmnEngineList bpmEngineConfiguration = new BpmnEngineList(); + public static BpmnEngineList getCamundaSaas8(String zeebeCloudRegister, + String zeebeCloudRegion, + String zeebeCloudClusterId, + String zeebeCloudClientId) { + BpmnEngineList bpmEngineConfiguration = new BpmnEngineList(); - BpmnEngineList.BpmnServerDefinition serverDefinition = new BpmnEngineList.BpmnServerDefinition(); - serverDefinition.serverType = BpmnEngineList.CamundaEngine.CAMUNDA_8; - serverDefinition.zeebeSaasRegion = zeebeCloudRegion; - serverDefinition.zeebeSaasClusterId = zeebeCloudClusterId; - serverDefinition.zeebeClientId = zeebeCloudClientId; + BpmnEngineList.BpmnServerDefinition serverDefinition = new BpmnEngineList.BpmnServerDefinition(); + serverDefinition.serverType = BpmnEngineList.CamundaEngine.CAMUNDA_8; + serverDefinition.zeebeSaasRegion = zeebeCloudRegion; + serverDefinition.zeebeSaasClusterId = zeebeCloudClusterId; + serverDefinition.zeebeClientId = zeebeCloudClientId; - bpmEngineConfiguration.addExplicitServer(serverDefinition); + bpmEngineConfiguration.addExplicitServer(serverDefinition); - return bpmEngineConfiguration; - } + return bpmEngineConfiguration; + } - public static BpmnEngineList getDummy() { - BpmnEngineList bpmEngineConfiguration = new BpmnEngineList(); + public static BpmnEngineList getDummy() { + BpmnEngineList bpmEngineConfiguration = new BpmnEngineList(); - BpmnEngineList.BpmnServerDefinition serverDefinition = new BpmnEngineList.BpmnServerDefinition(); - serverDefinition.serverType = BpmnEngineList.CamundaEngine.DUMMY; + BpmnEngineList.BpmnServerDefinition serverDefinition = new BpmnEngineList.BpmnServerDefinition(); + serverDefinition.serverType = BpmnEngineList.CamundaEngine.DUMMY; - bpmEngineConfiguration.addExplicitServer(serverDefinition); + bpmEngineConfiguration.addExplicitServer(serverDefinition); - return bpmEngineConfiguration; - } + return bpmEngineConfiguration; + } } diff --git a/src/main/java/org/camunda/automator/bpmnengine/BpmnEngineFactory.java b/src/main/java/org/camunda/automator/bpmnengine/BpmnEngineFactory.java index 6cc16f4..5fe7525 100644 --- a/src/main/java/org/camunda/automator/bpmnengine/BpmnEngineFactory.java +++ b/src/main/java/org/camunda/automator/bpmnengine/BpmnEngineFactory.java @@ -21,54 +21,54 @@ */ public class BpmnEngineFactory { - private static final BpmnEngineFactory bpmnEngineFactory = new BpmnEngineFactory(); - Map<BpmnEngineList.CamundaEngine, BpmnEngine> cacheEngine = new EnumMap<>(BpmnEngineList.CamundaEngine.class); - BenchmarkStartPiExceptionHandlingStrategy benchmarkStartPiExceptionHandlingStrategy = null; + private static final BpmnEngineFactory bpmnEngineFactory = new BpmnEngineFactory(); + Map<BpmnEngineList.CamundaEngine, BpmnEngine> cacheEngine = new EnumMap<>(BpmnEngineList.CamundaEngine.class); + BenchmarkStartPiExceptionHandlingStrategy benchmarkStartPiExceptionHandlingStrategy = null; - private BpmnEngineFactory() { - // use the getInstance() method - } + private BpmnEngineFactory() { + // use the getInstance() method + } - public static BpmnEngineFactory getInstance() { - return bpmnEngineFactory; - } + public static BpmnEngineFactory getInstance() { + return bpmnEngineFactory; + } - public static BpmnEngineFactory getInstance(BenchmarkStartPiExceptionHandlingStrategy benchmarkStartPiExceptionHandlingStrategy) { - bpmnEngineFactory.benchmarkStartPiExceptionHandlingStrategy = benchmarkStartPiExceptionHandlingStrategy; - return bpmnEngineFactory; - } + public static BpmnEngineFactory getInstance(BenchmarkStartPiExceptionHandlingStrategy benchmarkStartPiExceptionHandlingStrategy) { + bpmnEngineFactory.benchmarkStartPiExceptionHandlingStrategy = benchmarkStartPiExceptionHandlingStrategy; + return bpmnEngineFactory; + } - public BpmnEngine getEngineFromConfiguration(BpmnEngineList.BpmnServerDefinition serverDefinition, boolean logDebug) - throws AutomatorException { - BpmnEngine engine = cacheEngine.get(serverDefinition.serverType); - if (engine != null) - return engine; + public BpmnEngine getEngineFromConfiguration(BpmnEngineList.BpmnServerDefinition serverDefinition, boolean logDebug) + throws AutomatorException { + BpmnEngine engine = cacheEngine.get(serverDefinition.serverType); + if (engine != null) + return engine; - // instantiate and initialize the engine now - synchronized (this) { - engine = cacheEngine.get(serverDefinition.serverType); - if (engine != null) - return engine; + // instantiate and initialize the engine now + synchronized (this) { + engine = cacheEngine.get(serverDefinition.serverType); + if (engine != null) + return engine; - engine = switch (serverDefinition.serverType) { - case CAMUNDA_7 -> new BpmnEngineCamunda7(serverDefinition, logDebug); + engine = switch (serverDefinition.serverType) { + case CAMUNDA_7 -> new BpmnEngineCamunda7(serverDefinition, logDebug); - case CAMUNDA_8 -> - BpmnEngineCamunda8.getFromServerDefinition(serverDefinition, benchmarkStartPiExceptionHandlingStrategy, - logDebug); + case CAMUNDA_8 -> + BpmnEngineCamunda8.getFromServerDefinition(serverDefinition, benchmarkStartPiExceptionHandlingStrategy, + logDebug); - case CAMUNDA_8_SAAS -> - BpmnEngineCamunda8.getFromServerDefinition(serverDefinition, benchmarkStartPiExceptionHandlingStrategy, - logDebug); + case CAMUNDA_8_SAAS -> + BpmnEngineCamunda8.getFromServerDefinition(serverDefinition, benchmarkStartPiExceptionHandlingStrategy, + logDebug); - case DUMMY -> new BpmnEngineDummy(serverDefinition); + case DUMMY -> new BpmnEngineDummy(serverDefinition); - }; + }; - engine.init(); - engine.connection(); - cacheEngine.put(serverDefinition.serverType, engine); + engine.init(); + engine.connection(); + cacheEngine.put(serverDefinition.serverType, engine); + } + return engine; } - return engine; - } } diff --git a/src/main/java/org/camunda/automator/bpmnengine/camunda7/BpmnEngineCamunda7.java b/src/main/java/org/camunda/automator/bpmnengine/camunda7/BpmnEngineCamunda7.java index 570e0ea..33e20d7 100644 --- a/src/main/java/org/camunda/automator/bpmnengine/camunda7/BpmnEngineCamunda7.java +++ b/src/main/java/org/camunda/automator/bpmnengine/camunda7/BpmnEngineCamunda7.java @@ -10,31 +10,8 @@ import org.camunda.bpm.client.ExternalTaskClient; import org.camunda.bpm.client.backoff.ExponentialBackoffStrategy; import org.camunda.bpm.client.task.ExternalTaskHandler; -import org.camunda.community.rest.client.api.DeploymentApi; -import org.camunda.community.rest.client.api.EngineApi; -import org.camunda.community.rest.client.api.ExternalTaskApi; -import org.camunda.community.rest.client.api.ProcessDefinitionApi; -import org.camunda.community.rest.client.api.ProcessInstanceApi; -import org.camunda.community.rest.client.api.TaskApi; -import org.camunda.community.rest.client.api.VariableInstanceApi; -import org.camunda.community.rest.client.dto.CompleteExternalTaskDto; -import org.camunda.community.rest.client.dto.CompleteTaskDto; -import org.camunda.community.rest.client.dto.DeploymentWithDefinitionsDto; -import org.camunda.community.rest.client.dto.ExternalTaskDto; -import org.camunda.community.rest.client.dto.ExternalTaskQueryDto; -import org.camunda.community.rest.client.dto.LockExternalTaskDto; -import org.camunda.community.rest.client.dto.ProcessInstanceDto; -import org.camunda.community.rest.client.dto.ProcessInstanceQueryDto; -import org.camunda.community.rest.client.dto.ProcessInstanceQueryDtoSorting; -import org.camunda.community.rest.client.dto.ProcessInstanceWithVariablesDto; -import org.camunda.community.rest.client.dto.StartProcessInstanceDto; -import org.camunda.community.rest.client.dto.TaskDto; -import org.camunda.community.rest.client.dto.TaskQueryDto; -import org.camunda.community.rest.client.dto.TaskQueryDtoSorting; -import org.camunda.community.rest.client.dto.UserIdDto; -import org.camunda.community.rest.client.dto.VariableInstanceDto; -import org.camunda.community.rest.client.dto.VariableInstanceQueryDto; -import org.camunda.community.rest.client.dto.VariableValueDto; +import org.camunda.community.rest.client.api.*; +import org.camunda.community.rest.client.dto.*; import org.camunda.community.rest.client.invoker.ApiCallback; import org.camunda.community.rest.client.invoker.ApiClient; import org.camunda.community.rest.client.invoker.ApiException; @@ -43,11 +20,7 @@ import java.io.File; import java.time.Duration; -import java.util.Collections; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; /** * connection to a Camunda 7 server. This is one object created by the engine, and then one "init() " call. @@ -55,579 +28,579 @@ */ public class BpmnEngineCamunda7 implements BpmnEngine { - public static final int SEARCH_MAX_SIZE = 100; - private final Logger logger = LoggerFactory.getLogger(BpmnEngineCamunda7.class); - private final String serverUrl; - private final String userName; - private final String password; - private final int workerMaxJobsActive; - private final boolean logDebug; - ApiClient apiClient = null; - ProcessDefinitionApi processDefinitionApi; - TaskApi taskApi; - ExternalTaskApi externalTaskApi; - ProcessInstanceApi processInstanceApi; - VariableInstanceApi variableInstanceApi; - DeploymentApi deploymentApi; - EngineApi engineApi; - private int count = 0; - - /** - * @param serverDefinition definition to connect to the server - * @param logDebug if true, operation will be log as debug level - */ - public BpmnEngineCamunda7(BpmnEngineList.BpmnServerDefinition serverDefinition, boolean logDebug) { - this.serverUrl = serverDefinition.camunda7ServerUrl; - this.userName = serverDefinition.camunda7UserName; - this.password = serverDefinition.camunda7Password; - this.workerMaxJobsActive = serverDefinition.workerMaxJobsActive; - this.logDebug = logDebug; - init(); - } - - /** - * P - * - * @param serverUrl is "http://localhost:8080/engine-rest" - */ - public BpmnEngineCamunda7(String serverUrl, String userName, String password, boolean logDebug) { - this.serverUrl = serverUrl; - this.userName = userName; - this.password = password; - this.workerMaxJobsActive = 1; - this.logDebug = logDebug; - init(); - } - - @Override - public void init() { - apiClient = new ApiClient(); - apiClient.setBasePath(serverUrl); - if (!userName.trim().isEmpty()) { - apiClient.setUsername(userName); - apiClient.setPassword(password); - } else { + public static final int SEARCH_MAX_SIZE = 100; + private final Logger logger = LoggerFactory.getLogger(BpmnEngineCamunda7.class); + private final String serverUrl; + private final String userName; + private final String password; + private final int workerMaxJobsActive; + private final boolean logDebug; + ApiClient apiClient = null; + ProcessDefinitionApi processDefinitionApi; + TaskApi taskApi; + ExternalTaskApi externalTaskApi; + ProcessInstanceApi processInstanceApi; + VariableInstanceApi variableInstanceApi; + DeploymentApi deploymentApi; + EngineApi engineApi; + private int count = 0; + + /** + * @param serverDefinition definition to connect to the server + * @param logDebug if true, operation will be log as debug level + */ + public BpmnEngineCamunda7(BpmnEngineList.BpmnServerDefinition serverDefinition, boolean logDebug) { + this.serverUrl = serverDefinition.camunda7ServerUrl; + this.userName = serverDefinition.camunda7UserName; + this.password = serverDefinition.camunda7Password; + this.workerMaxJobsActive = serverDefinition.workerMaxJobsActive; + this.logDebug = logDebug; + init(); } - processDefinitionApi = new ProcessDefinitionApi(apiClient); + /** + * P + * + * @param serverUrl is "http://localhost:8080/engine-rest" + */ + public BpmnEngineCamunda7(String serverUrl, String userName, String password, boolean logDebug) { + this.serverUrl = serverUrl; + this.userName = userName; + this.password = password; + this.workerMaxJobsActive = 1; + this.logDebug = logDebug; + init(); + } - taskApi = new TaskApi(apiClient); + @Override + public void init() { + apiClient = new ApiClient(); + apiClient.setBasePath(serverUrl); + if (!userName.trim().isEmpty()) { + apiClient.setUsername(userName); + apiClient.setPassword(password); + } else { + } - externalTaskApi = new ExternalTaskApi(apiClient); + processDefinitionApi = new ProcessDefinitionApi(apiClient); - processInstanceApi = new ProcessInstanceApi(apiClient); + taskApi = new TaskApi(apiClient); - variableInstanceApi = new VariableInstanceApi(apiClient); + externalTaskApi = new ExternalTaskApi(apiClient); - deploymentApi = new DeploymentApi(apiClient); + processInstanceApi = new ProcessInstanceApi(apiClient); - engineApi = new EngineApi(apiClient); - } + variableInstanceApi = new VariableInstanceApi(apiClient); - public void connection() throws AutomatorException { - count++; - // we verify if we have the connection - // logger.info("Connection to Camunda7 server[{}] User[{}] password[***]", serverUrl, userName); - if (count > 2) - return; - try { - engineApi.getProcessEngineNames(); - logger.info("Connection successfully to Camunda7 [{}] ", apiClient.getBasePath()); - } catch (ApiException e) { - logger.error("Can't connect Camunda7 server[{}] User[{}]: {}", apiClient.getBasePath(), userName, e.toString()); - throw new AutomatorException("Can't connect to Camunda7 [" + apiClient.getBasePath() + "] : " + e); - } - } - - public void disconnection() throws AutomatorException { - // nothing to do here - } - - /** - * Engine is ready. If not, a connection() method must be call - * - * @return true if the engine is ready - */ - public boolean isReady() { - if (count > 2) - return true; - - try { - engineApi.getProcessEngineNames(); - } catch (ApiException e) { - // no need to log, connect will be called - return false; + deploymentApi = new DeploymentApi(apiClient); + + engineApi = new EngineApi(apiClient); } - return true; - } - - /* ******************************************************************** */ - /* */ - /* Process Instance */ - /* */ - /* ******************************************************************** */ - - @Override - public String createProcessInstance(String processId, String starterEventId, Map<String, Object> variables) - throws AutomatorException { - if (logDebug) { - logger.info("BpmnEngine7.CreateProcessInstance: Process[" + processId + "] StartEvent[" + starterEventId + "]"); + + public void connection() throws AutomatorException { + count++; + // we verify if we have the connection + // logger.info("Connection to Camunda7 server[{}] User[{}] password[***]", serverUrl, userName); + if (count > 2) + return; + try { + engineApi.getProcessEngineNames(); + logger.info("Connection successfully to Camunda7 [{}] ", apiClient.getBasePath()); + } catch (ApiException e) { + logger.error("Can't connect Camunda7 server[{}] User[{}]: {}", apiClient.getBasePath(), userName, e.toString()); + throw new AutomatorException("Can't connect to Camunda7 [" + apiClient.getBasePath() + "] : " + e); + } } - String dateString = dateToString(new Date()); - Map<String, VariableValueDto> variablesApi = new HashMap<>(); - for (Map.Entry<String, Object> entry : variables.entrySet()) { - variablesApi.put(entry.getKey(), new VariableValueDto().value(entry.getValue())); + public void disconnection() throws AutomatorException { + // nothing to do here } - try { - ProcessInstanceWithVariablesDto processInstanceDto = processDefinitionApi.startProcessInstanceByKey(processId, - new StartProcessInstanceDto().variables(variablesApi).businessKey(dateString)); - return processInstanceDto.getId(); - } catch (ApiException e) { - throw new AutomatorException( - "Can't create process instance in [" + processId + "] StartEvent[" + starterEventId + "]", e); + + /** + * Engine is ready. If not, a connection() method must be call + * + * @return true if the engine is ready + */ + public boolean isReady() { + if (count > 2) + return true; + + try { + engineApi.getProcessEngineNames(); + } catch (ApiException e) { + // no need to log, connect will be called + return false; + } + return true; } - } - @Override - public void endProcessInstance(String processInstanceId, boolean cleanAll) throws AutomatorException { - // To nothing at this moment - } + /* ******************************************************************** */ + /* */ + /* Process Instance */ + /* */ + /* ******************************************************************** */ + @Override + public String createProcessInstance(String processId, String starterEventId, Map<String, Object> variables) + throws AutomatorException { + if (logDebug) { + logger.info("BpmnEngine7.CreateProcessInstance: Process[" + processId + "] StartEvent[" + starterEventId + "]"); + } + String dateString = dateToString(new Date()); - /* ******************************************************************** */ - /* */ - /* User task */ - /* */ - /* ******************************************************************** */ + Map<String, VariableValueDto> variablesApi = new HashMap<>(); + for (Map.Entry<String, Object> entry : variables.entrySet()) { + variablesApi.put(entry.getKey(), new VariableValueDto().value(entry.getValue())); + } + try { + ProcessInstanceWithVariablesDto processInstanceDto = processDefinitionApi.startProcessInstanceByKey(processId, + new StartProcessInstanceDto().variables(variablesApi).businessKey(dateString)); + return processInstanceDto.getId(); + } catch (ApiException e) { + throw new AutomatorException( + "Can't create process instance in [" + processId + "] StartEvent[" + starterEventId + "]", e); + } + } - @Override - public List<String> searchUserTasksByProcessInstance(String processInstanceId, String userTaskId, int maxResult) - throws AutomatorException { - if (logDebug) { - logger.info("BpmnEngine7.searchForActivity: Process[" + processInstanceId + "] taskName[" + userTaskId + "]"); + @Override + public void endProcessInstance(String processInstanceId, boolean cleanAll) throws AutomatorException { + // To nothing at this moment } - // get the list of all sub process instance - List<String> listProcessInstance = getListSubProcessInstance(processInstanceId); - TaskQueryDto taskQueryDto = new TaskQueryDto(); - taskQueryDto.addProcessInstanceIdInItem(processInstanceId); - for (String subProcessInstance : listProcessInstance) { - taskQueryDto.addProcessInstanceIdInItem(subProcessInstance); + /* ******************************************************************** */ + /* */ + /* User task */ + /* */ + /* ******************************************************************** */ - } - taskQueryDto.addTaskDefinitionKeyInItem(userTaskId); - List<TaskDto> taskDtos = null; - try { - taskDtos = taskApi.queryTasks(0, maxResult, taskQueryDto); - } catch (ApiException e) { - throw new AutomatorException("Can't searchTask", e); - } - return taskDtos.stream().map(TaskDto::getId).toList(); - } + @Override + public List<String> searchUserTasksByProcessInstance(String processInstanceId, String userTaskId, int maxResult) + throws AutomatorException { + if (logDebug) { + logger.info("BpmnEngine7.searchForActivity: Process[" + processInstanceId + "] taskName[" + userTaskId + "]"); + } - @Override - public List<String> searchUserTasks(String userTaskId, int maxResult) throws AutomatorException { - if (logDebug) { - logger.info("BpmnEngine7.searchForActivity: taskName[{}]", userTaskId); - } + // get the list of all sub process instance + List<String> listProcessInstance = getListSubProcessInstance(processInstanceId); + + TaskQueryDto taskQueryDto = new TaskQueryDto(); + taskQueryDto.addProcessInstanceIdInItem(processInstanceId); + for (String subProcessInstance : listProcessInstance) { + taskQueryDto.addProcessInstanceIdInItem(subProcessInstance); - TaskQueryDto taskQueryDto = new TaskQueryDto(); - taskQueryDto.addTaskDefinitionKeyInItem(userTaskId); - List<TaskDto> taskDtos = null; - try { - taskDtos = taskApi.queryTasks(0, maxResult, taskQueryDto); - } catch (ApiException e) { - throw new AutomatorException("Can't searchTask", e); + } + taskQueryDto.addTaskDefinitionKeyInItem(userTaskId); + List<TaskDto> taskDtos = null; + try { + taskDtos = taskApi.queryTasks(0, maxResult, taskQueryDto); + } catch (ApiException e) { + throw new AutomatorException("Can't searchTask", e); + } + return taskDtos.stream().map(TaskDto::getId).toList(); } - return taskDtos.stream().map(TaskDto::getId).toList(); - } - @Override - public void executeUserTask(String userTaskId, String userId, Map<String, Object> variables) - throws AutomatorException { + @Override + public List<String> searchUserTasks(String userTaskId, int maxResult) throws AutomatorException { + if (logDebug) { + logger.info("BpmnEngine7.searchForActivity: taskName[{}]", userTaskId); + } - if (logDebug) { - logger.info("BpmnEngine7.executeUserTask: activityId[{}]", userTaskId); - } - try { - UserIdDto userIdDto = new UserIdDto(); - userIdDto.setUserId(userId == null ? "automator" : userId); - taskApi.claim(userTaskId, userIdDto); - Map<String, VariableValueDto> variablesApi = new HashMap<>(); - for (Map.Entry<String, Object> entry : variables.entrySet()) { - variablesApi.put(entry.getKey(), new VariableValueDto().value(entry.getValue())); - } - - taskApi.complete(userTaskId, new CompleteTaskDto().variables(variablesApi)); - } catch (ApiException e) { - throw new AutomatorException("Can't execute taskId[" + userTaskId + "] with userId[" + userId + "]", e); - } - } - - /* ******************************************************************** */ - /* */ - /* Service task */ - /* */ - /* ******************************************************************** */ - @Override - public RegisteredTask registerServiceTask(String workerId, - String topic, - boolean streamEnable, - Duration lockTime, - Object jobHandler, - FixedBackoffSupplier backoffSupplier) { - - if (!(jobHandler instanceof ExternalTaskHandler)) { - logger.error("handler is not a externalTaskHandler implementation, can't register the worker [{}], topic [{}]", - workerId, topic); - return null; - } - RegisteredTask registeredTask = new RegisteredTask(); - - ExternalTaskClient client = ExternalTaskClient.create() - .baseUrl(serverUrl) - .workerId(workerId) - .maxTasks(workerMaxJobsActive < 1 ? 1 : workerMaxJobsActive) - .lockDuration(lockTime.toMillis()) - .asyncResponseTimeout(20000) - .backoffStrategy(new ExponentialBackoffStrategy()) - .build(); - - registeredTask.topicSubscription = client.subscribe(topic) - .lockDuration(10000) - .handler((ExternalTaskHandler) jobHandler) - .open(); - return registeredTask; - - } - - /** - * Search service task - * - * @param processInstanceId processInstance - * @param serviceTaskId task name - * @param topic topic to search the task - * @param maxResult number of result - * @return the list of TaskId found according the criteria - * @throws AutomatorException any error during search - */ - @Override - public List<String> searchServiceTasks(String processInstanceId, String serviceTaskId, String topic, int maxResult) - throws AutomatorException { - if (logDebug) { - logger.info("BpmnEngine7.searchForActivity: Process[{}] taskName[{}]", processInstanceId, serviceTaskId); + TaskQueryDto taskQueryDto = new TaskQueryDto(); + taskQueryDto.addTaskDefinitionKeyInItem(userTaskId); + List<TaskDto> taskDtos = null; + try { + taskDtos = taskApi.queryTasks(0, maxResult, taskQueryDto); + } catch (ApiException e) { + throw new AutomatorException("Can't searchTask", e); + } + return taskDtos.stream().map(TaskDto::getId).toList(); } - // get the list of all sub process instance - List<String> listProcessInstance = getListSubProcessInstance(processInstanceId); - - ExternalTaskQueryDto externalTaskQueryDto = new ExternalTaskQueryDto(); - externalTaskQueryDto.addProcessInstanceIdInItem(processInstanceId); - for (String subProcessInstance : listProcessInstance) { - externalTaskQueryDto.addProcessInstanceIdInItem(subProcessInstance); + @Override + public void executeUserTask(String userTaskId, String userId, Map<String, Object> variables) + throws AutomatorException { + if (logDebug) { + logger.info("BpmnEngine7.executeUserTask: activityId[{}]", userTaskId); + } + try { + UserIdDto userIdDto = new UserIdDto(); + userIdDto.setUserId(userId == null ? "automator" : userId); + taskApi.claim(userTaskId, userIdDto); + Map<String, VariableValueDto> variablesApi = new HashMap<>(); + for (Map.Entry<String, Object> entry : variables.entrySet()) { + variablesApi.put(entry.getKey(), new VariableValueDto().value(entry.getValue())); + } + + taskApi.complete(userTaskId, new CompleteTaskDto().variables(variablesApi)); + } catch (ApiException e) { + throw new AutomatorException("Can't execute taskId[" + userTaskId + "] with userId[" + userId + "]", e); + } } - externalTaskQueryDto.activityId(serviceTaskId); - List<ExternalTaskDto> taskDtos; - try { - taskDtos = externalTaskApi.queryExternalTasks(0, 100, externalTaskQueryDto); - } catch (ApiException e) { - throw new AutomatorException("Can't searchTask", e); + /* ******************************************************************** */ + /* */ + /* Service task */ + /* */ + /* ******************************************************************** */ + @Override + public RegisteredTask registerServiceTask(String workerId, + String topic, + boolean streamEnable, + Duration lockTime, + Object jobHandler, + FixedBackoffSupplier backoffSupplier) { + + if (!(jobHandler instanceof ExternalTaskHandler)) { + logger.error("handler is not a externalTaskHandler implementation, can't register the worker [{}], topic [{}]", + workerId, topic); + return null; + } + RegisteredTask registeredTask = new RegisteredTask(); + + ExternalTaskClient client = ExternalTaskClient.create() + .baseUrl(serverUrl) + .workerId(workerId) + .maxTasks(workerMaxJobsActive < 1 ? 1 : workerMaxJobsActive) + .lockDuration(lockTime.toMillis()) + .asyncResponseTimeout(20000) + .backoffStrategy(new ExponentialBackoffStrategy()) + .build(); + + registeredTask.topicSubscription = client.subscribe(topic) + .lockDuration(10000) + .handler((ExternalTaskHandler) jobHandler) + .open(); + return registeredTask; + } - return taskDtos.stream().map(ExternalTaskDto::getId).toList(); - } - @Override - public void executeServiceTask(String serviceTaskId, String userId, Map<String, Object> variables) - throws AutomatorException { + /** + * Search service task + * + * @param processInstanceId processInstance + * @param serviceTaskId task name + * @param topic topic to search the task + * @param maxResult number of result + * @return the list of TaskId found according the criteria + * @throws AutomatorException any error during search + */ + @Override + public List<String> searchServiceTasks(String processInstanceId, String serviceTaskId, String topic, int maxResult) + throws AutomatorException { + if (logDebug) { + logger.info("BpmnEngine7.searchForActivity: Process[{}] taskName[{}]", processInstanceId, serviceTaskId); + } - if (logDebug) { - logger.info("BpmnEngine7.executeUserTask: activityId[{}]", serviceTaskId); - } - try { + // get the list of all sub process instance + List<String> listProcessInstance = getListSubProcessInstance(processInstanceId); - // Fetch and lock - String workerId = getUniqWorkerId(); - externalTaskApi.lock(serviceTaskId, new LockExternalTaskDto().workerId(workerId).lockDuration(10000L)); + ExternalTaskQueryDto externalTaskQueryDto = new ExternalTaskQueryDto(); + externalTaskQueryDto.addProcessInstanceIdInItem(processInstanceId); + for (String subProcessInstance : listProcessInstance) { + externalTaskQueryDto.addProcessInstanceIdInItem(subProcessInstance); - Map<String, VariableValueDto> variablesApi = new HashMap<>(); - for (Map.Entry<String, Object> entry : variables.entrySet()) { - variablesApi.put(entry.getKey(), new VariableValueDto().value(entry.getValue())); - } + } - ExternalCallBack externalCallBack = new ExternalCallBack(); - externalTaskApi.completeExternalTaskResourceAsync(serviceTaskId, - new CompleteExternalTaskDto().variables(variablesApi).workerId(workerId), externalCallBack); + externalTaskQueryDto.activityId(serviceTaskId); + List<ExternalTaskDto> taskDtos; + try { + taskDtos = externalTaskApi.queryExternalTasks(0, 100, externalTaskQueryDto); + } catch (ApiException e) { + throw new AutomatorException("Can't searchTask", e); + } + return taskDtos.stream().map(ExternalTaskDto::getId).toList(); + } - int counter = 0; - while (ExternalCallBack.STATUS.WAIT.equals(externalCallBack.status) && counter < 200) { - counter++; + @Override + public void executeServiceTask(String serviceTaskId, String userId, Map<String, Object> variables) + throws AutomatorException { + + if (logDebug) { + logger.info("BpmnEngine7.executeUserTask: activityId[{}]", serviceTaskId); + } try { - Thread.sleep(200); - } catch (InterruptedException e) { - // we don't care + + // Fetch and lock + String workerId = getUniqWorkerId(); + externalTaskApi.lock(serviceTaskId, new LockExternalTaskDto().workerId(workerId).lockDuration(10000L)); + + Map<String, VariableValueDto> variablesApi = new HashMap<>(); + for (Map.Entry<String, Object> entry : variables.entrySet()) { + variablesApi.put(entry.getKey(), new VariableValueDto().value(entry.getValue())); + } + + ExternalCallBack externalCallBack = new ExternalCallBack(); + externalTaskApi.completeExternalTaskResourceAsync(serviceTaskId, + new CompleteExternalTaskDto().variables(variablesApi).workerId(workerId), externalCallBack); + + int counter = 0; + while (ExternalCallBack.STATUS.WAIT.equals(externalCallBack.status) && counter < 200) { + counter++; + try { + Thread.sleep(200); + } catch (InterruptedException e) { + // we don't care + } + } + if (!ExternalCallBack.STATUS.SUCCESS.equals(externalCallBack.status)) { + throw new AutomatorException( + "Can't execute taskId[" + serviceTaskId + "] - answer[" + externalCallBack.status + "]"); + } + } catch (ApiException e) { + throw new AutomatorException("Can't execute taskId[" + serviceTaskId + "] with userId[" + userId + "]", e); } - } - if (!ExternalCallBack.STATUS.SUCCESS.equals(externalCallBack.status)) { - throw new AutomatorException( - "Can't execute taskId[" + serviceTaskId + "] - answer[" + externalCallBack.status + "]"); - } - } catch (ApiException e) { - throw new AutomatorException("Can't execute taskId[" + serviceTaskId + "] with userId[" + userId + "]", e); } - } - /* ******************************************************************** */ - /* */ - /* Generic task */ - /* */ - /* ******************************************************************** */ + /* ******************************************************************** */ + /* */ + /* Generic task */ + /* */ + /* ******************************************************************** */ - @Override - public List<TaskDescription> searchTasksByProcessInstanceId(String processInstanceId, String taskId, int maxResult) - throws AutomatorException { - // get the list of all sub process instance - List<String> listProcessInstance = getListSubProcessInstance(processInstanceId); + @Override + public List<TaskDescription> searchTasksByProcessInstanceId(String processInstanceId, String taskId, int maxResult) + throws AutomatorException { + // get the list of all sub process instance + List<String> listProcessInstance = getListSubProcessInstance(processInstanceId); - TaskQueryDto taskQueryDto = new TaskQueryDto(); - taskQueryDto.addProcessInstanceIdInItem(processInstanceId); - for (String subProcessInstance : listProcessInstance) { - taskQueryDto.addProcessInstanceIdInItem(subProcessInstance); + TaskQueryDto taskQueryDto = new TaskQueryDto(); + taskQueryDto.addProcessInstanceIdInItem(processInstanceId); + for (String subProcessInstance : listProcessInstance) { + taskQueryDto.addProcessInstanceIdInItem(subProcessInstance); + } + taskQueryDto.addTaskDefinitionKeyInItem(taskId); + List<TaskDto> taskDtos = null; + try { + taskDtos = taskApi.queryTasks(0, maxResult, taskQueryDto); + } catch (ApiException e) { + throw new AutomatorException("Can't searchTask", e); + } + return taskDtos.stream().map(t -> { + TaskDescription taskDescription = new TaskDescription(); + taskDescription.taskId = t.getName(); + taskDescription.type = ScenarioStep.Step.USERTASK; + taskDescription.isCompleted = true; + return taskDescription; + }).toList(); } - taskQueryDto.addTaskDefinitionKeyInItem(taskId); - List<TaskDto> taskDtos = null; - try { - taskDtos = taskApi.queryTasks(0, maxResult, taskQueryDto); - } catch (ApiException e) { - throw new AutomatorException("Can't searchTask", e); + + @Override + public List<ProcessDescription> searchProcessInstanceByVariable(String processId, + Map<String, Object> filterVariables, + int maxResult) throws AutomatorException { + return Collections.emptyList(); } - return taskDtos.stream().map(t -> { - TaskDescription taskDescription = new TaskDescription(); - taskDescription.taskId = t.getName(); - taskDescription.type = ScenarioStep.Step.USERTASK; - taskDescription.isCompleted = true; - return taskDescription; - }).toList(); - } - - @Override - public List<ProcessDescription> searchProcessInstanceByVariable(String processId, - Map<String, Object> filterVariables, - int maxResult) throws AutomatorException { - return Collections.emptyList(); - } - - @Override - public Map<String, Object> getVariables(String processInstanceId) throws AutomatorException { - - VariableInstanceQueryDto variableQuery = new VariableInstanceQueryDto(); - variableQuery.processInstanceIdIn(List.of(processInstanceId)); - try { - List<VariableInstanceDto> variableInstanceDtos = variableInstanceApi.queryVariableInstances(0, 1000, true, - variableQuery); - - Map<String, Object> variables = new HashMap<>(); - for (VariableInstanceDto variable : variableInstanceDtos) { - variables.put(variable.getName(), variable.getValue()); - } - return variables; - } catch (ApiException e) { - throw new AutomatorException("Can't searchVariables", e); + + @Override + public Map<String, Object> getVariables(String processInstanceId) throws AutomatorException { + + VariableInstanceQueryDto variableQuery = new VariableInstanceQueryDto(); + variableQuery.processInstanceIdIn(List.of(processInstanceId)); + try { + List<VariableInstanceDto> variableInstanceDtos = variableInstanceApi.queryVariableInstances(0, 1000, true, + variableQuery); + + Map<String, Object> variables = new HashMap<>(); + for (VariableInstanceDto variable : variableInstanceDtos) { + variables.put(variable.getName(), variable.getValue()); + } + return variables; + } catch (ApiException e) { + throw new AutomatorException("Can't searchVariables", e); + } } - } - - /* ******************************************************************** */ - /* */ - /* CountInformation */ - /* */ - /* ******************************************************************** */ - - @Override - public long countNumberOfProcessInstancesCreated(String processName, DateFilter startDate, DateFilter endDate) - throws AutomatorException { - - try { - int cumul = 0; - ProcessInstanceQueryDto processInstanceQuery = new ProcessInstanceQueryDto(); - processInstanceQuery = processInstanceQuery.addProcessDefinitionKeyInItem(processName); - processInstanceQuery.addSortingItem( - new ProcessInstanceQueryDtoSorting().sortBy(ProcessInstanceQueryDtoSorting.SortByEnum.INSTANCEID) - .sortOrder(ProcessInstanceQueryDtoSorting.SortOrderEnum.ASC)); - - int maxLoop = 0; - int firstResult = 0; - List<ProcessInstanceDto> processInstanceDtos; - do { - maxLoop++; - processInstanceDtos = processInstanceApi.queryProcessInstances(firstResult, SEARCH_MAX_SIZE, - processInstanceQuery); - firstResult += processInstanceDtos.size(); - cumul += processInstanceDtos.stream().filter(t -> { - Date datePI = stringToDate(t.getBusinessKey()); - if (datePI == null) - return false; - return datePI.after(startDate.getDate()); - }).count(); - } while (processInstanceDtos.size() >= SEARCH_MAX_SIZE && maxLoop < 1000); - return cumul; + /* ******************************************************************** */ + /* */ + /* CountInformation */ + /* */ + /* ******************************************************************** */ - } catch (Exception e) { - throw new AutomatorException("Error during countNumberOfProcessInstancesCreated"); + @Override + public long countNumberOfProcessInstancesCreated(String processName, DateFilter startDate, DateFilter endDate) + throws AutomatorException { - } - } - - @Override - public long countNumberOfProcessInstancesEnded(String processName, DateFilter startDate, DateFilter endDate) - throws AutomatorException { - throw new AutomatorException("Not yet implemented"); - } - - public long countNumberOfTasks(String processId, String taskId) throws AutomatorException { - try { - int cumul = 0; - TaskQueryDto taskQueryDto = new TaskQueryDto(); - taskQueryDto = taskQueryDto.addProcessDefinitionKeyInItem(processId); - taskQueryDto.addSortingItem(new TaskQueryDtoSorting().sortBy(TaskQueryDtoSorting.SortByEnum.INSTANCEID) - .sortOrder(TaskQueryDtoSorting.SortOrderEnum.ASC)); - - int maxLoop = 0; - int firstResult = 0; - List<TaskDto> taskDtos; - do { - maxLoop++; - taskDtos = taskApi.queryTasks(firstResult, SEARCH_MAX_SIZE, taskQueryDto); - - firstResult += taskDtos.size(); - cumul += taskDtos.size(); - - } while (taskDtos.size() >= SEARCH_MAX_SIZE && maxLoop < 1000); - return cumul; - - } catch (Exception e) { - throw new AutomatorException("Error during countNumberOfTasks"); + try { + int cumul = 0; + ProcessInstanceQueryDto processInstanceQuery = new ProcessInstanceQueryDto(); + processInstanceQuery = processInstanceQuery.addProcessDefinitionKeyInItem(processName); + processInstanceQuery.addSortingItem( + new ProcessInstanceQueryDtoSorting().sortBy(ProcessInstanceQueryDtoSorting.SortByEnum.INSTANCEID) + .sortOrder(ProcessInstanceQueryDtoSorting.SortOrderEnum.ASC)); + + int maxLoop = 0; + int firstResult = 0; + List<ProcessInstanceDto> processInstanceDtos; + do { + maxLoop++; + processInstanceDtos = processInstanceApi.queryProcessInstances(firstResult, SEARCH_MAX_SIZE, + processInstanceQuery); + firstResult += processInstanceDtos.size(); + cumul += processInstanceDtos.stream().filter(t -> { + Date datePI = stringToDate(t.getBusinessKey()); + if (datePI == null) + return false; + return datePI.after(startDate.getDate()); + }).count(); + + } while (processInstanceDtos.size() >= SEARCH_MAX_SIZE && maxLoop < 1000); + return cumul; + + } catch (Exception e) { + throw new AutomatorException("Error during countNumberOfProcessInstancesCreated"); + } } - } - - /* ******************************************************************** */ - /* */ - /* Deployment */ - /* */ - /* ******************************************************************** */ - - @Override - public String deployBpmn(File processFile, ScenarioDeployment.Policy policy) throws AutomatorException { - try { - DeploymentWithDefinitionsDto deploymentSource = deploymentApi.createDeployment(null, // tenantId - null, // deploymentSource - ScenarioDeployment.Policy.ONLYNOTEXIST.equals(policy), // deployChangedOnly, - Boolean.TRUE, // enableDuplicateFiltering, - processFile.getName(), // String deploymentName, - new Date(), //deploymentActivationTime, - processFile); - return deploymentSource.getId(); - } catch (ApiException e) { - throw new AutomatorException("Can't deploy process ", e); + + @Override + public long countNumberOfProcessInstancesEnded(String processName, DateFilter startDate, DateFilter endDate) + throws AutomatorException { + throw new AutomatorException("Not yet implemented"); } - } - - - - /* ******************************************************************** */ - /* */ - /* get server definition */ - /* */ - /* ******************************************************************** */ - - @Override - public BpmnEngineList.CamundaEngine getTypeCamundaEngine() { - return BpmnEngineList.CamundaEngine.CAMUNDA_7; - } - - @Override - public String getSignature() { - return BpmnEngineList.CamundaEngine.CAMUNDA_7 + " " + "serverUrl[" + serverUrl + "]"; - } - - @Override - public int getWorkerExecutionThreads() { - return workerMaxJobsActive; - } - - public void turnHighFlowMode(boolean hightFlowMode) { - } - - private String getUniqWorkerId() { - return Thread.currentThread().getName() + "-" + System.currentTimeMillis(); - } - - /** - * Collect all subprocess for a process instance - * - * @param rootProcessInstance root process instance - * @return list of SubProcess ID - * @throws AutomatorException if any errors arrive - */ - private List<String> getListSubProcessInstance(String rootProcessInstance) throws AutomatorException { - ProcessInstanceQueryDto processInstanceQueryDto = new ProcessInstanceQueryDto(); - processInstanceQueryDto.superProcessInstance(rootProcessInstance); - List<ProcessInstanceDto> processInstanceDtos; - try { - processInstanceDtos = processInstanceApi.queryProcessInstances(0, 100000, processInstanceQueryDto); - } catch (ApiException e) { - throw new AutomatorException("Can't searchSubProcess", e); + public long countNumberOfTasks(String processId, String taskId) throws AutomatorException { + try { + int cumul = 0; + TaskQueryDto taskQueryDto = new TaskQueryDto(); + taskQueryDto = taskQueryDto.addProcessDefinitionKeyInItem(processId); + taskQueryDto.addSortingItem(new TaskQueryDtoSorting().sortBy(TaskQueryDtoSorting.SortByEnum.INSTANCEID) + .sortOrder(TaskQueryDtoSorting.SortOrderEnum.ASC)); + + int maxLoop = 0; + int firstResult = 0; + List<TaskDto> taskDtos; + do { + maxLoop++; + taskDtos = taskApi.queryTasks(firstResult, SEARCH_MAX_SIZE, taskQueryDto); + + firstResult += taskDtos.size(); + cumul += taskDtos.size(); + + } while (taskDtos.size() >= SEARCH_MAX_SIZE && maxLoop < 1000); + return cumul; + + } catch (Exception e) { + throw new AutomatorException("Error during countNumberOfTasks"); + + } } - return processInstanceDtos.stream().map(ProcessInstanceDto::getId).toList(); - } - private String dateToString(Date date) { - return String.valueOf(date.getTime()); - } + /* ******************************************************************** */ + /* */ + /* Deployment */ + /* */ + /* ******************************************************************** */ + + @Override + public String deployBpmn(File processFile, ScenarioDeployment.Policy policy) throws AutomatorException { + try { + DeploymentWithDefinitionsDto deploymentSource = deploymentApi.createDeployment(null, // tenantId + null, // deploymentSource + ScenarioDeployment.Policy.ONLYNOTEXIST.equals(policy), // deployChangedOnly, + Boolean.TRUE, // enableDuplicateFiltering, + processFile.getName(), // String deploymentName, + new Date(), //deploymentActivationTime, + processFile); + return deploymentSource.getId(); + } catch (ApiException e) { + throw new AutomatorException("Can't deploy process ", e); + } - private Date stringToDate(String dateSt) { - if (dateSt == null) - return null; - return new Date(Long.valueOf(dateSt)); - } + } - /** - * Call back asynchronous - */ - public static class ExternalCallBack implements ApiCallback { - public STATUS status = STATUS.WAIT; - public ApiException e; + + /* ******************************************************************** */ + /* */ + /* get server definition */ + /* */ + /* ******************************************************************** */ @Override - public void onFailure(ApiException e, int i, Map map) { - this.status = STATUS.FAILURE; - this.e = e; + public BpmnEngineList.CamundaEngine getTypeCamundaEngine() { + return BpmnEngineList.CamundaEngine.CAMUNDA_7; } @Override - public void onSuccess(Object o, int i, Map map) { - this.status = STATUS.SUCCESS; + public String getSignature() { + return BpmnEngineList.CamundaEngine.CAMUNDA_7 + " " + "serverUrl[" + serverUrl + "]"; } @Override - public void onUploadProgress(long l, long l1, boolean b) { + public int getWorkerExecutionThreads() { + return workerMaxJobsActive; + } + public void turnHighFlowMode(boolean hightFlowMode) { } - @Override - public void onDownloadProgress(long l, long l1, boolean b) { + private String getUniqWorkerId() { + return Thread.currentThread().getName() + "-" + System.currentTimeMillis(); + } + + /** + * Collect all subprocess for a process instance + * + * @param rootProcessInstance root process instance + * @return list of SubProcess ID + * @throws AutomatorException if any errors arrive + */ + private List<String> getListSubProcessInstance(String rootProcessInstance) throws AutomatorException { + ProcessInstanceQueryDto processInstanceQueryDto = new ProcessInstanceQueryDto(); + processInstanceQueryDto.superProcessInstance(rootProcessInstance); + List<ProcessInstanceDto> processInstanceDtos; + try { + processInstanceDtos = processInstanceApi.queryProcessInstances(0, 100000, processInstanceQueryDto); + } catch (ApiException e) { + throw new AutomatorException("Can't searchSubProcess", e); + } + return processInstanceDtos.stream().map(ProcessInstanceDto::getId).toList(); + } + + private String dateToString(Date date) { + return String.valueOf(date.getTime()); + } + private Date stringToDate(String dateSt) { + if (dateSt == null) + return null; + return new Date(Long.valueOf(dateSt)); } - public enum STATUS {WAIT, FAILURE, SUCCESS} - } + /** + * Call back asynchronous + */ + public static class ExternalCallBack implements ApiCallback { + + public STATUS status = STATUS.WAIT; + public ApiException e; + + @Override + public void onFailure(ApiException e, int i, Map map) { + this.status = STATUS.FAILURE; + this.e = e; + } + + @Override + public void onSuccess(Object o, int i, Map map) { + this.status = STATUS.SUCCESS; + } + + @Override + public void onUploadProgress(long l, long l1, boolean b) { + + } + + @Override + public void onDownloadProgress(long l, long l1, boolean b) { + + } + + public enum STATUS {WAIT, FAILURE, SUCCESS} + } } diff --git a/src/main/java/org/camunda/automator/bpmnengine/camunda8/BenchmarkCompleteJobExceptionHandlingStrategy.java b/src/main/java/org/camunda/automator/bpmnengine/camunda8/BenchmarkCompleteJobExceptionHandlingStrategy.java index f8a5584..0668c93 100644 --- a/src/main/java/org/camunda/automator/bpmnengine/camunda8/BenchmarkCompleteJobExceptionHandlingStrategy.java +++ b/src/main/java/org/camunda/automator/bpmnengine/camunda8/BenchmarkCompleteJobExceptionHandlingStrategy.java @@ -14,28 +14,28 @@ @Component public class BenchmarkCompleteJobExceptionHandlingStrategy extends DefaultCommandExceptionHandlingStrategy { - @Autowired - private StatisticsCollector stats; + @Autowired + private StatisticsCollector stats; - public BenchmarkCompleteJobExceptionHandlingStrategy(@Autowired BackoffSupplier backoffSupplier) { - super(backoffSupplier, Executors.newScheduledThreadPool(1)); - } + public BenchmarkCompleteJobExceptionHandlingStrategy(@Autowired BackoffSupplier backoffSupplier) { + super(backoffSupplier, Executors.newScheduledThreadPool(1)); + } - @Override - public void handleCommandError(CommandWrapper command, Throwable throwable) { - if (StatusRuntimeException.class.isAssignableFrom(throwable.getClass())) { - StatusRuntimeException exception = (StatusRuntimeException) throwable; - stats.incCompletedJobsException(exception.getStatus().getCode().name()); + @Override + public void handleCommandError(CommandWrapper command, Throwable throwable) { + if (StatusRuntimeException.class.isAssignableFrom(throwable.getClass())) { + StatusRuntimeException exception = (StatusRuntimeException) throwable; + stats.incCompletedJobsException(exception.getStatus().getCode().name()); /* Backpressure on Job completion cannot happen at the moment (whitelisted) if (Status.Code.RESOURCE_EXHAUSTED == exception.getStatus().getCode()) { stats.getBackpressureOnJobCompleteMeter().mark(); return; }*/ - } else { - stats.incCompletedJobsException(throwable.getMessage()); - } + } else { + stats.incCompletedJobsException(throwable.getMessage()); + } - // use normal behavior, e.g. increasing back-off for backpressure - super.handleCommandError(command, throwable); - } + // use normal behavior, e.g. increasing back-off for backpressure + super.handleCommandError(command, throwable); + } } diff --git a/src/main/java/org/camunda/automator/bpmnengine/camunda8/BenchmarkStartPiExceptionHandlingStrategy.java b/src/main/java/org/camunda/automator/bpmnengine/camunda8/BenchmarkStartPiExceptionHandlingStrategy.java index 585b02e..a54983a 100644 --- a/src/main/java/org/camunda/automator/bpmnengine/camunda8/BenchmarkStartPiExceptionHandlingStrategy.java +++ b/src/main/java/org/camunda/automator/bpmnengine/camunda8/BenchmarkStartPiExceptionHandlingStrategy.java @@ -13,26 +13,26 @@ @Component public class BenchmarkStartPiExceptionHandlingStrategy extends DefaultCommandExceptionHandlingStrategy { - @Autowired - private StatisticsCollector stats; + @Autowired + private StatisticsCollector stats; - public BenchmarkStartPiExceptionHandlingStrategy(@Autowired BackoffSupplier backoffSupplier) { - super(backoffSupplier, Executors.newScheduledThreadPool(1)); - } + public BenchmarkStartPiExceptionHandlingStrategy(@Autowired BackoffSupplier backoffSupplier) { + super(backoffSupplier, Executors.newScheduledThreadPool(1)); + } - @Override - public void handleCommandError(CommandWrapper command, Throwable throwable) { - if (StatusRuntimeException.class.isAssignableFrom(throwable.getClass())) { - StatusRuntimeException exception = (StatusRuntimeException) throwable; - stats.incStartedProcessInstancesException(exception.getStatus().getCode().name()); - if (Status.Code.RESOURCE_EXHAUSTED == exception.getStatus().getCode()) { - stats.incStartedProcessInstancesBackpressure(); - return; // ignore backpressure, as we don't want to add a big wave of retries - } - } else { - stats.incStartedProcessInstancesException(throwable.getMessage()); + @Override + public void handleCommandError(CommandWrapper command, Throwable throwable) { + if (StatusRuntimeException.class.isAssignableFrom(throwable.getClass())) { + StatusRuntimeException exception = (StatusRuntimeException) throwable; + stats.incStartedProcessInstancesException(exception.getStatus().getCode().name()); + if (Status.Code.RESOURCE_EXHAUSTED == exception.getStatus().getCode()) { + stats.incStartedProcessInstancesBackpressure(); + return; // ignore backpressure, as we don't want to add a big wave of retries + } + } else { + stats.incStartedProcessInstancesException(throwable.getMessage()); + } + // use normal behavior + super.handleCommandError(command, throwable); } - // use normal behavior - super.handleCommandError(command, throwable); - } } diff --git a/src/main/java/org/camunda/automator/bpmnengine/camunda8/BpmnEngineCamunda8.java b/src/main/java/org/camunda/automator/bpmnengine/camunda8/BpmnEngineCamunda8.java index 7d3447e..c79dc65 100644 --- a/src/main/java/org/camunda/automator/bpmnengine/camunda8/BpmnEngineCamunda8.java +++ b/src/main/java/org/camunda/automator/bpmnengine/camunda8/BpmnEngineCamunda8.java @@ -1,14 +1,6 @@ package org.camunda.automator.bpmnengine.camunda8; -import io.camunda.common.auth.Authentication; -import io.camunda.common.auth.JwtConfig; -import io.camunda.common.auth.JwtCredential; -import io.camunda.common.auth.Product; -import io.camunda.common.auth.SaaSAuthentication; -import io.camunda.common.auth.SaaSAuthenticationBuilder; -import io.camunda.common.auth.SimpleAuthentication; -import io.camunda.common.auth.SimpleConfig; -import io.camunda.common.auth.SimpleCredential; +import io.camunda.common.auth.*; import io.camunda.common.auth.identity.IdentityConfig; import io.camunda.common.auth.identity.IdentityContainer; import io.camunda.common.json.SdkObjectMapper; @@ -17,35 +9,18 @@ import io.camunda.operate.CamundaOperateClient; import io.camunda.operate.CamundaOperateClientBuilder; import io.camunda.operate.exception.OperateException; -import io.camunda.operate.model.FlowNodeInstance; -import io.camunda.operate.model.FlowNodeInstanceState; -import io.camunda.operate.model.ProcessInstance; -import io.camunda.operate.model.ProcessInstanceState; -import io.camunda.operate.model.SearchResult; +import io.camunda.operate.model.*; import io.camunda.operate.search.DateFilter; -import io.camunda.operate.search.FlowNodeInstanceFilter; -import io.camunda.operate.search.ProcessInstanceFilter; -import io.camunda.operate.search.SearchQuery; -import io.camunda.operate.search.Sort; -import io.camunda.operate.search.SortOrder; -import io.camunda.operate.search.VariableFilter; +import io.camunda.operate.search.*; import io.camunda.tasklist.CamundaTaskListClient; import io.camunda.tasklist.CamundaTaskListClientBuilder; -import io.camunda.tasklist.dto.Pagination; -import io.camunda.tasklist.dto.Task; -import io.camunda.tasklist.dto.TaskList; -import io.camunda.tasklist.dto.TaskSearch; -import io.camunda.tasklist.dto.TaskState; import io.camunda.tasklist.dto.Variable; +import io.camunda.tasklist.dto.*; import io.camunda.tasklist.exception.TaskListException; import io.camunda.zeebe.client.ZeebeClient; import io.camunda.zeebe.client.ZeebeClientBuilder; import io.camunda.zeebe.client.api.command.FinalCommandStep; -import io.camunda.zeebe.client.api.response.ActivateJobsResponse; -import io.camunda.zeebe.client.api.response.ActivatedJob; -import io.camunda.zeebe.client.api.response.DeploymentEvent; -import io.camunda.zeebe.client.api.response.ProcessInstanceEvent; -import io.camunda.zeebe.client.api.response.Topology; +import io.camunda.zeebe.client.api.response.*; import io.camunda.zeebe.client.api.worker.JobHandler; import io.camunda.zeebe.client.api.worker.JobWorkerBuilderStep1; import io.camunda.zeebe.client.impl.oauth.OAuthCredentialsProvider; @@ -64,1102 +39,1112 @@ import java.net.URI; import java.net.URL; import java.time.Duration; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.Random; -import java.util.Set; +import java.util.*; import java.util.stream.Collectors; public class BpmnEngineCamunda8 implements BpmnEngine { - public static final String THIS_IS_A_COMPLETE_IMPOSSIBLE_VARIABLE_NAME = "ThisIsACompleteImpossibleVariableName"; - public static final int SEARCH_MAX_SIZE = 100; - public static final String SAAS_AUTHENTICATE_URL = "https://login.cloud.camunda.io/oauth/token"; - private final Logger logger = LoggerFactory.getLogger(BpmnEngineCamunda8.class); - private final BenchmarkStartPiExceptionHandlingStrategy exceptionHandlingStrategy; - boolean hightFlowMode = false; - /** - * It is not possible to search user task for a specfic processInstance. So, to realize this, a marker is created in each process instance. Retrieving the user task, - * the process instance can be found and correction can be done - */ - Map<String, Long> cacheProcessInstanceMarker = new HashMap<>(); - Random random = new Random(System.currentTimeMillis()); - private BpmnEngineList.BpmnServerDefinition serverDefinition; - private ZeebeClient zeebeClient; - private CamundaOperateClient operateClient; - private CamundaTaskListClient taskClient; - // Default - private BpmnEngineList.CamundaEngine typeCamundaEngine = BpmnEngineList.CamundaEngine.CAMUNDA_8; - - private BpmnEngineCamunda8(BenchmarkStartPiExceptionHandlingStrategy exceptionHandlingStrategy) { - this.exceptionHandlingStrategy = exceptionHandlingStrategy; - } - - /** - * Constructor from existing object - * - * @param serverDefinition server definition - * @param logDebug if true, operation will be logged as debug level - */ - public static BpmnEngineCamunda8 getFromServerDefinition(BpmnEngineList.BpmnServerDefinition serverDefinition, - BenchmarkStartPiExceptionHandlingStrategy benchmarkStartPiExceptionHandlingStrategy, - boolean logDebug) { - BpmnEngineCamunda8 bpmnEngineCamunda8 = new BpmnEngineCamunda8(benchmarkStartPiExceptionHandlingStrategy); - bpmnEngineCamunda8.serverDefinition = serverDefinition; - return bpmnEngineCamunda8; - - } - - /** - * Constructor to specify a Self Manage Zeebe Address por a Zeebe Saas - * - * @param zeebeSelfGatewayAddress Self Manage : zeebe address - * @param zeebePlainText Self Manage: Plain text - * @param operateUrl URL to access Operate - * @param operateUserName Operate user name - * @param operateUserPassword Operate password - * @param tasklistUrl Url to access TaskList - */ - public static BpmnEngineCamunda8 getFromCamunda8(String zeebeSelfGatewayAddress, - Boolean zeebePlainText, - String operateUrl, - String operateUserName, - String operateUserPassword, - String tasklistUrl, - BenchmarkStartPiExceptionHandlingStrategy benchmarkStartPiExceptionHandlingStrategy) { - BpmnEngineCamunda8 bpmnEngineCamunda8 = new BpmnEngineCamunda8(benchmarkStartPiExceptionHandlingStrategy); - bpmnEngineCamunda8.serverDefinition = new BpmnEngineList.BpmnServerDefinition(); - bpmnEngineCamunda8.serverDefinition.serverType = BpmnEngineList.CamundaEngine.CAMUNDA_8; - bpmnEngineCamunda8.serverDefinition = new BpmnEngineList.BpmnServerDefinition(); - bpmnEngineCamunda8.serverDefinition.zeebeGatewayAddress = zeebeSelfGatewayAddress; - bpmnEngineCamunda8.serverDefinition.zeebePlainText = zeebePlainText; - - - /* - * Connection to Operate + public static final String THIS_IS_A_COMPLETE_IMPOSSIBLE_VARIABLE_NAME = "ThisIsACompleteImpossibleVariableName"; + public static final int SEARCH_MAX_SIZE = 100; + public static final String SAAS_AUTHENTICATE_URL = "https://login.cloud.camunda.io/oauth/token"; + private final Logger logger = LoggerFactory.getLogger(BpmnEngineCamunda8.class); + private final BenchmarkStartPiExceptionHandlingStrategy exceptionHandlingStrategy; + boolean hightFlowMode = false; + /** + * It is not possible to search user task for a specfic processInstance. So, to realize this, a marker is created in each process instance. Retrieving the user task, + * the process instance can be found and correction can be done */ - bpmnEngineCamunda8.serverDefinition.operateUserName = operateUserName; - bpmnEngineCamunda8.serverDefinition.operateUserPassword = operateUserPassword; - bpmnEngineCamunda8.serverDefinition.operateUrl = operateUrl; - bpmnEngineCamunda8.serverDefinition.taskListUrl = tasklistUrl; - return bpmnEngineCamunda8; - - } - - /** - * Constructor to specify a Self Manage Zeebe Address por a Zeebe Saas - * - * @param zeebeSaasCloudRegion Saas Cloud region - * @param zeebeSaasCloudClusterId Saas Cloud ClusterID - * @param zeebeSaasCloudClientId Saas Cloud ClientID - * @param zeebeSaasClientSecret Saas Cloud Client Secret - * @param operateUrl URL to access Operate - * @param operateUserName Operate user name - * @param operateUserPassword Operate password - * @param tasklistUrl Url to access TaskList - */ - public static BpmnEngineCamunda8 getFromCamunda8SaaS(String zeebeSaasCloudRegion, - String zeebeSaasCloudClusterId, - String zeebeSaasAudience, - String zeebeSaasCloudClientId, - String zeebeSaasClientSecret, - String zeebeSaasAuthenticationUrl, - String operateUrl, - String operateUserName, - String operateUserPassword, - String tasklistUrl, - BenchmarkStartPiExceptionHandlingStrategy benchmarkStartPiExceptionHandlingStrategy) { - BpmnEngineCamunda8 bpmnEngineCamunda8 = new BpmnEngineCamunda8(benchmarkStartPiExceptionHandlingStrategy); - bpmnEngineCamunda8.serverDefinition = new BpmnEngineList.BpmnServerDefinition(); - bpmnEngineCamunda8.serverDefinition.serverType = BpmnEngineList.CamundaEngine.CAMUNDA_8; - - - /* - * SaaS Zeebe - */ - bpmnEngineCamunda8.serverDefinition.zeebeSaasRegion = zeebeSaasCloudRegion; - bpmnEngineCamunda8.serverDefinition.zeebeSaasClusterId = zeebeSaasCloudClusterId; - bpmnEngineCamunda8.serverDefinition.zeebeClientId = zeebeSaasCloudClientId; - bpmnEngineCamunda8.serverDefinition.zeebeClientSecret = zeebeSaasClientSecret; - bpmnEngineCamunda8.serverDefinition.authenticationUrl = zeebeSaasAuthenticationUrl; - bpmnEngineCamunda8.serverDefinition.zeebeAudience = zeebeSaasAudience; - - /* - * Connection to Operate - */ - bpmnEngineCamunda8.serverDefinition.operateUserName = operateUserName; - bpmnEngineCamunda8.serverDefinition.operateUserPassword = operateUserPassword; - bpmnEngineCamunda8.serverDefinition.operateUrl = operateUrl; - bpmnEngineCamunda8.serverDefinition.taskListUrl = tasklistUrl; - return bpmnEngineCamunda8; - } - - @Override - public void init() { - // nothing to do there - } - - public void connection() throws AutomatorException { - - this.typeCamundaEngine = this.serverDefinition.serverType; - StringBuilder analysis = new StringBuilder(); - try { - connectZeebe(analysis); - connectOperate(analysis); - connectTaskList(analysis); - logger.info("Zeebe: OK, Operate: OK, TaskList:OK {}", analysis); - - } catch (AutomatorException e) { - zeebeClient = null; - throw e; + Map<String, Long> cacheProcessInstanceMarker = new HashMap<>(); + Random random = new Random(System.currentTimeMillis()); + private BpmnEngineList.BpmnServerDefinition serverDefinition; + private ZeebeClient zeebeClient; + private CamundaOperateClient operateClient; + private CamundaTaskListClient taskClient; + // Default + private BpmnEngineList.CamundaEngine typeCamundaEngine = BpmnEngineList.CamundaEngine.CAMUNDA_8; + + private BpmnEngineCamunda8(BenchmarkStartPiExceptionHandlingStrategy exceptionHandlingStrategy) { + this.exceptionHandlingStrategy = exceptionHandlingStrategy; } - } - - public void disconnection() { - // nothing to do here - } - - /** - * Engine is ready. If not, a connection() method must be call - * - * @return true if the engine is ready - */ - public boolean isReady() { - return zeebeClient != null; - } - - /* ******************************************************************** */ - /* */ - /* Manage process instance */ - /* */ - /* ******************************************************************** */ - - /** - * HighFlowMode: when true, the class does not save anything, to reduce the footprint - * - * @param highFlowMode true or false - */ - public void turnHighFlowMode(boolean highFlowMode) { - this.hightFlowMode = highFlowMode; - } - - @Override - public String createProcessInstance(String processId, String starterEventId, Map<String, Object> variables) - throws AutomatorException { - try { - String marker = null; - if (!hightFlowMode) { - marker = getUniqueMarker(processId, starterEventId); - variables.put(THIS_IS_A_COMPLETE_IMPOSSIBLE_VARIABLE_NAME, marker); - } - FinalCommandStep createCommand = zeebeClient.newCreateInstanceCommand() - .bpmnProcessId(processId) - .latestVersion() - .variables(variables); - RefactoredCommandWrapper command = new RefactoredCommandWrapper(createCommand, - System.currentTimeMillis() + 5 * 60 * 1000, - // 5 minutes - "CreatePi" + processId, exceptionHandlingStrategy); - - ProcessInstanceEvent workflowInstanceEvent = (ProcessInstanceEvent) command.executeSync(); - Long processInstanceId = workflowInstanceEvent.getProcessInstanceKey(); - if (!hightFlowMode) { - cacheProcessInstanceMarker.put(marker, processInstanceId); - } - return String.valueOf(processInstanceId); - } catch (Exception e) { - throw new AutomatorException("CreateProcessInstance Error[" + processId + "] :" + e.getMessage()); - } - } - - public String createProcessInstanceDirect(String processId, String starterEventId, Map<String, Object> variables) - throws AutomatorException { - try { - String marker = null; - if (!hightFlowMode) { - marker = getUniqueMarker(processId, starterEventId); - variables.put(THIS_IS_A_COMPLETE_IMPOSSIBLE_VARIABLE_NAME, marker); - } + /** + * Constructor from existing object + * + * @param serverDefinition server definition + * @param logDebug if true, operation will be logged as debug level + */ + public static BpmnEngineCamunda8 getFromServerDefinition(BpmnEngineList.BpmnServerDefinition serverDefinition, + BenchmarkStartPiExceptionHandlingStrategy benchmarkStartPiExceptionHandlingStrategy, + boolean logDebug) { + BpmnEngineCamunda8 bpmnEngineCamunda8 = new BpmnEngineCamunda8(benchmarkStartPiExceptionHandlingStrategy); + bpmnEngineCamunda8.serverDefinition = serverDefinition; + return bpmnEngineCamunda8; - ProcessInstanceEvent workflowInstanceEvent = zeebeClient.newCreateInstanceCommand() - .bpmnProcessId(processId) - .latestVersion() - .variables(variables) - .send() - .join(); - Long processInstanceId = workflowInstanceEvent.getProcessInstanceKey(); - if (!hightFlowMode) { - cacheProcessInstanceMarker.put(marker, processInstanceId); - } - return String.valueOf(processInstanceId); - } catch (Exception e) { - throw new AutomatorException("Can't create in process [" + processId + "] :" + e.getMessage()); } - } - - - /* ******************************************************************** */ - /* */ - /* User tasks */ - /* */ - /* ******************************************************************** */ - - @Override - public void endProcessInstance(String processInstanceId, boolean cleanAll) throws AutomatorException { - // clean in the cache - List<String> markers = cacheProcessInstanceMarker.entrySet() - .stream() - .filter(t -> t.getValue().equals(Long.valueOf(processInstanceId))) - .map(Map.Entry::getKey) - .toList(); - markers.forEach(t -> cacheProcessInstanceMarker.remove(t)); - - } - - @Override - public List<String> searchUserTasksByProcessInstance(String processInstanceId, String userTaskId, int maxResult) - throws AutomatorException { - try { - // impossible to filter by the task name/ task type, so be ready to get a lot of flowNode and search the correct one - Long processInstanceIdLong = Long.valueOf(processInstanceId); - - TaskSearch taskSearch = new TaskSearch(); - taskSearch.setState(TaskState.CREATED); - taskSearch.setAssigned(Boolean.FALSE); - taskSearch.setWithVariables(true); - taskSearch.setPagination(new Pagination().setPageSize(maxResult)); - - TaskList tasksList = taskClient.getTasks(taskSearch); - List<String> listTasksResult = new ArrayList<>(); - do { - listTasksResult.addAll(tasksList.getItems().stream().filter(t -> { - List<Variable> listVariables = t.getVariables(); - Optional<Variable> markerTask = listVariables.stream() - .filter(v -> v.getName().equals(THIS_IS_A_COMPLETE_IMPOSSIBLE_VARIABLE_NAME)) - .findFirst(); - - if (markerTask.isEmpty()) - return false; - Long processInstanceIdTask = cacheProcessInstanceMarker.get(markerTask.get().getValue()); - return (processInstanceIdLong.equals(processInstanceIdTask)); - }).map(Task::getId) // Task to ID - .toList()); - - if (tasksList.size() > 0) - tasksList = taskClient.after(tasksList); - } while (tasksList.size() > 0); - return listTasksResult; + /** + * Constructor to specify a Self Manage Zeebe Address por a Zeebe Saas + * + * @param zeebeSelfGatewayAddress Self Manage : zeebe address + * @param zeebePlainText Self Manage: Plain text + * @param operateUrl URL to access Operate + * @param operateUserName Operate user name + * @param operateUserPassword Operate password + * @param tasklistUrl Url to access TaskList + */ + public static BpmnEngineCamunda8 getFromCamunda8(String zeebeSelfGatewayAddress, + Boolean zeebePlainText, + String operateUrl, + String operateUserName, + String operateUserPassword, + String tasklistUrl, + BenchmarkStartPiExceptionHandlingStrategy benchmarkStartPiExceptionHandlingStrategy) { + BpmnEngineCamunda8 bpmnEngineCamunda8 = new BpmnEngineCamunda8(benchmarkStartPiExceptionHandlingStrategy); + bpmnEngineCamunda8.serverDefinition = new BpmnEngineList.BpmnServerDefinition(); + bpmnEngineCamunda8.serverDefinition.serverType = BpmnEngineList.CamundaEngine.CAMUNDA_8; + bpmnEngineCamunda8.serverDefinition = new BpmnEngineList.BpmnServerDefinition(); + bpmnEngineCamunda8.serverDefinition.zeebeGatewayAddress = zeebeSelfGatewayAddress; + bpmnEngineCamunda8.serverDefinition.zeebePlainText = zeebePlainText; + + + /* + * Connection to Operate + */ + bpmnEngineCamunda8.serverDefinition.operateUserName = operateUserName; + bpmnEngineCamunda8.serverDefinition.operateUserPassword = operateUserPassword; + bpmnEngineCamunda8.serverDefinition.operateUrl = operateUrl; + bpmnEngineCamunda8.serverDefinition.taskListUrl = tasklistUrl; + return bpmnEngineCamunda8; - } catch (TaskListException e) { - throw new AutomatorException("Can't search users task " + e.getMessage()); } - } - - @Override - public List<String> searchUserTasks(String userTaskId, int maxResult) throws AutomatorException { - try { - // impossible to filter by the task name/ task type, so be ready to get a lot of flowNode and search the correct one - - TaskSearch taskSearch = new TaskSearch(); - taskSearch.setState(TaskState.CREATED); - taskSearch.setAssigned(Boolean.FALSE); - taskSearch.setWithVariables(true); - taskSearch.setPagination(new Pagination().setPageSize(maxResult)); - - TaskList tasksList = taskClient.getTasks(taskSearch); - List<String> listTasksResult = new ArrayList<>(); - do { - listTasksResult.addAll(tasksList.getItems().stream().map(Task::getId) // Task to ID - .toList()); - - if (tasksList.size() > 0) - tasksList = taskClient.after(tasksList); - } while (tasksList.size() > 0); - return listTasksResult; - - } catch (TaskListException e) { - throw new AutomatorException("Can't search users task " + e.getMessage()); - } - } - - /* ******************************************************************** */ - /* */ - /* Service tasks */ - /* */ - /* ******************************************************************** */ - @Override - public RegisteredTask registerServiceTask(String workerId, - String topic, - boolean streamEnabled, - Duration lockTime, - Object jobHandler, - FixedBackoffSupplier backoffSupplier) { - if (!(jobHandler instanceof JobHandler)) { - logger.error("handler is not a JobHandler implementation, can't register the worker [{}], topic [{}]", workerId, - topic); - return null; + /** + * Constructor to specify a Self Manage Zeebe Address por a Zeebe Saas + * + * @param zeebeSaasCloudRegion Saas Cloud region + * @param zeebeSaasCloudClusterId Saas Cloud ClusterID + * @param zeebeSaasCloudClientId Saas Cloud ClientID + * @param zeebeSaasClientSecret Saas Cloud Client Secret + * @param operateUrl URL to access Operate + * @param operateUserName Operate user name + * @param operateUserPassword Operate password + * @param tasklistUrl Url to access TaskList + */ + public static BpmnEngineCamunda8 getFromCamunda8SaaS(String zeebeSaasCloudRegion, + String zeebeSaasCloudClusterId, + String zeebeSaasAudience, + String zeebeSaasCloudClientId, + String zeebeSaasClientSecret, + String zeebeSaasAuthenticationUrl, + String operateUrl, + String operateUserName, + String operateUserPassword, + String tasklistUrl, + BenchmarkStartPiExceptionHandlingStrategy benchmarkStartPiExceptionHandlingStrategy) { + BpmnEngineCamunda8 bpmnEngineCamunda8 = new BpmnEngineCamunda8(benchmarkStartPiExceptionHandlingStrategy); + bpmnEngineCamunda8.serverDefinition = new BpmnEngineList.BpmnServerDefinition(); + bpmnEngineCamunda8.serverDefinition.serverType = BpmnEngineList.CamundaEngine.CAMUNDA_8; + + + /* + * SaaS Zeebe + */ + bpmnEngineCamunda8.serverDefinition.zeebeSaasRegion = zeebeSaasCloudRegion; + bpmnEngineCamunda8.serverDefinition.zeebeSaasClusterId = zeebeSaasCloudClusterId; + bpmnEngineCamunda8.serverDefinition.zeebeClientId = zeebeSaasCloudClientId; + bpmnEngineCamunda8.serverDefinition.zeebeClientSecret = zeebeSaasClientSecret; + bpmnEngineCamunda8.serverDefinition.authenticationUrl = zeebeSaasAuthenticationUrl; + bpmnEngineCamunda8.serverDefinition.zeebeAudience = zeebeSaasAudience; + + /* + * Connection to Operate + */ + bpmnEngineCamunda8.serverDefinition.operateUserName = operateUserName; + bpmnEngineCamunda8.serverDefinition.operateUserPassword = operateUserPassword; + bpmnEngineCamunda8.serverDefinition.operateUrl = operateUrl; + bpmnEngineCamunda8.serverDefinition.taskListUrl = tasklistUrl; + return bpmnEngineCamunda8; } - if (topic == null) { - logger.error("topic must not be null, can't register the worker [{}]", workerId); - return null; + @Override + public void init() { + // nothing to do there } - RegisteredTask registeredTask = new RegisteredTask(); - - logger.info("Create worker[{}] Topic[{}] StreamEnabled[{}] LockTime[{}] WorkerExecutionThreads[{}] MaxJobsActive[{}]", // label - workerId,topic,streamEnabled,lockTime, - serverDefinition.workerExecutionThreads, - serverDefinition.workerMaxJobsActive); + public void connection() throws AutomatorException { - JobWorkerBuilderStep1.JobWorkerBuilderStep3 step3 = zeebeClient.newWorker() - .jobType(topic) - .handler((JobHandler) jobHandler) - .timeout(lockTime) - .streamEnabled(streamEnabled) - .name(workerId); + this.typeCamundaEngine = this.serverDefinition.serverType; + StringBuilder analysis = new StringBuilder(); + try { + connectZeebe(analysis); + connectOperate(analysis); + connectTaskList(analysis); + logger.info("Zeebe: OK, Operate: OK, TaskList:OK {}", analysis); + + } catch (AutomatorException e) { + zeebeClient = null; + throw e; + } + } - if (backoffSupplier != null) { - step3.backoffSupplier(backoffSupplier); + public void disconnection() { + // nothing to do here } - registeredTask.jobWorker = step3.open(); - return registeredTask; - } - @Override - public void executeUserTask(String userTaskId, String userId, Map<String, Object> variables) - throws AutomatorException { - try { - taskClient.claim(userTaskId, serverDefinition.operateUserName); - taskClient.completeTask(userTaskId, variables); - } catch (TaskListException e) { - throw new AutomatorException("Can't execute task [" + userTaskId + "]"); + /** + * Engine is ready. If not, a connection() method must be call + * + * @return true if the engine is ready + */ + public boolean isReady() { + return zeebeClient != null; } - } - @Override - public List<String> searchServiceTasks(String processInstanceId, String serviceTaskId, String topic, int maxResult) - throws AutomatorException { - try { - if (operateClient == null) { - throw new AutomatorException("No Operate connection was provided"); - } - long processInstanceIdLong = Long.parseLong(processInstanceId); + /* ******************************************************************** */ + /* */ + /* Manage process instance */ + /* */ + /* ******************************************************************** */ - ProcessInstanceFilter processInstanceFilter = ProcessInstanceFilter.builder() - .parentKey(processInstanceIdLong) - .build(); + /** + * HighFlowMode: when true, the class does not save anything, to reduce the footprint + * + * @param highFlowMode true or false + */ + public void turnHighFlowMode(boolean highFlowMode) { + this.hightFlowMode = highFlowMode; + } - SearchQuery processInstanceQuery = new SearchQuery.Builder().filter(processInstanceFilter).size(100).build(); - - List<ProcessInstance> listProcessInstances = operateClient.searchProcessInstances(processInstanceQuery); - Set<Long> setProcessInstances = listProcessInstances.stream() - .map(ProcessInstance::getKey) - .collect(Collectors.toSet()); - setProcessInstances.add(processInstanceIdLong); - - ActivateJobsResponse jobsResponse = zeebeClient.newActivateJobsCommand() - .jobType(topic) - .maxJobsToActivate(10000) - .workerName(Thread.currentThread().getName()) - .send() - .join(); - List<String> listJobsId = new ArrayList<>(); - - for (ActivatedJob job : jobsResponse.getJobs()) { - if (setProcessInstances.contains(job.getProcessInstanceKey())) - listJobsId.add(String.valueOf(job.getKey())); - else { - zeebeClient.newFailCommand(job.getKey()).retries(2).send().join(); + @Override + public String createProcessInstance(String processId, String starterEventId, Map<String, Object> variables) + throws AutomatorException { + try { + String marker = null; + if (!hightFlowMode) { + marker = getUniqueMarker(processId, starterEventId); + variables.put(THIS_IS_A_COMPLETE_IMPOSSIBLE_VARIABLE_NAME, marker); + } + + FinalCommandStep createCommand = zeebeClient.newCreateInstanceCommand() + .bpmnProcessId(processId) + .latestVersion() + .variables(variables); + RefactoredCommandWrapper command = new RefactoredCommandWrapper(createCommand, + System.currentTimeMillis() + 5 * 60 * 1000, + // 5 minutes + "CreatePi" + processId, exceptionHandlingStrategy); + + ProcessInstanceEvent workflowInstanceEvent = (ProcessInstanceEvent) command.executeSync(); + Long processInstanceId = workflowInstanceEvent.getProcessInstanceKey(); + if (!hightFlowMode) { + cacheProcessInstanceMarker.put(marker, processInstanceId); + } + return String.valueOf(processInstanceId); + } catch (Exception e) { + throw new AutomatorException("CreateProcessInstance Error[" + processId + "] :" + e.getMessage()); } - } - return listJobsId; - - } catch (Exception e) { - throw new AutomatorException("Can't search service task topic[" + topic + "] : " + e.getMessage()); } - } - + public String createProcessInstanceDirect(String processId, String starterEventId, Map<String, Object> variables) + throws AutomatorException { + try { + String marker = null; + if (!hightFlowMode) { + marker = getUniqueMarker(processId, starterEventId); + variables.put(THIS_IS_A_COMPLETE_IMPOSSIBLE_VARIABLE_NAME, marker); + } + + ProcessInstanceEvent workflowInstanceEvent = zeebeClient.newCreateInstanceCommand() + .bpmnProcessId(processId) + .latestVersion() + .variables(variables) + .send() + .join(); + Long processInstanceId = workflowInstanceEvent.getProcessInstanceKey(); + if (!hightFlowMode) { + cacheProcessInstanceMarker.put(marker, processInstanceId); + } + return String.valueOf(processInstanceId); + } catch (Exception e) { + throw new AutomatorException("Can't create in process [" + processId + "] :" + e.getMessage()); + } + } - /* ******************************************************************** */ - /* */ - /* generic search */ - /* */ - /* ******************************************************************** */ + /* ******************************************************************** */ + /* */ + /* User tasks */ + /* */ + /* ******************************************************************** */ - @Override - public void executeServiceTask(String serviceTaskId, String workerId, Map<String, Object> variables) - throws AutomatorException { - try { - zeebeClient.newCompleteCommand(Long.valueOf(serviceTaskId)).variables(variables).send().join(); - } catch (Exception e) { - throw new AutomatorException("Can't execute service task " + e.getMessage()); - } - } + @Override + public void endProcessInstance(String processInstanceId, boolean cleanAll) throws AutomatorException { + // clean in the cache + List<String> markers = cacheProcessInstanceMarker.entrySet() + .stream() + .filter(t -> t.getValue().equals(Long.valueOf(processInstanceId))) + .map(Map.Entry::getKey) + .toList(); + markers.forEach(t -> cacheProcessInstanceMarker.remove(t)); - public void throwBpmnServiceTask(String serviceTaskId, - String workerId, - String errorCode, - String errorMessage, - Map<String, Object> variables) throws AutomatorException { - try { - zeebeClient.newThrowErrorCommand(Long.valueOf(serviceTaskId)) - .errorCode(errorCode) - .errorMessage(errorMessage) - .variables(variables) - .send() - .join(); - } catch (Exception e) { - throw new AutomatorException("Can't execute service task " + e.getMessage()); } - } - @Override - public List<TaskDescription> searchTasksByProcessInstanceId(String processInstanceId, String taskId, int maxResult) - throws AutomatorException { - try { - if (operateClient == null) { - throw new AutomatorException("No Operate connection was provided"); - } - - // impossible to filter by the task name/ task tyoe, so be ready to get a lot of flowNode and search the correct onee - FlowNodeInstanceFilter flownodeFilter = FlowNodeInstanceFilter.builder() - .processInstanceKey(Long.valueOf(processInstanceId)) - .build(); - - SearchQuery flownodeQuery = new SearchQuery.Builder().filter(flownodeFilter).size(maxResult).build(); - List<FlowNodeInstance> flownodes = operateClient.searchFlowNodeInstances(flownodeQuery); - return flownodes.stream().filter(t -> taskId.equals(t.getFlowNodeId())).map(t -> { - TaskDescription taskDescription = new TaskDescription(); - taskDescription.taskId = t.getFlowNodeId(); - taskDescription.type = getTaskType(t.getType()); // to implement - taskDescription.isCompleted = FlowNodeInstanceState.COMPLETED.equals(t.getState()); // to implement - return taskDescription; - }).toList(); - - } catch (OperateException e) { - throw new AutomatorException("Can't search users task " + e.getMessage()); + @Override + public List<String> searchUserTasksByProcessInstance(String processInstanceId, String userTaskId, int maxResult) + throws AutomatorException { + try { + // impossible to filter by the task name/ task type, so be ready to get a lot of flowNode and search the correct one + Long processInstanceIdLong = Long.valueOf(processInstanceId); + + TaskSearch taskSearch = new TaskSearch(); + taskSearch.setState(TaskState.CREATED); + taskSearch.setAssigned(Boolean.FALSE); + taskSearch.setWithVariables(true); + taskSearch.setPagination(new Pagination().setPageSize(maxResult)); + + TaskList tasksList = taskClient.getTasks(taskSearch); + List<String> listTasksResult = new ArrayList<>(); + do { + listTasksResult.addAll(tasksList.getItems().stream().filter(t -> { + List<Variable> listVariables = t.getVariables(); + Optional<Variable> markerTask = listVariables.stream() + .filter(v -> v.getName().equals(THIS_IS_A_COMPLETE_IMPOSSIBLE_VARIABLE_NAME)) + .findFirst(); + + if (markerTask.isEmpty()) + return false; + Long processInstanceIdTask = cacheProcessInstanceMarker.get(markerTask.get().getValue()); + return (processInstanceIdLong.equals(processInstanceIdTask)); + }).map(Task::getId) // Task to ID + .toList()); + + if (tasksList.size() > 0) + tasksList = taskClient.after(tasksList); + } while (tasksList.size() > 0); + + return listTasksResult; + + } catch (TaskListException e) { + throw new AutomatorException("Can't search users task " + e.getMessage()); + } } - } - public List<ProcessDescription> searchProcessInstanceByVariable(String processId, - Map<String, Object> filterVariables, - int maxResult) throws AutomatorException { - try { - if (operateClient == null) { - throw new AutomatorException("No Operate connection was provided"); - } + @Override + public List<String> searchUserTasks(String userTaskId, int maxResult) throws AutomatorException { + try { + // impossible to filter by the task name/ task type, so be ready to get a lot of flowNode and search the correct one - // impossible to filter by the task name/ task tyoe, so be ready to get a lot of flowNode and search the correct onee - ProcessInstanceFilter processInstanceFilter = ProcessInstanceFilter.builder().bpmnProcessId(processId).build(); + TaskSearch taskSearch = new TaskSearch(); + taskSearch.setState(TaskState.CREATED); + taskSearch.setAssigned(Boolean.FALSE); + taskSearch.setWithVariables(true); + taskSearch.setPagination(new Pagination().setPageSize(maxResult)); - SearchQuery processInstanceQuery = new SearchQuery.Builder().filter(processInstanceFilter) - .size(maxResult) - .build(); - List<ProcessInstance> listProcessInstances = operateClient.searchProcessInstances(processInstanceQuery); + TaskList tasksList = taskClient.getTasks(taskSearch); + List<String> listTasksResult = new ArrayList<>(); + do { + listTasksResult.addAll(tasksList.getItems().stream().map(Task::getId) // Task to ID + .toList()); - List<ProcessDescription> listProcessInstanceFind = new ArrayList<>(); - // now, we have to filter based on variableName/value + if (tasksList.size() > 0) + tasksList = taskClient.after(tasksList); + } while (tasksList.size() > 0); - for (ProcessInstance processInstance : listProcessInstances) { - Map<String, Object> processVariables = getVariables(processInstance.getKey().toString()); - List<Map.Entry<String, Object>> entriesNotFiltered = filterVariables.entrySet() - .stream() - .filter( - t -> processVariables.containsKey(t.getKey()) && processVariables.get(t.getKey()).equals(t.getValue())) - .toList(); + return listTasksResult; - if (entriesNotFiltered.isEmpty()) { + } catch (TaskListException e) { + throw new AutomatorException("Can't search users task " + e.getMessage()); + } + } - ProcessDescription processDescription = new ProcessDescription(); - processDescription.processInstanceId = processInstance.getKey().toString(); + /* ******************************************************************** */ + /* */ + /* Service tasks */ + /* */ + /* ******************************************************************** */ + @Override + public RegisteredTask registerServiceTask(String workerId, + String topic, + boolean streamEnabled, + Duration lockTime, + Object jobHandler, + FixedBackoffSupplier backoffSupplier) { + if (!(jobHandler instanceof JobHandler)) { + logger.error("handler is not a JobHandler implementation, can't register the worker [{}], topic [{}]", workerId, + topic); + return null; + } + if (topic == null) { + logger.error("topic must not be null, can't register the worker [{}]", workerId); + return null; - listProcessInstanceFind.add(processDescription); } - } - return listProcessInstanceFind; - } catch (OperateException e) { - throw new AutomatorException("Can't search users task " + e.getMessage()); - } - } - - private ScenarioStep.Step getTaskType(String taskTypeC8) { - if (taskTypeC8.equals("SERVICE_TASK")) - return ScenarioStep.Step.SERVICETASK; - else if (taskTypeC8.equals("USER_TASK")) - return ScenarioStep.Step.USERTASK; - else if (taskTypeC8.equals("START_EVENT")) - return ScenarioStep.Step.STARTEVENT; - else if (taskTypeC8.equals("END_EVENT")) - return ScenarioStep.Step.ENDEVENT; - else if (taskTypeC8.equals("EXCLUSIVE_GATEWAY")) - return ScenarioStep.Step.EXCLUSIVEGATEWAY; - else if (taskTypeC8.equals("PARALLEL_GATEWAY")) - return ScenarioStep.Step.PARALLELGATEWAY; - - return null; - } - - @Override - public Map<String, Object> getVariables(String processInstanceId) throws AutomatorException { - try { - if (operateClient == null) { - throw new AutomatorException("No Operate connection was provided"); - } + RegisteredTask registeredTask = new RegisteredTask(); - // impossible to filter by the task name/ task tyoe, so be ready to get a lot of flowNode and search the correct onee - VariableFilter variableFilter = VariableFilter.builder() - .processInstanceKey(Long.valueOf(processInstanceId)) - .build(); + logger.info("Create worker[{}] Topic[{}] StreamEnabled[{}] LockTime[{}] WorkerExecutionThreads[{}] MaxJobsActive[{}]", // label + workerId, topic, streamEnabled, lockTime, + serverDefinition.workerExecutionThreads, + serverDefinition.workerMaxJobsActive); - SearchQuery variableQuery = new SearchQuery.Builder().filter(variableFilter).build(); - List<io.camunda.operate.model.Variable> listVariables = operateClient.searchVariables(variableQuery); - Map<String, Object> variables = new HashMap<>(); - listVariables.forEach(t -> variables.put(t.getName(), t.getValue())); + JobWorkerBuilderStep1.JobWorkerBuilderStep3 step3 = zeebeClient.newWorker() + .jobType(topic) + .handler((JobHandler) jobHandler) + .timeout(lockTime) + .streamEnabled(streamEnabled) + .name(workerId); - return variables; - } catch (OperateException e) { - throw new AutomatorException("Can't search variables task " + e.getMessage()); - } - } - - /* ******************************************************************** */ - /* */ - /* CountInformation */ - /* */ - /* ******************************************************************** */ - public long countNumberOfProcessInstancesCreated(String processId, DateFilter startDate, DateFilter endDate) - throws AutomatorException { - if (operateClient == null) { - throw new AutomatorException("No Operate connection was provided"); + if (backoffSupplier != null) { + step3.backoffSupplier(backoffSupplier); + } + registeredTask.jobWorker = step3.open(); + return registeredTask; } - SearchQuery.Builder queryBuilder = new SearchQuery.Builder(); - try { - int cumul = 0; - SearchResult<ProcessInstance> searchResult = null; - queryBuilder = queryBuilder.filter(ProcessInstanceFilter.builder().bpmnProcessId(processId).build()); - queryBuilder.sort(new Sort("key", SortOrder.ASC)); - int maxLoop = 0; - do { - maxLoop++; - if (searchResult != null && !searchResult.getItems().isEmpty()) { - queryBuilder.searchAfter(searchResult.getSortValues()); + @Override + public void executeUserTask(String userTaskId, String userId, Map<String, Object> variables) + throws AutomatorException { + try { + taskClient.claim(userTaskId, serverDefinition.operateUserName); + taskClient.completeTask(userTaskId, variables); + } catch (TaskListException e) { + throw new AutomatorException("Can't execute task [" + userTaskId + "]"); } - SearchQuery searchQuery = queryBuilder.build(); - searchQuery.setSize(SEARCH_MAX_SIZE); - searchResult = operateClient.searchProcessInstanceResults(searchQuery); - - cumul += searchResult.getItems().stream().filter(t -> t.getStartDate().after(startDate.getDate())).count(); - - } while (searchResult.getItems().size() >= SEARCH_MAX_SIZE && maxLoop < 1000); - return cumul; - } catch (Exception e) { - throw new AutomatorException("Search countNumberProcessInstanceCreated " + e.getMessage()); } - } - public long countNumberOfProcessInstancesEnded(String processId, DateFilter startDate, DateFilter endDate) - throws AutomatorException { - if (operateClient == null) { - throw new AutomatorException("No Operate connection was provided"); - } + @Override + public List<String> searchServiceTasks(String processInstanceId, String serviceTaskId, String topic, int maxResult) + throws AutomatorException { + try { + if (operateClient == null) { + throw new AutomatorException("No Operate connection was provided"); + } + long processInstanceIdLong = Long.parseLong(processInstanceId); + + ProcessInstanceFilter processInstanceFilter = ProcessInstanceFilter.builder() + .parentKey(processInstanceIdLong) + .build(); + + SearchQuery processInstanceQuery = new SearchQuery.Builder().filter(processInstanceFilter).size(100).build(); + + List<ProcessInstance> listProcessInstances = operateClient.searchProcessInstances(processInstanceQuery); + Set<Long> setProcessInstances = listProcessInstances.stream() + .map(ProcessInstance::getKey) + .collect(Collectors.toSet()); + setProcessInstances.add(processInstanceIdLong); + + ActivateJobsResponse jobsResponse = zeebeClient.newActivateJobsCommand() + .jobType(topic) + .maxJobsToActivate(10000) + .workerName(Thread.currentThread().getName()) + .send() + .join(); + List<String> listJobsId = new ArrayList<>(); + + for (ActivatedJob job : jobsResponse.getJobs()) { + if (setProcessInstances.contains(job.getProcessInstanceKey())) + listJobsId.add(String.valueOf(job.getKey())); + else { + zeebeClient.newFailCommand(job.getKey()).retries(2).send().join(); + } + } + return listJobsId; - SearchQuery.Builder queryBuilder = new SearchQuery.Builder(); - try { - int cumul = 0; - SearchResult<ProcessInstance> searchResult = null; - - queryBuilder = queryBuilder.filter(ProcessInstanceFilter.builder().bpmnProcessId(processId) - // .startDate(startDate) - // .endDate(endDate) - .state(ProcessInstanceState.COMPLETED).build()); - - queryBuilder.sort(new Sort("key", SortOrder.ASC)); - int maxLoop = 0; - do { - maxLoop++; - if (searchResult != null && !searchResult.getItems().isEmpty()) { - queryBuilder.searchAfter(searchResult.getSortValues()); + } catch (Exception e) { + throw new AutomatorException("Can't search service task topic[" + topic + "] : " + e.getMessage()); } - SearchQuery searchQuery = queryBuilder.build(); - searchQuery.setSize(SEARCH_MAX_SIZE); - searchResult = operateClient.searchProcessInstanceResults(searchQuery); - cumul += searchResult.getItems().stream().filter(t -> t.getStartDate().after(startDate.getDate())).count(); + } - } while (searchResult.getItems().size() >= SEARCH_MAX_SIZE && maxLoop < 1000); - return cumul; - } catch (Exception e) { - throw new AutomatorException("Search countNumberProcessEnded " + e.getMessage()); - } - } - /* ******************************************************************** */ - /* */ - /* Deployment */ - /* */ - /* ******************************************************************** */ - - public long countNumberOfTasks(String processId, String taskId) throws AutomatorException { - if (operateClient == null) { - throw new AutomatorException("No Operate connection was provided"); - } - try { - int cumul = 0; - SearchResult<FlowNodeInstance> searchResult = null; - int maxLoop = 0; - do { - maxLoop++; + /* ******************************************************************** */ + /* */ + /* generic search */ + /* */ + /* ******************************************************************** */ - SearchQuery.Builder queryBuilder = new SearchQuery.Builder(); - queryBuilder = queryBuilder.filter(FlowNodeInstanceFilter.builder().flowNodeId(taskId).build()); - queryBuilder.sort(new Sort("key", SortOrder.ASC)); - if (searchResult != null && !searchResult.getItems().isEmpty()) { - queryBuilder.searchAfter(searchResult.getSortValues()); + @Override + public void executeServiceTask(String serviceTaskId, String workerId, Map<String, Object> variables) + throws AutomatorException { + try { + zeebeClient.newCompleteCommand(Long.valueOf(serviceTaskId)).variables(variables).send().join(); + } catch (Exception e) { + throw new AutomatorException("Can't execute service task " + e.getMessage()); } - SearchQuery searchQuery = queryBuilder.build(); - searchQuery.setSize(SEARCH_MAX_SIZE); - searchResult = operateClient.searchFlowNodeInstanceResults(searchQuery); - cumul += (long) searchResult.getItems().size(); - } while (searchResult.getItems().size() >= SEARCH_MAX_SIZE && maxLoop < 1000); - return cumul; - } catch (Exception e) { - throw new AutomatorException("Search countNumberProcessEnded " + e.getMessage()); } - } - - - /* ******************************************************************** */ - /* */ - /* get server definition */ - /* */ - /* ******************************************************************** */ - @Override - public String deployBpmn(File processFile, ScenarioDeployment.Policy policy) throws AutomatorException { - try { - DeploymentEvent event = zeebeClient.newDeployResourceCommand() - .addResourceFile(processFile.getAbsolutePath()) - .send() - .join(); + public void throwBpmnServiceTask(String serviceTaskId, + String workerId, + String errorCode, + String errorMessage, + Map<String, Object> variables) throws AutomatorException { + try { + zeebeClient.newThrowErrorCommand(Long.valueOf(serviceTaskId)) + .errorCode(errorCode) + .errorMessage(errorMessage) + .variables(variables) + .send() + .join(); + } catch (Exception e) { + throw new AutomatorException("Can't execute service task " + e.getMessage()); + } + } - return String.valueOf(event.getKey()); - } catch (Exception e) { - throw new AutomatorException("Can't deploy " + e.getMessage()); + /** + * @param processInstanceId filter on the processInstanceId. may be null + * @param filterTaskId filter on the taskId + * @param maxResult maximum Result + * @return list of Task + * @throws AutomatorException + */ + @Override + public List<TaskDescription> searchTasksByProcessInstanceId(String processInstanceId, String filterTaskId, int maxResult) + throws AutomatorException { + try { + if (operateClient == null) { + throw new AutomatorException("No Operate connection was provided"); + } + + // impossible to filter by the task name/ task tyoe, so be ready to get a lot of flowNode and search the correct onee + FlowNodeInstanceFilter flownodeFilter = FlowNodeInstanceFilter.builder() + .processInstanceKey(Long.valueOf(processInstanceId)) + .build(); + + SearchQuery flowNodeQuery = new SearchQuery.Builder().filter(flownodeFilter).size(maxResult).build(); + List<FlowNodeInstance> flowNodes = operateClient.searchFlowNodeInstances(flowNodeQuery); + return flowNodes.stream() + .filter(t -> filterTaskId == null || filterTaskId.equals(t.getFlowNodeId())) // Filter by name + .map(t -> { + TaskDescription taskDescription = new TaskDescription(); + taskDescription.taskId = t.getFlowNodeId(); + taskDescription.processInstanceId = String.valueOf(t.getProcessInstanceKey()); + taskDescription.startDate = t.getStartDate(); + taskDescription.endDate = t.getEndDate(); + taskDescription.type = getTaskType(t.getType()); // to implement + taskDescription.isCompleted = FlowNodeInstanceState.COMPLETED.equals(t.getState()); // to implement + return taskDescription; + }).toList(); + + } catch (OperateException e) { + throw new AutomatorException("Can't search users task " + e.getMessage()); + } } - } - @Override - public BpmnEngineList.CamundaEngine getTypeCamundaEngine() { - return typeCamundaEngine; - } + public List<ProcessDescription> searchProcessInstanceByVariable(String processId, + Map<String, Object> filterVariables, + int maxResult) throws AutomatorException { + try { + if (operateClient == null) { + throw new AutomatorException("No Operate connection was provided"); + } + + // impossible to filter by the task name/ task tyoe, so be ready to get a lot of flowNode and search the correct onee + ProcessInstanceFilter processInstanceFilter = ProcessInstanceFilter.builder().bpmnProcessId(processId).build(); + + SearchQuery processInstanceQuery = new SearchQuery.Builder().filter(processInstanceFilter) + .size(maxResult) + .build(); + List<ProcessInstance> listProcessInstances = operateClient.searchProcessInstances(processInstanceQuery); + + List<ProcessDescription> listProcessInstanceFind = new ArrayList<>(); + // now, we have to filter based on variableName/value + + for (ProcessInstance processInstance : listProcessInstances) { + Map<String, Object> processVariables = getVariables(processInstance.getKey().toString()); + List<Map.Entry<String, Object>> entriesNotFiltered = filterVariables.entrySet() + .stream() + .filter( + t -> processVariables.containsKey(t.getKey()) && processVariables.get(t.getKey()).equals(t.getValue())) + .toList(); + + if (entriesNotFiltered.isEmpty()) { + + ProcessDescription processDescription = new ProcessDescription(); + processDescription.processInstanceId = processInstance.getKey().toString(); + + listProcessInstanceFind.add(processDescription); + } + } + return listProcessInstanceFind; + } catch (OperateException e) { + throw new AutomatorException("Can't search users task " + e.getMessage()); + } + } - @Override - public String getSignature() { - String signature = typeCamundaEngine.toString() + " "; - if (typeCamundaEngine.equals(BpmnEngineList.CamundaEngine.CAMUNDA_8_SAAS)) - signature += - "Cloud ClientId[" + serverDefinition.zeebeClientId + "] ClusterId[" + serverDefinition.zeebeSaasClusterId - + "]"; - else - signature += "Address[" + serverDefinition.zeebeGatewayAddress + "]"; - signature += " numJobWorkerExecutionThreads[" + serverDefinition.workerExecutionThreads + "] workerMaxJobsActive[" - + serverDefinition.workerMaxJobsActive + "]"; - return signature; - } + private ScenarioStep.Step getTaskType(String taskTypeC8) { + if (taskTypeC8.equals("SERVICE_TASK")) + return ScenarioStep.Step.SERVICETASK; + else if (taskTypeC8.equals("USER_TASK")) + return ScenarioStep.Step.USERTASK; + else if (taskTypeC8.equals("START_EVENT")) + return ScenarioStep.Step.STARTEVENT; + else if (taskTypeC8.equals("END_EVENT")) + return ScenarioStep.Step.ENDEVENT; + else if (taskTypeC8.equals("EXCLUSIVE_GATEWAY")) + return ScenarioStep.Step.EXCLUSIVEGATEWAY; + else if (taskTypeC8.equals("PARALLEL_GATEWAY")) + return ScenarioStep.Step.PARALLELGATEWAY; + else if (taskTypeC8.equals("TASK")) + return ScenarioStep.Step.TASK; + else if (taskTypeC8.equals("SCRIPT_TASK")) + return ScenarioStep.Step.SCRIPTTASK; + + return null; + } - @Override - public int getWorkerExecutionThreads() { - return serverDefinition != null ? serverDefinition.workerExecutionThreads : 0; - } + @Override + public Map<String, Object> getVariables(String processInstanceId) throws AutomatorException { + try { + if (operateClient == null) { + throw new AutomatorException("No Operate connection was provided"); + } - private String getUniqueMarker(String processId, String starterEventId) { - return processId + "-" + random.nextInt(1000000); - } + // impossible to filter by the task name/ task tyoe, so be ready to get a lot of flowNode and search the correct onee + VariableFilter variableFilter = VariableFilter.builder() + .processInstanceKey(Long.valueOf(processInstanceId)) + .build(); - public ZeebeClient getZeebeClient() { - return zeebeClient; - } + SearchQuery variableQuery = new SearchQuery.Builder().filter(variableFilter).build(); + List<io.camunda.operate.model.Variable> listVariables = operateClient.searchVariables(variableQuery); + Map<String, Object> variables = new HashMap<>(); + listVariables.forEach(t -> variables.put(t.getName(), t.getValue())); + return variables; + } catch (OperateException e) { + throw new AutomatorException("Can't search variables task " + e.getMessage()); + } + } - /* ******************************************************************** */ - /* */ - /* Connection to each component */ - /* */ - /* ******************************************************************** */ + /* ******************************************************************** */ + /* */ + /* CountInformation */ + /* */ + /* ******************************************************************** */ + public long countNumberOfProcessInstancesCreated(String processId, DateFilter startDate, DateFilter endDate) + throws AutomatorException { + if (operateClient == null) { + throw new AutomatorException("No Operate connection was provided"); + } - private void connectZeebe(StringBuilder analysis) throws AutomatorException { + SearchQuery.Builder queryBuilder = new SearchQuery.Builder(); + try { + int cumul = 0; + SearchResult<ProcessInstance> searchResult = null; + queryBuilder = queryBuilder.filter(ProcessInstanceFilter.builder().bpmnProcessId(processId).build()); + queryBuilder.sort(new Sort("key", SortOrder.ASC)); + int maxLoop = 0; + do { + maxLoop++; + if (searchResult != null && !searchResult.getItems().isEmpty()) { + queryBuilder.searchAfter(searchResult.getSortValues()); + } + SearchQuery searchQuery = queryBuilder.build(); + searchQuery.setSize(SEARCH_MAX_SIZE); + searchResult = operateClient.searchProcessInstanceResults(searchQuery); + + cumul += searchResult.getItems().stream().filter(t -> t.getStartDate().after(startDate.getDate())).count(); + + } while (searchResult.getItems().size() >= SEARCH_MAX_SIZE && maxLoop < 1000); + return cumul; + } catch (Exception e) { + throw new AutomatorException("Search countNumberProcessInstanceCreated " + e.getMessage()); + } + } - // connection is critical, so let build the analysis + public long countNumberOfProcessInstancesEnded(String processId, DateFilter startDate, DateFilter endDate) + throws AutomatorException { + if (operateClient == null) { + throw new AutomatorException("No Operate connection was provided"); + } - boolean isOk = true; + SearchQuery.Builder queryBuilder = new SearchQuery.Builder(); + try { + int cumul = 0; + SearchResult<ProcessInstance> searchResult = null; + + queryBuilder = queryBuilder.filter(ProcessInstanceFilter.builder().bpmnProcessId(processId) + // .startDate(startDate) + // .endDate(endDate) + .state(ProcessInstanceState.COMPLETED).build()); + + queryBuilder.sort(new Sort("key", SortOrder.ASC)); + int maxLoop = 0; + do { + maxLoop++; + if (searchResult != null && !searchResult.getItems().isEmpty()) { + queryBuilder.searchAfter(searchResult.getSortValues()); + } + SearchQuery searchQuery = queryBuilder.build(); + searchQuery.setSize(SEARCH_MAX_SIZE); + searchResult = operateClient.searchProcessInstanceResults(searchQuery); + cumul += searchResult.getItems().stream().filter(t -> t.getStartDate().after(startDate.getDate())).count(); + + } while (searchResult.getItems().size() >= SEARCH_MAX_SIZE && maxLoop < 1000); + return cumul; - isOk = stillOk(serverDefinition.name, "ZeebeConnection", analysis, false, true, isOk); - this.typeCamundaEngine = this.serverDefinition.serverType; + } catch (Exception e) { + throw new AutomatorException("Search countNumberProcessEnded " + e.getMessage()); + } + } + /* ******************************************************************** */ + /* */ + /* Deployment */ + /* */ + /* ******************************************************************** */ + + public long countNumberOfTasks(String processId, String taskId) throws AutomatorException { + if (operateClient == null) { + throw new AutomatorException("No Operate connection was provided"); + } - ZeebeClientBuilder clientBuilder; + try { - // ---------------------------- Camunda Saas - if (BpmnEngineList.CamundaEngine.CAMUNDA_8_SAAS.equals(this.typeCamundaEngine)) { - analysis.append("SaaS;"); + int cumul = 0; + SearchResult<FlowNodeInstance> searchResult = null; + int maxLoop = 0; + do { + maxLoop++; + + SearchQuery.Builder queryBuilder = new SearchQuery.Builder(); + queryBuilder = queryBuilder.filter(FlowNodeInstanceFilter.builder().flowNodeId(taskId).build()); + queryBuilder.sort(new Sort("key", SortOrder.ASC)); + if (searchResult != null && !searchResult.getItems().isEmpty()) { + queryBuilder.searchAfter(searchResult.getSortValues()); + } + SearchQuery searchQuery = queryBuilder.build(); + searchQuery.setSize(SEARCH_MAX_SIZE); + searchResult = operateClient.searchFlowNodeInstanceResults(searchQuery); + cumul += (long) searchResult.getItems().size(); + } while (searchResult.getItems().size() >= SEARCH_MAX_SIZE && maxLoop < 1000); + return cumul; + } catch (Exception e) { + throw new AutomatorException("Search countNumberProcessEnded " + e.getMessage()); + } + } - String gatewayAddressCloud = - serverDefinition.zeebeSaasClusterId + "." + serverDefinition.zeebeSaasRegion + ".zeebe.camunda.io:443"; - isOk = stillOk(gatewayAddressCloud, "GatewayAddress", analysis, true, true, isOk); - isOk = stillOk(serverDefinition.zeebeClientId, "ClientId", analysis, true, true, isOk); - /* Connect to Camunda Cloud Cluster, assumes that credentials are set in environment variables. - * See JavaDoc on class level for details - */ - isOk = stillOk(serverDefinition.authenticationUrl, "authenticationUrl", analysis, true, true, isOk); - isOk = stillOk(serverDefinition.zeebeAudience, "zeebeAudience", analysis, true, true, isOk); - isOk = stillOk(serverDefinition.zeebeClientId, "ClientId", analysis, true, true, isOk); - isOk = stillOk(serverDefinition.zeebeClientSecret, "ClientSecret", analysis, true, true, isOk); + /* ******************************************************************** */ + /* */ + /* get server definition */ + /* */ + /* ******************************************************************** */ - try { + @Override + public String deployBpmn(File processFile, ScenarioDeployment.Policy policy) throws AutomatorException { + try { + DeploymentEvent event = zeebeClient.newDeployResourceCommand() + .addResourceFile(processFile.getAbsolutePath()) + .send() + .join(); - OAuthCredentialsProvider credentialsProvider = new OAuthCredentialsProviderBuilder() // formatting - .authorizationServerUrl( - serverDefinition.authenticationUrl != null ? serverDefinition.authenticationUrl : SAAS_AUTHENTICATE_URL) - .audience(serverDefinition.zeebeAudience) - .clientId(serverDefinition.zeebeClientId) - .clientSecret(serverDefinition.zeebeClientSecret) - .build(); + return String.valueOf(event.getKey()); + } catch (Exception e) { + throw new AutomatorException("Can't deploy " + e.getMessage()); + } + } - clientBuilder = ZeebeClient.newClientBuilder() - .gatewayAddress(gatewayAddressCloud) - .credentialsProvider(credentialsProvider); + @Override + public BpmnEngineList.CamundaEngine getTypeCamundaEngine() { + return typeCamundaEngine; + } - } catch (Exception e) { - zeebeClient = null; - throw new AutomatorException( - "BadCredential[" + serverDefinition.name + "] Analysis:" + analysis + " : " + e.getMessage()); - } + @Override + public String getSignature() { + String signature = typeCamundaEngine.toString() + " "; + if (typeCamundaEngine.equals(BpmnEngineList.CamundaEngine.CAMUNDA_8_SAAS)) + signature += + "Cloud ClientId[" + serverDefinition.zeebeClientId + "] ClusterId[" + serverDefinition.zeebeSaasClusterId + + "]"; + else + signature += "Address[" + serverDefinition.zeebeGatewayAddress + "]"; + signature += " numJobWorkerExecutionThreads[" + serverDefinition.workerExecutionThreads + "] workerMaxJobsActive[" + + serverDefinition.workerMaxJobsActive + "]"; + return signature; } - //---------------------------- Camunda 8 Self Manage - else if (BpmnEngineList.CamundaEngine.CAMUNDA_8.equals(this.typeCamundaEngine)) { - analysis.append("SelfManage;"); - isOk = stillOk(serverDefinition.zeebeGatewayAddress, "GatewayAddress", analysis, true, true, isOk); - if (serverDefinition.isAuthenticationUrl()) { - analysis.append("WithAuthentication;"); - isOk = stillOk(serverDefinition.authenticationUrl, "authenticationUrl", analysis, true, true, isOk); - isOk = stillOk(serverDefinition.zeebeAudience, "zeebeAudience", analysis, true, true, isOk); - isOk = stillOk(serverDefinition.zeebeClientId, "zeebeClientId", analysis, true, true, isOk); - isOk = stillOk(serverDefinition.zeebeClientSecret, "zeebeClientSecret", analysis, true, false, isOk); - isOk = stillOk(serverDefinition.zeebePlainText, "zeebePlainText", analysis, true, true, isOk); + @Override + public int getWorkerExecutionThreads() { + return serverDefinition != null ? serverDefinition.workerExecutionThreads : 0; + } - try { - OAuthCredentialsProvider credentialsProvider = new OAuthCredentialsProviderBuilder() // builder - .authorizationServerUrl(serverDefinition.authenticationUrl) - .audience(serverDefinition.zeebeAudience) - .clientId(serverDefinition.zeebeClientId) - .clientSecret(serverDefinition.zeebeClientSecret) - .build(); - clientBuilder = ZeebeClient.newClientBuilder() - .gatewayAddress(serverDefinition.zeebeGatewayAddress) - .defaultTenantId(serverDefinition.zeebeTenantId == null ? "<default>" : serverDefinition.zeebeTenantId) - .credentialsProvider(credentialsProvider); - if (Boolean.TRUE.equals(serverDefinition.zeebePlainText)) - clientBuilder.usePlaintext(); + private String getUniqueMarker(String processId, String starterEventId) { + return processId + "-" + random.nextInt(1000000); + } - } catch (Exception e) { - zeebeClient = null; - logger.error("Can't connect to Server[{}] Analysis:{} : {}", serverDefinition.name, analysis, e); - throw new AutomatorException( - "BadCredential[" + serverDefinition.name + "] Analysis:" + analysis + " : " + e.getMessage()); - } - } else { - analysis.append("NoAuthentication;"); - // connect to local deployment; assumes that authentication is disabled - clientBuilder = ZeebeClient.newClientBuilder() - .gatewayAddress(serverDefinition.zeebeGatewayAddress) - .usePlaintext(); - } - } else - throw new AutomatorException("Invalid configuration"); + public ZeebeClient getZeebeClient() { + return zeebeClient; + } - // ---------------- connection - try { - isOk = stillOk(serverDefinition.workerExecutionThreads, "ExecutionThread", analysis, false, true, isOk); - - analysis.append(" ExecutionThread["); - analysis.append(serverDefinition.workerExecutionThreads); - analysis.append("] MaxJobsActive["); - analysis.append(serverDefinition.workerMaxJobsActive); - analysis.append("] "); - if (serverDefinition.workerMaxJobsActive == -1) { - serverDefinition.workerMaxJobsActive = serverDefinition.workerExecutionThreads; - analysis.append("No workerMaxJobsActive defined, align to ExecutionThread["); - analysis.append(serverDefinition.workerExecutionThreads); - analysis.append("]"); - } - if (serverDefinition.workerExecutionThreads > serverDefinition.workerMaxJobsActive) { - logger.error( - "Camunda8 [{}] Incorrect definition: the workerExecutionThreads {} must be <= workerMaxJobsActive {} , else ZeebeClient will not fetch enough jobs to feed threads", - serverDefinition.name, serverDefinition.workerExecutionThreads, serverDefinition.workerMaxJobsActive); - } - if (!isOk) - throw new AutomatorException("Invalid configuration " + analysis); - clientBuilder.numJobWorkerExecutionThreads(serverDefinition.workerExecutionThreads); - clientBuilder.defaultJobWorkerMaxJobsActive(serverDefinition.workerMaxJobsActive); + /* ******************************************************************** */ + /* */ + /* Connection to each component */ + /* */ + /* ******************************************************************** */ - analysis.append("Zeebe connection..."); - zeebeClient = clientBuilder.build(); + private void connectZeebe(StringBuilder analysis) throws AutomatorException { - // simple test - Topology join = zeebeClient.newTopologyRequest().send().join(); + // connection is critical, so let build the analysis - // Actually, if an error arrived, an exception is thrown + boolean isOk = true; - analysis.append(join != null ? "successfully, " : "error, "); + isOk = stillOk(serverDefinition.name, "ZeebeConnection", analysis, false, true, isOk); + this.typeCamundaEngine = this.serverDefinition.serverType; - } catch (Exception e) { - zeebeClient = null; - logger.error("Can't connect to Server[{}] Analysis:{} : {}", serverDefinition.name, analysis, e); - throw new AutomatorException( - "Can't connect to Server[" + serverDefinition.name + "] Analysis:" + analysis + " Fail : " + e.getMessage()); - } - } - - /** - * Connect Operate - * - * @param analysis to cpmplete the analysis - * @throws AutomatorException in case of error - */ - private void connectOperate(StringBuilder analysis) throws AutomatorException { - if (!serverDefinition.isOperate()) { - analysis.append("No operate connection required, "); - return; - } - analysis.append("Operate connection..."); + ZeebeClientBuilder clientBuilder; - boolean isOk = true; - isOk = stillOk(serverDefinition.operateUrl, "operateUrl", analysis, true, true, isOk); + // ---------------------------- Camunda Saas + if (BpmnEngineList.CamundaEngine.CAMUNDA_8_SAAS.equals(this.typeCamundaEngine)) { + analysis.append("SaaS;"); - CamundaOperateClientBuilder camundaOperateClientBuilder = new CamundaOperateClientBuilder(); - // ---------------------------- Camunda Saas - if (BpmnEngineList.CamundaEngine.CAMUNDA_8_SAAS.equals(this.typeCamundaEngine)) { + String gatewayAddressCloud = + serverDefinition.zeebeSaasClusterId + "." + serverDefinition.zeebeSaasRegion + ".zeebe.camunda.io:443"; + isOk = stillOk(gatewayAddressCloud, "GatewayAddress", analysis, true, true, isOk); + isOk = stillOk(serverDefinition.zeebeClientId, "ClientId", analysis, true, true, isOk); - try { - isOk = stillOk(serverDefinition.zeebeSaasRegion, "zeebeSaasRegion", analysis, true, true, isOk); - isOk = stillOk(serverDefinition.zeebeSaasClusterId, "zeebeSaasClusterId", analysis, true, true, isOk); - isOk = stillOk(serverDefinition.zeebeClientId, "zeebeClientId", analysis, true, true, isOk); - isOk = stillOk(serverDefinition.zeebeClientSecret, "zeebeClientSecret", analysis, true, false, isOk); - - URL operateUrl = URI.create("https://" + serverDefinition.zeebeSaasRegion + ".operate.camunda.io/" - + serverDefinition.zeebeSaasClusterId).toURL(); - - SaaSAuthenticationBuilder saaSAuthenticationBuilder = SaaSAuthentication.builder(); - JwtConfig jwtConfig = new JwtConfig(); - jwtConfig.addProduct(Product.OPERATE, - new JwtCredential(serverDefinition.zeebeClientId, serverDefinition.zeebeClientSecret, - serverDefinition.operateAudience != null ? serverDefinition.operateAudience : "operate.camunda.io", - serverDefinition.authenticationUrl != null ? - serverDefinition.authenticationUrl : - SAAS_AUTHENTICATE_URL)); - - Authentication saasAuthentication = SaaSAuthentication.builder() - .withJwtConfig(jwtConfig) - .withJsonMapper(new SdkObjectMapper()) - .build(); - - camundaOperateClientBuilder.authentication(saasAuthentication) - .operateUrl(serverDefinition.operateUrl) - .setup() - .build(); + /* Connect to Camunda Cloud Cluster, assumes that credentials are set in environment variables. + * See JavaDoc on class level for details + */ + isOk = stillOk(serverDefinition.authenticationUrl, "authenticationUrl", analysis, true, true, isOk); + isOk = stillOk(serverDefinition.zeebeAudience, "zeebeAudience", analysis, true, true, isOk); + isOk = stillOk(serverDefinition.zeebeClientId, "ClientId", analysis, true, true, isOk); + isOk = stillOk(serverDefinition.zeebeClientSecret, "ClientSecret", analysis, true, true, isOk); - } catch (Exception e) { - zeebeClient = null; - logger.error("Can't connect to SaaS environemnt[{}] Analysis:{} : {}", serverDefinition.name, analysis, e); - throw new AutomatorException( - "Can't connect to SaaS environment[" + serverDefinition.name + "] Analysis:" + analysis + " fail : " - + e.getMessage()); - } + try { - //---------------------------- Camunda 8 Self Manage - } else if (BpmnEngineList.CamundaEngine.CAMUNDA_8.equals(this.typeCamundaEngine)) { + OAuthCredentialsProvider credentialsProvider = new OAuthCredentialsProviderBuilder() // formatting + .authorizationServerUrl( + serverDefinition.authenticationUrl != null ? serverDefinition.authenticationUrl : SAAS_AUTHENTICATE_URL) + .audience(serverDefinition.zeebeAudience) + .clientId(serverDefinition.zeebeClientId) + .clientSecret(serverDefinition.zeebeClientSecret) + .build(); - isOk = stillOk(serverDefinition.zeebeGatewayAddress, "GatewayAddress", analysis, true, true, isOk); + clientBuilder = ZeebeClient.newClientBuilder() + .gatewayAddress(gatewayAddressCloud) + .credentialsProvider(credentialsProvider); - try { - if (serverDefinition.isAuthenticationUrl()) { - isOk = stillOk(serverDefinition.authenticationUrl, "authenticationUrl", analysis, true, true, isOk); - isOk = stillOk(serverDefinition.operateClientId, "operateClientId", analysis, true, true, isOk); - isOk = stillOk(serverDefinition.operateClientSecret, "operateClientSecret", analysis, true, false, isOk); - - IdentityConfiguration identityConfiguration = new IdentityConfiguration.Builder().withBaseUrl( - serverDefinition.identityUrl) - .withIssuer(serverDefinition.authenticationUrl) - .withIssuerBackendUrl(serverDefinition.authenticationUrl) - .withClientId(serverDefinition.operateClientId) - .withClientSecret(serverDefinition.operateClientSecret) - .withAudience(serverDefinition.operateAudience) - .build(); - Identity identity = new Identity(identityConfiguration); - - IdentityConfig identityConfig = new IdentityConfig(); - identityConfig.addProduct(Product.OPERATE, new IdentityContainer(identity, identityConfiguration)); - - JwtConfig jwtConfig = new JwtConfig(); - jwtConfig.addProduct(Product.OPERATE, new JwtCredential(serverDefinition.operateClientId, // clientId - serverDefinition.operateClientSecret, // clientSecret - "zeebe-api", // audience - serverDefinition.authenticationUrl)); - - io.camunda.common.auth.SelfManagedAuthenticationBuilder identityAuthenticationBuilder = io.camunda.common.auth.SelfManagedAuthentication.builder(); - identityAuthenticationBuilder.withJwtConfig(jwtConfig); - identityAuthenticationBuilder.withIdentityConfig(identityConfig); - - Authentication identityAuthentication = identityAuthenticationBuilder.build(); - camundaOperateClientBuilder.authentication(identityAuthentication) - .operateUrl(serverDefinition.operateUrl) - .setup() - .build(); - - } else { - // Simple authentication - isOk = stillOk(serverDefinition.operateUserName, "operateUserName", analysis, true, true, isOk); - isOk = stillOk(serverDefinition.operateUserPassword, "operateUserPassword", analysis, true, false, isOk); - - SimpleCredential simpleCredential = new SimpleCredential(serverDefinition.operateUrl, - serverDefinition.operateUserName, serverDefinition.operateUserPassword); - - SimpleConfig jwtConfig = new io.camunda.common.auth.SimpleConfig(); - jwtConfig.addProduct(Product.OPERATE, simpleCredential); - - io.camunda.common.auth.SimpleAuthenticationBuilder simpleAuthenticationBuilder = SimpleAuthentication.builder(); - simpleAuthenticationBuilder.withSimpleConfig(jwtConfig); - - Authentication simpleAuthentication = simpleAuthenticationBuilder.build(); - camundaOperateClientBuilder.authentication(simpleAuthentication) - .operateUrl(serverDefinition.operateUrl) - .setup() - .build(); + } catch (Exception e) { + zeebeClient = null; + throw new AutomatorException( + "BadCredential[" + serverDefinition.name + "] Analysis:" + analysis + " : " + e.getMessage()); + } } - } catch (Exception e) { - logger.error("Can't connect to SaaS environment[{}] Analysis:{} : {}", serverDefinition.name, analysis, e); - throw new AutomatorException( - "Can't connect to SaaS environment[" + serverDefinition.name + "] Analysis:" + analysis + " fail : " - + e.getMessage()); - } - } else - throw new AutomatorException("Invalid configuration"); + //---------------------------- Camunda 8 Self Manage + else if (BpmnEngineList.CamundaEngine.CAMUNDA_8.equals(this.typeCamundaEngine)) { + analysis.append("SelfManage;"); + isOk = stillOk(serverDefinition.zeebeGatewayAddress, "GatewayAddress", analysis, true, true, isOk); + if (serverDefinition.isAuthenticationUrl()) { + analysis.append("WithAuthentication;"); + isOk = stillOk(serverDefinition.authenticationUrl, "authenticationUrl", analysis, true, true, isOk); + isOk = stillOk(serverDefinition.zeebeAudience, "zeebeAudience", analysis, true, true, isOk); + isOk = stillOk(serverDefinition.zeebeClientId, "zeebeClientId", analysis, true, true, isOk); + isOk = stillOk(serverDefinition.zeebeClientSecret, "zeebeClientSecret", analysis, true, false, isOk); + isOk = stillOk(serverDefinition.zeebePlainText, "zeebePlainText", analysis, true, true, isOk); + + try { + OAuthCredentialsProvider credentialsProvider = new OAuthCredentialsProviderBuilder() // builder + .authorizationServerUrl(serverDefinition.authenticationUrl) + .audience(serverDefinition.zeebeAudience) + .clientId(serverDefinition.zeebeClientId) + .clientSecret(serverDefinition.zeebeClientSecret) + .build(); + clientBuilder = ZeebeClient.newClientBuilder() + .gatewayAddress(serverDefinition.zeebeGatewayAddress) + .defaultTenantId(serverDefinition.zeebeTenantId == null ? "<default>" : serverDefinition.zeebeTenantId) + .credentialsProvider(credentialsProvider); + if (Boolean.TRUE.equals(serverDefinition.zeebePlainText)) + clientBuilder.usePlaintext(); + + } catch (Exception e) { + zeebeClient = null; + logger.error("Can't connect to Server[{}] Analysis:{} : {}", serverDefinition.name, analysis, e); + throw new AutomatorException( + "BadCredential[" + serverDefinition.name + "] Analysis:" + analysis + " : " + e.getMessage()); + } + } else { + analysis.append("NoAuthentication;"); + // connect to local deployment; assumes that authentication is disabled + clientBuilder = ZeebeClient.newClientBuilder() + .gatewayAddress(serverDefinition.zeebeGatewayAddress) + .usePlaintext(); + } + } else + throw new AutomatorException("Invalid configuration"); + + // ---------------- connection + try { + isOk = stillOk(serverDefinition.workerExecutionThreads, "ExecutionThread", analysis, false, true, isOk); - if (!isOk) - throw new AutomatorException("Invalid configuration " + analysis); + analysis.append(" ExecutionThread["); + analysis.append(serverDefinition.workerExecutionThreads); + analysis.append("] MaxJobsActive["); + analysis.append(serverDefinition.workerMaxJobsActive); + analysis.append("] "); + if (serverDefinition.workerMaxJobsActive == -1) { + serverDefinition.workerMaxJobsActive = serverDefinition.workerExecutionThreads; + analysis.append("No workerMaxJobsActive defined, align to ExecutionThread["); + analysis.append(serverDefinition.workerExecutionThreads); + analysis.append("]"); + } + if (serverDefinition.workerExecutionThreads > serverDefinition.workerMaxJobsActive) { + logger.error( + "Camunda8 [{}] Incorrect definition: the workerExecutionThreads {} must be <= workerMaxJobsActive {} , else ZeebeClient will not fetch enough jobs to feed threads", + serverDefinition.name, serverDefinition.workerExecutionThreads, serverDefinition.workerMaxJobsActive); + } - // ---------------- connection - try { + if (!isOk) + throw new AutomatorException("Invalid configuration " + analysis); - operateClient = camundaOperateClientBuilder.build(); + clientBuilder.numJobWorkerExecutionThreads(serverDefinition.workerExecutionThreads); + clientBuilder.defaultJobWorkerMaxJobsActive(serverDefinition.workerMaxJobsActive); - analysis.append("successfully, "); + analysis.append("Zeebe connection..."); + zeebeClient = clientBuilder.build(); - } catch (Exception e) { - logger.error("Can't connect to Server[{}] Analysis:{} : {}", serverDefinition.name, analysis, e); - throw new AutomatorException( - "Can't connect to Server[" + serverDefinition.name + "] Analysis:" + analysis + " Fail : " + e.getMessage()); - } - } - - /** - * Connect to TaskList - * - * @param analysis complete the analysis - * @throws AutomatorException in case of error - */ - private void connectTaskList(StringBuilder analysis) throws AutomatorException { - - if (!serverDefinition.isTaskList()) { - analysis.append("No TaskList connection required, "); - return; - } - analysis.append("Tasklist ..."); + // simple test + Topology join = zeebeClient.newTopologyRequest().send().join(); - boolean isOk = true; - isOk = stillOk(serverDefinition.taskListUrl, "taskListUrl", analysis, true, true, isOk); + // Actually, if an error arrived, an exception is thrown - CamundaTaskListClientBuilder taskListBuilder = CamundaTaskListClient.builder(); - // ---------------------------- Camunda Saas - if (BpmnEngineList.CamundaEngine.CAMUNDA_8_SAAS.equals(this.typeCamundaEngine)) { - try { - isOk = stillOk(serverDefinition.zeebeSaasRegion, "zeebeSaasRegion", analysis, true, true, isOk); - isOk = stillOk(serverDefinition.zeebeSaasClusterId, "zeebeSaasClusterId", analysis, true, true, isOk); - isOk = stillOk(serverDefinition.taskListClientId, "taskListClientId", analysis, true, true, isOk); - isOk = stillOk(serverDefinition.taskListClientSecret, "taskListClientSecret", analysis, true, false, isOk); + analysis.append(join != null ? "successfully, " : "error, "); - String taskListUrl = "https://" + serverDefinition.zeebeSaasRegion + ".tasklist.camunda.io/" - + serverDefinition.zeebeSaasClusterId; + } catch (Exception e) { + zeebeClient = null; + logger.error("Can't connect to Server[{}] Analysis:{} : {}", serverDefinition.name, analysis, e); + throw new AutomatorException( + "Can't connect to Server[" + serverDefinition.name + "] Analysis:" + analysis + " Fail : " + e.getMessage()); + } + } - taskListBuilder.taskListUrl(taskListUrl) - .saaSAuthentication(serverDefinition.taskListClientId, serverDefinition.taskListClientSecret); - } catch (Exception e) { - logger.error("Can't connect to SaaS environemnt[{}] Analysis:{} : {}", serverDefinition.name, analysis, e); - throw new AutomatorException( - "Can't connect to SaaS environment[" + serverDefinition.name + "] Analysis:" + analysis + " fail : " - + e.getMessage()); - } + /** + * Connect Operate + * + * @param analysis to cpmplete the analysis + * @throws AutomatorException in case of error + */ + private void connectOperate(StringBuilder analysis) throws AutomatorException { + if (!serverDefinition.isOperate()) { + analysis.append("No operate connection required, "); + return; + } + analysis.append("Operate connection..."); + + boolean isOk = true; + isOk = stillOk(serverDefinition.operateUrl, "operateUrl", analysis, true, true, isOk); + + CamundaOperateClientBuilder camundaOperateClientBuilder = new CamundaOperateClientBuilder(); + // ---------------------------- Camunda Saas + if (BpmnEngineList.CamundaEngine.CAMUNDA_8_SAAS.equals(this.typeCamundaEngine)) { + + try { + isOk = stillOk(serverDefinition.zeebeSaasRegion, "zeebeSaasRegion", analysis, true, true, isOk); + isOk = stillOk(serverDefinition.zeebeSaasClusterId, "zeebeSaasClusterId", analysis, true, true, isOk); + isOk = stillOk(serverDefinition.zeebeClientId, "zeebeClientId", analysis, true, true, isOk); + isOk = stillOk(serverDefinition.zeebeClientSecret, "zeebeClientSecret", analysis, true, false, isOk); + + URL operateUrl = URI.create("https://" + serverDefinition.zeebeSaasRegion + ".operate.camunda.io/" + + serverDefinition.zeebeSaasClusterId).toURL(); + + SaaSAuthenticationBuilder saaSAuthenticationBuilder = SaaSAuthentication.builder(); + JwtConfig jwtConfig = new JwtConfig(); + jwtConfig.addProduct(Product.OPERATE, + new JwtCredential(serverDefinition.zeebeClientId, serverDefinition.zeebeClientSecret, + serverDefinition.operateAudience != null ? serverDefinition.operateAudience : "operate.camunda.io", + serverDefinition.authenticationUrl != null ? + serverDefinition.authenticationUrl : + SAAS_AUTHENTICATE_URL)); + + Authentication saasAuthentication = SaaSAuthentication.builder() + .withJwtConfig(jwtConfig) + .withJsonMapper(new SdkObjectMapper()) + .build(); + + camundaOperateClientBuilder.authentication(saasAuthentication) + .operateUrl(serverDefinition.operateUrl) + .setup() + .build(); + + } catch (Exception e) { + zeebeClient = null; + logger.error("Can't connect to SaaS environemnt[{}] Analysis:{} : {}", serverDefinition.name, analysis, e); + throw new AutomatorException( + "Can't connect to SaaS environment[" + serverDefinition.name + "] Analysis:" + analysis + " fail : " + + e.getMessage()); + } + + //---------------------------- Camunda 8 Self Manage + } else if (BpmnEngineList.CamundaEngine.CAMUNDA_8.equals(this.typeCamundaEngine)) { + + isOk = stillOk(serverDefinition.zeebeGatewayAddress, "GatewayAddress", analysis, true, true, isOk); + + try { + if (serverDefinition.isAuthenticationUrl()) { + isOk = stillOk(serverDefinition.authenticationUrl, "authenticationUrl", analysis, true, true, isOk); + isOk = stillOk(serverDefinition.operateClientId, "operateClientId", analysis, true, true, isOk); + isOk = stillOk(serverDefinition.operateClientSecret, "operateClientSecret", analysis, true, false, isOk); + + IdentityConfiguration identityConfiguration = new IdentityConfiguration.Builder().withBaseUrl( + serverDefinition.identityUrl) + .withIssuer(serverDefinition.authenticationUrl) + .withIssuerBackendUrl(serverDefinition.authenticationUrl) + .withClientId(serverDefinition.operateClientId) + .withClientSecret(serverDefinition.operateClientSecret) + .withAudience(serverDefinition.operateAudience) + .build(); + Identity identity = new Identity(identityConfiguration); + + IdentityConfig identityConfig = new IdentityConfig(); + identityConfig.addProduct(Product.OPERATE, new IdentityContainer(identity, identityConfiguration)); + + JwtConfig jwtConfig = new JwtConfig(); + jwtConfig.addProduct(Product.OPERATE, new JwtCredential(serverDefinition.operateClientId, // clientId + serverDefinition.operateClientSecret, // clientSecret + "zeebe-api", // audience + serverDefinition.authenticationUrl)); + + io.camunda.common.auth.SelfManagedAuthenticationBuilder identityAuthenticationBuilder = io.camunda.common.auth.SelfManagedAuthentication.builder(); + identityAuthenticationBuilder.withJwtConfig(jwtConfig); + identityAuthenticationBuilder.withIdentityConfig(identityConfig); + + Authentication identityAuthentication = identityAuthenticationBuilder.build(); + camundaOperateClientBuilder.authentication(identityAuthentication) + .operateUrl(serverDefinition.operateUrl) + .setup() + .build(); + + } else { + // Simple authentication + isOk = stillOk(serverDefinition.operateUserName, "operateUserName", analysis, true, true, isOk); + isOk = stillOk(serverDefinition.operateUserPassword, "operateUserPassword", analysis, true, false, isOk); + + SimpleCredential simpleCredential = new SimpleCredential(serverDefinition.operateUrl, + serverDefinition.operateUserName, serverDefinition.operateUserPassword); + + SimpleConfig jwtConfig = new io.camunda.common.auth.SimpleConfig(); + jwtConfig.addProduct(Product.OPERATE, simpleCredential); + + io.camunda.common.auth.SimpleAuthenticationBuilder simpleAuthenticationBuilder = SimpleAuthentication.builder(); + simpleAuthenticationBuilder.withSimpleConfig(jwtConfig); + + Authentication simpleAuthentication = simpleAuthenticationBuilder.build(); + camundaOperateClientBuilder.authentication(simpleAuthentication) + .operateUrl(serverDefinition.operateUrl) + .setup() + .build(); + } + } catch (Exception e) { + logger.error("Can't connect to SaaS environment[{}] Analysis:{} : {}", serverDefinition.name, analysis, e); + throw new AutomatorException( + "Can't connect to SaaS environment[" + serverDefinition.name + "] Analysis:" + analysis + " fail : " + + e.getMessage()); + } + + } else + throw new AutomatorException("Invalid configuration"); + + if (!isOk) + throw new AutomatorException("Invalid configuration " + analysis); + + // ---------------- connection + try { - //---------------------------- Camunda 8 Self Manage - } else if (BpmnEngineList.CamundaEngine.CAMUNDA_8.equals(this.typeCamundaEngine)) { + operateClient = camundaOperateClientBuilder.build(); - if (serverDefinition.isAuthenticationUrl()) { - isOk = stillOk(serverDefinition.taskListClientId, "taskListClientId", analysis, true, true, isOk); - isOk = stillOk(serverDefinition.taskListClientSecret, "taskListClientSecret", analysis, true, false, isOk); - isOk = stillOk(serverDefinition.authenticationUrl, "authenticationUrl", analysis, true, true, isOk); - isOk = stillOk(serverDefinition.taskListKeycloakUrl, "taskListKeycloakUrl", analysis, true, true, isOk); - - taskListBuilder.taskListUrl(serverDefinition.taskListUrl) - .selfManagedAuthentication(serverDefinition.taskListClientId, serverDefinition.taskListClientSecret, - serverDefinition.taskListKeycloakUrl); - } else { - isOk = stillOk(serverDefinition.taskListUserName, "User", analysis, true, true, isOk); - isOk = stillOk(serverDefinition.taskListUserPassword, "Password", analysis, true, false, isOk); - - SimpleConfig simpleConf = new SimpleConfig(); - simpleConf.addProduct(Product.TASKLIST, - new SimpleCredential(serverDefinition.taskListUrl, serverDefinition.taskListUserName, - serverDefinition.taskListUserPassword)); - Authentication auth = SimpleAuthentication.builder().withSimpleConfig(simpleConf).build(); - - taskListBuilder.taskListUrl(serverDefinition.taskListUrl) - .authentication(auth) - .cookieExpiration(Duration.ofSeconds(5)); - } - } else - throw new AutomatorException("Invalid configuration"); + analysis.append("successfully, "); - if (!isOk) - throw new AutomatorException("Invalid configuration " + analysis); + } catch (Exception e) { + logger.error("Can't connect to Server[{}] Analysis:{} : {}", serverDefinition.name, analysis, e); + throw new AutomatorException( + "Can't connect to Server[" + serverDefinition.name + "] Analysis:" + analysis + " Fail : " + e.getMessage()); + } + } - // ---------------- connection - try { + /** + * Connect to TaskList + * + * @param analysis complete the analysis + * @throws AutomatorException in case of error + */ + private void connectTaskList(StringBuilder analysis) throws AutomatorException { - taskClient = taskListBuilder.build(); - analysis.append("successfully, "); + if (!serverDefinition.isTaskList()) { + analysis.append("No TaskList connection required, "); + return; + } + analysis.append("Tasklist ..."); + + boolean isOk = true; + isOk = stillOk(serverDefinition.taskListUrl, "taskListUrl", analysis, true, true, isOk); + + CamundaTaskListClientBuilder taskListBuilder = CamundaTaskListClient.builder(); + // ---------------------------- Camunda Saas + if (BpmnEngineList.CamundaEngine.CAMUNDA_8_SAAS.equals(this.typeCamundaEngine)) { + try { + isOk = stillOk(serverDefinition.zeebeSaasRegion, "zeebeSaasRegion", analysis, true, true, isOk); + isOk = stillOk(serverDefinition.zeebeSaasClusterId, "zeebeSaasClusterId", analysis, true, true, isOk); + isOk = stillOk(serverDefinition.taskListClientId, "taskListClientId", analysis, true, true, isOk); + isOk = stillOk(serverDefinition.taskListClientSecret, "taskListClientSecret", analysis, true, false, isOk); + + String taskListUrl = "https://" + serverDefinition.zeebeSaasRegion + ".tasklist.camunda.io/" + + serverDefinition.zeebeSaasClusterId; + + taskListBuilder.taskListUrl(taskListUrl) + .saaSAuthentication(serverDefinition.taskListClientId, serverDefinition.taskListClientSecret); + } catch (Exception e) { + logger.error("Can't connect to SaaS environemnt[{}] Analysis:{} : {}", serverDefinition.name, analysis, e); + throw new AutomatorException( + "Can't connect to SaaS environment[" + serverDefinition.name + "] Analysis:" + analysis + " fail : " + + e.getMessage()); + } + + //---------------------------- Camunda 8 Self Manage + } else if (BpmnEngineList.CamundaEngine.CAMUNDA_8.equals(this.typeCamundaEngine)) { + + if (serverDefinition.isAuthenticationUrl()) { + isOk = stillOk(serverDefinition.taskListClientId, "taskListClientId", analysis, true, true, isOk); + isOk = stillOk(serverDefinition.taskListClientSecret, "taskListClientSecret", analysis, true, false, isOk); + isOk = stillOk(serverDefinition.authenticationUrl, "authenticationUrl", analysis, true, true, isOk); + isOk = stillOk(serverDefinition.taskListKeycloakUrl, "taskListKeycloakUrl", analysis, true, true, isOk); + + taskListBuilder.taskListUrl(serverDefinition.taskListUrl) + .selfManagedAuthentication(serverDefinition.taskListClientId, serverDefinition.taskListClientSecret, + serverDefinition.taskListKeycloakUrl); + } else { + isOk = stillOk(serverDefinition.taskListUserName, "User", analysis, true, true, isOk); + isOk = stillOk(serverDefinition.taskListUserPassword, "Password", analysis, true, false, isOk); + + SimpleConfig simpleConf = new SimpleConfig(); + simpleConf.addProduct(Product.TASKLIST, + new SimpleCredential(serverDefinition.taskListUrl, serverDefinition.taskListUserName, + serverDefinition.taskListUserPassword)); + Authentication auth = SimpleAuthentication.builder().withSimpleConfig(simpleConf).build(); + + taskListBuilder.taskListUrl(serverDefinition.taskListUrl) + .authentication(auth) + .cookieExpiration(Duration.ofSeconds(5)); + } + } else + throw new AutomatorException("Invalid configuration"); + + if (!isOk) + throw new AutomatorException("Invalid configuration " + analysis); + + // ---------------- connection + try { - } catch (Exception e) { - logger.error("Can't connect to Server[{}] Analysis:{} : {}", serverDefinition.name, analysis, e); - throw new AutomatorException( - "Can't connect to Server[" + serverDefinition.name + "] Analysis:" + analysis + " Fail : " + e.getMessage()); - } + taskClient = taskListBuilder.build(); + analysis.append("successfully, "); + + } catch (Exception e) { + logger.error("Can't connect to Server[{}] Analysis:{} : {}", serverDefinition.name, analysis, e); + throw new AutomatorException( + "Can't connect to Server[" + serverDefinition.name + "] Analysis:" + analysis + " Fail : " + e.getMessage()); + } /* 1.6.1 boolean isOk = true; @@ -1206,48 +1191,48 @@ private void connectTaskList(StringBuilder analysis) throws AutomatorException { } */ - } - - /** - * add in analysis and check the consistence - * - * @param value value to check - * @param message name of parameter - * @param analysis analysis builder - * @param check true if the value must not be null or empty - * @param displayValueInAnalysis true if the value can be added in the analysis - * @param wasOkBefore previous value, is returned if this check is Ok - * @return previous value is ok false else - */ - private boolean stillOk(Object value, - String message, - StringBuilder analysis, - boolean check, - boolean displayValueInAnalysis, - boolean wasOkBefore) { - analysis.append(message); - analysis.append("["); - analysis.append(getDisplayValue(value, displayValueInAnalysis)); - analysis.append("], "); - - if (check) { - if (value == null || (value instanceof String valueString && valueString.isEmpty())) { - analysis.append("No "); + } + + /** + * add in analysis and check the consistence + * + * @param value value to check + * @param message name of parameter + * @param analysis analysis builder + * @param check true if the value must not be null or empty + * @param displayValueInAnalysis true if the value can be added in the analysis + * @param wasOkBefore previous value, is returned if this check is Ok + * @return previous value is ok false else + */ + private boolean stillOk(Object value, + String message, + StringBuilder analysis, + boolean check, + boolean displayValueInAnalysis, + boolean wasOkBefore) { analysis.append(message); - logger.error("Check failed {} value:[{}]", message, getDisplayValue(value, displayValueInAnalysis)); - return false; - } + analysis.append("["); + analysis.append(getDisplayValue(value, displayValueInAnalysis)); + analysis.append("], "); + + if (check) { + if (value == null || (value instanceof String valueString && valueString.isEmpty())) { + analysis.append("No "); + analysis.append(message); + logger.error("Check failed {} value:[{}]", message, getDisplayValue(value, displayValueInAnalysis)); + return false; + } + } + return wasOkBefore; + } + + private String getDisplayValue(Object value, boolean displayValueInAnalysis) { + if (value == null) + return "null"; + if (displayValueInAnalysis) + return value.toString(); + if (value.toString().length() <= 3) + return "***"; + return value.toString().substring(0, 3) + "***"; } - return wasOkBefore; - } - - private String getDisplayValue(Object value, boolean displayValueInAnalysis) { - if (value == null) - return "null"; - if (displayValueInAnalysis) - return value.toString(); - if (value.toString().length() <= 3) - return "***"; - return value.toString().substring(0, 3) + "***"; - } } diff --git a/src/main/java/org/camunda/automator/bpmnengine/camunda8/StatisticsCollector.java b/src/main/java/org/camunda/automator/bpmnengine/camunda8/StatisticsCollector.java index 5df37b6..29f15ea 100644 --- a/src/main/java/org/camunda/automator/bpmnengine/camunda8/StatisticsCollector.java +++ b/src/main/java/org/camunda/automator/bpmnengine/camunda8/StatisticsCollector.java @@ -8,42 +8,42 @@ @Component public class StatisticsCollector { - private final Date startTime = new Date(); + private final Date startTime = new Date(); - private final long lastPrintStartedProcessInstances = 0; - private final long lastPrintCompletedProcessInstances = 0; - private final long lastPrintCompletedJobs = 0; - private final long lastPrintStartedProcessInstancesBackpressure = 0; + private final long lastPrintStartedProcessInstances = 0; + private final long lastPrintCompletedProcessInstances = 0; + private final long lastPrintCompletedJobs = 0; + private final long lastPrintStartedProcessInstancesBackpressure = 0; - private long piPerSecondGoal; + private long piPerSecondGoal; - @PostConstruct - public void init() { - } + @PostConstruct + public void init() { + } - public void hintOnNewPiPerSecondGoald(long piPerSecondGoal) { - this.piPerSecondGoal = piPerSecondGoal; - } + public void hintOnNewPiPerSecondGoald(long piPerSecondGoal) { + this.piPerSecondGoal = piPerSecondGoal; + } - public void incStartedProcessInstances() { - } + public void incStartedProcessInstances() { + } - public void incStartedProcessInstancesBackpressure() { - } + public void incStartedProcessInstancesBackpressure() { + } - public void incCompletedProcessInstances() { - } + public void incCompletedProcessInstances() { + } - public void incCompletedProcessInstances(long startMillis, long endMillis) { - } + public void incCompletedProcessInstances(long startMillis, long endMillis) { + } - public void incCompletedJobs() { - } + public void incCompletedJobs() { + } - public void incStartedProcessInstancesException(String exceptionMessage) { - } + public void incStartedProcessInstancesException(String exceptionMessage) { + } - public void incCompletedJobsException(String exceptionMessage) { - } + public void incCompletedJobsException(String exceptionMessage) { + } } diff --git a/src/main/java/org/camunda/automator/bpmnengine/camunda8/refactoring/RefactoredCommandWrapper.java b/src/main/java/org/camunda/automator/bpmnengine/camunda8/refactoring/RefactoredCommandWrapper.java index b120f06..ae5c95f 100644 --- a/src/main/java/org/camunda/automator/bpmnengine/camunda8/refactoring/RefactoredCommandWrapper.java +++ b/src/main/java/org/camunda/automator/bpmnengine/camunda8/refactoring/RefactoredCommandWrapper.java @@ -15,75 +15,75 @@ */ public class RefactoredCommandWrapper extends CommandWrapper { - private final FinalCommandStep<Void> command; - private final long deadline; - private final String entityLogInfo; - private final DefaultCommandExceptionHandlingStrategy commandExceptionHandlingStrategy; - private final int maxRetries = 20; - private long currentRetryDelay = 50L; - private int invocationCounter = 0; + private final FinalCommandStep<Void> command; + private final long deadline; + private final String entityLogInfo; + private final DefaultCommandExceptionHandlingStrategy commandExceptionHandlingStrategy; + private final int maxRetries = 20; + private long currentRetryDelay = 50L; + private int invocationCounter = 0; - public RefactoredCommandWrapper(FinalCommandStep<Void> command, - long deadline, - String entityLogInfo, - DefaultCommandExceptionHandlingStrategy commandExceptionHandlingStrategy) { - super(command, null, commandExceptionHandlingStrategy); - this.command = command; - this.deadline = deadline; - this.entityLogInfo = entityLogInfo; - this.commandExceptionHandlingStrategy = commandExceptionHandlingStrategy; - } + public RefactoredCommandWrapper(FinalCommandStep<Void> command, + long deadline, + String entityLogInfo, + DefaultCommandExceptionHandlingStrategy commandExceptionHandlingStrategy) { + super(command, null, commandExceptionHandlingStrategy); + this.command = command; + this.deadline = deadline; + this.entityLogInfo = entityLogInfo; + this.commandExceptionHandlingStrategy = commandExceptionHandlingStrategy; + } - @Override - public void executeAsync() { - ++this.invocationCounter; - ZeebeFuture<Void> zeebeFuture = this.command.send(); - if (commandExceptionHandlingStrategy != null) - zeebeFuture.exceptionally(t -> { - this.commandExceptionHandlingStrategy.handleCommandError(this, t); - return null; - }); - } + @Override + public void executeAsync() { + ++this.invocationCounter; + ZeebeFuture<Void> zeebeFuture = this.command.send(); + if (commandExceptionHandlingStrategy != null) + zeebeFuture.exceptionally(t -> { + this.commandExceptionHandlingStrategy.handleCommandError(this, t); + return null; + }); + } - public Object executeSync() { - ++this.invocationCounter; - ZeebeFuture<Void> zeebeFutur = this.command.send(); - if (commandExceptionHandlingStrategy != null) - zeebeFutur.exceptionally(t -> { - this.commandExceptionHandlingStrategy.handleCommandError(this, t); - return null; - }); - return zeebeFutur.join(); - } + public Object executeSync() { + ++this.invocationCounter; + ZeebeFuture<Void> zeebeFutur = this.command.send(); + if (commandExceptionHandlingStrategy != null) + zeebeFutur.exceptionally(t -> { + this.commandExceptionHandlingStrategy.handleCommandError(this, t); + return null; + }); + return zeebeFutur.join(); + } - @Override - public void increaseBackoffUsing(BackoffSupplier backoffSupplier) { - this.currentRetryDelay = backoffSupplier.supplyRetryDelay(this.currentRetryDelay); - } + @Override + public void increaseBackoffUsing(BackoffSupplier backoffSupplier) { + this.currentRetryDelay = backoffSupplier.supplyRetryDelay(this.currentRetryDelay); + } - @Override - public void scheduleExecutionUsing(ScheduledExecutorService scheduledExecutorService) { - scheduledExecutorService.schedule(this::executeAsync, this.currentRetryDelay, TimeUnit.MILLISECONDS); - } + @Override + public void scheduleExecutionUsing(ScheduledExecutorService scheduledExecutorService) { + scheduledExecutorService.schedule(this::executeAsync, this.currentRetryDelay, TimeUnit.MILLISECONDS); + } - @Override - public String toString() { - return "{command=" + this.command.getClass() + ", entity=" + this.entityLogInfo + ", currentRetryDelay=" - + this.currentRetryDelay + '}'; - } + @Override + public String toString() { + return "{command=" + this.command.getClass() + ", entity=" + this.entityLogInfo + ", currentRetryDelay=" + + this.currentRetryDelay + '}'; + } - @Override - public boolean hasMoreRetries() { - if (this.jobDeadlineExceeded()) { - return false; - } else { - return this.invocationCounter < this.maxRetries; + @Override + public boolean hasMoreRetries() { + if (this.jobDeadlineExceeded()) { + return false; + } else { + return this.invocationCounter < this.maxRetries; + } } - } - @Override - public boolean jobDeadlineExceeded() { - return Instant.now().getEpochSecond() > this.deadline; - } + @Override + public boolean jobDeadlineExceeded() { + return Instant.now().getEpochSecond() > this.deadline; + } } diff --git a/src/main/java/org/camunda/automator/bpmnengine/dummy/BpmnEngineDummy.java b/src/main/java/org/camunda/automator/bpmnengine/dummy/BpmnEngineDummy.java index 3fbbbb0..8be203f 100644 --- a/src/main/java/org/camunda/automator/bpmnengine/dummy/BpmnEngineDummy.java +++ b/src/main/java/org/camunda/automator/bpmnengine/dummy/BpmnEngineDummy.java @@ -17,149 +17,149 @@ public class BpmnEngineDummy implements BpmnEngine { - private final Logger logger = LoggerFactory.getLogger(BpmnEngineDummy.class); - - public BpmnEngineDummy(BpmnEngineList.BpmnServerDefinition serverDefinition) { - } - - @Override - public void init() { - logger.info("BpmnEngineDummy.Init:"); - } - - public void connection() throws AutomatorException { - // nothing to do here - } - - public void disconnection() throws AutomatorException { - // nothing to do here - } - - /** - * Engine is ready. If not, a connection() method must be call - * - * @return ready if the engine is ready - true everytime - */ - public boolean isReady() { - return true; - } - - @Override - public String createProcessInstance(String processId, String starterEventId, Map<String, Object> variables) - throws AutomatorException { - logger.info("BpmnEngineDummy.CreateProcessInstance: Process[" + processId + "] StartEvent[" + starterEventId + "]"); - return "111"; - } - - @Override - public void endProcessInstance(String processInstanceId, boolean cleanAll) throws AutomatorException { - - } - - @Override - public List<String> searchUserTasksByProcessInstance(String processInstanceId, String userTaskId, int maxResult) - throws AutomatorException { - logger.info("BpmnEngineDummy.searchForActivity: Process[" + processInstanceId + "] taskName[" + userTaskId + "]"); - return List.of("5555"); - } - - @Override - public List<String> searchUserTasks(String userTaskId, int maxResult) throws AutomatorException { - logger.info("BpmnEngineDummy.searchForActivity: taskName[" + userTaskId + "]"); - return List.of("5555"); - } - - @Override - public void executeUserTask(String userTaskId, String userId, Map<String, Object> variables) - throws AutomatorException { - logger.info("BpmnEngineDummy.executeUserTask: activityId[" + userTaskId + "]"); - } - - @Override - public RegisteredTask registerServiceTask(String workerId, - String topic, - boolean streamEnable, - Duration lockTime, - Object jobHandler, - FixedBackoffSupplier backoffSupplier) { - return null; - } - - @Override - public List<String> searchServiceTasks(String processInstanceId, String serviceTaskId, String topic, int maxResult) - throws AutomatorException { - return Collections.emptyList(); - } - - @Override - public void executeServiceTask(String serviceTaskId, String workerId, Map<String, Object> variables) - throws AutomatorException { - } - - @Override - public List<TaskDescription> searchTasksByProcessInstanceId(String processInstanceId, String taskId, int maxResult) - throws AutomatorException { - return Collections.emptyList(); - } - - @Override - public List<ProcessDescription> searchProcessInstanceByVariable(String processId, - Map<String, Object> filterVariables, - int maxResult) throws AutomatorException { - return Collections.emptyList(); - } - - @Override - public Map<String, Object> getVariables(String processInstanceId) throws AutomatorException { - return Collections.emptyMap(); - } - - - - /* ******************************************************************** */ - /* */ - /* CountInformation */ - /* */ - /* ******************************************************************** */ - - @Override - public long countNumberOfProcessInstancesCreated(String processName, DateFilter startDate, DateFilter endDate) - throws AutomatorException { - throw new AutomatorException("Not yet implemented"); - } - - @Override - public long countNumberOfProcessInstancesEnded(String processName, DateFilter startDate, DateFilter endDate) - throws AutomatorException { - throw new AutomatorException("Not yet implemented"); - } - - public long countNumberOfTasks(String processId, String taskId) throws AutomatorException { - throw new AutomatorException("Not yet implemented"); - } - - @Override - public String deployBpmn(File processFile, ScenarioDeployment.Policy policy) throws AutomatorException { - return null; - } - - @Override - public BpmnEngineList.CamundaEngine getTypeCamundaEngine() { - return BpmnEngineList.CamundaEngine.DUMMY; - } - - @Override - public String getSignature() { - return BpmnEngineList.CamundaEngine.DUMMY.toString(); - } - - @Override - - public int getWorkerExecutionThreads() { - return 0; - } - - public void turnHighFlowMode(boolean hightFlowMode) { - } + private final Logger logger = LoggerFactory.getLogger(BpmnEngineDummy.class); + + public BpmnEngineDummy(BpmnEngineList.BpmnServerDefinition serverDefinition) { + } + + @Override + public void init() { + logger.info("BpmnEngineDummy.Init:"); + } + + public void connection() throws AutomatorException { + // nothing to do here + } + + public void disconnection() throws AutomatorException { + // nothing to do here + } + + /** + * Engine is ready. If not, a connection() method must be call + * + * @return ready if the engine is ready - true everytime + */ + public boolean isReady() { + return true; + } + + @Override + public String createProcessInstance(String processId, String starterEventId, Map<String, Object> variables) + throws AutomatorException { + logger.info("BpmnEngineDummy.CreateProcessInstance: Process[" + processId + "] StartEvent[" + starterEventId + "]"); + return "111"; + } + + @Override + public void endProcessInstance(String processInstanceId, boolean cleanAll) throws AutomatorException { + + } + + @Override + public List<String> searchUserTasksByProcessInstance(String processInstanceId, String userTaskId, int maxResult) + throws AutomatorException { + logger.info("BpmnEngineDummy.searchForActivity: Process[" + processInstanceId + "] taskName[" + userTaskId + "]"); + return List.of("5555"); + } + + @Override + public List<String> searchUserTasks(String userTaskId, int maxResult) throws AutomatorException { + logger.info("BpmnEngineDummy.searchForActivity: taskName[" + userTaskId + "]"); + return List.of("5555"); + } + + @Override + public void executeUserTask(String userTaskId, String userId, Map<String, Object> variables) + throws AutomatorException { + logger.info("BpmnEngineDummy.executeUserTask: activityId[" + userTaskId + "]"); + } + + @Override + public RegisteredTask registerServiceTask(String workerId, + String topic, + boolean streamEnable, + Duration lockTime, + Object jobHandler, + FixedBackoffSupplier backoffSupplier) { + return null; + } + + @Override + public List<String> searchServiceTasks(String processInstanceId, String serviceTaskId, String topic, int maxResult) + throws AutomatorException { + return Collections.emptyList(); + } + + @Override + public void executeServiceTask(String serviceTaskId, String workerId, Map<String, Object> variables) + throws AutomatorException { + } + + @Override + public List<TaskDescription> searchTasksByProcessInstanceId(String processInstanceId, String taskId, int maxResult) + throws AutomatorException { + return Collections.emptyList(); + } + + @Override + public List<ProcessDescription> searchProcessInstanceByVariable(String processId, + Map<String, Object> filterVariables, + int maxResult) throws AutomatorException { + return Collections.emptyList(); + } + + @Override + public Map<String, Object> getVariables(String processInstanceId) throws AutomatorException { + return Collections.emptyMap(); + } + + + + /* ******************************************************************** */ + /* */ + /* CountInformation */ + /* */ + /* ******************************************************************** */ + + @Override + public long countNumberOfProcessInstancesCreated(String processName, DateFilter startDate, DateFilter endDate) + throws AutomatorException { + throw new AutomatorException("Not yet implemented"); + } + + @Override + public long countNumberOfProcessInstancesEnded(String processName, DateFilter startDate, DateFilter endDate) + throws AutomatorException { + throw new AutomatorException("Not yet implemented"); + } + + public long countNumberOfTasks(String processId, String taskId) throws AutomatorException { + throw new AutomatorException("Not yet implemented"); + } + + @Override + public String deployBpmn(File processFile, ScenarioDeployment.Policy policy) throws AutomatorException { + return null; + } + + @Override + public BpmnEngineList.CamundaEngine getTypeCamundaEngine() { + return BpmnEngineList.CamundaEngine.DUMMY; + } + + @Override + public String getSignature() { + return BpmnEngineList.CamundaEngine.DUMMY.toString(); + } + + @Override + + public int getWorkerExecutionThreads() { + return 0; + } + + public void turnHighFlowMode(boolean hightFlowMode) { + } } diff --git a/src/main/java/org/camunda/automator/configuration/BpmnEngineList.java b/src/main/java/org/camunda/automator/configuration/BpmnEngineList.java index 2b8c49f..5222766 100644 --- a/src/main/java/org/camunda/automator/configuration/BpmnEngineList.java +++ b/src/main/java/org/camunda/automator/configuration/BpmnEngineList.java @@ -13,586 +13,582 @@ import org.springframework.stereotype.Component; import javax.annotation.PostConstruct; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import java.util.StringTokenizer; +import java.util.*; @Component public class BpmnEngineList { - public static final int DEFAULT_VALUE_EXECUTION_THREADS = 100; - public static final int DEFAULT_VALUE_MAX_JOBS_ACTIVE = -1; - public static final String CONF_WORKER_MAX_JOBS_ACTIVE = "workerMaxJobsActive"; - public static final String CONF_WORKER_EXECUTION_THREADS = "workerExecutionThreads"; - public static final String CONF_TASK_LIST_URL = "taskListUrl"; - public static final String CONF_TASK_LIST_USER_NAME = "taskListUserName"; - public static final String CONF_TASK_LIST_PASSWORD = "taskListUserPassword"; - public static final String CONF_TASK_LIST_CLIENT_ID = "taskListClientId"; - public static final String CONF_TASK_LIST_CLIENT_SECRET = "taskListClientSecret"; - // Example taskListKeycloakUrl: "http://localhost:18080/auth/realms/camunda-platform" - public static final String CONF_TASK_LIST_KEYCLOAK_URL = "taskListKeycloakUrl"; - - public static final String CONF_IDENTITY_URL = "identityUrl"; - public static final String CONF_OPERATE_URL = "operateUrl"; - public static final String CONF_OPERATE_USER_PASSWORD = "operateUserPassword"; - public static final String CONF_OPERATE_USER_NAME = "operateUserName"; - public static final String CONF_AUTHENTICATIONURL = "authenticationUrl"; - public static final String CONF_OPERATE_CLIENT_ID = "operateClientId"; - public static final String CONF_OPERATE_CLIENT_SECRET = "operateClientSecret"; - public static final String CONF_OPERATE_AUDIENCE = "operateAudientce"; - - public static final String CONF_ZEEBE_GATEWAY_ADDRESS = "zeebeGatewayAddress"; - public static final String CONF_URL = "url"; - public static final String CONF_TYPE = "type"; - public static final String CONF_TYPE_V_CAMUNDA_8 = "camunda8"; - public static final String CONF_TYPE_V_CAMUNDA_8_SAAS = "camunda8Saas"; - public static final String CONF_TYPE_V_CAMUNDA_7 = "camunda7"; - - public static final String CONF_ZEEBE_SAAS_REGION = "region"; - public static final String CONF_ZEEBE_SECRET = "zeebeClientSecret"; - public static final String CONF_ZEEBE_SAAS_CLUSTER_ID = "clusterId"; - public static final String CONF_ZEEBE_CLIENT_ID = "zeebeClientId"; - public static final String CONF_ZEEBE_AUDIENCE = "zeebeAudience"; - public static final String CONF_ZEEBE_PLAINTEXT = "zeebePlainText"; - public static final String ZEEBE_DEFAULT_AUDIENCE = "zeebe.camunda.io"; - - static Logger logger = LoggerFactory.getLogger(BpmnEngineList.class); - - @Autowired - ConfigurationServersEngine configurationServersEngine; - - private List<BpmnServerDefinition> allServers = new ArrayList<>(); - - @PostConstruct - public void init() { - allServers = new ArrayList<>(); - - try { - // get From Server Connection - allServers.addAll(getFromServerConfiguration()); - - // decode the serverConnections - allServers.addAll(getFromServersConnectionList()); - - // decode serversList - allServers.addAll(getFromServersList()); - - // log all servers detected - logger.info("ConfigurationBpmEngine: servers detected : {} ", allServers.size()); - for (BpmnServerDefinition server : allServers) { - String serverDetails = "Configuration Server Type[" + server.serverType + "] "; - if (server.serverType == null) { - logger.error("ServerType not declared for server [{}]", server.name); - return; + public static final int DEFAULT_VALUE_EXECUTION_THREADS = 100; + public static final int DEFAULT_VALUE_MAX_JOBS_ACTIVE = -1; + public static final String CONF_WORKER_MAX_JOBS_ACTIVE = "workerMaxJobsActive"; + public static final String CONF_WORKER_EXECUTION_THREADS = "workerExecutionThreads"; + public static final String CONF_TASK_LIST_URL = "taskListUrl"; + public static final String CONF_TASK_LIST_USER_NAME = "taskListUserName"; + public static final String CONF_TASK_LIST_PASSWORD = "taskListUserPassword"; + public static final String CONF_TASK_LIST_CLIENT_ID = "taskListClientId"; + public static final String CONF_TASK_LIST_CLIENT_SECRET = "taskListClientSecret"; + // Example taskListKeycloakUrl: "http://localhost:18080/auth/realms/camunda-platform" + public static final String CONF_TASK_LIST_KEYCLOAK_URL = "taskListKeycloakUrl"; + + public static final String CONF_IDENTITY_URL = "identityUrl"; + public static final String CONF_OPERATE_URL = "operateUrl"; + public static final String CONF_OPERATE_USER_PASSWORD = "operateUserPassword"; + public static final String CONF_OPERATE_USER_NAME = "operateUserName"; + public static final String CONF_AUTHENTICATIONURL = "authenticationUrl"; + public static final String CONF_OPERATE_CLIENT_ID = "operateClientId"; + public static final String CONF_OPERATE_CLIENT_SECRET = "operateClientSecret"; + public static final String CONF_OPERATE_AUDIENCE = "operateAudientce"; + + public static final String CONF_ZEEBE_GATEWAY_ADDRESS = "zeebeGatewayAddress"; + public static final String CONF_URL = "url"; + public static final String CONF_TYPE = "type"; + public static final String CONF_TYPE_V_CAMUNDA_8 = "camunda8"; + public static final String CONF_TYPE_V_CAMUNDA_8_SAAS = "camunda8Saas"; + public static final String CONF_TYPE_V_CAMUNDA_7 = "camunda7"; + + public static final String CONF_ZEEBE_SAAS_REGION = "region"; + public static final String CONF_ZEEBE_SECRET = "zeebeClientSecret"; + public static final String CONF_ZEEBE_SAAS_CLUSTER_ID = "clusterId"; + public static final String CONF_ZEEBE_CLIENT_ID = "zeebeClientId"; + public static final String CONF_ZEEBE_AUDIENCE = "zeebeAudience"; + public static final String CONF_ZEEBE_PLAINTEXT = "zeebePlainText"; + public static final String ZEEBE_DEFAULT_AUDIENCE = "zeebe.camunda.io"; + + static Logger logger = LoggerFactory.getLogger(BpmnEngineList.class); + + @Autowired + ConfigurationServersEngine configurationServersEngine; + + private List<BpmnServerDefinition> allServers = new ArrayList<>(); + + @PostConstruct + public void init() { + allServers = new ArrayList<>(); + + try { + // get From Server Connection + allServers.addAll(getFromServerConfiguration()); + + // decode the serverConnections + allServers.addAll(getFromServersConnectionList()); + + // decode serversList + allServers.addAll(getFromServersList()); + + // log all servers detected + logger.info("ConfigurationBpmEngine: servers detected : {} ", allServers.size()); + for (BpmnServerDefinition server : allServers) { + String serverDetails = "Configuration Server Type[" + server.serverType + "] "; + if (server.serverType == null) { + logger.error("ServerType not declared for server [{}]", server.name); + return; + } + + serverDetails += switch (server.serverType) { + case CAMUNDA_8 -> "ZeebeadressGateway [" + server.zeebeGatewayAddress + "]"; + case CAMUNDA_8_SAAS -> + "ZeebeClientId [" + server.zeebeClientId + "] ClusterId[" + server.zeebeSaasClusterId + "] RegionId[" + + server.zeebeSaasRegion + "]"; + case CAMUNDA_7 -> "Camunda7URL [" + server.camunda7ServerUrl + "]"; + case DUMMY -> "Dummy"; + }; + logger.info(serverDetails); + } + } catch (Exception e) { + logger.error("Error during initialization : {}", e.getMessage()); } + } - serverDetails += switch (server.serverType) { - case CAMUNDA_8 -> "ZeebeadressGateway [" + server.zeebeGatewayAddress + "]"; - case CAMUNDA_8_SAAS -> - "ZeebeClientId [" + server.zeebeClientId + "] ClusterId[" + server.zeebeSaasClusterId + "] RegionId[" - + server.zeebeSaasRegion + "]"; - case CAMUNDA_7 -> "Camunda7URL [" + server.camunda7ServerUrl + "]"; - case DUMMY -> "Dummy"; - }; - logger.info(serverDetails); - } - } catch (Exception e) { - logger.error("Error during initialization : {}", e.getMessage()); + /** + * Add an explicit server, by the API + * + * @param bpmnEngineConfiguration server to add in the list + */ + public void addExplicitServer(BpmnServerDefinition bpmnEngineConfiguration) { + allServers.add(bpmnEngineConfiguration); } - } - - /** - * Add an explicit server, by the API - * - * @param bpmnEngineConfiguration server to add in the list - */ - public void addExplicitServer(BpmnServerDefinition bpmnEngineConfiguration) { - allServers.add(bpmnEngineConfiguration); - } - - public List<BpmnServerDefinition> getListServers() { - return allServers; - } - - /** - * get a server by its name - * - * @param serverName serverName - * @return the server, or null - * @throws AutomatorException on any error - */ - public BpmnEngineList.BpmnServerDefinition getByServerName(String serverName) throws AutomatorException { - Optional<BpmnServerDefinition> first = allServers.stream().filter(t -> t.name.equals(serverName)).findFirst(); - return first.isPresent() ? first.get() : null; - } - - /** - * get a server by its type - * - * @param serverType type of server CAMUNDA 8 ? 7 ? - * @return a server - * @throws AutomatorException on any error - */ - public BpmnEngineList.BpmnServerDefinition getByServerType(CamundaEngine serverType) { - Optional<BpmnServerDefinition> first = allServers.stream() - .filter(t -> sameType(t.serverType, serverType)) - .findFirst(); - return first.isPresent() ? first.get() : null; - } - - public boolean getLogDebug() { - return configurationServersEngine.logDebug; - } - - /* ******************************************************************** */ - /* */ - /* Different information in the YAML */ - /* */ - /* ******************************************************************** */ - - /** - * Explode the configuration serverConnections - * - * @return list of server definition - * @throws AutomatorException any errors - */ - private List<BpmnServerDefinition> getFromServersConnectionList() throws AutomatorException { - // not possible to use a Stream: decode throw an exception - List<BpmnServerDefinition> list = new ArrayList<>(); - int count = 0; - for (String s : configurationServersEngine.serversConnection) { - count++; - if (s.isEmpty()) - continue; - BpmnServerDefinition bpmnServerDefinition = decodeServerConnection(s, "Range in ConnectionString: #" + count); - if (bpmnServerDefinition.serverType == null) { - logger.error("Server Type can't be detected in string [{}]", s); - continue; - } - - list.add(bpmnServerDefinition); + + public List<BpmnServerDefinition> getListServers() { + return allServers; } - return list; - } - - /** - * getFromServerList - * in configuration, give a list of server. - * - * @return the list of available server - * @throws AutomatorException in case of error - */ - private List<BpmnServerDefinition> getFromServersList() throws AutomatorException { - List<BpmnServerDefinition> serverList = new ArrayList<>(); - - int count = 0; - for (Map<String, Object> serverMap : configurationServersEngine.getServersList()) { - count++; - BpmnServerDefinition bpmnServerDefinition = new BpmnServerDefinition(); - bpmnServerDefinition.name = getString("name", serverMap, null, "ServerList #" + count, true); - String contextLog = "ServerList #" + count + " Name [" + bpmnServerDefinition.name + "]"; - bpmnServerDefinition.workerMaxJobsActive = getInteger(CONF_WORKER_MAX_JOBS_ACTIVE, serverMap, - DEFAULT_VALUE_MAX_JOBS_ACTIVE, contextLog); - - if (CONF_TYPE_V_CAMUNDA_7.equalsIgnoreCase(getString(CONF_TYPE, serverMap, null, contextLog, true))) { - bpmnServerDefinition.serverType = CamundaEngine.CAMUNDA_7; - bpmnServerDefinition.camunda7ServerUrl = getString(CONF_URL, serverMap, null, contextLog, true); - if (bpmnServerDefinition.camunda7ServerUrl == null) - throw new AutomatorException( - "Incorrect Definition - [url] expected for [" + CONF_TYPE_V_CAMUNDA_7 + "] type " + contextLog); - } - - if (CONF_TYPE_V_CAMUNDA_8.equalsIgnoreCase(getString(CONF_TYPE, serverMap, null, contextLog, true))) { - bpmnServerDefinition.serverType = CamundaEngine.CAMUNDA_8; - bpmnServerDefinition.zeebeGatewayAddress = getString(CONF_ZEEBE_GATEWAY_ADDRESS, serverMap, null, contextLog, - true); - bpmnServerDefinition.zeebeClientId = getString(CONF_ZEEBE_CLIENT_ID, serverMap, null, contextLog, false); - bpmnServerDefinition.zeebeClientSecret = getString(CONF_ZEEBE_SECRET, serverMap, null, contextLog, false); - bpmnServerDefinition.zeebeAudience = getString(CONF_ZEEBE_AUDIENCE, serverMap, ZEEBE_DEFAULT_AUDIENCE, - contextLog, false); - bpmnServerDefinition.zeebePlainText = getBoolean(CONF_ZEEBE_PLAINTEXT, serverMap, true, contextLog, false); - bpmnServerDefinition.authenticationUrl = getString(CONF_AUTHENTICATIONURL, serverMap, null, contextLog, false); - - bpmnServerDefinition.identityUrl = getString(CONF_IDENTITY_URL, serverMap, null, contextLog, false); - bpmnServerDefinition.operateUrl = getString(CONF_OPERATE_URL, serverMap, null, contextLog, false); - bpmnServerDefinition.operateUserName = getString(CONF_OPERATE_USER_NAME, serverMap, "Demo", contextLog, false); - bpmnServerDefinition.operateUserPassword = getString(CONF_OPERATE_USER_PASSWORD, serverMap, "Demo", contextLog, - false); - bpmnServerDefinition.operateClientId = getString(CONF_OPERATE_CLIENT_ID, serverMap, null, contextLog, false); - bpmnServerDefinition.operateClientSecret = getString(CONF_OPERATE_CLIENT_SECRET, serverMap, null, contextLog, - false); - bpmnServerDefinition.operateAudience = getString(CONF_OPERATE_AUDIENCE, serverMap, null, contextLog, false); - - bpmnServerDefinition.taskListUrl = getString(CONF_TASK_LIST_URL, serverMap, null, contextLog, false); - bpmnServerDefinition.taskListUserName = getString(CONF_TASK_LIST_USER_NAME, serverMap, null, contextLog, false); - bpmnServerDefinition.taskListUserPassword = getString(CONF_TASK_LIST_PASSWORD, serverMap, null, contextLog, - false); - bpmnServerDefinition.taskListClientId = getString(CONF_TASK_LIST_CLIENT_ID, serverMap, null, contextLog, false); - bpmnServerDefinition.taskListClientSecret = getString(CONF_TASK_LIST_CLIENT_SECRET, serverMap, null, contextLog, - false); - bpmnServerDefinition.taskListKeycloakUrl = getString(CONF_TASK_LIST_KEYCLOAK_URL, serverMap, null, contextLog, - false); - - bpmnServerDefinition.workerExecutionThreads = getInteger(CONF_WORKER_EXECUTION_THREADS, serverMap, - DEFAULT_VALUE_EXECUTION_THREADS, contextLog); - if (bpmnServerDefinition.zeebeGatewayAddress == null) - throw new AutomatorException( - "Incorrect Definition - [zeebeGatewayAddress] expected for [" + CONF_TYPE_V_CAMUNDA_8 + "] type"); - } - - if (CONF_TYPE_V_CAMUNDA_8_SAAS.equalsIgnoreCase(getString(CONF_TYPE, serverMap, null, contextLog, true))) { - bpmnServerDefinition.serverType = CamundaEngine.CAMUNDA_8_SAAS; - bpmnServerDefinition.zeebeSaasRegion = getString(CONF_ZEEBE_SAAS_REGION, serverMap, null, contextLog, true); - bpmnServerDefinition.zeebeSaasClusterId = getString(CONF_ZEEBE_SAAS_CLUSTER_ID, serverMap, null, contextLog, - true); - bpmnServerDefinition.zeebeClientId = getString(CONF_ZEEBE_CLIENT_ID, serverMap, null, contextLog, true); - bpmnServerDefinition.zeebeClientSecret = getString(CONF_ZEEBE_SECRET, serverMap, null, contextLog, true); - bpmnServerDefinition.zeebeAudience = getString(CONF_ZEEBE_AUDIENCE, serverMap, ZEEBE_DEFAULT_AUDIENCE, - contextLog, true); - bpmnServerDefinition.authenticationUrl = getString(CONF_AUTHENTICATIONURL, serverMap, - "https://login.cloud.camunda.io/oauth/token", contextLog, false); - - bpmnServerDefinition.workerExecutionThreads = getInteger(CONF_WORKER_EXECUTION_THREADS, serverMap, - DEFAULT_VALUE_EXECUTION_THREADS, contextLog); - bpmnServerDefinition.operateUserName = getString(CONF_OPERATE_USER_NAME, serverMap, null, contextLog, false); - bpmnServerDefinition.operateUserPassword = getString(CONF_OPERATE_USER_PASSWORD, serverMap, null, contextLog, - false); - bpmnServerDefinition.operateUrl = getString(CONF_OPERATE_URL, serverMap, null, contextLog, false); - bpmnServerDefinition.taskListUrl = getString(CONF_TASK_LIST_URL, serverMap, null, contextLog, false); - bpmnServerDefinition.taskListClientId = getString(CONF_TASK_LIST_CLIENT_ID, serverMap, null, contextLog, false); - bpmnServerDefinition.taskListClientSecret = getString(CONF_TASK_LIST_CLIENT_SECRET, serverMap, null, contextLog, - false); - - if (bpmnServerDefinition.zeebeSaasRegion == null || bpmnServerDefinition.zeebeClientSecret == null - || bpmnServerDefinition.zeebeSaasClusterId == null || bpmnServerDefinition.zeebeClientId == null) - throw new AutomatorException( - "Incorrect Definition - [zeebeCloudRegister],[zeebeCloudRegion], [zeebeClientSecret},[zeebeCloudClusterId],[zeebeCloudClientId] expected for [Camunda8SaaS] type"); - } - serverList.add(bpmnServerDefinition); + + /** + * get a server by its name + * + * @param serverName serverName + * @return the server, or null + * @throws AutomatorException on any error + */ + public BpmnEngineList.BpmnServerDefinition getByServerName(String serverName) throws AutomatorException { + Optional<BpmnServerDefinition> first = allServers.stream().filter(t -> t.name.equals(serverName)).findFirst(); + return first.isPresent() ? first.get() : null; } - return serverList; - } - - /** - * DecodeServerConnection - * - * @param connectionString connection string - * @return a ServerDefinition - * @throws AutomatorException on any error - */ - private BpmnServerDefinition decodeServerConnection(String connectionString, String contextLog) - throws AutomatorException { - StringTokenizer st = new StringTokenizer(connectionString, ","); - BpmnServerDefinition bpmnServerDefinition = new BpmnServerDefinition(); - bpmnServerDefinition.name = (st.hasMoreTokens() ? st.nextToken() : null); - try { - bpmnServerDefinition.serverType = st.hasMoreTokens() ? CamundaEngine.valueOf(st.nextToken()) : null; - if (CamundaEngine.CAMUNDA_7.equals(bpmnServerDefinition.serverType)) { - bpmnServerDefinition.camunda7ServerUrl = (st.hasMoreTokens() ? st.nextToken() : null); - - } else if (CamundaEngine.CAMUNDA_8.equals(bpmnServerDefinition.serverType)) { - bpmnServerDefinition.zeebeGatewayAddress = (st.hasMoreTokens() ? st.nextToken() : null); - bpmnServerDefinition.operateUrl = (st.hasMoreTokens() ? st.nextToken() : null); - bpmnServerDefinition.operateUserName = (st.hasMoreTokens() ? st.nextToken() : null); - bpmnServerDefinition.operateUserPassword = (st.hasMoreTokens() ? st.nextToken() : null); - bpmnServerDefinition.taskListUrl = (st.hasMoreTokens() ? st.nextToken() : null); - bpmnServerDefinition.workerExecutionThreads = (st.hasMoreTokens() ? - parseInt(CONF_WORKER_EXECUTION_THREADS, st.nextToken(), DEFAULT_VALUE_EXECUTION_THREADS, contextLog) : - null); - bpmnServerDefinition.workerMaxJobsActive = (st.hasMoreTokens() ? - parseInt(CONF_WORKER_MAX_JOBS_ACTIVE, st.nextToken(), DEFAULT_VALUE_MAX_JOBS_ACTIVE, contextLog) : - null); - - } else if (CamundaEngine.CAMUNDA_8_SAAS.equals(bpmnServerDefinition.serverType)) { - bpmnServerDefinition.zeebeSaasRegion = (st.hasMoreTokens() ? st.nextToken() : null); - bpmnServerDefinition.zeebeSaasClusterId = (st.hasMoreTokens() ? st.nextToken() : null); - bpmnServerDefinition.zeebeClientId = (st.hasMoreTokens() ? st.nextToken() : null); - bpmnServerDefinition.zeebeClientSecret = (st.hasMoreTokens() ? st.nextToken() : null); - bpmnServerDefinition.zeebeAudience = (st.hasMoreTokens() ? st.nextToken() : null); - bpmnServerDefinition.operateClientId = (st.hasMoreTokens() ? st.nextToken() : null); - bpmnServerDefinition.operateClientSecret = (st.hasMoreTokens() ? st.nextToken() : null); - bpmnServerDefinition.taskListClientId = (st.hasMoreTokens() ? st.nextToken() : null); - bpmnServerDefinition.taskListClientSecret = (st.hasMoreTokens() ? st.nextToken() : null); - - bpmnServerDefinition.workerExecutionThreads = (st.hasMoreTokens() ? - parseInt(CONF_WORKER_EXECUTION_THREADS, st.nextToken(), DEFAULT_VALUE_EXECUTION_THREADS, contextLog) : - null); - bpmnServerDefinition.workerMaxJobsActive = (st.hasMoreTokens() ? - parseInt(CONF_WORKER_MAX_JOBS_ACTIVE, st.nextToken(), DEFAULT_VALUE_MAX_JOBS_ACTIVE, contextLog) : - null); - } - return bpmnServerDefinition; - } catch (Exception e) { - throw new AutomatorException("Can't decode string [" + connectionString + "] " + e.getMessage()); + + /** + * get a server by its type + * + * @param serverType type of server CAMUNDA 8 ? 7 ? + * @return a server + * @throws AutomatorException on any error + */ + public BpmnEngineList.BpmnServerDefinition getByServerType(CamundaEngine serverType) { + Optional<BpmnServerDefinition> first = allServers.stream() + .filter(t -> sameType(t.serverType, serverType)) + .findFirst(); + return first.isPresent() ? first.get() : null; } - } - - /** - * Get the list from the serverConfiguration. If the variable exist, then use the value. Easy to configure for K8 - * - * @return list of BpmnServer - */ - private List<BpmnServerDefinition> getFromServerConfiguration() { - List<BpmnServerDefinition> list = new ArrayList<>(); - - // get the direct list - if (hasValue(configurationServersEngine.camunda7Url)) { - BpmnServerDefinition camunda7 = new BpmnServerDefinition(); - camunda7.serverType = CamundaEngine.CAMUNDA_7; - camunda7.name = configurationServersEngine.camunda7Name; - camunda7.camunda7ServerUrl = configurationServersEngine.camunda7Url; - camunda7.camunda7UserName = configurationServersEngine.camunda7UserName; - camunda7.camunda7Password = configurationServersEngine.camunda7Password; - - camunda7.workerMaxJobsActive = parseInt("Camunda7." + CONF_WORKER_MAX_JOBS_ACTIVE, - configurationServersEngine.C7WorkerMaxJobsActive, DEFAULT_VALUE_MAX_JOBS_ACTIVE, ""); - camunda7.workerExecutionThreads = parseInt("Camunda7." + CONF_WORKER_EXECUTION_THREADS, - configurationServersEngine.C7WorkerMaxJobsActive, DEFAULT_VALUE_EXECUTION_THREADS, ""); - - camunda7.workerMaxJobsActive = parseInt("Camunda7." + CONF_WORKER_MAX_JOBS_ACTIVE, - configurationServersEngine.C7WorkerMaxJobsActive, DEFAULT_VALUE_MAX_JOBS_ACTIVE, ""); - list.add(camunda7); - logger.info("Configuration: Camunda7 Name[{}] url[{}] MaxJobsActive[{}]", camunda7.name, - camunda7.camunda7ServerUrl, camunda7.workerMaxJobsActive); + + public boolean getLogDebug() { + return configurationServersEngine.logDebug; } - if (hasValue(configurationServersEngine.zeebeGatewayAddress)) { - BpmnServerDefinition camunda8 = new BpmnServerDefinition(); - camunda8.serverType = CamundaEngine.CAMUNDA_8; - camunda8.name = configurationServersEngine.zeebeName; - camunda8.zeebeGatewayAddress = configurationServersEngine.zeebeGatewayAddress; - camunda8.workerExecutionThreads = parseInt("Camunda8." + CONF_WORKER_EXECUTION_THREADS, - configurationServersEngine.zeebeWorkerExecutionThreads, DEFAULT_VALUE_EXECUTION_THREADS, ""); - camunda8.workerMaxJobsActive = parseInt("Camunda8." + CONF_WORKER_MAX_JOBS_ACTIVE, - configurationServersEngine.zeebeWorkerMaxJobsActive, DEFAULT_VALUE_MAX_JOBS_ACTIVE, ""); - camunda8.operateUrl = configurationServersEngine.zeebeOperateUrl; - camunda8.operateUserName = configurationServersEngine.zeebeOperateUserName; - camunda8.operateUserPassword = configurationServersEngine.zeebeOperateUserPassword; - camunda8.taskListUrl = configurationServersEngine.zeebeTaskListUrl; - camunda8.taskListUserName = configurationServersEngine.zeebeTaskListUserName; - camunda8.taskListUserPassword = configurationServersEngine.zeebeTaskListUserPassword; - list.add(camunda8); - logger.info( - "Configuration: Camunda8 Name[{}] zeebeGateway[{}] MaxJobsActive[{}] WorkerThreads[{}] " + "OperateURL[{}]", - camunda8.name, camunda8.camunda7ServerUrl, camunda8.workerMaxJobsActive, camunda8.workerExecutionThreads, - camunda8.operateUrl); + /* ******************************************************************** */ + /* */ + /* Different information in the YAML */ + /* */ + /* ******************************************************************** */ + + /** + * Explode the configuration serverConnections + * + * @return list of server definition + * @throws AutomatorException any errors + */ + private List<BpmnServerDefinition> getFromServersConnectionList() throws AutomatorException { + // not possible to use a Stream: decode throw an exception + List<BpmnServerDefinition> list = new ArrayList<>(); + int count = 0; + for (String s : configurationServersEngine.serversConnection) { + count++; + if (s.isEmpty()) + continue; + BpmnServerDefinition bpmnServerDefinition = decodeServerConnection(s, "Range in ConnectionString: #" + count); + if (bpmnServerDefinition.serverType == null) { + logger.error("Server Type can't be detected in string [{}]", s); + continue; + } + + list.add(bpmnServerDefinition); + } + return list; } - if (hasValue(configurationServersEngine.zeebeSaasClusterId)) { - BpmnServerDefinition camunda8 = new BpmnServerDefinition(); - camunda8.serverType = CamundaEngine.CAMUNDA_8_SAAS; - camunda8.name = configurationServersEngine.zeebeName; - camunda8.zeebeSaasRegion = configurationServersEngine.zeebeSaasRegion; - camunda8.zeebeSaasClusterId = configurationServersEngine.zeebeSaasClusterId; - camunda8.zeebeClientId = configurationServersEngine.zeebeSaasClientId; - camunda8.zeebeClientSecret = configurationServersEngine.zeebeSaasClientSecret; - camunda8.authenticationUrl = configurationServersEngine.zeebeSaasOAuthUrl; - camunda8.zeebeAudience = configurationServersEngine.zeebeSaasAudience; - camunda8.operateUrl = configurationServersEngine.zeebeOperateUrl; - camunda8.operateUserName = configurationServersEngine.zeebeOperateUserName; - camunda8.operateUserPassword = configurationServersEngine.zeebeOperateUserPassword; - camunda8.taskListUrl = configurationServersEngine.zeebeTaskListUrl; - list.add(camunda8); + /** + * getFromServerList + * in configuration, give a list of server. + * + * @return the list of available server + * @throws AutomatorException in case of error + */ + private List<BpmnServerDefinition> getFromServersList() throws AutomatorException { + List<BpmnServerDefinition> serverList = new ArrayList<>(); + + int count = 0; + for (Map<String, Object> serverMap : configurationServersEngine.getServersList()) { + count++; + BpmnServerDefinition bpmnServerDefinition = new BpmnServerDefinition(); + bpmnServerDefinition.name = getString("name", serverMap, null, "ServerList #" + count, true); + String contextLog = "ServerList #" + count + " Name [" + bpmnServerDefinition.name + "]"; + bpmnServerDefinition.workerMaxJobsActive = getInteger(CONF_WORKER_MAX_JOBS_ACTIVE, serverMap, + DEFAULT_VALUE_MAX_JOBS_ACTIVE, contextLog); + + if (CONF_TYPE_V_CAMUNDA_7.equalsIgnoreCase(getString(CONF_TYPE, serverMap, null, contextLog, true))) { + bpmnServerDefinition.serverType = CamundaEngine.CAMUNDA_7; + bpmnServerDefinition.camunda7ServerUrl = getString(CONF_URL, serverMap, null, contextLog, true); + if (bpmnServerDefinition.camunda7ServerUrl == null) + throw new AutomatorException( + "Incorrect Definition - [url] expected for [" + CONF_TYPE_V_CAMUNDA_7 + "] type " + contextLog); + } + + if (CONF_TYPE_V_CAMUNDA_8.equalsIgnoreCase(getString(CONF_TYPE, serverMap, null, contextLog, true))) { + bpmnServerDefinition.serverType = CamundaEngine.CAMUNDA_8; + bpmnServerDefinition.zeebeGatewayAddress = getString(CONF_ZEEBE_GATEWAY_ADDRESS, serverMap, null, contextLog, + true); + bpmnServerDefinition.zeebeClientId = getString(CONF_ZEEBE_CLIENT_ID, serverMap, null, contextLog, false); + bpmnServerDefinition.zeebeClientSecret = getString(CONF_ZEEBE_SECRET, serverMap, null, contextLog, false); + bpmnServerDefinition.zeebeAudience = getString(CONF_ZEEBE_AUDIENCE, serverMap, ZEEBE_DEFAULT_AUDIENCE, + contextLog, false); + bpmnServerDefinition.zeebePlainText = getBoolean(CONF_ZEEBE_PLAINTEXT, serverMap, true, contextLog, false); + bpmnServerDefinition.authenticationUrl = getString(CONF_AUTHENTICATIONURL, serverMap, null, contextLog, false); + + bpmnServerDefinition.identityUrl = getString(CONF_IDENTITY_URL, serverMap, null, contextLog, false); + bpmnServerDefinition.operateUrl = getString(CONF_OPERATE_URL, serverMap, null, contextLog, false); + bpmnServerDefinition.operateUserName = getString(CONF_OPERATE_USER_NAME, serverMap, "Demo", contextLog, false); + bpmnServerDefinition.operateUserPassword = getString(CONF_OPERATE_USER_PASSWORD, serverMap, "Demo", contextLog, + false); + bpmnServerDefinition.operateClientId = getString(CONF_OPERATE_CLIENT_ID, serverMap, null, contextLog, false); + bpmnServerDefinition.operateClientSecret = getString(CONF_OPERATE_CLIENT_SECRET, serverMap, null, contextLog, + false); + bpmnServerDefinition.operateAudience = getString(CONF_OPERATE_AUDIENCE, serverMap, null, contextLog, false); + + bpmnServerDefinition.taskListUrl = getString(CONF_TASK_LIST_URL, serverMap, null, contextLog, false); + bpmnServerDefinition.taskListUserName = getString(CONF_TASK_LIST_USER_NAME, serverMap, null, contextLog, false); + bpmnServerDefinition.taskListUserPassword = getString(CONF_TASK_LIST_PASSWORD, serverMap, null, contextLog, + false); + bpmnServerDefinition.taskListClientId = getString(CONF_TASK_LIST_CLIENT_ID, serverMap, null, contextLog, false); + bpmnServerDefinition.taskListClientSecret = getString(CONF_TASK_LIST_CLIENT_SECRET, serverMap, null, contextLog, + false); + bpmnServerDefinition.taskListKeycloakUrl = getString(CONF_TASK_LIST_KEYCLOAK_URL, serverMap, null, contextLog, + false); + + bpmnServerDefinition.workerExecutionThreads = getInteger(CONF_WORKER_EXECUTION_THREADS, serverMap, + DEFAULT_VALUE_EXECUTION_THREADS, contextLog); + if (bpmnServerDefinition.zeebeGatewayAddress == null) + throw new AutomatorException( + "Incorrect Definition - [zeebeGatewayAddress] expected for [" + CONF_TYPE_V_CAMUNDA_8 + "] type"); + } + + if (CONF_TYPE_V_CAMUNDA_8_SAAS.equalsIgnoreCase(getString(CONF_TYPE, serverMap, null, contextLog, true))) { + bpmnServerDefinition.serverType = CamundaEngine.CAMUNDA_8_SAAS; + bpmnServerDefinition.zeebeSaasRegion = getString(CONF_ZEEBE_SAAS_REGION, serverMap, null, contextLog, true); + bpmnServerDefinition.zeebeSaasClusterId = getString(CONF_ZEEBE_SAAS_CLUSTER_ID, serverMap, null, contextLog, + true); + bpmnServerDefinition.zeebeClientId = getString(CONF_ZEEBE_CLIENT_ID, serverMap, null, contextLog, true); + bpmnServerDefinition.zeebeClientSecret = getString(CONF_ZEEBE_SECRET, serverMap, null, contextLog, true); + bpmnServerDefinition.zeebeAudience = getString(CONF_ZEEBE_AUDIENCE, serverMap, ZEEBE_DEFAULT_AUDIENCE, + contextLog, true); + bpmnServerDefinition.authenticationUrl = getString(CONF_AUTHENTICATIONURL, serverMap, + "https://login.cloud.camunda.io/oauth/token", contextLog, false); + + bpmnServerDefinition.workerExecutionThreads = getInteger(CONF_WORKER_EXECUTION_THREADS, serverMap, + DEFAULT_VALUE_EXECUTION_THREADS, contextLog); + bpmnServerDefinition.operateUserName = getString(CONF_OPERATE_USER_NAME, serverMap, null, contextLog, false); + bpmnServerDefinition.operateUserPassword = getString(CONF_OPERATE_USER_PASSWORD, serverMap, null, contextLog, + false); + bpmnServerDefinition.operateUrl = getString(CONF_OPERATE_URL, serverMap, null, contextLog, false); + bpmnServerDefinition.taskListUrl = getString(CONF_TASK_LIST_URL, serverMap, null, contextLog, false); + bpmnServerDefinition.taskListClientId = getString(CONF_TASK_LIST_CLIENT_ID, serverMap, null, contextLog, false); + bpmnServerDefinition.taskListClientSecret = getString(CONF_TASK_LIST_CLIENT_SECRET, serverMap, null, contextLog, + false); + + if (bpmnServerDefinition.zeebeSaasRegion == null || bpmnServerDefinition.zeebeClientSecret == null + || bpmnServerDefinition.zeebeSaasClusterId == null || bpmnServerDefinition.zeebeClientId == null) + throw new AutomatorException( + "Incorrect Definition - [zeebeCloudRegister],[zeebeCloudRegion], [zeebeClientSecret},[zeebeCloudClusterId],[zeebeCloudClientId] expected for [Camunda8SaaS] type"); + } + serverList.add(bpmnServerDefinition); + } + return serverList; } - return list; - } - - - - - /* ******************************************************************** */ - /* */ - /* Toolbox */ - /* */ - /* ******************************************************************** */ - - private String getString(String name, - Map<String, Object> recordData, - String defaultValue, - String contextLog, - boolean isMandatory) { - try { - if (!recordData.containsKey(name)) { - if (isMandatory) { - if (defaultValue == null) - logger.error("{}Variable [{}] not defined in {}", contextLog, name, contextLog); - else - logger.info("{} Variable [{}] not defined in {}", contextLog, name, contextLog); + + /** + * DecodeServerConnection + * + * @param connectionString connection string + * @return a ServerDefinition + * @throws AutomatorException on any error + */ + private BpmnServerDefinition decodeServerConnection(String connectionString, String contextLog) + throws AutomatorException { + StringTokenizer st = new StringTokenizer(connectionString, ","); + BpmnServerDefinition bpmnServerDefinition = new BpmnServerDefinition(); + bpmnServerDefinition.name = (st.hasMoreTokens() ? st.nextToken() : null); + try { + bpmnServerDefinition.serverType = st.hasMoreTokens() ? CamundaEngine.valueOf(st.nextToken()) : null; + if (CamundaEngine.CAMUNDA_7.equals(bpmnServerDefinition.serverType)) { + bpmnServerDefinition.camunda7ServerUrl = (st.hasMoreTokens() ? st.nextToken() : null); + + } else if (CamundaEngine.CAMUNDA_8.equals(bpmnServerDefinition.serverType)) { + bpmnServerDefinition.zeebeGatewayAddress = (st.hasMoreTokens() ? st.nextToken() : null); + bpmnServerDefinition.operateUrl = (st.hasMoreTokens() ? st.nextToken() : null); + bpmnServerDefinition.operateUserName = (st.hasMoreTokens() ? st.nextToken() : null); + bpmnServerDefinition.operateUserPassword = (st.hasMoreTokens() ? st.nextToken() : null); + bpmnServerDefinition.taskListUrl = (st.hasMoreTokens() ? st.nextToken() : null); + bpmnServerDefinition.workerExecutionThreads = (st.hasMoreTokens() ? + parseInt(CONF_WORKER_EXECUTION_THREADS, st.nextToken(), DEFAULT_VALUE_EXECUTION_THREADS, contextLog) : + null); + bpmnServerDefinition.workerMaxJobsActive = (st.hasMoreTokens() ? + parseInt(CONF_WORKER_MAX_JOBS_ACTIVE, st.nextToken(), DEFAULT_VALUE_MAX_JOBS_ACTIVE, contextLog) : + null); + + } else if (CamundaEngine.CAMUNDA_8_SAAS.equals(bpmnServerDefinition.serverType)) { + bpmnServerDefinition.zeebeSaasRegion = (st.hasMoreTokens() ? st.nextToken() : null); + bpmnServerDefinition.zeebeSaasClusterId = (st.hasMoreTokens() ? st.nextToken() : null); + bpmnServerDefinition.zeebeClientId = (st.hasMoreTokens() ? st.nextToken() : null); + bpmnServerDefinition.zeebeClientSecret = (st.hasMoreTokens() ? st.nextToken() : null); + bpmnServerDefinition.zeebeAudience = (st.hasMoreTokens() ? st.nextToken() : null); + bpmnServerDefinition.operateClientId = (st.hasMoreTokens() ? st.nextToken() : null); + bpmnServerDefinition.operateClientSecret = (st.hasMoreTokens() ? st.nextToken() : null); + bpmnServerDefinition.taskListClientId = (st.hasMoreTokens() ? st.nextToken() : null); + bpmnServerDefinition.taskListClientSecret = (st.hasMoreTokens() ? st.nextToken() : null); + + bpmnServerDefinition.workerExecutionThreads = (st.hasMoreTokens() ? + parseInt(CONF_WORKER_EXECUTION_THREADS, st.nextToken(), DEFAULT_VALUE_EXECUTION_THREADS, contextLog) : + null); + bpmnServerDefinition.workerMaxJobsActive = (st.hasMoreTokens() ? + parseInt(CONF_WORKER_MAX_JOBS_ACTIVE, st.nextToken(), DEFAULT_VALUE_MAX_JOBS_ACTIVE, contextLog) : + null); + } + return bpmnServerDefinition; + } catch (Exception e) { + throw new AutomatorException("Can't decode string [" + connectionString + "] " + e.getMessage()); } - return defaultValue; - } - return (String) recordData.get(name); - } catch (Exception e) { - logger.error("{} Variable [{}] {} bad definition {}", contextLog, name, contextLog, e.getMessage()); - return defaultValue; } - } - private Boolean getBoolean(String name, + /** + * Get the list from the serverConfiguration. If the variable exist, then use the value. Easy to configure for K8 + * + * @return list of BpmnServer + */ + private List<BpmnServerDefinition> getFromServerConfiguration() { + List<BpmnServerDefinition> list = new ArrayList<>(); + + // get the direct list + if (hasValue(configurationServersEngine.camunda7Url)) { + BpmnServerDefinition camunda7 = new BpmnServerDefinition(); + camunda7.serverType = CamundaEngine.CAMUNDA_7; + camunda7.name = configurationServersEngine.camunda7Name; + camunda7.camunda7ServerUrl = configurationServersEngine.camunda7Url; + camunda7.camunda7UserName = configurationServersEngine.camunda7UserName; + camunda7.camunda7Password = configurationServersEngine.camunda7Password; + + camunda7.workerMaxJobsActive = parseInt("Camunda7." + CONF_WORKER_MAX_JOBS_ACTIVE, + configurationServersEngine.C7WorkerMaxJobsActive, DEFAULT_VALUE_MAX_JOBS_ACTIVE, ""); + camunda7.workerExecutionThreads = parseInt("Camunda7." + CONF_WORKER_EXECUTION_THREADS, + configurationServersEngine.C7WorkerMaxJobsActive, DEFAULT_VALUE_EXECUTION_THREADS, ""); + + camunda7.workerMaxJobsActive = parseInt("Camunda7." + CONF_WORKER_MAX_JOBS_ACTIVE, + configurationServersEngine.C7WorkerMaxJobsActive, DEFAULT_VALUE_MAX_JOBS_ACTIVE, ""); + list.add(camunda7); + logger.info("Configuration: Camunda7 Name[{}] url[{}] MaxJobsActive[{}]", camunda7.name, + camunda7.camunda7ServerUrl, camunda7.workerMaxJobsActive); + } + if (hasValue(configurationServersEngine.zeebeGatewayAddress)) { + BpmnServerDefinition camunda8 = new BpmnServerDefinition(); + camunda8.serverType = CamundaEngine.CAMUNDA_8; + camunda8.name = configurationServersEngine.zeebeName; + camunda8.zeebeGatewayAddress = configurationServersEngine.zeebeGatewayAddress; + camunda8.workerExecutionThreads = parseInt("Camunda8." + CONF_WORKER_EXECUTION_THREADS, + configurationServersEngine.zeebeWorkerExecutionThreads, DEFAULT_VALUE_EXECUTION_THREADS, ""); + camunda8.workerMaxJobsActive = parseInt("Camunda8." + CONF_WORKER_MAX_JOBS_ACTIVE, + configurationServersEngine.zeebeWorkerMaxJobsActive, DEFAULT_VALUE_MAX_JOBS_ACTIVE, ""); + camunda8.operateUrl = configurationServersEngine.zeebeOperateUrl; + camunda8.operateUserName = configurationServersEngine.zeebeOperateUserName; + camunda8.operateUserPassword = configurationServersEngine.zeebeOperateUserPassword; + camunda8.taskListUrl = configurationServersEngine.zeebeTaskListUrl; + camunda8.taskListUserName = configurationServersEngine.zeebeTaskListUserName; + camunda8.taskListUserPassword = configurationServersEngine.zeebeTaskListUserPassword; + list.add(camunda8); + logger.info( + "Configuration: Camunda8 Name[{}] zeebeGateway[{}] MaxJobsActive[{}] WorkerThreads[{}] " + "OperateURL[{}]", + camunda8.name, camunda8.camunda7ServerUrl, camunda8.workerMaxJobsActive, camunda8.workerExecutionThreads, + camunda8.operateUrl); + + } + if (hasValue(configurationServersEngine.zeebeSaasClusterId)) { + BpmnServerDefinition camunda8 = new BpmnServerDefinition(); + camunda8.serverType = CamundaEngine.CAMUNDA_8_SAAS; + camunda8.name = configurationServersEngine.zeebeName; + camunda8.zeebeSaasRegion = configurationServersEngine.zeebeSaasRegion; + camunda8.zeebeSaasClusterId = configurationServersEngine.zeebeSaasClusterId; + camunda8.zeebeClientId = configurationServersEngine.zeebeSaasClientId; + camunda8.zeebeClientSecret = configurationServersEngine.zeebeSaasClientSecret; + camunda8.authenticationUrl = configurationServersEngine.zeebeSaasOAuthUrl; + camunda8.zeebeAudience = configurationServersEngine.zeebeSaasAudience; + camunda8.operateUrl = configurationServersEngine.zeebeOperateUrl; + camunda8.operateUserName = configurationServersEngine.zeebeOperateUserName; + camunda8.operateUserPassword = configurationServersEngine.zeebeOperateUserPassword; + camunda8.taskListUrl = configurationServersEngine.zeebeTaskListUrl; + list.add(camunda8); + + } + return list; + } + + + + + /* ******************************************************************** */ + /* */ + /* Toolbox */ + /* */ + /* ******************************************************************** */ + + private String getString(String name, Map<String, Object> recordData, - Boolean defaultValue, + String defaultValue, String contextLog, boolean isMandatory) { - try { - if (!recordData.containsKey(name)) { - if (isMandatory) { - if (defaultValue == null) - logger.error("{}Variable [{}] not defined in {}", contextLog, name, contextLog); - else - logger.info("{} Variable [{}] not defined in {}", contextLog, name, contextLog); + try { + if (!recordData.containsKey(name)) { + if (isMandatory) { + if (defaultValue == null) + logger.error("{}Variable [{}] not defined in {}", contextLog, name, contextLog); + else + logger.info("{} Variable [{}] not defined in {}", contextLog, name, contextLog); + } + return defaultValue; + } + return (String) recordData.get(name); + } catch (Exception e) { + logger.error("{} Variable [{}] {} bad definition {}", contextLog, name, contextLog, e.getMessage()); + return defaultValue; } - return defaultValue; - } - if (recordData.get(name) instanceof Boolean valueBoolean) - return valueBoolean; - return Boolean.valueOf(recordData.get(name).toString()); - } catch (Exception e) { - logger.error("{} Variable [{}] {} bad definition {}", contextLog, name, contextLog, e.getMessage()); - return defaultValue; - } - } - - private Integer getInteger(String name, Map<String, Object> recordData, Integer defaultValue, String contextLog) { - try { - if (!recordData.containsKey(name)) { - if (defaultValue == null) - logger.error("Variable [{}] not defined in {}", name, contextLog); - else - logger.info("Variable [{}] not defined in {}", name, contextLog); - return defaultValue; - } - return (Integer) recordData.get(name); - } catch (Exception e) { - logger.error("Variable [{}] {} bad definition {}", name, contextLog, e.getMessage()); - return defaultValue; - } - } - - private int parseInt(String label, String value, int defaultValue, String contextLog) { - try { - if (value.equals("''")) - return defaultValue; - return Integer.parseInt(value); - } catch (Exception e) { - logger.error("Can't parse value [{}] at [{}] {}", value, label, contextLog); - return defaultValue; } - } - - private boolean hasValue(String value) { - if (value == null) - return false; - if (value.equals("''")) - return false; - return !value.trim().isEmpty(); - } - - /** - * Compare type : CAMUNDA_8 and CAMUNDA_8_SAAS are considered as equals - * - * @param type1 type one to compare - * @param type2 type two to compare - * @return true if types are identical - */ - private boolean sameType(CamundaEngine type1, CamundaEngine type2) { - if (type1.equals(CamundaEngine.CAMUNDA_8_SAAS)) - type1 = CamundaEngine.CAMUNDA_8; - if (type2.equals(CamundaEngine.CAMUNDA_8_SAAS)) - type2 = CamundaEngine.CAMUNDA_8; - return type1.equals(type2); - } - - public enum CamundaEngine {CAMUNDA_7, CAMUNDA_8, CAMUNDA_8_SAAS, DUMMY} - - public static class BpmnServerDefinition { - public String name; - - public CamundaEngine serverType; - /** - * My Zeebe Address - */ - public String zeebeGatewayAddress; - public Boolean zeebePlainText; + private Boolean getBoolean(String name, + Map<String, Object> recordData, + Boolean defaultValue, + String contextLog, + boolean isMandatory) { + try { + if (!recordData.containsKey(name)) { + if (isMandatory) { + if (defaultValue == null) + logger.error("{}Variable [{}] not defined in {}", contextLog, name, contextLog); + else + logger.info("{} Variable [{}] not defined in {}", contextLog, name, contextLog); + } + return defaultValue; + } + if (recordData.get(name) instanceof Boolean valueBoolean) + return valueBoolean; + return Boolean.valueOf(recordData.get(name).toString()); + } catch (Exception e) { + logger.error("{} Variable [{}] {} bad definition {}", contextLog, name, contextLog, e.getMessage()); + return defaultValue; + } + } - /** - * SaaS Zeebe - */ - public String zeebeSaasRegion; - public String zeebeSaasClusterId; - public String zeebeClientId; - public String zeebeClientSecret; - public String zeebeAudience; - public String zeebeTenantId = null; - - public String identityUrl; - /** - * Connection to Operate - */ - public String operateUserName; - public String operateUserPassword; - public String operateUrl; - - // something like "http://localhost:18080/auth/realms/camunda-platform/protocol/openid-connect/token" - public String authenticationUrl; - public String operateClientId; - public String operateClientSecret; - public String operateAudience; - - public String taskListUrl; - public String taskListUserName; - public String taskListUserPassword; - public String taskListClientId; - public String taskListClientSecret; - public String taskListKeycloakUrl; + private Integer getInteger(String name, Map<String, Object> recordData, Integer defaultValue, String contextLog) { + try { + if (!recordData.containsKey(name)) { + if (defaultValue == null) + logger.error("Variable [{}] not defined in {}", name, contextLog); + else + logger.info("Variable [{}] not defined in {}", name, contextLog); + return defaultValue; + } + return (Integer) recordData.get(name); + } catch (Exception e) { + logger.error("Variable [{}] {} bad definition {}", name, contextLog, e.getMessage()); + return defaultValue; + } + } - /** - * Camunda 7 - */ - public String camunda7ServerUrl; - public String camunda7UserName; - public String camunda7Password; + private int parseInt(String label, String value, int defaultValue, String contextLog) { + try { + if (value.equals("''")) + return defaultValue; + return Integer.parseInt(value); + } catch (Exception e) { + logger.error("Can't parse value [{}] at [{}] {}", value, label, contextLog); + return defaultValue; + } + } - /** - * Common Camunda 7 and Camunda8 - */ - public Integer workerExecutionThreads = Integer.valueOf(DEFAULT_VALUE_EXECUTION_THREADS); - public Integer workerMaxJobsActive = Integer.valueOf(DEFAULT_VALUE_MAX_JOBS_ACTIVE); + private boolean hasValue(String value) { + if (value == null) + return false; + if (value.equals("''")) + return false; + return !value.trim().isEmpty(); + } /** - * return true if the definition have an Operate connection valid + * Compare type : CAMUNDA_8 and CAMUNDA_8_SAAS are considered as equals * - * @return true is Operate is required + * @param type1 type one to compare + * @param type2 type two to compare + * @return true if types are identical */ - public boolean isOperate() { - return !(operateUrl == null || operateUrl.isEmpty()); + private boolean sameType(CamundaEngine type1, CamundaEngine type2) { + if (type1.equals(CamundaEngine.CAMUNDA_8_SAAS)) + type1 = CamundaEngine.CAMUNDA_8; + if (type2.equals(CamundaEngine.CAMUNDA_8_SAAS)) + type2 = CamundaEngine.CAMUNDA_8; + return type1.equals(type2); } - public boolean isTaskList() { - return !(taskListUrl == null || taskListUrl.isEmpty()); - } + public enum CamundaEngine {CAMUNDA_7, CAMUNDA_8, CAMUNDA_8_SAAS, DUMMY} + + public static class BpmnServerDefinition { + public String name; + + public CamundaEngine serverType; + + /** + * My Zeebe Address + */ + public String zeebeGatewayAddress; + public Boolean zeebePlainText; + + /** + * SaaS Zeebe + */ + public String zeebeSaasRegion; + public String zeebeSaasClusterId; + public String zeebeClientId; + public String zeebeClientSecret; + public String zeebeAudience; + public String zeebeTenantId = null; + + public String identityUrl; + /** + * Connection to Operate + */ + public String operateUserName; + public String operateUserPassword; + public String operateUrl; + + // something like "http://localhost:18080/auth/realms/camunda-platform/protocol/openid-connect/token" + public String authenticationUrl; + public String operateClientId; + public String operateClientSecret; + public String operateAudience; + + public String taskListUrl; + public String taskListUserName; + public String taskListUserPassword; + public String taskListClientId; + public String taskListClientSecret; + public String taskListKeycloakUrl; + + /** + * Camunda 7 + */ + public String camunda7ServerUrl; + public String camunda7UserName; + public String camunda7Password; + + /** + * Common Camunda 7 and Camunda8 + */ + public Integer workerExecutionThreads = Integer.valueOf(DEFAULT_VALUE_EXECUTION_THREADS); + public Integer workerMaxJobsActive = Integer.valueOf(DEFAULT_VALUE_MAX_JOBS_ACTIVE); + + /** + * return true if the definition have an Operate connection valid + * + * @return true is Operate is required + */ + public boolean isOperate() { + return !(operateUrl == null || operateUrl.isEmpty()); + } - public boolean isAuthenticationUrl() { - return !(authenticationUrl == null || authenticationUrl.isEmpty()); - } + public boolean isTaskList() { + return !(taskListUrl == null || taskListUrl.isEmpty()); + } + + public boolean isAuthenticationUrl() { + return !(authenticationUrl == null || authenticationUrl.isEmpty()); + } - public String getSynthesis() { - String synthesis = serverType.name(); - if (serverType.equals(CamundaEngine.CAMUNDA_7)) { - synthesis += " url[" + camunda7ServerUrl + "] userName[" + camunda7UserName + "]"; - } - if (serverType.equals(CamundaEngine.CAMUNDA_8)) { - synthesis += " address[" + zeebeGatewayAddress + "] workerThread[" + workerExecutionThreads + "] MaxJobActive[" - + workerMaxJobsActive + "]"; - } - if (serverType.equals(CamundaEngine.CAMUNDA_8_SAAS)) { - synthesis += " clientId[" + zeebeClientId + "] workerThread[" + workerExecutionThreads + "] MaxJobActive[" - + workerMaxJobsActive + "]"; - } - return synthesis; + public String getSynthesis() { + String synthesis = serverType.name(); + if (serverType.equals(CamundaEngine.CAMUNDA_7)) { + synthesis += " url[" + camunda7ServerUrl + "] userName[" + camunda7UserName + "]"; + } + if (serverType.equals(CamundaEngine.CAMUNDA_8)) { + synthesis += " address[" + zeebeGatewayAddress + "] workerThread[" + workerExecutionThreads + "] MaxJobActive[" + + workerMaxJobsActive + "]"; + } + if (serverType.equals(CamundaEngine.CAMUNDA_8_SAAS)) { + synthesis += " clientId[" + zeebeClientId + "] workerThread[" + workerExecutionThreads + "] MaxJobActive[" + + workerMaxJobsActive + "]"; + } + return synthesis; + } } - } } diff --git a/src/main/java/org/camunda/automator/configuration/ConfigurationServersEngine.java b/src/main/java/org/camunda/automator/configuration/ConfigurationServersEngine.java index c36017e..d4877ae 100644 --- a/src/main/java/org/camunda/automator/configuration/ConfigurationServersEngine.java +++ b/src/main/java/org/camunda/automator/configuration/ConfigurationServersEngine.java @@ -11,84 +11,84 @@ @ConfigurationProperties("automator") public class ConfigurationServersEngine { - // @ V alue("${automator.logDebug:false}") - public boolean logDebug = false; - - @Value("#{'${automator.serversConnection}'.split(';')}") - public List<String> serversConnection; - - public List<Map<String, Object>> serversList; - - @Value("${automator.servers.camunda7.url:''}") - public String camunda7Url; - @Value("${automator.servers.camunda7.username:}") - public String camunda7UserName; - @Value("${automator.servers.camunda7.password:}") - public String camunda7Password; - @Value("${automator.servers.camunda7.name:''}") - public String camunda7Name; - @Value("${automator.servers.camunda7.workerMaxJobsActive:''}") - public String C7WorkerMaxJobsActive; - - @Value("${automator.servers.camunda8.name:''}") - public String zeebeName; - @Value("${automator.servers.camunda8.zeebeGatewayAddress:''}") - public String zeebeGatewayAddress; - @Value("${automator.servers.camunda8.operateUrl:''}") - public String zeebeOperateUrl; - @Value("${automator.servers.camunda8.operateUserName:''}") - public String zeebeOperateUserName; - @Value("${automator.servers.camunda8.operateUserPassword:''}") - public String zeebeOperateUserPassword; - - @Value("${automator.servers.camunda8.taskListUrl:''}") - public String zeebeTaskListUrl; - @Value("${automator.servers.camunda8.taskListUserName:''}") - public String zeebeTaskListUserName; - @Value("${automator.servers.camunda8.taskListUserPassword:''}") - public String zeebeTaskListUserPassword; - - @Value("${automator.servers.camunda8.workerExecutionThreads:''}") - public String zeebeWorkerExecutionThreads; - @Value("${automator.servers.camunda8.workerMaxJobsActive:''}") - public String zeebeWorkerMaxJobsActive; - - @Value("${automator.servers.camunda8Saas.region:''}") - public String zeebeSaasRegion; - @Value("${automator.servers.camunda8Saas.clusterId:''}") - public String zeebeSaasClusterId; - @Value("${automator.servers.camunda8Saas.clientId:''}") - public String zeebeSaasClientId; - - @Value("${automator.servers.camunda8Saas.secret:''}") - public String zeebeSaasClientSecret; - - @Value("${automator.servers.camunda8Saas.oAuthUrl:''}") - public String zeebeSaasOAuthUrl; - @Value("${automator.servers.camunda8Saas.audience:''}") - public String zeebeSaasAudience; - - @Value("${automator.servers.camunda8Saas.operateUrl:''}") - public String zeebeSaasOperateUrl; - @Value("${automator.servers.camunda8Saas.operateUserName:''}") - public String zeebeSaasOperateUserName; - @Value("${automator.servers.camunda8Saas.operateUserPassword:''}") - public String zeebeSaasOperateUserPassword; - @Value("${automator.servers.camunda8Saas.taskListUrl:''}") - public String zeebeSaasTaskListUrl; - @Value("${automator.servers.camunda8Saas.workerExecutionThreads:''}") - public String zeebeSaasWorkerExecutionThreads; - @Value("${automator.servers.camunda8Saas.workerMaxJobsActive:''}") - public String zeebeSaasWorkerMaxJobsActive; - - public List<Map<String, Object>> getServersList() { - return serversList; - } - - // this method is mandatory for Spring to get the value and to force it as a List<Map<>> - public void setServersList(List<Map<String, Object>> serversList) { - this.serversList = serversList; - } + // @ V alue("${automator.logDebug:false}") + public boolean logDebug = false; + + @Value("#{'${automator.serversConnection}'.split(';')}") + public List<String> serversConnection; + + public List<Map<String, Object>> serversList; + + @Value("${automator.servers.camunda7.url:''}") + public String camunda7Url; + @Value("${automator.servers.camunda7.username:}") + public String camunda7UserName; + @Value("${automator.servers.camunda7.password:}") + public String camunda7Password; + @Value("${automator.servers.camunda7.name:''}") + public String camunda7Name; + @Value("${automator.servers.camunda7.workerMaxJobsActive:''}") + public String C7WorkerMaxJobsActive; + + @Value("${automator.servers.camunda8.name:''}") + public String zeebeName; + @Value("${automator.servers.camunda8.zeebeGatewayAddress:''}") + public String zeebeGatewayAddress; + @Value("${automator.servers.camunda8.operateUrl:''}") + public String zeebeOperateUrl; + @Value("${automator.servers.camunda8.operateUserName:''}") + public String zeebeOperateUserName; + @Value("${automator.servers.camunda8.operateUserPassword:''}") + public String zeebeOperateUserPassword; + + @Value("${automator.servers.camunda8.taskListUrl:''}") + public String zeebeTaskListUrl; + @Value("${automator.servers.camunda8.taskListUserName:''}") + public String zeebeTaskListUserName; + @Value("${automator.servers.camunda8.taskListUserPassword:''}") + public String zeebeTaskListUserPassword; + + @Value("${automator.servers.camunda8.workerExecutionThreads:''}") + public String zeebeWorkerExecutionThreads; + @Value("${automator.servers.camunda8.workerMaxJobsActive:''}") + public String zeebeWorkerMaxJobsActive; + + @Value("${automator.servers.camunda8Saas.region:''}") + public String zeebeSaasRegion; + @Value("${automator.servers.camunda8Saas.clusterId:''}") + public String zeebeSaasClusterId; + @Value("${automator.servers.camunda8Saas.clientId:''}") + public String zeebeSaasClientId; + + @Value("${automator.servers.camunda8Saas.secret:''}") + public String zeebeSaasClientSecret; + + @Value("${automator.servers.camunda8Saas.oAuthUrl:''}") + public String zeebeSaasOAuthUrl; + @Value("${automator.servers.camunda8Saas.audience:''}") + public String zeebeSaasAudience; + + @Value("${automator.servers.camunda8Saas.operateUrl:''}") + public String zeebeSaasOperateUrl; + @Value("${automator.servers.camunda8Saas.operateUserName:''}") + public String zeebeSaasOperateUserName; + @Value("${automator.servers.camunda8Saas.operateUserPassword:''}") + public String zeebeSaasOperateUserPassword; + @Value("${automator.servers.camunda8Saas.taskListUrl:''}") + public String zeebeSaasTaskListUrl; + @Value("${automator.servers.camunda8Saas.workerExecutionThreads:''}") + public String zeebeSaasWorkerExecutionThreads; + @Value("${automator.servers.camunda8Saas.workerMaxJobsActive:''}") + public String zeebeSaasWorkerMaxJobsActive; + + public List<Map<String, Object>> getServersList() { + return serversList; + } + + // this method is mandatory for Spring to get the value and to force it as a List<Map<>> + public void setServersList(List<Map<String, Object>> serversList) { + this.serversList = serversList; + } } diff --git a/src/main/java/org/camunda/automator/configuration/ConfigurationStartup.java b/src/main/java/org/camunda/automator/configuration/ConfigurationStartup.java index 230f46a..fedc556 100644 --- a/src/main/java/org/camunda/automator/configuration/ConfigurationStartup.java +++ b/src/main/java/org/camunda/automator/configuration/ConfigurationStartup.java @@ -17,134 +17,134 @@ @PropertySource("classpath:application.yaml") @Configuration public class ConfigurationStartup { - static Logger logger = LoggerFactory.getLogger(ConfigurationStartup.class); - @Value("${automator.startup.scenarioPath}") - public String scenarioPath; - @Value("${automator.startup.logLevel:MONITORING}") - public String logLevel; - @Value("${automator.startup.deeptracking:false}") - public boolean deepTracking; - @Value("${automator.startup.policyExecution:DEPLOYPROCESS|WARMINGUP|CREATION|SERVICETASK|USERTASK}") - public String policyExecution; - - @Value("${automator.startEvent.nbThreads:#{null}}") - public Integer startEventNbThreads; - - /** - * it may be necessary to wait the other component to warm up - */ - @Value("${automator.startup.waitWarmUpServer:PT0S}") - public String waitWarmupServer; - - @Value("${automator.startup.serverName}") - private String serverName; - - @Value("#{'${automator.startup.scenarioFileAtStartup:}'.split(';')}") - private List<String> scenarioFileAtStartup; - - @Value("${automator.startup.scenarioResourceAtStartup:}") - private Resource scenarioResourceAtStartup; - - @Value("#{'${automator.startup.filterService:}'.split(';')}") - private List<String> filterService; - - public String getServerName() { - return serverName; - } - - public void setLogLevel(String logLevel) { - this.logLevel = logLevel; - } - - public RunParameters.LOGLEVEL getLogLevelEnum() { - try { - return RunParameters.LOGLEVEL.valueOf(logLevel); - } catch (Exception e) { - logger.error("Unknow LogLevel (automator.startup.loglevel) : [{}} ", logLevel); - return RunParameters.LOGLEVEL.MONITORING; - } - } - - public boolean deepTracking() { - return deepTracking; - } - - public boolean isPolicyExecutionCreation() { - String policyExtended = "|" + policyExecution + "|"; - return policyExtended.contains("|CREATION|"); - } - - public boolean isPolicyExecutionServiceTask() { - String policyExtended = "|" + policyExecution + "|"; - return policyExtended.contains("|SERVICETASK|"); - } - - public boolean isPolicyExecutionUserTask() { - String policyExtended = "|" + policyExecution + "|"; - return policyExtended.contains("|USERTASK|"); - } - - public boolean isPolicyExecutionWarmingUp() { - String policyExtended = "|" + policyExecution + "|"; - return policyExtended.contains("|WARMINGUP|"); - } - - public boolean isPolicyDeployProcess() { - String policyExtended = "|" + policyExecution + "|"; - return policyExtended.contains("|DEPLOYPROCESS|"); - } - - public Integer getStartEventNbThreads() { - return startEventNbThreads; - } - - public List<String> getScenarioFileAtStartup() { - return recalibrateAfterSplit(scenarioFileAtStartup); - } - - /** - * Return the name for the variable scenarioAtStartup - * - * @return the name - */ - public String getScenarioFileAtStartupName() { - return "automator.startup.scenarioAtStartup"; - } - - /** - * Return the list of collection - only one at this moment - * - * @return list of scenario detected as a resource - */ - public List<Resource> getScenarioResourceAtStartup() { - return Collections.singletonList(scenarioResourceAtStartup); - } - - /** - * return the name of the resourceAtStartup variable name - * - * @return name of the variable - */ - public String getScenarioResourceAtStartupName() { - return "automator.startup.scenarioResourceAtStartup"; - } - - public List<String> getFilterService() { - return recalibrateAfterSplit(filterService); - } - - public Duration getWarmingUpServer() { - try { - return Duration.parse(waitWarmupServer); - } catch (Exception e) { - logger.error("Can't parse warmup [{}]", waitWarmupServer); - return Duration.ZERO; - } - } - - private List<String> recalibrateAfterSplit(List<String> originalList) { - if (originalList.size() == 1 && originalList.get(0).isEmpty()) - return Collections.emptyList(); - return originalList; - } + static Logger logger = LoggerFactory.getLogger(ConfigurationStartup.class); + @Value("${automator.startup.scenarioPath}") + public String scenarioPath; + @Value("${automator.startup.logLevel:MONITORING}") + public String logLevel; + @Value("${automator.startup.deeptracking:false}") + public boolean deepTracking; + @Value("${automator.startup.policyExecution:DEPLOYPROCESS|WARMINGUP|CREATION|SERVICETASK|USERTASK}") + public String policyExecution; + + @Value("${automator.startEvent.nbThreads:#{null}}") + public Integer startEventNbThreads; + + /** + * it may be necessary to wait the other component to warm up + */ + @Value("${automator.startup.waitWarmUpServer:PT0S}") + public String waitWarmupServer; + + @Value("${automator.startup.serverName}") + private String serverName; + + @Value("#{'${automator.startup.scenarioFileAtStartup:}'.split(';')}") + private List<String> scenarioFileAtStartup; + + @Value("${automator.startup.scenarioResourceAtStartup:}") + private Resource scenarioResourceAtStartup; + + @Value("#{'${automator.startup.filterService:}'.split(';')}") + private List<String> filterService; + + public String getServerName() { + return serverName; + } + + public void setLogLevel(String logLevel) { + this.logLevel = logLevel; + } + + public RunParameters.LOGLEVEL getLogLevelEnum() { + try { + return RunParameters.LOGLEVEL.valueOf(logLevel); + } catch (Exception e) { + logger.error("Unknow LogLevel (automator.startup.loglevel) : [{}} ", logLevel); + return RunParameters.LOGLEVEL.MONITORING; + } + } + + public boolean deepTracking() { + return deepTracking; + } + + public boolean isPolicyExecutionCreation() { + String policyExtended = "|" + policyExecution + "|"; + return policyExtended.contains("|CREATION|"); + } + + public boolean isPolicyExecutionServiceTask() { + String policyExtended = "|" + policyExecution + "|"; + return policyExtended.contains("|SERVICETASK|"); + } + + public boolean isPolicyExecutionUserTask() { + String policyExtended = "|" + policyExecution + "|"; + return policyExtended.contains("|USERTASK|"); + } + + public boolean isPolicyExecutionWarmingUp() { + String policyExtended = "|" + policyExecution + "|"; + return policyExtended.contains("|WARMINGUP|"); + } + + public boolean isPolicyDeployProcess() { + String policyExtended = "|" + policyExecution + "|"; + return policyExtended.contains("|DEPLOYPROCESS|"); + } + + public Integer getStartEventNbThreads() { + return startEventNbThreads; + } + + public List<String> getScenarioFileAtStartup() { + return recalibrateAfterSplit(scenarioFileAtStartup); + } + + /** + * Return the name for the variable scenarioAtStartup + * + * @return the name + */ + public String getScenarioFileAtStartupName() { + return "automator.startup.scenarioAtStartup"; + } + + /** + * Return the list of collection - only one at this moment + * + * @return list of scenario detected as a resource + */ + public List<Resource> getScenarioResourceAtStartup() { + return Collections.singletonList(scenarioResourceAtStartup); + } + + /** + * return the name of the resourceAtStartup variable name + * + * @return name of the variable + */ + public String getScenarioResourceAtStartupName() { + return "automator.startup.scenarioResourceAtStartup"; + } + + public List<String> getFilterService() { + return recalibrateAfterSplit(filterService); + } + + public Duration getWarmingUpServer() { + try { + return Duration.parse(waitWarmupServer); + } catch (Exception e) { + logger.error("Can't parse warmup [{}]", waitWarmupServer); + return Duration.ZERO; + } + } + + private List<String> recalibrateAfterSplit(List<String> originalList) { + if (originalList.size() == 1 && originalList.get(0).isEmpty()) + return Collections.emptyList(); + return originalList; + } } diff --git a/src/main/java/org/camunda/automator/content/ContentManager.java b/src/main/java/org/camunda/automator/content/ContentManager.java new file mode 100644 index 0000000..dafa0fd --- /dev/null +++ b/src/main/java/org/camunda/automator/content/ContentManager.java @@ -0,0 +1,104 @@ +package org.camunda.automator.content; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.PropertySource; +import org.springframework.stereotype.Component; +import org.springframework.web.multipart.MultipartFile; + +import javax.annotation.PostConstruct; +import java.io.*; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; +import java.util.List; +import java.util.stream.Collectors; + +@Component +@PropertySource("classpath:application.yaml") +@Configuration + +public class ContentManager { + private static final Logger logger = LoggerFactory.getLogger(ContentManager.class.getName()); + @Value("${automator.content.repositoryPath}") + public String repositoryPath; + @Value("${automator.content.uploadPath}") + public String uploadPath; + + public File getFromName(String scenarioName) { + return new File(repositoryPath + File.separator + scenarioName + ".json"); + } + + + public void saveFromMultiPartFile(MultipartFile file, String fileName) { + // save the file on a temporary disk + OutputStream outputStream = null; + File fileScenario = null; + try { + fileScenario = new File(repositoryPath + File.separator + fileName); + // Open an OutputStream to the temporary file + outputStream = new FileOutputStream(fileScenario); + // Transfer data from InputStream to OutputStream + byte[] buffer = new byte[1024 * 100]; // 100Ko + int bytesRead; + int count = 0; + InputStream inputStream = file.getInputStream(); + while ((bytesRead = inputStream.read(buffer)) != -1) { + count += bytesRead; + outputStream.write(buffer, 0, bytesRead); + } + outputStream.flush(); + outputStream.close(); + outputStream = null; + } catch (Exception e) { + logger.error("Can't load File [" + fileName + "] : " + e.getMessage()); + } finally { + if (outputStream != null) + try { + outputStream.close(); + } catch (Exception e) { + // do nothing + } + } + } + + @PostConstruct + public void init() { + Path sourceDirectory = Paths.get(uploadPath); + Path targetDirectory = Paths.get(repositoryPath); + logger.info("ContentManager initiaalisation Copied: [{}] to [{}]", sourceDirectory, targetDirectory); + + int nbFilesCopied = 0; + try { + // Create target directory if it doesn't exist + if (!Files.exists(targetDirectory)) { + Files.createDirectories(targetDirectory); + } + + // Copy all files from source to target + List<Path> listFiles = Files.walk(sourceDirectory) + .filter(Files::isRegularFile).toList(); + + for (Path sourcePath : listFiles)// Filter only regular files + { + try { + Path targetPath = targetDirectory.resolve(sourceDirectory.relativize(sourcePath)); + Files.copy(sourcePath, targetPath, StandardCopyOption.REPLACE_EXISTING); + logger.info("Copied: [{}] tp [{}]", sourcePath, targetPath); + nbFilesCopied++; + } catch (IOException e) { + logger.error("Error copying file: [{}] -> [{}] : {}", sourcePath, targetDirectory, e.getMessage()); + } + } + + + } catch (IOException e) { + logger.error("Error occurred: {} ", e.getMessage()); + } + logger.info("End of ContentManager {} files copied", nbFilesCopied); + } + +} diff --git a/src/main/java/org/camunda/automator/content/ContentRestController.java b/src/main/java/org/camunda/automator/content/ContentRestController.java new file mode 100644 index 0000000..41db040 --- /dev/null +++ b/src/main/java/org/camunda/automator/content/ContentRestController.java @@ -0,0 +1,40 @@ +package org.camunda.automator.content; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestPart; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.multipart.MultipartFile; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@RestController +public class ContentRestController { + private static final Logger logger = LoggerFactory.getLogger(ContentRestController.class.getName()); + + + @Autowired + ContentManager contentManager; + + @PostMapping(value = "/api/content/add", consumes = { + MediaType.MULTIPART_FORM_DATA_VALUE}, produces = MediaType.APPLICATION_JSON_VALUE) + public Map<String, Object> upload(@RequestPart("File") List<MultipartFile> uploadedfiles) { + Map<String, Object> status = new HashMap<>(); + for (MultipartFile file : uploadedfiles) { + String resultFile = "Load [" + file.getName() + "]"; + + // is this worker is running? + String jarFileName = file.getOriginalFilename(); + contentManager.saveFromMultiPartFile(file, jarFileName); + + } + return new HashMap<>(); + } + + +} \ No newline at end of file diff --git a/src/main/java/org/camunda/automator/definition/Scenario.java b/src/main/java/org/camunda/automator/definition/Scenario.java index 59bf4c5..ff8bce3 100644 --- a/src/main/java/org/camunda/automator/definition/Scenario.java +++ b/src/main/java/org/camunda/automator/definition/Scenario.java @@ -12,13 +12,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.BufferedReader; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; +import java.io.*; import java.util.ArrayList; import java.util.List; @@ -26,177 +20,177 @@ * the Scenario Head group a scenario definition */ public class Scenario { - static Logger logger = LoggerFactory.getLogger(Scenario.class); - - private final List<ScenarioDeployment> deployments = new ArrayList<>(); - private final List<ScenarioStep> flows = new ArrayList<>(); - /** - * Type UNIT - */ - private final List<ScenarioExecution> executions = new ArrayList<>(); - - public TYPESCENARIO typeScenario; - - /** - * Type FLOW - */ - private ScenarioWarmingUp warmingUp; - private ScenarioFlowControl flowControl; - private String name; - private String version; - private String processName; - private String processId; - /** - * Server to run the scenario (optional, will be overide by the configuration) - */ - private String serverName; - private String serverType; - /** - * This value is fulfill only if the scenario was read from a file - */ - private String scenarioFile = null; - - public static Scenario createFromJson(String jsonContent) { - GsonBuilder builder = new GsonBuilder(); - builder.setPrettyPrinting(); - - Gson gson = builder.create(); - Scenario scenario = gson.fromJson(jsonContent, Scenario.class); - if (scenario == null) { - logger.error("Scenario: Can't build scenario from content [{}]", jsonContent); - return null; - } - scenario.afterUnSerialize(); - return scenario; - } - - public static Scenario createFromFile(File scenarioFile) throws AutomatorException { - try { - - Scenario scenario = createFromInputStream(new FileInputStream(scenarioFile), scenarioFile.getAbsolutePath()); - scenario.scenarioFile = scenarioFile.getAbsolutePath(); - scenario.initialize(); - return scenario; - - } catch (FileNotFoundException e) { - throw new AutomatorException("Can't access file [" + scenarioFile.getAbsolutePath() + "] " + e.getMessage()); - } catch (AutomatorException e) { - throw e; - } - } - - /** - * Load the scenario from a File - * - * @param scenarioInput InputStream to read - * @return the scenario - * @throws AutomatorException if file cannot be read or it's not a Json file - */ - public static Scenario createFromInputStream(InputStream scenarioInput, String origin) throws AutomatorException { - logger.info("Load Scenario [{}] from InputStream", origin); - try (BufferedReader br = new BufferedReader(new InputStreamReader(scenarioInput))) { - StringBuilder jsonContent = new StringBuilder(); - String st; - while ((st = br.readLine()) != null) - jsonContent.append(st); - - Scenario scnHead = createFromJson(jsonContent.toString()); - if (scnHead == null) { - throw new AutomatorException("Scenario: can't load from JSON [" + jsonContent + "] "); - } - scnHead.initialize(); - return scnHead; - } catch (IOException e) { - logger.error("CreateScenarioFromInputString: origin[{}] error {} : {} ", origin, e.getMessage(), e.toString()); - throw new AutomatorException("Can't load content from [" + origin + "] " + e.getMessage()); - } - - } - - /** - * Initialize the scenario and complete it - */ - private void initialize() { - } - - /** - * Add a new execution - * - * @return the scenario itself - */ - public Scenario addExecution(ScenarioExecution scnExecution) { - executions.add(scnExecution); - return this; - } - - public List<ScenarioExecution> getExecutions() { - return executions; - } - - public List<ScenarioStep> getFlows() { - return flows; - } - - public ScenarioWarmingUp getWarmingUp() { - return warmingUp; - } - - public ScenarioFlowControl getFlowControl() { - return flowControl; - } - - public List<ScenarioDeployment> getDeployments() { - return deployments; - } - - public String getName() { - return name; - } - - public Scenario setName(String name) { - this.name = name; - return this; - } - - public String getVersion() { - return version; - } - - public String getProcessName() { - return processName; - } - - public String getProcessId() { - return processId; - } - - public Scenario setProcessId(String processId) { - this.processId = processId; - return this; - } - - public File getScenarioFile() { - try { - return new File(scenarioFile); - } catch (Exception e) { - logger.error("Can't access file [{}] ", scenarioFile); - return null; - } - } - - public String getServerName() { - if (serverName == null || serverName.isEmpty()) - return null; - return serverName; - } - - private void afterUnSerialize() { - // Attention, now we have to manually set the tree relation - for (ScenarioExecution scnExecution : getExecutions()) { - scnExecution.afterUnSerialize(this); - } - } - - public enum TYPESCENARIO {FLOW, UNIT} + static Logger logger = LoggerFactory.getLogger(Scenario.class); + + private final List<ScenarioDeployment> deployments = new ArrayList<>(); + private final List<ScenarioStep> flows = new ArrayList<>(); + /** + * Type UNIT + */ + private final List<ScenarioExecution> executions = new ArrayList<>(); + + public TYPESCENARIO typeScenario; + + /** + * Type FLOW + */ + private ScenarioWarmingUp warmingUp; + private ScenarioFlowControl flowControl; + private String name; + private String version; + private String processName; + private String processId; + /** + * Server to run the scenario (optional, will be overide by the configuration) + */ + private String serverName; + private String serverType; + /** + * This value is fulfill only if the scenario was read from a file + */ + private String scenarioFile = null; + + public static Scenario createFromJson(String jsonContent) { + GsonBuilder builder = new GsonBuilder(); + builder.setPrettyPrinting(); + + Gson gson = builder.create(); + Scenario scenario = gson.fromJson(jsonContent, Scenario.class); + if (scenario == null) { + logger.error("Scenario: Can't build scenario from content [{}]", jsonContent); + return null; + } + scenario.afterUnSerialize(); + return scenario; + } + + public static Scenario createFromFile(File scenarioFile) throws AutomatorException { + try { + + Scenario scenario = createFromInputStream(new FileInputStream(scenarioFile), scenarioFile.getAbsolutePath()); + scenario.scenarioFile = scenarioFile.getAbsolutePath(); + scenario.initialize(); + return scenario; + + } catch (FileNotFoundException e) { + throw new AutomatorException("Can't access file [" + scenarioFile.getAbsolutePath() + "] " + e.getMessage()); + } catch (AutomatorException e) { + throw e; + } + } + + /** + * Load the scenario from a File + * + * @param scenarioInput InputStream to read + * @return the scenario + * @throws AutomatorException if file cannot be read or it's not a Json file + */ + public static Scenario createFromInputStream(InputStream scenarioInput, String origin) throws AutomatorException { + logger.info("Load Scenario [{}] from InputStream", origin); + try (BufferedReader br = new BufferedReader(new InputStreamReader(scenarioInput))) { + StringBuilder jsonContent = new StringBuilder(); + String st; + while ((st = br.readLine()) != null) + jsonContent.append(st); + + Scenario scnHead = createFromJson(jsonContent.toString()); + if (scnHead == null) { + throw new AutomatorException("Scenario: can't load from JSON [" + jsonContent + "] "); + } + scnHead.initialize(); + return scnHead; + } catch (IOException e) { + logger.error("CreateScenarioFromInputString: origin[{}] error {} : {} ", origin, e.getMessage(), e.toString()); + throw new AutomatorException("Can't load content from [" + origin + "] " + e.getMessage()); + } + + } + + /** + * Initialize the scenario and complete it + */ + private void initialize() { + } + + /** + * Add a new execution + * + * @return the scenario itself + */ + public Scenario addExecution(ScenarioExecution scnExecution) { + executions.add(scnExecution); + return this; + } + + public List<ScenarioExecution> getExecutions() { + return executions; + } + + public List<ScenarioStep> getFlows() { + return flows; + } + + public ScenarioWarmingUp getWarmingUp() { + return warmingUp; + } + + public ScenarioFlowControl getFlowControl() { + return flowControl; + } + + public List<ScenarioDeployment> getDeployments() { + return deployments; + } + + public String getName() { + return name; + } + + public Scenario setName(String name) { + this.name = name; + return this; + } + + public String getVersion() { + return version; + } + + public String getProcessName() { + return processName; + } + + public String getProcessId() { + return processId; + } + + public Scenario setProcessId(String processId) { + this.processId = processId; + return this; + } + + public File getScenarioFile() { + try { + return new File(scenarioFile); + } catch (Exception e) { + logger.error("Can't access file [{}] ", scenarioFile); + return null; + } + } + + public String getServerName() { + if (serverName == null || serverName.isEmpty()) + return null; + return serverName; + } + + private void afterUnSerialize() { + // Attention, now we have to manually set the tree relation + for (ScenarioExecution scnExecution : getExecutions()) { + scnExecution.afterUnSerialize(this); + } + } + + public enum TYPESCENARIO {FLOW, UNIT} } diff --git a/src/main/java/org/camunda/automator/definition/ScenarioDeployment.java b/src/main/java/org/camunda/automator/definition/ScenarioDeployment.java index 7db6cb4..c211c0b 100644 --- a/src/main/java/org/camunda/automator/definition/ScenarioDeployment.java +++ b/src/main/java/org/camunda/automator/definition/ScenarioDeployment.java @@ -3,23 +3,23 @@ import org.camunda.automator.configuration.BpmnEngineList; public class ScenarioDeployment { - /** - * type of server - */ - public BpmnEngineList.CamundaEngine serverType; - /** - * Type pf deployment - */ - public String typeDeployment; - /** - * Name of the file - */ - public String processFile; + /** + * type of server + */ + public BpmnEngineList.CamundaEngine serverType; + /** + * Type pf deployment + */ + public String typeDeployment; + /** + * Name of the file + */ + public String processFile; - public Policy policy; + public Policy policy; - public enum TypeDeployment {PROCESS} + public enum TypeDeployment {PROCESS} - public enum Policy {ONLYNOTEXIST, ALWAYS} + public enum Policy {ONLYNOTEXIST, ALWAYS} } diff --git a/src/main/java/org/camunda/automator/definition/ScenarioExecution.java b/src/main/java/org/camunda/automator/definition/ScenarioExecution.java index 132bf2d..0d0af65 100644 --- a/src/main/java/org/camunda/automator/definition/ScenarioExecution.java +++ b/src/main/java/org/camunda/automator/definition/ScenarioExecution.java @@ -9,132 +9,136 @@ */ public class ScenarioExecution { - private final List<ScenarioStep> steps = new ArrayList<>(); - private Scenario scnHead; - private ScenarioVerification verifications; - - /** - * Name of this execution - */ - private String name; - /** - * Number of process instance to create - */ - private Integer numberProcessInstances; - - /** - * Number of thread in parallel to execute all process instances. Default is 1 - */ - private Integer numberOfThreads; - private Policy policy; - /** - * if set to false, this execution is skipped - */ - private Boolean execution; - - /** - * Note: when the object is un-serialized from JSON, scnHead is null - * - * @param scenario root information - */ - protected ScenarioExecution(Scenario scenario) { - this.scnHead = scenario; - } - - public static ScenarioExecution createExecution(Scenario scnHead) { - return new ScenarioExecution(scnHead); - } - - - - /* ******************************************************************** */ - /* */ - /* Creator and setter to help the API */ - /* */ - /* ******************************************************************** */ - - /** - * After UnSerialize, all link to parent are not restored - * - * @param scnHead head of scenario - */ - public void afterUnSerialize(Scenario scnHead) { - this.scnHead = scnHead; - for (ScenarioStep scnStep : steps) { - scnStep.afterUnSerialize(this); + private final List<ScenarioStep> steps = new ArrayList<>(); + private Scenario scnHead; + private ScenarioVerification verifications; + + /** + * Name of this execution + */ + private String name; + /** + * Number of process instance to create + */ + private Integer numberProcessInstances; + + /** + * Number of thread in parallel to execute all process instances. Default is 1 + */ + private Integer numberOfThreads; + private Policy policy; + /** + * if set to false, this execution is skipped + */ + private Boolean execution; + + /** + * Note: when the object is un-serialized from JSON, scnHead is null + * + * @param scenario root information + */ + protected ScenarioExecution(Scenario scenario) { + this.scnHead = scenario; } - } - - /** - * Add a step in the scenario - * - * @param step step part of the scenario - * @return this object - */ - public ScenarioExecution addStep(ScenarioStep step) { - steps.add(step); - return this; - } - - public List<ScenarioStep> getSteps() { - return steps == null ? Collections.emptyList() : steps; - } - - public ScenarioVerification getVerifications() { - return verifications; - } - - - - /* ******************************************************************** */ - /* */ - /* getter */ - /* */ - /* ******************************************************************** */ - - public int getNumberProcessInstances() { - return numberProcessInstances == null ? 1 : numberProcessInstances; - } - - /** - * Ask this execution to execute a number of process instance. - * - * @param numberProcessInstances number of process instance to execute - * @return this object - */ - public ScenarioExecution setNumberProcessInstances(int numberProcessInstances) { - this.numberProcessInstances = numberProcessInstances; - return this; - } - - public Scenario getScnHead() { - return scnHead; - } - - public String getName() { - return name; - } - - public ScenarioExecution setName(String name) { - this.name = name; - return this; - } - - public int getNumberOfThreads() { - return (numberOfThreads == null ? 1 : numberOfThreads <= 0 ? 1 : numberOfThreads); - } - - public Policy getPolicy() { - return (policy == null ? Policy.STOPATFIRSTERROR : policy); - } - - public boolean isExecution() { - return execution == null || Boolean.TRUE.equals(execution); - } - - /** - * Decide what to do when an error is find: stop or continue? - * default is STOPATFIRSTERROR - */ - public enum Policy {STOPATFIRSTERROR, CONTINUE} + + public static ScenarioExecution createExecution(Scenario scnHead) { + return new ScenarioExecution(scnHead); + } + + + + /* ******************************************************************** */ + /* */ + /* Creator and setter to help the API */ + /* */ + /* ******************************************************************** */ + + /** + * After UnSerialize, all link to parent are not restored + * + * @param scnHead head of scenario + */ + public void afterUnSerialize(Scenario scnHead) { + this.scnHead = scnHead; + for (ScenarioStep scnStep : steps) { + scnStep.afterUnSerialize(this); + } + } + + /** + * Add a step in the scenario + * + * @param step step part of the scenario + * @return this object + */ + public ScenarioExecution addStep(ScenarioStep step) { + steps.add(step); + return this; + } + + public List<ScenarioStep> getSteps() { + return steps == null ? Collections.emptyList() : steps; + } + + public ScenarioVerification getVerifications() { + return verifications; + } + + + + /* ******************************************************************** */ + /* */ + /* getter */ + /* */ + /* ******************************************************************** */ + + public int getNumberProcessInstances() { + return numberProcessInstances == null ? 1 : numberProcessInstances; + } + + /** + * Ask this execution to execute a number of process instance. + * + * @param numberProcessInstances number of process instance to execute + * @return this object + */ + public ScenarioExecution setNumberProcessInstances(int numberProcessInstances) { + this.numberProcessInstances = numberProcessInstances; + return this; + } + + public Scenario getScnHead() { + return scnHead; + } + + public String getName() { + return name; + } + + public ScenarioExecution setName(String name) { + this.name = name; + return this; + } + + public int getNumberOfThreads() { + return (numberOfThreads == null ? 1 : numberOfThreads <= 0 ? 1 : numberOfThreads); + } + + public void setNumberOfThreads(Integer numberOfThreads) { + this.numberOfThreads = numberOfThreads; + } + + public Policy getPolicy() { + return (policy == null ? Policy.STOPATFIRSTERROR : policy); + } + + public boolean isExecution() { + return execution == null || Boolean.TRUE.equals(execution); + } + + /** + * Decide what to do when an error is find: stop or continue? + * default is STOPATFIRSTERROR + */ + public enum Policy {STOPATFIRSTERROR, CONTINUE} } diff --git a/src/main/java/org/camunda/automator/definition/ScenarioFlowControl.java b/src/main/java/org/camunda/automator/definition/ScenarioFlowControl.java index b413e9d..ad5eebc 100644 --- a/src/main/java/org/camunda/automator/definition/ScenarioFlowControl.java +++ b/src/main/java/org/camunda/automator/definition/ScenarioFlowControl.java @@ -11,49 +11,49 @@ import java.util.List; public class ScenarioFlowControl { - private String duration; + private String duration; - private Integer increaseStep; - private List<Objective> objectives; + private Integer increaseStep; + private List<Objective> objectives; - public Duration getDuration() { - try { - return Duration.parse(duration); - } catch (Exception e) { - return Duration.ofMinutes(10); + public Duration getDuration() { + try { + return Duration.parse(duration); + } catch (Exception e) { + return Duration.ofMinutes(10); + } } - } - - public Integer getIncreaseStep() { - return increaseStep; - } - - public List<Objective> getObjectives() { - return objectives == null ? Collections.emptyList() : objectives; - } - - public static class Objective { - public int index; - public String name; - public String label; - public TYPEOBJECTIVE type; - public String processId; - public String taskId; - public String period; - public Integer value; - public Integer standardDeviation; - - public int getStandardDeviation() { - return standardDeviation == null ? 0 : standardDeviation; + + public Integer getIncreaseStep() { + return increaseStep; } - public String getInformation() { - String information = (name == null ? "" : name + "-") + (label == null ? "" : label); - if (information.length() > 0) - return information; - return (type == null ? "NoType" : type.toString()) + " period[" + period + "] value:[" + value + "]"; + public List<Objective> getObjectives() { + return objectives == null ? Collections.emptyList() : objectives; } - public enum TYPEOBJECTIVE {CREATED, ENDED, USERTASK, FLOWRATEUSERTASKMN} - } + public static class Objective { + public int index; + public String name; + public String label; + public TYPEOBJECTIVE type; + public String processId; + public String taskId; + public String period; + public Integer value; + public Integer standardDeviation; + + public int getStandardDeviation() { + return standardDeviation == null ? 0 : standardDeviation; + } + + public String getInformation() { + String information = (name == null ? "" : name + "-") + (label == null ? "" : label); + if (information.length() > 0) + return information; + return (type == null ? "NoType" : type.toString()) + " period[" + period + "] value:[" + value + "]"; + } + + public enum TYPEOBJECTIVE {CREATED, ENDED, USERTASK, FLOWRATEUSERTASKMN} + } } diff --git a/src/main/java/org/camunda/automator/definition/ScenarioStep.java b/src/main/java/org/camunda/automator/definition/ScenarioStep.java index d451a6e..aec8558 100644 --- a/src/main/java/org/camunda/automator/definition/ScenarioStep.java +++ b/src/main/java/org/camunda/automator/definition/ScenarioStep.java @@ -15,277 +15,276 @@ public class ScenarioStep { - /** - * each component contains an operations, to fulfill variables - * operations; stringtodate() - */ - private final Map<String, String> variablesOperation = Collections.emptyMap(); - private final Long fixedBackOffDelay = 0L; - private final MODEEXECUTION modeExecution = MODEEXECUTION.CLASSICAL; - private final Boolean streamEnabled = true; - /** - * Receive a step range in the scenario, which help to identify the step - */ - private final int stepNumber = -1; - /** - * In case of a Flow Step, the number of workers to execute this tasks - */ - private Integer nbThreads = Integer.valueOf(1); - - private final Integer nbTokens = null; - /** - * if the step is used in a WarmingUp operation, it can decide this is the time to finish it - * Expression is - * UserTaskThreashold(<taskId>,<numberOfTaskExpected>) - */ - private String endWarmingUp; - private ScenarioExecution scnExecution; - private Step type; - private String taskId; - /** - * Name is optional in the step, help to find it in case of error - */ - private String name; - /** - * to execute a service task in C8, topic is mandatory - */ - private String topic; - private Map<String, Object> variables = Collections.emptyMap(); - private String userId; - /** - * ISO 8601: PT10S - */ - private String delay; - /** - * ISO 8601: PT10S - */ - private String waitingTime; - /** - * Optional, may not be set - */ - private Integer numberOfExecutions; - /** - * In case of a Flow step, the frequency to execute this step, for example PT10S every 10 seconds - */ - private String frequency; - /** - * In case of FlowStep, the processId to execute the step - */ - private String processId; - - public ScenarioStep(ScenarioExecution scnExecution) { - this.scnExecution = scnExecution; - } - - public static ScenarioStep createStepCreate(ScenarioExecution scnExecution, String starterId) { - ScenarioStep scenarioStep = new ScenarioStep(scnExecution); - scenarioStep.type = Step.STARTEVENT; - scenarioStep.taskId = starterId; - return scenarioStep; - } - - /* ******************************************************************** */ - /* */ - /* Creator and setter to help the API */ - /* */ - /* ******************************************************************** */ - - public static ScenarioStep createStepUserTask(ScenarioExecution scnExecution, String activityId) { - ScenarioStep scenarioStep = new ScenarioStep(scnExecution); - scenarioStep.type = Step.USERTASK; - scenarioStep.taskId = activityId; - return scenarioStep; - } - - public String getInformation() { - return "step_" + stepNumber + " " // cartouche - + (name == null ? "" : ("[" + name + "]:")) // name - + getType().toString() // type - + ",taskId:[" + getTaskId() + "]" + (getTopic() == null ? "" : " topic:[" + getTopic() + "]"); - } - - public Step getType() { - return type; - } - - public ScenarioStep setType(Step type) { - this.type = type; - return this; - } - - public String getTaskId() { - return taskId; - } - - public ScenarioStep setTaskId(String taskId) { - this.taskId = taskId; - return this; - } - - public String getUserId() { - return userId; - } - - public ScenarioStep setUserId(String userId) { - this.userId = userId; - return this; - } - - public String getTopic() { - return topic; - } - - public boolean isStreamEnabled() { - return streamEnabled == null || streamEnabled.booleanValue(); - } - - /* ******************************************************************** */ - /* */ - /* getter */ - /* */ - /* ******************************************************************** */ - - public Map<String, String> getVariablesOperations() { - return variablesOperation == null ? Collections.emptyMap() : variablesOperation; - } - - public Map<String, Object> getVariables() { - return variables == null ? Collections.emptyMap() : variables; - } - - public ScenarioStep setVariables(Map<String, Object> variables) { - this.variables = variables; - return this; - } - - public String getDelay() { - return delay; - } - - public ScenarioStep setDelay(String delay) { - this.delay = delay; - return this; - } - - public String getWaitingTime() { - return waitingTime; - } - - public void setWaitingTime(String waitingTime) { - this.waitingTime = waitingTime; - } - - /** - * Return the waiting time in Duration - * - * @return Duration, defaultDuration if error - */ - public Duration getWaitingTimeDuration(Duration defaultDuration) { - try { - return Duration.parse(waitingTime); - } catch (Exception e) { - return defaultDuration; - } - } - - public ScenarioExecution getScnExecution() { - return scnExecution; - } - - public void setScnExecution(ScenarioExecution scnExecution) { - this.scnExecution = scnExecution; - } - - public int getNumberOfExecutions() { - return numberOfExecutions == null ? 1 : numberOfExecutions; - } - - public void setNumberOfExecutions(int numberOfExecutions) { - this.numberOfExecutions = numberOfExecutions; - } - - public String getFrequency() { - return frequency; - } - - public int getNbThreads() { - return nbThreads == null || nbThreads == 0 ? 1 : nbThreads; - } - - public void setNbThreads(int nbThreads) { - this.nbThreads = nbThreads; - } - - public int getNbTokens() { - return nbTokens == null ? 1 : nbTokens; - } - - public String getProcessId() { - return processId; - } - - public long getFixedBackOffDelay() { - return fixedBackOffDelay == null ? 0 : fixedBackOffDelay.longValue(); - } - - protected void afterUnSerialize(ScenarioExecution scnExecution) { - this.scnExecution = scnExecution; - } - - public void checkConsistence() throws AutomatorException { - if (getTaskId() == null || getTaskId().trim().isEmpty()) - throw new AutomatorException("Step taskId is mandatory"); - switch (type) { - case SERVICETASK -> { - if (getTopic() == null || getTopic().trim().isEmpty()) - throw new AutomatorException("Step.SERVICETASK: " + getTaskId() + " topic is mandatory"); - } - default -> { - } - } - } - - public String getEndWarmingUp() { - return endWarmingUp; - } - - public MODEEXECUTION getModeExecution() { - return modeExecution == null ? MODEEXECUTION.CLASSICAL : modeExecution; - } - - /** - * Return an uniq ID of the step (use to - * - * @return the id of the step - */ - public String getId() { - return getType() + " " + switch (getType()) { - case STARTEVENT -> getProcessId() + "(" + getTaskId() + ")"; - case SERVICETASK -> getTopic(); - - default -> ""; - }; - } - - /** - * MODE EXECUTION - * CLASSICAL, WAIT: the worker wait the waitingTime time - * THREAD, ASYNCHRONOUS: the worker release the method, wait asynchronously the waiting time and send back the answer - * THREADTOKEN, ASYNCHRONOUSLIMITED: same as THREAD, but use the maxClient information to not accept more than this number - * In ASYNCHRONOUS, the method can potentially have millions of works in parallel (it accept <NumberOfClients> works, - * but because it finishes the method, then Zeebe Client will accept more works. So, with a waiting time of 1 mn, it may have a lot - * of works in progress in the client. - * This mode limit the number of current execution on the worker. it redeems immediately the method, but when we reach this - * limitation, it froze the worker, waiting for a slot. - */ - public enum MODEEXECUTION {CLASSICAL, THREAD, THREADTOKEN, WAIT, ASYNCHRONOUS, ASYNCHRONOUSLIMITED} - - /* ******************************************************************** */ - /* */ - /* Check consistence */ - /* */ - /* ******************************************************************** */ - - public enum Step {STARTEVENT, USERTASK, SERVICETASK, MESSAGE, ENDEVENT, EXCLUSIVEGATEWAY, PARALLELGATEWAY} + /** + * each component contains an operations, to fulfill variables + * operations; stringtodate() + */ + private final Map<String, String> variablesOperation = Collections.emptyMap(); + private final Long fixedBackOffDelay = 0L; + private final MODEEXECUTION modeExecution = MODEEXECUTION.CLASSICAL; + private final Boolean streamEnabled = true; + /** + * Receive a step range in the scenario, which help to identify the step + */ + private final int stepNumber = -1; + private final Integer nbTokens = null; + /** + * In case of a Flow Step, the number of workers to execute this tasks + */ + private Integer nbThreads = Integer.valueOf(1); + /** + * if the step is used in a WarmingUp operation, it can decide this is the time to finish it + * Expression is + * UserTaskThreashold(<taskId>,<numberOfTaskExpected>) + */ + private String endWarmingUp; + private ScenarioExecution scnExecution; + private Step type; + private String taskId; + /** + * Name is optional in the step, help to find it in case of error + */ + private String name; + /** + * to execute a service task in C8, topic is mandatory + */ + private String topic; + private Map<String, Object> variables = Collections.emptyMap(); + private String userId; + /** + * ISO 8601: PT10S + */ + private String delay; + /** + * ISO 8601: PT10S + */ + private String waitingTime; + /** + * Optional, may not be set + */ + private Integer numberOfExecutions; + /** + * In case of a Flow step, the frequency to execute this step, for example PT10S every 10 seconds + */ + private String frequency; + /** + * In case of FlowStep, the processId to execute the step + */ + private String processId; + + public ScenarioStep(ScenarioExecution scnExecution) { + this.scnExecution = scnExecution; + } + + public static ScenarioStep createStepCreate(ScenarioExecution scnExecution, String starterId) { + ScenarioStep scenarioStep = new ScenarioStep(scnExecution); + scenarioStep.type = Step.STARTEVENT; + scenarioStep.taskId = starterId; + return scenarioStep; + } + + /* ******************************************************************** */ + /* */ + /* Creator and setter to help the API */ + /* */ + /* ******************************************************************** */ + + public static ScenarioStep createStepUserTask(ScenarioExecution scnExecution, String activityId) { + ScenarioStep scenarioStep = new ScenarioStep(scnExecution); + scenarioStep.type = Step.USERTASK; + scenarioStep.taskId = activityId; + return scenarioStep; + } + + public String getInformation() { + return "step_" + stepNumber + " " // cartouche + + (name == null ? "" : ("[" + name + "]:")) // name + + getType().toString() // type + + ",taskId:[" + getTaskId() + "]" + (getTopic() == null ? "" : " topic:[" + getTopic() + "]"); + } + + public Step getType() { + return type; + } + + public ScenarioStep setType(Step type) { + this.type = type; + return this; + } + + public String getTaskId() { + return taskId; + } + + public ScenarioStep setTaskId(String taskId) { + this.taskId = taskId; + return this; + } + + public String getUserId() { + return userId; + } + + public ScenarioStep setUserId(String userId) { + this.userId = userId; + return this; + } + + public String getTopic() { + return topic; + } + + public boolean isStreamEnabled() { + return streamEnabled == null || streamEnabled.booleanValue(); + } + + /* ******************************************************************** */ + /* */ + /* getter */ + /* */ + /* ******************************************************************** */ + + public Map<String, String> getVariablesOperations() { + return variablesOperation == null ? Collections.emptyMap() : variablesOperation; + } + + public Map<String, Object> getVariables() { + return variables == null ? Collections.emptyMap() : variables; + } + + public ScenarioStep setVariables(Map<String, Object> variables) { + this.variables = variables; + return this; + } + + public String getDelay() { + return delay; + } + + public ScenarioStep setDelay(String delay) { + this.delay = delay; + return this; + } + + public String getWaitingTime() { + return waitingTime; + } + + public void setWaitingTime(String waitingTime) { + this.waitingTime = waitingTime; + } + + /** + * Return the waiting time in Duration + * + * @return Duration, defaultDuration if error + */ + public Duration getWaitingTimeDuration(Duration defaultDuration) { + try { + return Duration.parse(waitingTime); + } catch (Exception e) { + return defaultDuration; + } + } + + public ScenarioExecution getScnExecution() { + return scnExecution; + } + + public void setScnExecution(ScenarioExecution scnExecution) { + this.scnExecution = scnExecution; + } + + public int getNumberOfExecutions() { + return numberOfExecutions == null ? 1 : numberOfExecutions; + } + + public void setNumberOfExecutions(int numberOfExecutions) { + this.numberOfExecutions = numberOfExecutions; + } + + public String getFrequency() { + return frequency; + } + + public int getNbThreads() { + return nbThreads == null || nbThreads == 0 ? 1 : nbThreads; + } + + public void setNbThreads(int nbThreads) { + this.nbThreads = nbThreads; + } + + public int getNbTokens() { + return nbTokens == null ? 1 : nbTokens; + } + + public String getProcessId() { + return processId; + } + + public long getFixedBackOffDelay() { + return fixedBackOffDelay == null ? 0 : fixedBackOffDelay.longValue(); + } + + protected void afterUnSerialize(ScenarioExecution scnExecution) { + this.scnExecution = scnExecution; + } + + public void checkConsistence() throws AutomatorException { + if (getTaskId() == null || getTaskId().trim().isEmpty()) + throw new AutomatorException("Step taskId is mandatory"); + switch (type) { + case SERVICETASK -> { + if (getTopic() == null || getTopic().trim().isEmpty()) + throw new AutomatorException("Step.SERVICETASK: " + getTaskId() + " topic is mandatory"); + } + default -> { + } + } + } + + public String getEndWarmingUp() { + return endWarmingUp; + } + + public MODEEXECUTION getModeExecution() { + return modeExecution == null ? MODEEXECUTION.CLASSICAL : modeExecution; + } + + /** + * Return an uniq ID of the step (use to + * + * @return the id of the step + */ + public String getId() { + return getType() + " " + switch (getType()) { + case STARTEVENT -> getProcessId() + "(" + getTaskId() + ")"; + case SERVICETASK -> getTopic(); + + default -> ""; + }; + } + + /** + * MODE EXECUTION + * CLASSICAL, WAIT: the worker wait the waitingTime time + * THREAD, ASYNCHRONOUS: the worker release the method, wait asynchronously the waiting time and send back the answer + * THREADTOKEN, ASYNCHRONOUSLIMITED: same as THREAD, but use the maxClient information to not accept more than this number + * In ASYNCHRONOUS, the method can potentially have millions of works in parallel (it accept <NumberOfClients> works, + * but because it finishes the method, then Zeebe Client will accept more works. So, with a waiting time of 1 mn, it may have a lot + * of works in progress in the client. + * This mode limit the number of current execution on the worker. it redeems immediately the method, but when we reach this + * limitation, it froze the worker, waiting for a slot. + */ + public enum MODEEXECUTION {CLASSICAL, THREAD, THREADTOKEN, WAIT, ASYNCHRONOUS, ASYNCHRONOUSLIMITED} + + /* ******************************************************************** */ + /* */ + /* Check consistence */ + /* */ + /* ******************************************************************** */ + + public enum Step {STARTEVENT, USERTASK, SERVICETASK, MESSAGE, ENDEVENT, EXCLUSIVEGATEWAY, PARALLELGATEWAY, TASK, SCRIPTTASK} } diff --git a/src/main/java/org/camunda/automator/definition/ScenarioTool.java b/src/main/java/org/camunda/automator/definition/ScenarioTool.java index cab9678..30871a8 100644 --- a/src/main/java/org/camunda/automator/definition/ScenarioTool.java +++ b/src/main/java/org/camunda/automator/definition/ScenarioTool.java @@ -8,26 +8,26 @@ public class ScenarioTool { - public static File loadFile(String fileName, RunScenario runScenario) throws AutomatorException { - File file = new File(fileName); - if (file.exists()) - return file; - - // maybe the file is present under the scenario path? - if (runScenario.getScenario().getScenarioFile() != null) { - File pathScenario = runScenario.getScenario().getScenarioFile().getParentFile(); - file = new File(pathScenario + "/" + fileName); - if (file.exists()) - return file; - } - String currentPath = null; + public static File loadFile(String fileName, RunScenario runScenario) throws AutomatorException { + File file = new File(fileName); + if (file.exists()) + return file; + + // maybe the file is present under the scenario path? + if (runScenario.getScenario().getScenarioFile() != null) { + File pathScenario = runScenario.getScenario().getScenarioFile().getParentFile(); + file = new File(pathScenario + "/" + fileName); + if (file.exists()) + return file; + } + String currentPath = null; + + try { + currentPath = new File(".").getCanonicalPath(); + } catch (IOException e) { + } + + throw new AutomatorException("File [" + fileName + "] does not exist - current path =[" + currentPath + "]"); - try { - currentPath = new File(".").getCanonicalPath(); - } catch (IOException e) { } - - throw new AutomatorException("File [" + fileName + "] does not exist - current path =[" + currentPath + "]"); - - } } diff --git a/src/main/java/org/camunda/automator/definition/ScenarioVerification.java b/src/main/java/org/camunda/automator/definition/ScenarioVerification.java index d650143..9b8a074 100644 --- a/src/main/java/org/camunda/automator/definition/ScenarioVerification.java +++ b/src/main/java/org/camunda/automator/definition/ScenarioVerification.java @@ -6,49 +6,60 @@ import java.util.Map; public class ScenarioVerification { - private final ScenarioExecution scenarioExecution; - /** - * List of activities to check - * Maybe null due the Gson deserializer if there is no definition - */ - private List<ScenarioVerificationTask> activities = new ArrayList<>(); - /** - * List of Variables to check - * Maybe null due the Gson deserializer if there is no definition - */ - private List<ScenarioVerificationVariable> variables = new ArrayList<>(); - /** - * Variable to search the process instance, if only the verification is running - * Maybe null due the Gson deserializer if there is no definition - */ - private Map<String, Object> searchProcessInstanceByVariable; - - protected ScenarioVerification(ScenarioExecution scenarioExecution) { - this.scenarioExecution = scenarioExecution; - } - - public List<ScenarioVerificationTask> getActivities() { - return activities == null ? Collections.emptyList() : activities; - } - - public void setActivities(List<ScenarioVerificationTask> activities) { - this.activities = activities; - } - - public Map<String, Object> getSearchProcessInstanceByVariable() { - return searchProcessInstanceByVariable == null ? Collections.emptyMap() : searchProcessInstanceByVariable; - } - - public List<ScenarioVerificationVariable> getVariables() { - return variables == null ? Collections.emptyList() : variables; - } - - public void setVariables(List<ScenarioVerificationVariable> variables) { - this.variables = variables; - } - - public ScenarioExecution getScenarioExecution() { - return scenarioExecution; - } + private final ScenarioExecution scenarioExecution; + /** + * List of activities to check + * Maybe null due the Gson deserializer if there is no definition + */ + private List<ScenarioVerificationTask> activities = new ArrayList<>(); + /** + * List of Variables to check + * Maybe null due the Gson deserializer if there is no definition + */ + private List<ScenarioVerificationVariable> variables = new ArrayList<>(); + + /** + * List of duration to check + * Maybe null due the Gson deserializer if there is no definition + */ + private final List<ScenarioVerificationPerformance> performances = new ArrayList<>(); + + /** + * Variable to search the process instance, if only the verification is running + * Maybe null due the Gson deserializer if there is no definition + */ + private Map<String, Object> searchProcessInstanceByVariable; + + protected ScenarioVerification(ScenarioExecution scenarioExecution) { + this.scenarioExecution = scenarioExecution; + } + + public List<ScenarioVerificationTask> getActivities() { + return activities == null ? Collections.emptyList() : activities; + } + + public void setActivities(List<ScenarioVerificationTask> activities) { + this.activities = activities; + } + + public Map<String, Object> getSearchProcessInstanceByVariable() { + return searchProcessInstanceByVariable == null ? Collections.emptyMap() : searchProcessInstanceByVariable; + } + + public List<ScenarioVerificationVariable> getVariables() { + return variables == null ? Collections.emptyList() : variables; + } + + public void setVariables(List<ScenarioVerificationVariable> variables) { + this.variables = variables; + } + + public List<ScenarioVerificationPerformance> getPerformances() { + return performances == null ? Collections.emptyList() : performances; + } + + public ScenarioExecution getScenarioExecution() { + return scenarioExecution; + } } diff --git a/src/main/java/org/camunda/automator/definition/ScenarioVerificationBasic.java b/src/main/java/org/camunda/automator/definition/ScenarioVerificationBasic.java index d5b3206..e84bf62 100644 --- a/src/main/java/org/camunda/automator/definition/ScenarioVerificationBasic.java +++ b/src/main/java/org/camunda/automator/definition/ScenarioVerificationBasic.java @@ -2,5 +2,5 @@ public interface ScenarioVerificationBasic { - String getSynthesis(); + String getSynthesis(); } diff --git a/src/main/java/org/camunda/automator/definition/ScenarioVerificationPerformance.java b/src/main/java/org/camunda/automator/definition/ScenarioVerificationPerformance.java new file mode 100644 index 0000000..328fbc3 --- /dev/null +++ b/src/main/java/org/camunda/automator/definition/ScenarioVerificationPerformance.java @@ -0,0 +1,62 @@ +package org.camunda.automator.definition; + +import java.time.Duration; + +public class ScenarioVerificationPerformance implements ScenarioVerificationBasic { + public String fromFlowNode; + public String fromMarker; + public String toFlowNode; + public String toMarker; + public String duration; + + public void setFromFlowNode(String fromFlowNode) { + this.fromFlowNode = fromFlowNode; + } + + public void setToFlowNode(String toFlowNode) { + this.toFlowNode = toFlowNode; + } + + public void setDuration(String duration) { + this.duration = duration; + } + + public Marker getMarker(String marker) { + try { + if (marker == null) + return Marker.BEGIN; + return Marker.valueOf(marker); + } catch (Exception e) { + return Marker.BEGIN; + } + } + + public Marker getFromMarker() { + return getMarker(fromMarker); + } + + public void setFromMarker(String fromMarker) { + this.fromMarker = fromMarker; + } + + public Marker getToMarker() { + return getMarker(toMarker); + } + + public void setToMarker(String toMarker) { + this.toMarker = toMarker; + } + + public long getDurationInMs() { + return Duration.parse(duration).toMillis(); + } + + public String getSynthesis() { + return "PerformanceCheck [" + fromFlowNode + "] => [" + toFlowNode + "] in [" + duration + "]"; + } + + public enum Marker {BEGIN, END} + +} + + diff --git a/src/main/java/org/camunda/automator/definition/ScenarioVerificationTask.java b/src/main/java/org/camunda/automator/definition/ScenarioVerificationTask.java index 39a9224..0e423d0 100644 --- a/src/main/java/org/camunda/automator/definition/ScenarioVerificationTask.java +++ b/src/main/java/org/camunda/automator/definition/ScenarioVerificationTask.java @@ -1,48 +1,48 @@ package org.camunda.automator.definition; public class ScenarioVerificationTask implements ScenarioVerificationBasic { - private final ScenarioVerification scenarioVerification; - public ScenarioStep.Step type; - public String taskId; - public Integer numberOfTasks; - public StepState state; + private final ScenarioVerification scenarioVerification; + public ScenarioStep.Step type; + public String taskId; + public Integer numberOfTasks; + public StepState state; - public ScenarioVerificationTask(ScenarioVerification scenarioVerification) { - this.scenarioVerification = scenarioVerification; - } + public ScenarioVerificationTask(ScenarioVerification scenarioVerification) { + this.scenarioVerification = scenarioVerification; + } - public ScenarioStep.Step getType() { - return type; - } + public ScenarioStep.Step getType() { + return type; + } - public void setType(ScenarioStep.Step type) { - this.type = type; - } + public void setType(ScenarioStep.Step type) { + this.type = type; + } - public String getTaskId() { - return taskId; - } + public String getTaskId() { + return taskId; + } - public void setTaskId(String taskId) { - this.taskId = taskId; - } + public void setTaskId(String taskId) { + this.taskId = taskId; + } - public int getNumberOfTasks() { - return numberOfTasks == null ? 1 : numberOfTasks; - } + public int getNumberOfTasks() { + return numberOfTasks == null ? 1 : numberOfTasks; + } - public void setNumberOfTasks(int numberOfTasks) { - this.numberOfTasks = numberOfTasks; - } + public void setNumberOfTasks(int numberOfTasks) { + this.numberOfTasks = numberOfTasks; + } - public ScenarioVerification getScenarioVerification() { - return scenarioVerification; - } + public ScenarioVerification getScenarioVerification() { + return scenarioVerification; + } - public String getSynthesis() { - return "ActivityCheck [" + taskId + "] " + state.toString(); - } + public String getSynthesis() { + return "ActivityCheck [" + taskId + "] state[" + (state == null ? "" : state.toString()) + "]"; + } - public enum StepState {COMPLETED, ACTIVE} + public enum StepState {COMPLETED, ACTIVE} } diff --git a/src/main/java/org/camunda/automator/definition/ScenarioVerificationVariable.java b/src/main/java/org/camunda/automator/definition/ScenarioVerificationVariable.java index 9affe2a..d1e1a40 100644 --- a/src/main/java/org/camunda/automator/definition/ScenarioVerificationVariable.java +++ b/src/main/java/org/camunda/automator/definition/ScenarioVerificationVariable.java @@ -1,11 +1,19 @@ package org.camunda.automator.definition; public class ScenarioVerificationVariable implements ScenarioVerificationBasic { - public String name; - public Object value; + public String name; + public Object value; - public String getSynthesis() { - return "VariableCheck [" + name + "]=[" + value + "]"; - } + public void setName(String name) { + this.name = name; + } + + public void setValue(Object value) { + this.value = value; + } + + public String getSynthesis() { + return "VariableCheck [" + name + "]=[" + value + "]"; + } } diff --git a/src/main/java/org/camunda/automator/definition/ScenarioWarmingUp.java b/src/main/java/org/camunda/automator/definition/ScenarioWarmingUp.java index 554012e..d75fd89 100644 --- a/src/main/java/org/camunda/automator/definition/ScenarioWarmingUp.java +++ b/src/main/java/org/camunda/automator/definition/ScenarioWarmingUp.java @@ -13,22 +13,22 @@ public class ScenarioWarmingUp { - /** - * The warmingUp will take this duration maximum, except if during this time, all operations warmingUp declare the end - * (see ScenarioStep) - */ - public String duration; - public List<ScenarioStep> operations; - - public boolean useServiceTasks = false; - public boolean useUserTasks = false; - - public Duration getDuration() { - return duration == null ? Duration.ZERO : Duration.parse(duration); - } - - public List<ScenarioStep> getOperations() { - return operations == null ? Collections.emptyList() : operations; - } + /** + * The warmingUp will take this duration maximum, except if during this time, all operations warmingUp declare the end + * (see ScenarioStep) + */ + public String duration; + public List<ScenarioStep> operations; + + public boolean useServiceTasks = false; + public boolean useUserTasks = false; + + public Duration getDuration() { + return duration == null ? Duration.ZERO : Duration.parse(duration); + } + + public List<ScenarioStep> getOperations() { + return operations == null ? Collections.emptyList() : operations; + } } diff --git a/src/main/java/org/camunda/automator/engine/AutomatorException.java b/src/main/java/org/camunda/automator/engine/AutomatorException.java index f501fef..b042efc 100644 --- a/src/main/java/org/camunda/automator/engine/AutomatorException.java +++ b/src/main/java/org/camunda/automator/engine/AutomatorException.java @@ -3,28 +3,28 @@ import org.camunda.community.rest.client.invoker.ApiException; public class AutomatorException extends Exception { - public int code; - public String message; + public int code; + public String message; - public AutomatorException(int code, String message) { - this.code = code; - this.message = message; - } + public AutomatorException(int code, String message) { + this.code = code; + this.message = message; + } - public AutomatorException(String message) { - this.message = message; - } + public AutomatorException(String message) { + this.message = message; + } - public AutomatorException(String message, ApiException exception) { - this.code = exception.getCode(); - this.message = message + " : " + exception.getMessage() + " " + exception.getResponseBody(); - } + public AutomatorException(String message, ApiException exception) { + this.code = exception.getCode(); + this.message = message + " : " + exception.getMessage() + " " + exception.getResponseBody(); + } - public String getMessage() { - return message; - } + public String getMessage() { + return message; + } - public int getCode() { - return code; - } + public int getCode() { + return code; + } } diff --git a/src/main/java/org/camunda/automator/engine/RunParameters.java b/src/main/java/org/camunda/automator/engine/RunParameters.java index 4ce7b1b..d060ea2 100644 --- a/src/main/java/org/camunda/automator/engine/RunParameters.java +++ b/src/main/java/org/camunda/automator/engine/RunParameters.java @@ -4,247 +4,247 @@ import java.util.List; public class RunParameters { - private LOGLEVEL logLevel = LOGLEVEL.MONITORING; - - private String serverName; - - private int numberOfThreadsPerScenario = 10; - - /** - * Return the number of thread to use in the start event. Coming from the configuration. - * it may be n - */ - private Integer startEventNbThreads; - - /** - * Execute the scenario (execution part): create process instance, execute user & service task - */ - private boolean execution = false; - - /** - * On execution, it's possible to pilot each item, one by one - */ - private boolean creation = true; - private boolean servicetask = true; - private boolean usertask = true; - /** - * Verify the scenario (verification part) : check that tasks exist - */ - private boolean verification = false; - - /** - * After the execution, clean the processInstance - */ - private boolean clearAllAfter = false; - - /** - * Allow any deployment - */ - private boolean deploymentProcess = true; - - private boolean fullDetailsSynthesis = false; - private List<String> filterServiceTask = Collections.emptyList(); - - private boolean deepTracking = true; - /** - * Load the scenario path here. Some functions may be relative to this path - */ - private String scenarioPath; - - private boolean warmingUp = true; - - public RunParameters() { - } - - public LOGLEVEL getLogLevel() { - return logLevel; - } - - public RunParameters setLogLevel(LOGLEVEL logLevel) { - this.logLevel = logLevel; - return this; - } - - public String getServerName() { - return this.serverName; - } - - public RunParameters setServerName(String serverName) { - this.serverName = serverName; - return this; - } - - public boolean isExecution() { - return execution; - } - - public RunParameters setExecution(boolean execution) { - this.execution = execution; - return this; - } - - public boolean isCreation() { - return creation; - } - - public RunParameters setCreation(boolean creation) { - this.creation = creation; - return this; - } - - public boolean isServiceTask() { - return servicetask; - } - - public RunParameters setServiceTask(boolean servicetask) { - this.servicetask = servicetask; - return this; - } - - public boolean isUserTask() { - return usertask; - } - - public RunParameters setUserTask(boolean usertask) { - this.usertask = usertask; - return this; - } - - public boolean isVerification() { - return verification; - } - - public RunParameters setVerification(boolean verification) { - this.verification = verification; - return this; - } - - public boolean isClearAllAfter() { - return clearAllAfter; - } - - public RunParameters setClearAllAfter(boolean clearAllAfter) { - this.clearAllAfter = clearAllAfter; - return this; - } - - public boolean isDeploymentProcess() { - return deploymentProcess; - } - - public RunParameters setDeploymentProcess(boolean deploymentProcess) { - this.deploymentProcess = deploymentProcess; - return this; - } - - public boolean isFullDetailsSynthesis() { - return fullDetailsSynthesis; - } - - public RunParameters setFullDetailsSynthesis(boolean fullDetailsSynthesis) { - this.fullDetailsSynthesis = fullDetailsSynthesis; - return this; - } - - public List<String> getFilterServiceTask() { - return filterServiceTask; - } - - public RunParameters setFilterServiceTask(List<String> filterServiceTask) { - this.filterServiceTask = filterServiceTask; - return this; - } - - public boolean isDeepTracking() { - return deepTracking; - } - - public RunParameters setDeepTracking(boolean deepTracking) { - this.deepTracking = deepTracking; - return this; - } - - public String getScenarioPath() { - return scenarioPath; - } - - public RunParameters setScenarioPath(String scenarioPath) { - this.scenarioPath = scenarioPath; - return this; - } - - public boolean isWarmingUp() { - return warmingUp; - } - - public RunParameters setWarmingUp(boolean warmingUp) { - this.warmingUp = warmingUp; - return this; - } - - public int getNumberOfThreadsPerScenario() { - return (numberOfThreadsPerScenario <= 0 ? 1 : numberOfThreadsPerScenario); - } - - public RunParameters setNumberOfThreadsPerScenario(int numberOfThreadsPerScenario) { - this.numberOfThreadsPerScenario = numberOfThreadsPerScenario; - return this; - } - - /** - * return the nbThreads to use in a start event, comming from the configuration - * If the configuration does not specify anything, then return null. - * - * @return the number of thread to use for the start event - */ - public Integer getStartEventNbThreads() { - return startEventNbThreads; - } - - public void setStartEventNbThreads(Integer startEventNbThreads) { - this.startEventNbThreads = startEventNbThreads; - } - - public boolean showLevelDebug() { - return getLogLevelAsNumber() >= 5; - } - - public boolean showLevelInfo() { - return getLogLevelAsNumber() >= 4; - } - - public boolean showLevelMonitoring() { - return getLogLevelAsNumber() >= 3; - } - - public boolean showLevelDashboard() { - return getLogLevelAsNumber() >= 2; - } - - public void setFilterExecutionServiceTask(List<String> filterServiceTask) { - this.filterServiceTask = filterServiceTask; - } - - public boolean blockExecutionServiceTask(String topic) { - // no filter: execute everything - if (filterServiceTask.isEmpty()) - return false; - // filter in place: only if the topic is registered - return !filterServiceTask.contains(topic); - } - - private int getLogLevelAsNumber() { - return switch (logLevel) { - case NOTHING -> 0; - case MAIN -> 1; - case DASHBOARD -> 2; - case MONITORING -> 3; - case INFO -> 4; - case DEBUG -> 5; - default -> 0; - }; - } - - public enum LOGLEVEL {DEBUG, INFO, MONITORING, DASHBOARD, MAIN, NOTHING} + private LOGLEVEL logLevel = LOGLEVEL.MONITORING; + + private String serverName; + + private int numberOfThreadsPerScenario = 10; + + /** + * Return the number of thread to use in the start event. Coming from the configuration. + * it may be n + */ + private Integer startEventNbThreads; + + /** + * Execute the scenario (execution part): create process instance, execute user & service task + */ + private boolean execution = false; + + /** + * On execution, it's possible to pilot each item, one by one + */ + private boolean creation = true; + private boolean servicetask = true; + private boolean usertask = true; + /** + * Verify the scenario (verification part) : check that tasks exist + */ + private boolean verification = false; + + /** + * After the execution, clean the processInstance + */ + private boolean clearAllAfter = false; + + /** + * Allow any deployment + */ + private boolean deploymentProcess = true; + + private boolean fullDetailsSynthesis = false; + private List<String> filterServiceTask = Collections.emptyList(); + + private boolean deepTracking = true; + /** + * Load the scenario path here. Some functions may be relative to this path + */ + private String scenarioPath; + + private boolean warmingUp = true; + + public RunParameters() { + } + + public LOGLEVEL getLogLevel() { + return logLevel; + } + + public RunParameters setLogLevel(LOGLEVEL logLevel) { + this.logLevel = logLevel; + return this; + } + + public String getServerName() { + return this.serverName; + } + + public RunParameters setServerName(String serverName) { + this.serverName = serverName; + return this; + } + + public boolean isExecution() { + return execution; + } + + public RunParameters setExecution(boolean execution) { + this.execution = execution; + return this; + } + + public boolean isCreation() { + return creation; + } + + public RunParameters setCreation(boolean creation) { + this.creation = creation; + return this; + } + + public boolean isServiceTask() { + return servicetask; + } + + public RunParameters setServiceTask(boolean servicetask) { + this.servicetask = servicetask; + return this; + } + + public boolean isUserTask() { + return usertask; + } + + public RunParameters setUserTask(boolean usertask) { + this.usertask = usertask; + return this; + } + + public boolean isVerification() { + return verification; + } + + public RunParameters setVerification(boolean verification) { + this.verification = verification; + return this; + } + + public boolean isClearAllAfter() { + return clearAllAfter; + } + + public RunParameters setClearAllAfter(boolean clearAllAfter) { + this.clearAllAfter = clearAllAfter; + return this; + } + + public boolean isDeploymentProcess() { + return deploymentProcess; + } + + public RunParameters setDeploymentProcess(boolean deploymentProcess) { + this.deploymentProcess = deploymentProcess; + return this; + } + + public boolean isFullDetailsSynthesis() { + return fullDetailsSynthesis; + } + + public RunParameters setFullDetailsSynthesis(boolean fullDetailsSynthesis) { + this.fullDetailsSynthesis = fullDetailsSynthesis; + return this; + } + + public List<String> getFilterServiceTask() { + return filterServiceTask; + } + + public RunParameters setFilterServiceTask(List<String> filterServiceTask) { + this.filterServiceTask = filterServiceTask; + return this; + } + + public boolean isDeepTracking() { + return deepTracking; + } + + public RunParameters setDeepTracking(boolean deepTracking) { + this.deepTracking = deepTracking; + return this; + } + + public String getScenarioPath() { + return scenarioPath; + } + + public RunParameters setScenarioPath(String scenarioPath) { + this.scenarioPath = scenarioPath; + return this; + } + + public boolean isWarmingUp() { + return warmingUp; + } + + public RunParameters setWarmingUp(boolean warmingUp) { + this.warmingUp = warmingUp; + return this; + } + + public int getNumberOfThreadsPerScenario() { + return (numberOfThreadsPerScenario <= 0 ? 1 : numberOfThreadsPerScenario); + } + + public RunParameters setNumberOfThreadsPerScenario(int numberOfThreadsPerScenario) { + this.numberOfThreadsPerScenario = numberOfThreadsPerScenario; + return this; + } + + /** + * return the nbThreads to use in a start event, comming from the configuration + * If the configuration does not specify anything, then return null. + * + * @return the number of thread to use for the start event + */ + public Integer getStartEventNbThreads() { + return startEventNbThreads; + } + + public void setStartEventNbThreads(Integer startEventNbThreads) { + this.startEventNbThreads = startEventNbThreads; + } + + public boolean showLevelDebug() { + return getLogLevelAsNumber() >= 5; + } + + public boolean showLevelInfo() { + return getLogLevelAsNumber() >= 4; + } + + public boolean showLevelMonitoring() { + return getLogLevelAsNumber() >= 3; + } + + public boolean showLevelDashboard() { + return getLogLevelAsNumber() >= 2; + } + + public void setFilterExecutionServiceTask(List<String> filterServiceTask) { + this.filterServiceTask = filterServiceTask; + } + + public boolean blockExecutionServiceTask(String topic) { + // no filter: execute everything + if (filterServiceTask.isEmpty()) + return false; + // filter in place: only if the topic is registered + return !filterServiceTask.contains(topic); + } + + private int getLogLevelAsNumber() { + return switch (logLevel) { + case NOTHING -> 0; + case MAIN -> 1; + case DASHBOARD -> 2; + case MONITORING -> 3; + case INFO -> 4; + case DEBUG -> 5; + default -> 0; + }; + } + + public enum LOGLEVEL {DEBUG, INFO, MONITORING, DASHBOARD, MAIN, NOTHING} } diff --git a/src/main/java/org/camunda/automator/engine/RunResult.java b/src/main/java/org/camunda/automator/engine/RunResult.java index f78dfe8..1e44c8d 100644 --- a/src/main/java/org/camunda/automator/engine/RunResult.java +++ b/src/main/java/org/camunda/automator/engine/RunResult.java @@ -6,369 +6,395 @@ /* ******************************************************************** */ package org.camunda.automator.engine; +import org.camunda.automator.definition.ScenarioExecution; import org.camunda.automator.definition.ScenarioStep; import org.camunda.automator.definition.ScenarioVerificationBasic; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.ArrayList; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.stream.Collectors; public class RunResult { - /** - * Scenario attached to this execution - */ - private final RunScenario runScenario; - /** - * List of error. If empty, the scenario was executed with success - */ - private final List<ErrorDescription> listErrors = new ArrayList<>(); - private final List<StepExecution> listDetailsSteps = new ArrayList<>(); - private final List<VerificationStatus> listVerifications = new ArrayList<>(); - /** - * process instance started for this execution. The executionResult stand for only one process instance - */ - private final List<String> listProcessInstancesId = new ArrayList<>(); - private final List<String> listProcessIdDeployed = new ArrayList<>(); - /** - * Keep a photo of process instance created/failed per processid - */ - private final Map<String, RecordCreationPI> recordCreationPIMap = new HashMap<>(); - Logger logger = LoggerFactory.getLogger(RunResult.class); - private int numberOfSteps = 0; - private int numberOfErrorSteps = 0; - - /** - * Time to execute it - */ - private long timeExecution; - - private Date startDate; - private Date endDate; - - public RunResult(RunScenario runScenario) { - this.runScenario = runScenario; - - } - - public Date getStartDate() { - return this.startDate; - } - - public void setStartDate(Date date) { - this.startDate = date; - } - - public Date getEndDate() { - return this.endDate; - } - - public void setEndDate(Date date) { - this.endDate = date; - } - - /** - * Add the process instance - this is mandatory to - * - * @param processInstanceId processInstanceId to add - */ - public void addProcessInstanceId(String processId, String processInstanceId) { - this.listProcessInstancesId.add(processInstanceId); - - RecordCreationPI create = recordCreationPIMap.getOrDefault(processId, new RecordCreationPI(processId)); - create.nbCreated++; - recordCreationPIMap.put(processId, create); - } - - - /* ******************************************************************** */ - /* */ - /* method used during the execution to collect information */ - /* */ - /* ******************************************************************** */ - - /** - * large flow: just register the number of PI - */ - public void registerAddProcessInstance(String processId, boolean withSuccess) { - RecordCreationPI create = recordCreationPIMap.getOrDefault(processId, new RecordCreationPI(processId)); - if (withSuccess) - create.nbCreated++; - else - create.nbFailed++; - recordCreationPIMap.put(processId, create); - } - - public void addTimeExecution(long timeToAdd) { - this.timeExecution += timeToAdd; - } - - public void addStepExecution(ScenarioStep step, long timeExecution) { - addTimeExecution(timeExecution); - numberOfSteps++; - if (runScenario.getRunParameters().showLevelInfo()) { - StepExecution scenarioExecution = new StepExecution(this); - scenarioExecution.step = step; - listDetailsSteps.add(scenarioExecution); - } - } - - /** - * large flow: just register the number of execution - */ - public void registerAddStepExecution() { - numberOfSteps++; - } - - public void registerAddErrorStepExecution() { - numberOfErrorSteps++; - - } - - public List<ErrorDescription> getListErrors() { - return listErrors; - } - - /* ******************************************************************** */ - /* */ - /* Errors */ - /* */ - /* ******************************************************************** */ - - public void addError(ScenarioStep step, String explanation) { - this.listErrors.add(new ErrorDescription(step, explanation)); - logger.error((step == null ? "" : step.getType().toString()) + " " + explanation); - - } - - public void addError(ScenarioStep step, AutomatorException e) { - this.listErrors.add(new ErrorDescription(step, e.getMessage())); - } - - public void addVerification(ScenarioVerificationBasic verification, boolean isSuccess, String message) { - VerificationStatus verificationStatus = new VerificationStatus(); - verificationStatus.verification = verification; - verificationStatus.isSuccess = isSuccess; - verificationStatus.message = message; - this.listVerifications.add(verificationStatus); - } - - public boolean hasErrors() { - return !listErrors.isEmpty(); - } - - /* ******************************************************************** */ - /* */ - /* Verifications */ - /* */ - /* ******************************************************************** */ - - public List<VerificationStatus> getListVerifications() { - return listVerifications; - } - - /** - * Merge the result in this result - * - * @param result the result object - */ - public void add(RunResult result) { - addTimeExecution(result.getTimeExecution()); - listErrors.addAll(result.listErrors); - listVerifications.addAll(result.listVerifications); - for (Map.Entry<String, RecordCreationPI> entry : result.recordCreationPIMap.entrySet()) { - RecordCreationPI currentReference = recordCreationPIMap.getOrDefault(entry.getKey(), - new RecordCreationPI(entry.getKey())); - currentReference.nbFailed += entry.getValue().nbFailed; - currentReference.nbCreated += entry.getValue().nbCreated; - - recordCreationPIMap.put(entry.getKey(), currentReference); - } - numberOfSteps += result.numberOfSteps; - numberOfErrorSteps += result.numberOfErrorSteps; - // we collect the list only if the level is low - if (runScenario.getRunParameters() != null && runScenario.getRunParameters().showLevelInfo()) { - listDetailsSteps.addAll(result.listDetailsSteps); - listProcessInstancesId.addAll(result.listProcessInstancesId); - } - } - - /* ******************************************************************** */ - /* */ - /* merge */ - /* */ - /* ******************************************************************** */ - - public boolean isSuccess() { - long nbVerificationErrors = listVerifications.stream().filter(t -> !t.isSuccess).count(); - return listErrors.isEmpty() && nbVerificationErrors == 0; - } - - /* ******************************************************************** */ - /* */ - /* method to get information */ - /* */ - /* ******************************************************************** */ - - public String getFirstProcessInstanceId() { - return listProcessInstancesId.isEmpty() ? null : listProcessInstancesId.get(0); - } - - public List<String> getProcessInstanceId() { - return this.listProcessInstancesId; - } - - public long getTimeExecution() { - return timeExecution; - } - - public void setTimeExecution(long timeExecution) { - this.timeExecution = timeExecution; - } - - public List<String> getProcessIdDeployed() { - return listProcessIdDeployed; - } - - public void addDeploymentProcessId(String processId) { - this.listProcessIdDeployed.add(processId); - } - - public Map<String, RecordCreationPI> getRecordCreationPI() { - return recordCreationPIMap; - } - - public long getRecordCreationPIAllProcesses() { - long sum = 0; - for (RecordCreationPI value : recordCreationPIMap.values()) - sum += value.nbCreated; - return sum; - } - - public int getNumberOfSteps() { - return numberOfSteps; - } - - public int getNumberOfErrorSteps() { - return numberOfErrorSteps; - } - - /** - * @return a synthesis - */ - public String getSynthesis(boolean fullDetail) { - StringBuilder synthesis = new StringBuilder(); - synthesis.append((isSuccess() && !hasErrors()) ? "SUCCESS " : "FAIL "); - synthesis.append(runScenario.getScenario().getName()); - synthesis.append("("); - synthesis.append(runScenario.getScenario().getProcessId()); - synthesis.append("): "); - - StringBuilder append = synthesis.append(timeExecution); - synthesis.append(" timeExecution(ms), "); - RecordCreationPI recordCreationPI = recordCreationPIMap.get(runScenario.getScenario().getProcessId()); - synthesis.append(recordCreationPI == null ? 0 : recordCreationPI.nbCreated); - synthesis.append(" PICreated, "); - synthesis.append(recordCreationPI == null ? 0 : recordCreationPI.nbFailed); - synthesis.append(" PIFailed, "); - synthesis.append(numberOfSteps); - synthesis.append(" stepsExecuted, "); - synthesis.append(numberOfErrorSteps); - synthesis.append(" errorStepsExecuted, "); - - StringBuilder errorMessage = new StringBuilder(); - // add errors - errorMessage.append(listErrors.stream() // stream - .map(t -> { - return (t.step != null ? t.step.toString() : "") + t.explanation + "\n"; - }).collect(Collectors.joining(","))); + /** + * Scenario attached to this execution + */ + private final RunScenario runScenario; + + private final ScenarioExecution scnExecution; + + /** + * List of error. If empty, the scenario was executed with success + */ + private final List<ErrorDescription> listErrors = new ArrayList<>(); + private final List<StepExecution> listDetailsSteps = new ArrayList<>(); + private final List<VerificationStatus> listVerifications = new ArrayList<>(); + /** + * process instance started for this execution. The executionResult stand for only one process instance + */ + private final List<String> listProcessInstancesId = new ArrayList<>(); + private final List<String> listProcessIdDeployed = new ArrayList<>(); + /** + * Keep a photo of process instance created/failed per processid + */ + private final Map<String, RecordCreationPI> recordCreationPIMap = new HashMap<>(); + Logger logger = LoggerFactory.getLogger(RunResult.class); + private int numberOfSteps = 0; + private int numberOfErrorSteps = 0; + + /** + * Time to execute it + */ + private long timeExecution; + + private Date startDate; + private Date endDate; + private final List<RunResult> listRunResults = new ArrayList<>(); + + public RunResult(RunScenario runScenario) { + this.runScenario = runScenario; + this.scnExecution = null; + } + + public RunResult(RunScenario runScenario, ScenarioExecution scnExecution) { + this.runScenario = runScenario; + this.scnExecution = scnExecution; + + } + + public Date getStartDate() { + return this.startDate; + } + + public void setStartDate(Date date) { + this.startDate = date; + } + + public Date getEndDate() { + return this.endDate; + } + + public void setEndDate(Date date) { + this.endDate = date; + } + + + /* ******************************************************************** */ + /* */ + /* method used during the execution to collect information */ + /* */ + /* ******************************************************************** */ + + /** + * Add the process instance - this is mandatory to + * + * @param processInstanceId processInstanceId to add + */ + public void addProcessInstanceId(String processId, String processInstanceId) { + this.listProcessInstancesId.add(processInstanceId); + + RecordCreationPI create = recordCreationPIMap.getOrDefault(processId, new RecordCreationPI(processId)); + create.nbCreated++; + recordCreationPIMap.put(processId, create); + } - if (fullDetail) { - synthesis.append(errorMessage); + /** + * large flow: just register the number of PI + */ + public void registerAddProcessInstance(String processId, boolean withSuccess) { + RecordCreationPI create = recordCreationPIMap.getOrDefault(processId, new RecordCreationPI(processId)); + if (withSuccess) + create.nbCreated++; + else + create.nbFailed++; + recordCreationPIMap.put(processId, create); } - StringBuilder verificationMessage = new StringBuilder(); - verificationMessage.append(listVerifications.stream().map(t -> { - return t.verification.getSynthesis() + "? " + (t.isSuccess ? "OK" : "FAIL") + " " + t.message + "\n"; - }).collect(Collectors.joining(","))); - if (fullDetail) { - synthesis.append(verificationMessage); + + public void addTimeExecution(long timeToAdd) { + this.timeExecution += timeToAdd; } - // add full details - if (fullDetail) { - synthesis.append(" ListOfPICreated: "); - synthesis.append(listProcessInstancesId.stream() // stream - .collect(Collectors.joining(","))); + public void addStepExecution(ScenarioStep step, long timeExecution) { + addTimeExecution(timeExecution); + numberOfSteps++; + if (runScenario.getRunParameters().showLevelInfo()) { + StepExecution scenarioExecution = new StepExecution(this); + scenarioExecution.step = step; + listDetailsSteps.add(scenarioExecution); + } } - return synthesis.toString(); - } + /** + * large flow: just register the number of execution + */ + public void registerAddStepExecution() { + numberOfSteps++; + } - public static class StepExecution { - public final List<ErrorDescription> listErrors = new ArrayList<>(); - private final RunResult scenarioExecutionResult; - public ScenarioStep step; - public long timeExecution; + public void registerAddErrorStepExecution() { + numberOfErrorSteps++; - public StepExecution(RunResult scenarioExecutionResult) { - this.scenarioExecutionResult = scenarioExecutionResult; } - public void addError(ErrorDescription error) { - listErrors.add(error); + /* ******************************************************************** */ + /* */ + /* Errors */ + /* */ + /* ******************************************************************** */ + + public List<ErrorDescription> getListErrors() { + return listErrors; } - } - /* ******************************************************************** */ - /* */ - /* local class */ - /* */ - /* ******************************************************************** */ + public void addError(ScenarioStep step, String explanation) { + this.listErrors.add(new ErrorDescription(step, explanation)); + logger.error((step == null ? "" : step.getType().toString()) + " " + explanation); - public static class ErrorDescription { - public ScenarioStep step; - public ScenarioVerificationBasic verificationBasic; - public String explanation; + } - public ErrorDescription(ScenarioStep step, String explanation) { - this.step = step; - this.explanation = explanation; + public void addError(ScenarioStep step, AutomatorException e) { + this.listErrors.add(new ErrorDescription(step, e.getMessage())); } - public ErrorDescription(ScenarioVerificationBasic verificationBasic, String explanation) { - this.verificationBasic = verificationBasic; - this.explanation = explanation; + public void addVerification(ScenarioVerificationBasic verification, boolean isSuccess, String message) { + VerificationStatus verificationStatus = new VerificationStatus(); + verificationStatus.verification = verification; + verificationStatus.isSuccess = isSuccess; + verificationStatus.message = message; + this.listVerifications.add(verificationStatus); + } + + /* ******************************************************************** */ + /* */ + /* Verifications */ + /* */ + /* ******************************************************************** */ + + public boolean hasErrors() { + return !listErrors.isEmpty(); + } + + public List<VerificationStatus> getListVerifications() { + return listVerifications; + } + + /** + * Merge the result in this result + * + * @param result the result object + */ + public void merge(RunResult result) { + addTimeExecution(result.getTimeExecution()); + listErrors.addAll(result.listErrors); + listVerifications.addAll(result.listVerifications); + for (Map.Entry<String, RecordCreationPI> entry : result.recordCreationPIMap.entrySet()) { + RecordCreationPI currentReference = recordCreationPIMap.getOrDefault(entry.getKey(), + new RecordCreationPI(entry.getKey())); + currentReference.nbFailed += entry.getValue().nbFailed; + currentReference.nbCreated += entry.getValue().nbCreated; + + recordCreationPIMap.put(entry.getKey(), currentReference); + } + numberOfSteps += result.numberOfSteps; + numberOfErrorSteps += result.numberOfErrorSteps; + listRunResults.addAll(result.listRunResults); + // we collect the list only if the level is low + if (runScenario.getRunParameters() != null && runScenario.getRunParameters().showLevelInfo()) { + listDetailsSteps.addAll(result.listDetailsSteps); + listProcessInstancesId.addAll(result.listProcessInstancesId); + } + } + + public void add(RunResult runResult) { + // We keep track of the result in a list + listRunResults.add(runResult); + merge(runResult); + } + + /* ******************************************************************** */ + /* */ + /* merge */ + /* */ + /* ******************************************************************** */ + + public boolean isSuccess() { + long nbVerificationErrors = listVerifications.stream().filter(t -> !t.isSuccess).count(); + return listErrors.isEmpty() && nbVerificationErrors == 0; } - } - public static class RecordCreationPI { - public String processId; - public long nbCreated = 0; - public long nbFailed = 0; + /* ******************************************************************** */ + /* */ + /* method to get information */ + /* */ + /* ******************************************************************** */ - public RecordCreationPI(String processId) { - this.processId = processId; + public String getFirstProcessInstanceId() { + return listProcessInstancesId.isEmpty() ? null : listProcessInstancesId.get(0); } - public void add(RecordCreationPI record) { - if (record == null) - return; - nbCreated += record.nbCreated; - nbFailed += record.nbFailed; + public List<String> getProcessInstanceId() { + return this.listProcessInstancesId; } - public String toString() { - return "Created[" + nbCreated + "] Failed[" + nbFailed + "]"; + public long getTimeExecution() { + return timeExecution; } - } - public class VerificationStatus { - public ScenarioVerificationBasic verification; - public boolean isSuccess; - public String message; - } + public void setTimeExecution(long timeExecution) { + this.timeExecution = timeExecution; + } + + public List<String> getProcessIdDeployed() { + return listProcessIdDeployed; + } + + public void addDeploymentProcessId(String processId) { + this.listProcessIdDeployed.add(processId); + } + + public Map<String, RecordCreationPI> getRecordCreationPI() { + return recordCreationPIMap; + } + + public long getRecordCreationPIAllProcesses() { + long sum = 0; + for (RecordCreationPI value : recordCreationPIMap.values()) + sum += value.nbCreated; + return sum; + } + + public int getNumberOfSteps() { + return numberOfSteps; + } + + public int getNumberOfErrorSteps() { + return numberOfErrorSteps; + } + + public List<RunResult> getListRunResults() { + return listRunResults; + } + + public RunScenario getRunScenario() { + return runScenario; + } + + public ScenarioExecution getScnExecution() { + return scnExecution; + } + + /** + * @return a synthesis + */ + public String getSynthesis(boolean fullDetail) { + StringBuilder synthesis = new StringBuilder(); + synthesis.append((isSuccess() && !hasErrors()) ? "SUCCESS " : "FAIL "); + synthesis.append(runScenario.getScenario().getName()); + synthesis.append("("); + synthesis.append(runScenario.getScenario().getProcessId()); + synthesis.append("): "); + + StringBuilder append = synthesis.append(timeExecution); + synthesis.append(" timeExecution(ms), "); + RecordCreationPI recordCreationPI = recordCreationPIMap.get(runScenario.getScenario().getProcessId()); + synthesis.append(recordCreationPI == null ? 0 : recordCreationPI.nbCreated); + synthesis.append(" PICreated, "); + synthesis.append(recordCreationPI == null ? 0 : recordCreationPI.nbFailed); + synthesis.append(" PIFailed, "); + synthesis.append(numberOfSteps); + synthesis.append(" stepsExecuted, "); + synthesis.append(numberOfErrorSteps); + synthesis.append(" errorStepsExecuted, "); + + StringBuilder errorMessage = new StringBuilder(); + // add errors + errorMessage.append(listErrors.stream() // stream + .map(t -> { + return (t.step != null ? t.step.toString() : "") + t.explanation + "\n"; + }).collect(Collectors.joining(","))); + + if (fullDetail) { + synthesis.append(errorMessage); + } + StringBuilder verificationMessage = new StringBuilder(); + verificationMessage.append(listVerifications.stream().map(t -> { + return t.verification.getSynthesis() + "? " + (t.isSuccess ? "OK" : "FAIL") + " " + t.message + "\n"; + }).collect(Collectors.joining(","))); + if (fullDetail) { + synthesis.append(verificationMessage); + } + // add full details + if (fullDetail) { + synthesis.append(" ListOfPICreated: "); + + synthesis.append(listProcessInstancesId.stream() // stream + .collect(Collectors.joining(","))); + } + return synthesis.toString(); + + } + + public static class StepExecution { + public final List<ErrorDescription> listErrors = new ArrayList<>(); + private final RunResult scenarioExecutionResult; + public ScenarioStep step; + public long timeExecution; + + public StepExecution(RunResult scenarioExecutionResult) { + this.scenarioExecutionResult = scenarioExecutionResult; + } + + public void addError(ErrorDescription error) { + listErrors.add(error); + } + } + + /* ******************************************************************** */ + /* */ + /* local class */ + /* */ + /* ******************************************************************** */ + + public static class ErrorDescription { + public ScenarioStep step; + public ScenarioVerificationBasic verificationBasic; + public String explanation; + + public ErrorDescription(ScenarioStep step, String explanation) { + this.step = step; + this.explanation = explanation; + } + + public ErrorDescription(ScenarioVerificationBasic verificationBasic, String explanation) { + this.verificationBasic = verificationBasic; + this.explanation = explanation; + } + } + + public static class RecordCreationPI { + public String processId; + public long nbCreated = 0; + public long nbFailed = 0; + + public RecordCreationPI(String processId) { + this.processId = processId; + } + + public void add(RecordCreationPI record) { + if (record == null) + return; + nbCreated += record.nbCreated; + nbFailed += record.nbFailed; + } + + public String toString() { + return "Created[" + nbCreated + "] Failed[" + nbFailed + "]"; + } + } + + public class VerificationStatus { + public ScenarioVerificationBasic verification; + public boolean isSuccess; + public String message; + } } diff --git a/src/main/java/org/camunda/automator/engine/RunScenario.java b/src/main/java/org/camunda/automator/engine/RunScenario.java index d7a88c6..8ca09b5 100644 --- a/src/main/java/org/camunda/automator/engine/RunScenario.java +++ b/src/main/java/org/camunda/automator/engine/RunScenario.java @@ -17,11 +17,7 @@ import java.util.ArrayList; import java.util.Date; import java.util.List; -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; +import java.util.concurrent.*; /** * This object executes a scenario, in a context. Context is @@ -30,234 +26,249 @@ * - the RunParameters */ public class RunScenario { - private final Scenario scenario; - private final BpmnEngine bpmnEngine; - private final RunParameters runParameters; - private final ServiceAccess serviceAccess; - Logger logger = LoggerFactory.getLogger(RunScenario.class); - - /** - * @param scenario scenario to be executed - * @param bpmnEngine engine to connect - * @param runParameters different parameters to run the scenario - * @param serviceAccess service access to access all services, this object is created per execution - */ - public RunScenario(Scenario scenario, - BpmnEngine bpmnEngine, - RunParameters runParameters, - ServiceAccess serviceAccess) { - this.scenario = scenario; - this.bpmnEngine = bpmnEngine; - this.runParameters = runParameters; - this.serviceAccess = serviceAccess; - } - - /** - * Execute the scenario. - * A scenario is composed of - * - deployment - * - execution (which contains the verifications) - * <p> - * these steps are controlled by the runParameters - * - * @return tue result object - */ - public RunResult runScenario() { - RunResult result = new RunResult(this); - - // control - if (scenario.typeScenario == null) { - result.addError(null, "TypeScenario undefined"); - } - if (scenario.typeScenario.equals(Scenario.TYPESCENARIO.UNIT)) { - if (scenario.getExecutions() == null || scenario.getExecutions().isEmpty()) - result.addError(null, "TypeScenario[" + Scenario.TYPESCENARIO.UNIT + "] must have a list of [executions]"); - } else if (scenario.typeScenario.equals(Scenario.TYPESCENARIO.FLOW)) { - if (scenario.getFlowControl() == null) - result.addError(null, "TypeScenario[" + Scenario.TYPESCENARIO.FLOW + "] must have a list of [flowControl]"); - if (scenario.getFlows() == null || scenario.getFlows().isEmpty()) - result.addError(null, "TypeScenario[" + Scenario.TYPESCENARIO.FLOW + "] must have a list of [flows]"); + private final Scenario scenario; + private final BpmnEngine bpmnEngine; + private final RunParameters runParameters; + private final ServiceAccess serviceAccess; + Logger logger = LoggerFactory.getLogger(RunScenario.class); + + /** + * @param scenario scenario to be executed + * @param bpmnEngine engine to connect + * @param runParameters different parameters to run the scenario + * @param serviceAccess service access to access all services, this object is created per execution + */ + public RunScenario(Scenario scenario, + BpmnEngine bpmnEngine, + RunParameters runParameters, + ServiceAccess serviceAccess) { + this.scenario = scenario; + this.bpmnEngine = bpmnEngine; + this.runParameters = runParameters; + this.serviceAccess = serviceAccess; } - if (result.hasErrors()) - return result; - - logger.info("RunScenario: ------ Deployment ({})", runParameters.isDeploymentProcess()); - if (runParameters.isDeploymentProcess()) - result.add(runDeployment()); - logger.info("RunScenario: ------ End deployment "); - - // verification is inside execution - result.add(runExecutions()); - return result; - } - - /** - * run only the deployments on the process - test to verify the engine is performed - * - * @return result of deployment - */ - public RunResult runDeployment() { - RunResult result = new RunResult(this); - - // first, do we have to deploy something? - if (scenario.getDeployments() != null) { - for (ScenarioDeployment deployment : scenario.getDeployments()) { - - boolean sameTypeServer = false; - if (deployment.serverType.equals(BpmnEngineList.CamundaEngine.CAMUNDA_7)) { - sameTypeServer = bpmnEngine.getTypeCamundaEngine().equals(BpmnEngineList.CamundaEngine.CAMUNDA_7); - } else if (deployment.serverType.equals(BpmnEngineList.CamundaEngine.CAMUNDA_8)) { - sameTypeServer = bpmnEngine.getTypeCamundaEngine().equals(BpmnEngineList.CamundaEngine.CAMUNDA_8) - || bpmnEngine.getTypeCamundaEngine().equals(BpmnEngineList.CamundaEngine.CAMUNDA_8_SAAS); - } - if (sameTypeServer) { - try { - long begin = System.currentTimeMillis(); - File processFile = ScenarioTool.loadFile(deployment.processFile, this); - logger.info("Deploy process[{}] on {}", processFile.getName(), bpmnEngine.getSignature()); - result.addDeploymentProcessId(bpmnEngine.deployBpmn(processFile, deployment.policy)); - result.addTimeExecution(System.currentTimeMillis() - begin); - } catch (AutomatorException e) { - result.addError(null, "Can't deploy process [" + deployment.processFile + "] " + e.getMessage()); - } - } else { - logger.info("RunScenario: can't Deploy ({}), not the same server", deployment.processFile); + /** + * Execute the scenario. + * A scenario is composed of + * - deployment + * - execution (which contains the verifications) + * <p> + * these steps are controlled by the runParameters + * + * @return tue result object + */ + public RunResult runScenario() { + RunResult result = new RunResult(this); + + // control + if (scenario.typeScenario == null) { + result.addError(null, "TypeScenario undefined"); } - } - } - return result; - } - - /** - * Execute the scenario. - * Note: this method is multi thread safe. - * Note: if the execution has verification AND runParameters.execution == true, then the verification is started - * - * @return the execution - */ - public RunResult runExecutions() { - RunResult result = new RunResult(this); - result.setStartDate(new Date()); - - // the scenario can be an Execution or a Flow - if (scenario.typeScenario.equals(Scenario.TYPESCENARIO.UNIT)) { - // each execution is run in a different thread - ExecutorService executor = Executors.newFixedThreadPool(runParameters.getNumberOfThreadsPerScenario()); - - List<Future<?>> listFutures = new ArrayList<>(); - logger.info("RunScenario: ------ execution UNIT scenario [{}] {} execution on {} Threads", scenario.getName(), - scenario.getExecutions().size(), runParameters.getNumberOfThreadsPerScenario()); - - for (int i = 0; i < scenario.getExecutions().size(); i++) { - ScenarioExecution scnExecution = scenario.getExecutions().get(i); - ScnExecutionCallable scnExecutionCallable = new ScnExecutionCallable("Agent-" + i, this, scnExecution, - runParameters); - - listFutures.add(executor.submit(scnExecutionCallable)); - } - - // wait the end of all executions - try { - for (Future<?> f : listFutures) { - Object scnRunResult = f.get(); - result.add((RunResult) scnRunResult); + // ------------ unit scenario + if (scenario.typeScenario.equals(Scenario.TYPESCENARIO.UNIT)) { + if (scenario.getExecutions() == null || scenario.getExecutions().isEmpty()) { + result.addError(null, "TypeScenario[" + Scenario.TYPESCENARIO.UNIT + "] must have a list of [executions]"); + return result; + } + // force information in execution + for (ScenarioExecution execution : scenario.getExecutions()) { + execution.setNumberProcessInstances(1); + execution.setNumberOfThreads(1); + } + // Verification must be move to true + runParameters.setVerification(true); + + + // ------------- flow scenario + } else if (scenario.typeScenario.equals(Scenario.TYPESCENARIO.FLOW)) { + if (scenario.getFlowControl() == null) + result.addError(null, "TypeScenario[" + Scenario.TYPESCENARIO.FLOW + "] must have a list of [flowControl]"); + if (scenario.getFlows() == null || scenario.getFlows().isEmpty()) + result.addError(null, "TypeScenario[" + Scenario.TYPESCENARIO.FLOW + "] must have a list of [flows]"); } + if (result.hasErrors()) + return result; - } catch (ExecutionException ee) { - result.addError(null, "Error during executing in parallel " + ee.getMessage()); + logger.info("RunScenario: ------ Deployment ({})", runParameters.isDeploymentProcess()); + if (runParameters.isDeploymentProcess()) + result.merge(runDeployment()); + logger.info("RunScenario: ------ End deployment "); - } catch (Exception e) { - result.addError(null, "Error during executing in parallel " + e.getMessage()); - } - logger.info("RunScenario: ------ End execution"); + // verification is inside execution + result.merge(runExecutions()); + return result; } - if (scenario.typeScenario.equals(Scenario.TYPESCENARIO.FLOW)) { - logger.info("RunScenario: ------ execution FLOW scenario [{}]", scenario.getName()); - RunScenarioFlows scenarioFlows = new RunScenarioFlows(serviceAccess, this); - scenarioFlows.execute(result); - logger.info("RunScenario: ------ End execution"); + + /** + * run only the deployments on the process - test to verify the engine is performed + * + * @return result of deployment + */ + public RunResult runDeployment() { + RunResult result = new RunResult(this); + + // first, do we have to deploy something? + if (scenario.getDeployments() != null) { + for (ScenarioDeployment deployment : scenario.getDeployments()) { + + boolean sameTypeServer = false; + if (deployment.serverType.equals(BpmnEngineList.CamundaEngine.CAMUNDA_7)) { + sameTypeServer = bpmnEngine.getTypeCamundaEngine().equals(BpmnEngineList.CamundaEngine.CAMUNDA_7); + } else if (deployment.serverType.equals(BpmnEngineList.CamundaEngine.CAMUNDA_8)) { + sameTypeServer = bpmnEngine.getTypeCamundaEngine().equals(BpmnEngineList.CamundaEngine.CAMUNDA_8) + || bpmnEngine.getTypeCamundaEngine().equals(BpmnEngineList.CamundaEngine.CAMUNDA_8_SAAS); + } + if (sameTypeServer) { + try { + long begin = System.currentTimeMillis(); + File processFile = ScenarioTool.loadFile(deployment.processFile, this); + logger.info("Deploy process[{}] on {}", processFile.getName(), bpmnEngine.getSignature()); + result.addDeploymentProcessId(bpmnEngine.deployBpmn(processFile, deployment.policy)); + result.addTimeExecution(System.currentTimeMillis() - begin); + } catch (AutomatorException e) { + result.addError(null, "Can't deploy process [" + deployment.processFile + "] " + e.getMessage()); + } + } else { + logger.info("RunScenario: can't Deploy ({}), not the same server", deployment.processFile); + + } + } + } + return result; } - return result; - } + /** + * Execute the scenario. + * Note: this method is multi thread safe. + * Note: if the execution has verification AND runParameters.execution == true, then the verification is started + * + * @return the execution + */ + public RunResult runExecutions() { + RunResult result = new RunResult(this); + result.setStartDate(new Date()); + + // the scenario can be an Execution or a Flow + if (scenario.typeScenario.equals(Scenario.TYPESCENARIO.UNIT)) { + + // each execution is run in a different thread + ExecutorService executor = Executors.newFixedThreadPool(scenario.getExecutions().size()); + + List<Future<?>> listFutures = new ArrayList<>(); + logger.info("RunScenario: ------ execution UNIT scenario [{}] {} execution on {} Threads", scenario.getName(), + scenario.getExecutions().size(), runParameters.getNumberOfThreadsPerScenario()); + + for (int i = 0; i < scenario.getExecutions().size(); i++) { + ScenarioExecution scnExecution = scenario.getExecutions().get(i); + ScnExecutionCallable scnExecutionCallable = new ScnExecutionCallable("Agent-" + i, this, scnExecution, + runParameters); + + listFutures.add(executor.submit(scnExecutionCallable)); + } + + // wait the end of all executions + try { + for (Future<?> f : listFutures) { + Object scnRunResult = f.get(); + // We want to keep separate all results, in case of a Unit Test + result.add((RunResult) scnRunResult); + } + + } catch (ExecutionException ee) { + result.addError(null, "Error during executing in parallel " + ee.getMessage()); + + } catch (Exception e) { + result.addError(null, "Error during executing in parallel " + e.getMessage()); + } + logger.info("RunScenario: ------ End execution"); + } + if (scenario.typeScenario.equals(Scenario.TYPESCENARIO.FLOW)) { + logger.info("RunScenario: ------ execution FLOW scenario [{}]", scenario.getName()); + RunScenarioFlows scenarioFlows = new RunScenarioFlows(serviceAccess, this); + scenarioFlows.execute(result); + logger.info("RunScenario: ------ End execution"); + } - /** - * for one execution, run verifications - * - * @param scnExecution execution to check - * @return result of execution - */ - public RunResult runVerifications(ScenarioExecution scnExecution) { - RunResult result = new RunResult(this); + return result; + } - RunScenarioVerification verifications = new RunScenarioVerification(scnExecution); - result.add(verifications.runVerifications(this, result.getFirstProcessInstanceId())); - return result; + /** + * for one execution, run verifications + * + * @param scnExecution execution to check + * @return result of execution + */ + public RunResult runVerifications(ScenarioExecution scnExecution) { + RunResult result = new RunResult(this); - } + RunScenarioVerification verifications = new RunScenarioVerification(scnExecution); + result.merge(verifications.runVerifications(this, result.getFirstProcessInstanceId())); + return result; - public Scenario getScenario() { - return scenario; - } + } - public BpmnEngine getBpmnEngine() { - return bpmnEngine; - } + public Scenario getScenario() { + return scenario; + } - public RunParameters getRunParameters() { - return runParameters; - } + public BpmnEngine getBpmnEngine() { + return bpmnEngine; + } - public ServiceAccess getServiceAccess() { - return serviceAccess; - } + public RunParameters getRunParameters() { + return runParameters; + } + public ServiceAccess getServiceAccess() { + return serviceAccess; + } - /* ******************************************************************** */ - /* */ - /* Callable class */ - /* */ - /* Each execution are executed in different thread */ - /* ******************************************************************** */ - private static class ScnExecutionCallable implements Callable { - private final String agentName; - private final ScenarioExecution scnExecution; - private final RunScenario runScenario; - private final RunParameters runParameters; + /* ******************************************************************** */ + /* */ + /* Callable class */ + /* */ + /* Each execution are executed in different thread */ + /* ******************************************************************** */ - private RunResult scnRunResult; + private static class ScnExecutionCallable implements Callable { + private final String agentName; + private final ScenarioExecution scnExecution; + private final RunScenario runScenario; + private final RunParameters runParameters; - ScnExecutionCallable(String agentName, - RunScenario runScenario, - ScenarioExecution scnExecution, - RunParameters runParameters) { - this.agentName = agentName; - this.runScenario = runScenario; - this.scnExecution = scnExecution; - this.runParameters = runParameters; - } + private RunResult scnRunResult; - @Override - public Object call() { - RunScenarioUnit scnRunExecution = new RunScenarioUnit(runScenario, scnExecution); - scnRunExecution.setAgentName(agentName); + ScnExecutionCallable(String agentName, + RunScenario runScenario, + ScenarioExecution scnExecution, + RunParameters runParameters) { + this.agentName = agentName; + this.runScenario = runScenario; + this.scnExecution = scnExecution; + this.runParameters = runParameters; + } - /** - * Execution AND verifications are processed - * An execution may be MULTIPLE process instance, and each must be verified - */ - scnRunResult = scnRunExecution.runExecution(); + @Override + public Object call() { + RunScenarioUnit scnRunExecution = new RunScenarioUnit(runScenario, scnExecution); + scnRunExecution.setAgentName(agentName); - return scnRunResult; - } + /** + * Execution AND verifications are processed + * An execution may be MULTIPLE process instance, and each must be verified + */ + scnRunResult = scnRunExecution.runExecution(); - public RunResult getScnRunResult() { - return scnRunResult; + return scnRunResult; + } + + public RunResult getScnRunResult() { + return scnRunResult; + } } - } } diff --git a/src/main/java/org/camunda/automator/engine/RunZeebeOperation.java b/src/main/java/org/camunda/automator/engine/RunZeebeOperation.java index c76088e..962f4b1 100644 --- a/src/main/java/org/camunda/automator/engine/RunZeebeOperation.java +++ b/src/main/java/org/camunda/automator/engine/RunZeebeOperation.java @@ -14,32 +14,32 @@ import java.util.Map; public class RunZeebeOperation { - private static final Logger logger = LoggerFactory.getLogger(RunZeebeOperation.class); + private static final Logger logger = LoggerFactory.getLogger(RunZeebeOperation.class); - // Static method only - private RunZeebeOperation() { - } + // Static method only + private RunZeebeOperation() { + } - /** - * Resolve variables - */ - public static Map<String, Object> getVariablesStep(RunScenario runScenario, ScenarioStep step, int index) - throws AutomatorException { - Map<String, Object> variablesCompleted = new HashMap<>(); - variablesCompleted.putAll(step.getVariables()); + /** + * Resolve variables + */ + public static Map<String, Object> getVariablesStep(RunScenario runScenario, ScenarioStep step, int index) + throws AutomatorException { + Map<String, Object> variablesCompleted = new HashMap<>(); + variablesCompleted.putAll(step.getVariables()); - // execute all operations now - for (Map.Entry<String, String> entryOperation : step.getVariablesOperations().entrySet()) { - if (runScenario.getRunParameters().showLevelDebug()) - logger.info("Scenario Key[{}] Value[{}] Step {}", entryOperation.getKey(), entryOperation.getValue(), - step.getInformation()); - variablesCompleted.put(entryOperation.getKey(), - runScenario.getServiceAccess().serviceDataOperation.execute(entryOperation.getValue(), runScenario, - "Step " + step.getInformation(), index)); - } - if (runScenario.getRunParameters().showLevelDebug() && !variablesCompleted.isEmpty()) - logger.info("SetVariable [{}] {}", step.getVariables(), step.getInformation()); + // execute all operations now + for (Map.Entry<String, String> entryOperation : step.getVariablesOperations().entrySet()) { + if (runScenario.getRunParameters().showLevelDebug()) + logger.info("Scenario Key[{}] Value[{}] Step {}", entryOperation.getKey(), entryOperation.getValue(), + step.getInformation()); + variablesCompleted.put(entryOperation.getKey(), + runScenario.getServiceAccess().serviceDataOperation.execute(entryOperation.getValue(), runScenario, + "Step " + step.getInformation(), index)); + } + if (runScenario.getRunParameters().showLevelDebug() && !variablesCompleted.isEmpty()) + logger.info("SetVariable [{}] {}", step.getVariables(), step.getInformation()); - return variablesCompleted; - } + return variablesCompleted; + } } diff --git a/src/main/java/org/camunda/automator/engine/SchedulerExecution.java b/src/main/java/org/camunda/automator/engine/SchedulerExecution.java index 41ed4a5..878a3aa 100644 --- a/src/main/java/org/camunda/automator/engine/SchedulerExecution.java +++ b/src/main/java/org/camunda/automator/engine/SchedulerExecution.java @@ -16,23 +16,23 @@ @ConfigurationProperties(prefix = "automator.scheduler") public class SchedulerExecution { - @Value("${automator.scheduler.scenario-path:''}") - public String scenarioPath; + @Value("${automator.scheduler.scenario-path:''}") + public String scenarioPath; - // https://www.baeldung.com/spring-boot-yaml-list - // @Value("${automator.scheduler.colors}") - @Autowired - BpmnEngineList bpmnEngineConfiguration; - Logger logger = LoggerFactory.getLogger(SchedulerExecution.class); - @Autowired - ServiceAccess serviceAccess; + // https://www.baeldung.com/spring-boot-yaml-list + // @Value("${automator.scheduler.colors}") + @Autowired + BpmnEngineList bpmnEngineConfiguration; + Logger logger = LoggerFactory.getLogger(SchedulerExecution.class); + @Autowired + ServiceAccess serviceAccess; - @PostConstruct - public void init() { - // We run the CLI, do nothing - if (AutomatorCLI.isRunningCLI) - return; - logger.info("SchedulerExecution soon"); - } + @PostConstruct + public void init() { + // We run the CLI, do nothing + if (AutomatorCLI.isRunningCLI) + return; + logger.info("SchedulerExecution soon"); + } } diff --git a/src/main/java/org/camunda/automator/engine/flow/CreateProcessInstanceThread.java b/src/main/java/org/camunda/automator/engine/flow/CreateProcessInstanceThread.java index d71e754..a5b1367 100644 --- a/src/main/java/org/camunda/automator/engine/flow/CreateProcessInstanceThread.java +++ b/src/main/java/org/camunda/automator/engine/flow/CreateProcessInstanceThread.java @@ -18,203 +18,203 @@ import java.util.stream.Collectors; public class CreateProcessInstanceThread { - private final int executionBatchNumber; - private final ScenarioStep scenarioStep; - private final RunScenario runScenario; - private final RunResult runResult; - private final Logger logger = LoggerFactory.getLogger(CreateProcessInstanceThread.class); - private final List<StartProcess> listStartProcess = new ArrayList<>(); - - /** - * @param executionBatchNumber Each time a new batch is running, this number increase - * @param scenarioStep scenario step - * @param runScenario scenario - * @param runResult result to fulfill - */ - public CreateProcessInstanceThread(int executionBatchNumber, - ScenarioStep scenarioStep, - RunScenario runScenario, - RunResult runResult) { - this.executionBatchNumber = executionBatchNumber; - this.scenarioStep = scenarioStep; - this.runScenario = runScenario; - this.runResult = runResult; - } - - /** - * After the duration, we stop - * - * @param durationToCreateProcessInstances maximum duration to produce all PI - */ - public void createProcessInstances(Duration durationToCreateProcessInstances) { - - int nbThreads = scenarioStep.getNbThreads() == 0 ? 1 : scenarioStep.getNbThreads(); - - // the configuration may overload this value - Integer configurationNbThreads = runScenario.getRunParameters().getStartEventNbThreads(); - String additionalComment = ""; - if (configurationNbThreads != null) { - additionalComment = "(nbThreads overrided by the configuration: " + configurationNbThreads + ")"; - nbThreads = configurationNbThreads.intValue(); - } - - ExecutorService executor = Executors.newFixedThreadPool(nbThreads); - int totalNumberOfPi = 0; - - int processInstancePerThread = (int) Math.ceil(1.0 * scenarioStep.getNumberOfExecutions() / nbThreads); - logger.info("StartNbThreads Step:[{}] PI:{} Duration:[{}] Thread:{} {} PI/thread:{}", scenarioStep.getTaskId(), - scenarioStep.getNumberOfExecutions(), durationToCreateProcessInstances, nbThreads, additionalComment, - processInstancePerThread); - // Submit tasks to the executor - for (int i = 0; i < nbThreads; i++) { - int numberOfProcessInstanceToStart = Math.min(processInstancePerThread, - scenarioStep.getNumberOfExecutions() - totalNumberOfPi); - totalNumberOfPi += numberOfProcessInstanceToStart; - StartProcess task = new StartProcess(executionBatchNumber, i, numberOfProcessInstanceToStart, - durationToCreateProcessInstances, scenarioStep, runScenario, runResult); - executor.submit(task); - listStartProcess.add(task); - } - // Shut down the executor and wait for all tasks to complete - executor.shutdown(); - try { - executor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS); - } catch (InterruptedException e) { - logger.error("Error during waiting for the end of all tasks"); - } - } - - public List<String> getListProcessInstances() { - return listStartProcess.stream().flatMap(t -> t.listProcessInstances.stream()).collect(Collectors.toList()); - } - - public int getNumberOfRunningThreads() { - return (int) listStartProcess.stream().filter(t -> t.isRunning()).count(); - } - - public int getTotalCreation() { - return listStartProcess.stream().mapToInt(t -> t.nbCreation).sum(); - } - - public int getTotalFailed() { - return listStartProcess.stream().mapToInt(t -> t.nbFailed).sum(); - } - - /** - * return true if the creation overload the durationToCreate: we can't create all PI in the duration - * - * @return true if it wasn't possible to create all PI during the duration - */ - public boolean isOverload() { - return listStartProcess.stream().anyMatch(t -> t.isOverload); - } - - /** - * This subclass start numberOfProcessInstanceToStart of process instances. - * Multiple threads doing the same operation are running at the same time. - */ - private class StartProcess implements Runnable { + private final int executionBatchNumber; private final ScenarioStep scenarioStep; - private final RunResult runResult; private final RunScenario runScenario; - private final int executionBatchNumber; - private final int indexInBatch; - int numberOfProcessInstanceToStart; - List<String> listProcessInstances = new ArrayList<>(); - int nbCreation = 0; - int nbFailed = 0; + private final RunResult runResult; + private final Logger logger = LoggerFactory.getLogger(CreateProcessInstanceThread.class); + private final List<StartProcess> listStartProcess = new ArrayList<>(); + + /** + * @param executionBatchNumber Each time a new batch is running, this number increase + * @param scenarioStep scenario step + * @param runScenario scenario + * @param runResult result to fulfill + */ + public CreateProcessInstanceThread(int executionBatchNumber, + ScenarioStep scenarioStep, + RunScenario runScenario, + RunResult runResult) { + this.executionBatchNumber = executionBatchNumber; + this.scenarioStep = scenarioStep; + this.runScenario = runScenario; + this.runResult = runResult; + } + /** - * the batch number + * After the duration, we stop + * + * @param durationToCreateProcessInstances maximum duration to produce all PI */ - boolean isOverload = false; + public void createProcessInstances(Duration durationToCreateProcessInstances) { + + int nbThreads = scenarioStep.getNbThreads() == 0 ? 1 : scenarioStep.getNbThreads(); + + // the configuration may overload this value + Integer configurationNbThreads = runScenario.getRunParameters().getStartEventNbThreads(); + String additionalComment = ""; + if (configurationNbThreads != null) { + additionalComment = "(nbThreads overrided by the configuration: " + configurationNbThreads + ")"; + nbThreads = configurationNbThreads.intValue(); + } - boolean isRunning = false; + ExecutorService executor = Executors.newFixedThreadPool(nbThreads); + int totalNumberOfPi = 0; + + int processInstancePerThread = (int) Math.ceil(1.0 * scenarioStep.getNumberOfExecutions() / nbThreads); + logger.info("StartNbThreads Step:[{}] PI:{} Duration:[{}] Thread:{} {} PI/thread:{}", scenarioStep.getTaskId(), + scenarioStep.getNumberOfExecutions(), durationToCreateProcessInstances, nbThreads, additionalComment, + processInstancePerThread); + // Submit tasks to the executor + for (int i = 0; i < nbThreads; i++) { + int numberOfProcessInstanceToStart = Math.min(processInstancePerThread, + scenarioStep.getNumberOfExecutions() - totalNumberOfPi); + totalNumberOfPi += numberOfProcessInstanceToStart; + StartProcess task = new StartProcess(executionBatchNumber, i, numberOfProcessInstanceToStart, + durationToCreateProcessInstances, scenarioStep, runScenario, runResult); + executor.submit(task); + listStartProcess.add(task); + } + // Shut down the executor and wait for all tasks to complete + executor.shutdown(); + try { + executor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS); + } catch (InterruptedException e) { + logger.error("Error during waiting for the end of all tasks"); + } + } + + public List<String> getListProcessInstances() { + return listStartProcess.stream().flatMap(t -> t.listProcessInstances.stream()).collect(Collectors.toList()); + } + + public int getNumberOfRunningThreads() { + return (int) listStartProcess.stream().filter(t -> t.isRunning()).count(); + } - Duration durationToCreateProcessInstances; + public int getTotalCreation() { + return listStartProcess.stream().mapToInt(t -> t.nbCreation).sum(); + } + + public int getTotalFailed() { + return listStartProcess.stream().mapToInt(t -> t.nbFailed).sum(); + } /** - * @param executionBatchNumber batch number executed - * @param indexInBatch the component number, when multiple component where generated to handle the flow - * @param numberOfProcessInstanceToStart number of process instance to start by this object - * @param durationToCreateProcessInstances duration max allowed to create process instance - * @param scenarioStep step to use to create the process instance - * @param runScenario scenario to use - * @param runResult result object to save information + * return true if the creation overload the durationToCreate: we can't create all PI in the duration + * + * @return true if it wasn't possible to create all PI during the duration */ - public StartProcess(int executionBatchNumber, - int indexInBatch, - int numberOfProcessInstanceToStart, - Duration durationToCreateProcessInstances, - ScenarioStep scenarioStep, - RunScenario runScenario, - RunResult runResult) { - this.executionBatchNumber = executionBatchNumber; - this.indexInBatch = indexInBatch; - this.durationToCreateProcessInstances = durationToCreateProcessInstances; - this.numberOfProcessInstanceToStart = numberOfProcessInstanceToStart; - this.runResult = runResult; - this.runScenario = runScenario; - this.scenarioStep = scenarioStep; + public boolean isOverload() { + return listStartProcess.stream().anyMatch(t -> t.isOverload); } /** - * This thread will create numberOfProcessInstanceToStart, but it monitor the time, and if the time is over - * the Duration, it stop + * This subclass start numberOfProcessInstanceToStart of process instances. + * Multiple threads doing the same operation are running at the same time. */ - @Override - public void run() { - isRunning = true; - boolean alreadyLoggedError = false; - isOverload = false; - long begin = System.currentTimeMillis(); - for (int i = 0; i < numberOfProcessInstanceToStart; i++) { - - // operation - try { - Map<String, Object> variables = RunZeebeOperation.getVariablesStep(runScenario, scenarioStep, indexInBatch); - String processInstance = runScenario.getBpmnEngine() - .createProcessInstance(scenarioStep.getProcessId(), scenarioStep.getTaskId(), // activityId - variables); - - if (runScenario.getRunParameters().showLevelDebug()) - logger.info("batch_#{} Create ProcessInstance:{} Variables {}", executionBatchNumber, processInstance, - variables); - - if (listProcessInstances.size() < 21) - listProcessInstances.add(processInstance); - nbCreation++; - runResult.registerAddProcessInstance(scenarioStep.getProcessId(), true); - - } catch (AutomatorException e) { - if (!alreadyLoggedError) - runResult.addError(scenarioStep, - "batch_#" + executionBatchNumber + "-" + scenarioStep.getId() + " Error at creation: [" + e.getMessage() - + "]"); - alreadyLoggedError = true; - nbFailed++; - runResult.registerAddProcessInstance(scenarioStep.getProcessId(), false); + private class StartProcess implements Runnable { + private final ScenarioStep scenarioStep; + private final RunResult runResult; + private final RunScenario runScenario; + private final int executionBatchNumber; + private final int indexInBatch; + int numberOfProcessInstanceToStart; + List<String> listProcessInstances = new ArrayList<>(); + int nbCreation = 0; + int nbFailed = 0; + /** + * the batch number + */ + boolean isOverload = false; + + boolean isRunning = false; + + Duration durationToCreateProcessInstances; + + /** + * @param executionBatchNumber batch number executed + * @param indexInBatch the component number, when multiple component where generated to handle the flow + * @param numberOfProcessInstanceToStart number of process instance to start by this object + * @param durationToCreateProcessInstances duration max allowed to create process instance + * @param scenarioStep step to use to create the process instance + * @param runScenario scenario to use + * @param runResult result object to save information + */ + public StartProcess(int executionBatchNumber, + int indexInBatch, + int numberOfProcessInstanceToStart, + Duration durationToCreateProcessInstances, + ScenarioStep scenarioStep, + RunScenario runScenario, + RunResult runResult) { + this.executionBatchNumber = executionBatchNumber; + this.indexInBatch = indexInBatch; + this.durationToCreateProcessInstances = durationToCreateProcessInstances; + this.numberOfProcessInstanceToStart = numberOfProcessInstanceToStart; + this.runResult = runResult; + this.runScenario = runScenario; + this.scenarioStep = scenarioStep; } - // do we have to stop the execution? - long currentTimeMillis = System.currentTimeMillis(); - Duration durationCurrent = durationToCreateProcessInstances.minusMillis(currentTimeMillis - begin); - if (durationCurrent.isNegative()) { - // log only at the debug mode (thread per thread), in monitoring log only at batch level - if (runScenario.getRunParameters().showLevelDebug()) { - // take too long to create the required process instance, so stop now. - logger.info("batch_#{} {} Over the duration. Created {} when expected {} in {} ms", executionBatchNumber, - scenarioStep.getId(), nbCreation, numberOfProcessInstanceToStart, currentTimeMillis - begin); - } - isOverload = true; - break; - } - } - isRunning = false; - } + /** + * This thread will create numberOfProcessInstanceToStart, but it monitor the time, and if the time is over + * the Duration, it stop + */ + @Override + public void run() { + isRunning = true; + boolean alreadyLoggedError = false; + isOverload = false; + long begin = System.currentTimeMillis(); + for (int i = 0; i < numberOfProcessInstanceToStart; i++) { + + // operation + try { + Map<String, Object> variables = RunZeebeOperation.getVariablesStep(runScenario, scenarioStep, indexInBatch); + String processInstance = runScenario.getBpmnEngine() + .createProcessInstance(scenarioStep.getProcessId(), scenarioStep.getTaskId(), // activityId + variables); + + if (runScenario.getRunParameters().showLevelDebug()) + logger.info("batch_#{} Create ProcessInstance:{} Variables {}", executionBatchNumber, processInstance, + variables); + + if (listProcessInstances.size() < 21) + listProcessInstances.add(processInstance); + nbCreation++; + runResult.registerAddProcessInstance(scenarioStep.getProcessId(), true); + + } catch (AutomatorException e) { + if (!alreadyLoggedError) + runResult.addError(scenarioStep, + "batch_#" + executionBatchNumber + "-" + scenarioStep.getId() + " Error at creation: [" + e.getMessage() + + "]"); + alreadyLoggedError = true; + nbFailed++; + runResult.registerAddProcessInstance(scenarioStep.getProcessId(), false); + } + // do we have to stop the execution? + long currentTimeMillis = System.currentTimeMillis(); + Duration durationCurrent = durationToCreateProcessInstances.minusMillis(currentTimeMillis - begin); + if (durationCurrent.isNegative()) { + // log only at the debug mode (thread per thread), in monitoring log only at batch level + if (runScenario.getRunParameters().showLevelDebug()) { + // take too long to create the required process instance, so stop now. + logger.info("batch_#{} {} Over the duration. Created {} when expected {} in {} ms", executionBatchNumber, + scenarioStep.getId(), nbCreation, numberOfProcessInstanceToStart, currentTimeMillis - begin); + } + isOverload = true; + break; + } + } + + isRunning = false; + } - public boolean isRunning() { - return isRunning; + public boolean isRunning() { + return isRunning; + } } - } } diff --git a/src/main/java/org/camunda/automator/engine/flow/FixedBackoffSupplier.java b/src/main/java/org/camunda/automator/engine/flow/FixedBackoffSupplier.java index 4456ebb..866b177 100644 --- a/src/main/java/org/camunda/automator/engine/flow/FixedBackoffSupplier.java +++ b/src/main/java/org/camunda/automator/engine/flow/FixedBackoffSupplier.java @@ -10,14 +10,14 @@ public class FixedBackoffSupplier implements BackoffSupplier { - private long fixedBackOffDelay = 0; + private long fixedBackOffDelay = 0; - public FixedBackoffSupplier(long fixedBackOffDelay) { - this.fixedBackOffDelay = fixedBackOffDelay; - } + public FixedBackoffSupplier(long fixedBackOffDelay) { + this.fixedBackOffDelay = fixedBackOffDelay; + } - @Override - public long supplyRetryDelay(long currentRetryDelay) { - return fixedBackOffDelay; - } + @Override + public long supplyRetryDelay(long currentRetryDelay) { + return fixedBackOffDelay; + } } \ No newline at end of file diff --git a/src/main/java/org/camunda/automator/engine/flow/RunObjectives.java b/src/main/java/org/camunda/automator/engine/flow/RunObjectives.java index fb853a6..6dbf3a3 100644 --- a/src/main/java/org/camunda/automator/engine/flow/RunObjectives.java +++ b/src/main/java/org/camunda/automator/engine/flow/RunObjectives.java @@ -14,295 +14,291 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.ArrayList; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; public class RunObjectives { - private final BpmnEngine bpmnEngine; - private final Map<String, RunResult.RecordCreationPI> recordCreationPIMap; - private final Map<Integer, List<SavePhoto>> flowRateMnObjective = new HashMap<>(); - private final List<ScenarioFlowControl.Objective> listObjectives; - Logger logger = LoggerFactory.getLogger(RunObjectives.class); - private DateFilter startDateFilter; - private DateFilter endDateFilter; - private long lastHeartBeat; + private final BpmnEngine bpmnEngine; + private final Map<String, RunResult.RecordCreationPI> recordCreationPIMap; + private final Map<Integer, List<SavePhoto>> flowRateMnObjective = new HashMap<>(); + private final List<ScenarioFlowControl.Objective> listObjectives; + Logger logger = LoggerFactory.getLogger(RunObjectives.class); + private DateFilter startDateFilter; + private DateFilter endDateFilter; + private long lastHeartBeat; - public RunObjectives(List<ScenarioFlowControl.Objective> listObjectives, - BpmnEngine bpmnEngine, - Map<String, RunResult.RecordCreationPI> recordCreationPIMap) { - this.listObjectives = listObjectives; - this.bpmnEngine = bpmnEngine; - this.recordCreationPIMap = recordCreationPIMap; + public RunObjectives(List<ScenarioFlowControl.Objective> listObjectives, + BpmnEngine bpmnEngine, + Map<String, RunResult.RecordCreationPI> recordCreationPIMap) { + this.listObjectives = listObjectives; + this.bpmnEngine = bpmnEngine; + this.recordCreationPIMap = recordCreationPIMap; - for (int i = 0; i < listObjectives.size(); i++) { - listObjectives.get(i).index = i; + for (int i = 0; i < listObjectives.size(); i++) { + listObjectives.get(i).index = i; + } } - } - public void setStartDate(Date startTestDate) { - this.startDateFilter = new DateFilter(startTestDate); - this.lastHeartBeat = System.currentTimeMillis(); - } + public void setStartDate(Date startTestDate) { + this.startDateFilter = new DateFilter(startTestDate); + this.lastHeartBeat = System.currentTimeMillis(); + } - public void setEndDate(Date endTestDate) { - this.endDateFilter = new DateFilter(endTestDate); - } + public void setEndDate(Date endTestDate) { + this.endDateFilter = new DateFilter(endTestDate); + } - /** - * heartbeat - */ - public void heartBeat() { - long currentTime = System.currentTimeMillis(); - // only one minutes - if (currentTime - lastHeartBeat < 1000 * 60) - return; + /** + * heartbeat + */ + public void heartBeat() { + long currentTime = System.currentTimeMillis(); + // only one minutes + if (currentTime - lastHeartBeat < 1000 * 60) + return; - // one minutes: do we have a FLOWRATEUSERTASKMN objective - for (ScenarioFlowControl.Objective objective : listObjectives) { - if (ScenarioFlowControl.Objective.TYPEOBJECTIVE.FLOWRATEUSERTASKMN.equals(objective.type)) { - // get the value - SavePhoto currentPhoto = new SavePhoto(); - try { - currentPhoto.nbOfTasks = bpmnEngine.countNumberOfTasks(objective.processId, objective.taskId); - } catch (AutomatorException e) { - logger.error("Can't get NumberOfTask "); + // one minutes: do we have a FLOWRATEUSERTASKMN objective + for (ScenarioFlowControl.Objective objective : listObjectives) { + if (ScenarioFlowControl.Objective.TYPEOBJECTIVE.FLOWRATEUSERTASKMN.equals(objective.type)) { + // get the value + SavePhoto currentPhoto = new SavePhoto(); + try { + currentPhoto.nbOfTasks = bpmnEngine.countNumberOfTasks(objective.processId, objective.taskId); + } catch (AutomatorException e) { + logger.error("Can't get NumberOfTask "); + } + List<SavePhoto> listValues = flowRateMnObjective.getOrDefault(objective.index, new ArrayList<>()); + SavePhoto previousPhoto = listValues.isEmpty() ? new SavePhoto() : listValues.get(listValues.size() - 1); + currentPhoto.delta = currentPhoto.nbOfTasks - previousPhoto.nbOfTasks; + listValues.add(currentPhoto); + flowRateMnObjective.put(objective.index, listValues); + logger.info("heartBeat: FlowRateUserTaskMn [{}] prev [{}} current [{}] delta [{}] expected [{}] in {} s", + objective.getInformation(), previousPhoto.nbOfTasks, currentPhoto.nbOfTasks, currentPhoto.delta, + objective.value, (currentTime - lastHeartBeat) / 1000); + } } - List<SavePhoto> listValues = flowRateMnObjective.getOrDefault(objective.index, new ArrayList<>()); - SavePhoto previousPhoto = listValues.isEmpty() ? new SavePhoto() : listValues.get(listValues.size() - 1); - currentPhoto.delta = currentPhoto.nbOfTasks - previousPhoto.nbOfTasks; - listValues.add(currentPhoto); - flowRateMnObjective.put(objective.index, listValues); - logger.info("heartBeat: FlowRateUserTaskMn [{}] prev [{}} current [{}] delta [{}] expected [{}] in {} s", - objective.getInformation(), previousPhoto.nbOfTasks, currentPhoto.nbOfTasks, currentPhoto.delta, - objective.value, (currentTime - lastHeartBeat) / 1000); - } + lastHeartBeat = currentTime; } - lastHeartBeat = currentTime; - } - /** - * Check the objective, and return an analysis string; If the string is empty, the objectif is reach - * - * @return empty if the objective is Ok, else an analysis - */ - public List<ObjectiveResult> check() { - List<ObjectiveResult> listCheck = new ArrayList<>(); - for (ScenarioFlowControl.Objective objective : listObjectives) { - if (objective.type == null) { - logger.error("Objective {} does not have a type", objective.getInformation()); - ObjectiveResult objectiveResult = new ObjectiveResult(objective); - objectiveResult.success = false; - objectiveResult.analysis = "Error: Objective " + objective.getInformation() + " does not have a type"; - listCheck.add(objectiveResult); - continue; - } - listCheck.add(switch (objective.type) { - case CREATED -> checkObjectiveCreated(objective); - case ENDED -> checkObjectiveEnded(objective); - case USERTASK -> checkObjectiveUserTask(objective); - case FLOWRATEUSERTASKMN -> checkObjectiveFlowRate(objective); - }); + /** + * Check the objective, and return an analysis string; If the string is empty, the objectif is reach + * + * @return empty if the objective is Ok, else an analysis + */ + public List<ObjectiveResult> check() { + List<ObjectiveResult> listCheck = new ArrayList<>(); + for (ScenarioFlowControl.Objective objective : listObjectives) { + if (objective.type == null) { + logger.error("Objective {} does not have a type", objective.getInformation()); + ObjectiveResult objectiveResult = new ObjectiveResult(objective); + objectiveResult.success = false; + objectiveResult.analysis = "Error: Objective " + objective.getInformation() + " does not have a type"; + listCheck.add(objectiveResult); + continue; + } + listCheck.add(switch (objective.type) { + case CREATED -> checkObjectiveCreated(objective); + case ENDED -> checkObjectiveEnded(objective); + case USERTASK -> checkObjectiveUserTask(objective); + case FLOWRATEUSERTASKMN -> checkObjectiveFlowRate(objective); + }); + } + return listCheck; } - return listCheck; - } - /** - * Creation: does the number of process instance was created? - * - * @param objective objective to reach - * @return result - */ - private ObjectiveResult checkObjectiveCreated(ScenarioFlowControl.Objective objective) { - ObjectiveResult objectiveResult = new ObjectiveResult(objective); - objectiveResult.objectiveValue = objective.value; - if (objective.value <= 0) { - objectiveResult.success = true; - objectiveResult.analysis += "No value to reach"; - return objectiveResult; - } - try { - long processInstancesCreatedAPI = bpmnEngine.countNumberOfProcessInstancesCreated(objective.processId, - startDateFilter, endDateFilter); - RunResult.RecordCreationPI recordCreation = recordCreationPIMap.getOrDefault(objective.processId, - new RunResult.RecordCreationPI(objective.processId)); + /** + * Creation: does the number of process instance was created? + * + * @param objective objective to reach + * @return result + */ + private ObjectiveResult checkObjectiveCreated(ScenarioFlowControl.Objective objective) { + ObjectiveResult objectiveResult = new ObjectiveResult(objective); + objectiveResult.objectiveValue = objective.value; + if (objective.value <= 0) { + objectiveResult.success = true; + objectiveResult.analysis += "No value to reach"; + return objectiveResult; + } + try { + long processInstancesCreatedAPI = bpmnEngine.countNumberOfProcessInstancesCreated(objective.processId, + startDateFilter, endDateFilter); + RunResult.RecordCreationPI recordCreation = recordCreationPIMap.getOrDefault(objective.processId, + new RunResult.RecordCreationPI(objective.processId)); - objectiveResult.recordedSuccessValue = recordCreation.nbCreated; - objectiveResult.recordedFailValue = recordCreation.nbFailed; + objectiveResult.recordedSuccessValue = recordCreation.nbCreated; + objectiveResult.recordedFailValue = recordCreation.nbFailed; - int percent = (int) (100.0 * objectiveResult.recordedSuccessValue / (objective.value == 0 ? 1 : objective.value)); + int percent = (int) (100.0 * objectiveResult.recordedSuccessValue / (objective.value == 0 ? 1 : objective.value)); - objectiveResult.analysis += "Objective " + objective.getInformation() // informatin - + ": Goal[" + objective.value // objective - + "] Created(zeebeAPI)[" + processInstancesCreatedAPI // Value by the API, not really accurate - + "] Created(AutomatorRecord)[" + objectiveResult.recordedSuccessValue // value recorded by automator - + " (" + percent + " % )" // percent based on the recorded value - + " CreateFail(AutomatorRecord)[" + objectiveResult.recordedFailValue + "]"; + objectiveResult.analysis += "Objective " + objective.getInformation() // informatin + + ": Goal[" + objective.value // objective + + "] Created(zeebeAPI)[" + processInstancesCreatedAPI // Value by the API, not really accurate + + "] Created(AutomatorRecord)[" + objectiveResult.recordedSuccessValue // value recorded by automator + + " (" + percent + " % )" // percent based on the recorded value + + " CreateFail(AutomatorRecord)[" + objectiveResult.recordedFailValue + "]"; - if (objectiveResult.recordedSuccessValue < objective.value) { - objectiveResult.success = false; - } - } catch (AutomatorException e) { - objectiveResult.success = false; - objectiveResult.analysis += "Can't search countNumberOfProcessInstancesCreated " + e.getMessage(); + if (objectiveResult.recordedSuccessValue < objective.value) { + objectiveResult.success = false; + } + } catch (AutomatorException e) { + objectiveResult.success = false; + objectiveResult.analysis += "Can't search countNumberOfProcessInstancesCreated " + e.getMessage(); + } + return objectiveResult; } - return objectiveResult; - } - /** - * ObjectiveEnded : does process ended? - * - * @param objective objective to reach - * @return result - */ - private ObjectiveResult checkObjectiveEnded(ScenarioFlowControl.Objective objective) { - ObjectiveResult objectiveResult = new ObjectiveResult(objective); - objectiveResult.objectiveValue = objective.value; - if (objective.value <= 0) { - objectiveResult.success = true; - objectiveResult.analysis += "No value to reach"; - return objectiveResult; - } - try { - objectiveResult.recordedSuccessValue = bpmnEngine.countNumberOfProcessInstancesEnded(objective.processId, - startDateFilter, endDateFilter); - if (objectiveResult.recordedSuccessValue < objective.value) { - objectiveResult.analysis += - "Fail: " + objective.getInformation() + " : " + objective.value + " ended expected, " - + objectiveResult.recordedSuccessValue + " created (" + (int) ( - 100.0 * objectiveResult.recordedSuccessValue / objective.value) + " %), "; - objectiveResult.success = false; - } + /** + * ObjectiveEnded : does process ended? + * + * @param objective objective to reach + * @return result + */ + private ObjectiveResult checkObjectiveEnded(ScenarioFlowControl.Objective objective) { + ObjectiveResult objectiveResult = new ObjectiveResult(objective); + objectiveResult.objectiveValue = objective.value; + if (objective.value <= 0) { + objectiveResult.success = true; + objectiveResult.analysis += "No value to reach"; + return objectiveResult; + } + try { + objectiveResult.recordedSuccessValue = bpmnEngine.countNumberOfProcessInstancesEnded(objective.processId, + startDateFilter, endDateFilter); + if (objectiveResult.recordedSuccessValue < objective.value) { + objectiveResult.analysis += + "Fail: " + objective.getInformation() + " : " + objective.value + " ended expected, " + + objectiveResult.recordedSuccessValue + " created (" + (int) ( + 100.0 * objectiveResult.recordedSuccessValue / objective.value) + " %), "; + objectiveResult.success = false; + } - } catch (AutomatorException e) { - objectiveResult.success = false; - objectiveResult.analysis += "Can't search NumberOfProcessInstanceEnded: " + e.getMessage(); + } catch (AutomatorException e) { + objectiveResult.success = false; + objectiveResult.analysis += "Can't search NumberOfProcessInstanceEnded: " + e.getMessage(); + } + return objectiveResult; } - return objectiveResult; - } - /** - * UserTask: does user tasks are present? - * - * @param objective objective to reach - * @return result - */ - private ObjectiveResult checkObjectiveUserTask(ScenarioFlowControl.Objective objective) { - ObjectiveResult objectiveResult = new ObjectiveResult(objective); - objectiveResult.objectiveValue = objective.value; - if (objective.value <= 0) { - objectiveResult.success = true; - objectiveResult.analysis += "No value to reach"; - return objectiveResult; - } - try { - objectiveResult.recordedSuccessValue = bpmnEngine.countNumberOfTasks(objective.processId, objective.taskId); - if (objectiveResult.recordedSuccessValue < objective.value) { - objectiveResult.analysis += - "Fail: " + objective.getInformation() + " : [" + objective.value + "] tasks expected, "; - objectiveResult.analysis += - objectiveResult.recordedSuccessValue + " found (" + (int) (100.0 * objectiveResult.recordedSuccessValue - / objective.value) + " %), "; - objectiveResult.success = false; - } - } catch (AutomatorException e) { - objectiveResult.success = false; - objectiveResult.analysis += "Can't search NumberOfProcessInstanceEnded: " + e.getMessage(); + /** + * UserTask: does user tasks are present? + * + * @param objective objective to reach + * @return result + */ + private ObjectiveResult checkObjectiveUserTask(ScenarioFlowControl.Objective objective) { + ObjectiveResult objectiveResult = new ObjectiveResult(objective); + objectiveResult.objectiveValue = objective.value; + if (objective.value <= 0) { + objectiveResult.success = true; + objectiveResult.analysis += "No value to reach"; + return objectiveResult; + } + try { + objectiveResult.recordedSuccessValue = bpmnEngine.countNumberOfTasks(objective.processId, objective.taskId); + if (objectiveResult.recordedSuccessValue < objective.value) { + objectiveResult.analysis += + "Fail: " + objective.getInformation() + " : [" + objective.value + "] tasks expected, "; + objectiveResult.analysis += + objectiveResult.recordedSuccessValue + " found (" + (int) (100.0 * objectiveResult.recordedSuccessValue + / objective.value) + " %), "; + objectiveResult.success = false; + } + } catch (AutomatorException e) { + objectiveResult.success = false; + objectiveResult.analysis += "Can't search NumberOfProcessInstanceEnded: " + e.getMessage(); + } + return objectiveResult; } - return objectiveResult; - } - /** - * FlowRate - * - * @param objective objective to reach - * @return result - */ - private ObjectiveResult checkObjectiveFlowRate(ScenarioFlowControl.Objective objective) { - ObjectiveResult objectiveResult = new ObjectiveResult(objective); - // check all values - try { - long lowThreshold = (long) (((double) objective.value) * (1.0 - - ((double) objective.getStandardDeviation()) / 100.0)); - objectiveResult.objectiveValue = objective.value; - objectiveResult.analysis += - "Threshold[" + objective.value + "] standardDeviation[" + objective.getStandardDeviation() + "] LowThreshold[" - + lowThreshold + "]"; - long sumValues = 0; - List<SavePhoto> listValues = flowRateMnObjective.getOrDefault(objective.index, new ArrayList<>()); - if (listValues.isEmpty()) { - objectiveResult.analysis += "No values"; - objectiveResult.success = false; - return objectiveResult; - } + /** + * FlowRate + * + * @param objective objective to reach + * @return result + */ + private ObjectiveResult checkObjectiveFlowRate(ScenarioFlowControl.Objective objective) { + ObjectiveResult objectiveResult = new ObjectiveResult(objective); + // check all values + try { + long lowThreshold = (long) (((double) objective.value) * (1.0 + - ((double) objective.getStandardDeviation()) / 100.0)); + objectiveResult.objectiveValue = objective.value; + objectiveResult.analysis += + "Threshold[" + objective.value + "] standardDeviation[" + objective.getStandardDeviation() + "] LowThreshold[" + + lowThreshold + "]"; + long sumValues = 0; + List<SavePhoto> listValues = flowRateMnObjective.getOrDefault(objective.index, new ArrayList<>()); + if (listValues.isEmpty()) { + objectiveResult.analysis += "No values"; + objectiveResult.success = false; + return objectiveResult; + } - StringBuilder valuesString = new StringBuilder(); - int numberUnderThreshold = 0; - int count = 0; - for (SavePhoto photo : listValues) { - sumValues += photo.delta; - count++; - if (count == 50) { - valuesString.append("... TooManyValues["); - valuesString.append(listValues.size()); - valuesString.append("]"); - } - if (count < 50) { - valuesString.append(photo.delta); - valuesString.append(","); - } + StringBuilder valuesString = new StringBuilder(); + int numberUnderThreshold = 0; + int count = 0; + for (SavePhoto photo : listValues) { + sumValues += photo.delta; + count++; + if (count == 50) { + valuesString.append("... TooManyValues["); + valuesString.append(listValues.size()); + valuesString.append("]"); + } + if (count < 50) { + valuesString.append(photo.delta); + valuesString.append(","); + } - if (photo.delta < lowThreshold) { - numberUnderThreshold++; + if (photo.delta < lowThreshold) { + numberUnderThreshold++; + } + } + if (numberUnderThreshold > 0) { + objectiveResult.analysis += + "NumberOrValueUnderThreshold[" + numberUnderThreshold + "], values: " + valuesString; + objectiveResult.success = false; + } + // the total must be at the value + long averageValue = (long) (((double) sumValues) / listValues.size()); + objectiveResult.recordedSuccessValue = averageValue; + if (averageValue < objective.value) { + objectiveResult.analysis += "AverageUnderObjective[" + averageValue + "]"; + objectiveResult.success = false; + } else { + objectiveResult.analysis += "AverageReach[" + averageValue + "]"; + } + } catch (Exception e) { + logger.error("Error during checkFlowRateObjective {}", e.getMessage()); + objectiveResult.success = false; } - } - if (numberUnderThreshold > 0) { - objectiveResult.analysis += - "NumberOrValueUnderThreshold[" + numberUnderThreshold + "], values: " + valuesString; - objectiveResult.success = false; - } - // the total must be at the value - long averageValue = (long) (((double) sumValues) / listValues.size()); - objectiveResult.recordedSuccessValue = averageValue; - if (averageValue < objective.value) { - objectiveResult.analysis += "AverageUnderObjective[" + averageValue + "]"; - objectiveResult.success = false; - } else { - objectiveResult.analysis += "AverageReach[" + averageValue + "]"; - } - } catch (Exception e) { - logger.error("Error during checkFlowRateObjective {}", e.getMessage()); - objectiveResult.success = false; - } - return objectiveResult; + return objectiveResult; - } + } - public static class ObjectiveResult { - public String analysis = ""; - public boolean success = true; - public long objectiveValue; - public long recordedSuccessValue; - public long recordedFailValue; - ScenarioFlowControl.Objective objective; + public static class ObjectiveResult { + public String analysis = ""; + public boolean success = true; + public long objectiveValue; + public long recordedSuccessValue; + public long recordedFailValue; + ScenarioFlowControl.Objective objective; - public ObjectiveResult(ScenarioFlowControl.Objective objective) { - this.objective = objective; + public ObjectiveResult(ScenarioFlowControl.Objective objective) { + this.objective = objective; + } } - } - /** - * Key is the Objective Index - * Value is a list of two information: - * - the reference value in the slot - * - the - */ - public static class SavePhoto { - public long nbOfTasks = 0; - public long delta = 0; + /** + * Key is the Objective Index + * Value is a list of two information: + * - the reference value in the slot + * - the + */ + public static class SavePhoto { + public long nbOfTasks = 0; + public long delta = 0; - } + } } diff --git a/src/main/java/org/camunda/automator/engine/flow/RunScenarioFlowBasic.java b/src/main/java/org/camunda/automator/engine/flow/RunScenarioFlowBasic.java index 8dca818..73d830a 100644 --- a/src/main/java/org/camunda/automator/engine/flow/RunScenarioFlowBasic.java +++ b/src/main/java/org/camunda/automator/engine/flow/RunScenarioFlowBasic.java @@ -14,68 +14,68 @@ public abstract class RunScenarioFlowBasic { - protected final RunResult runResult; - private final ScenarioStep scenarioStep; - private final RunScenario runScenario; + protected final RunResult runResult; + private final ScenarioStep scenarioStep; + private final RunScenario runScenario; - RunScenarioFlowBasic(ScenarioStep scenarioStep, RunScenario runScenario, RunResult runResult) { - this.scenarioStep = scenarioStep; - this.runScenario = runScenario; - this.runResult = runResult; - } + RunScenarioFlowBasic(ScenarioStep scenarioStep, RunScenario runScenario, RunResult runResult) { + this.scenarioStep = scenarioStep; + this.runScenario = runScenario; + this.runResult = runResult; + } - /** - * Return an uniq ID of the step - * - * @return the ID of the step - */ - public String getId() { - return scenarioStep.getId(); - } + /** + * Return an uniq ID of the step + * + * @return the ID of the step + */ + public String getId() { + return scenarioStep.getId(); + } - /** - * the task return the topic to address: - * - topic for a service task - * - taskId for a user task - */ - public abstract String getTopic(); + /** + * the task return the topic to address: + * - topic for a service task + * - taskId for a user task + */ + public abstract String getTopic(); - public RunScenario getRunScenario() { - return runScenario; - } + public RunScenario getRunScenario() { + return runScenario; + } - /** - * The flow return the runResult given at the execution - * - * @return result - */ - public RunResult getRunResult() { - return runResult; - } + /** + * The flow return the runResult given at the execution + * + * @return result + */ + public RunResult getRunResult() { + return runResult; + } - /** - * The flow execute a step - return it - * - * @return scenarioStep - */ - public ScenarioStep getScenarioStep() { - return scenarioStep; - } + /** + * The flow execute a step - return it + * + * @return scenarioStep + */ + public ScenarioStep getScenarioStep() { + return scenarioStep; + } - /** - * Start the execution. Attention, only errors must be reported in the result - */ - public abstract void execute(); + /** + * Start the execution. Attention, only errors must be reported in the result + */ + public abstract void execute(); - public abstract STATUS getStatus(); + public abstract STATUS getStatus(); - public abstract int getCurrentNumberOfThreads(); + public abstract int getCurrentNumberOfThreads(); - /** - * The flow must stop now - */ - public abstract void pleaseStop(); + /** + * The flow must stop now + */ + public abstract void pleaseStop(); - public enum STATUS {RUNNING, STOPPING, STOPPED} + public enum STATUS {RUNNING, STOPPING, STOPPED} } diff --git a/src/main/java/org/camunda/automator/engine/flow/RunScenarioFlowServiceTask.java b/src/main/java/org/camunda/automator/engine/flow/RunScenarioFlowServiceTask.java index c951b2c..85e5396 100644 --- a/src/main/java/org/camunda/automator/engine/flow/RunScenarioFlowServiceTask.java +++ b/src/main/java/org/camunda/automator/engine/flow/RunScenarioFlowServiceTask.java @@ -33,247 +33,249 @@ import java.util.concurrent.Semaphore; public class RunScenarioFlowServiceTask extends RunScenarioFlowBasic { - private static final TrackActiveWorker trackActiveWorkers = new TrackActiveWorker(); - private static final TrackActiveWorker trackAsynchronousWorkers = new TrackActiveWorker(); - private final TaskScheduler scheduler; - private final Semaphore semaphore; - Logger logger = LoggerFactory.getLogger(RunScenarioFlowServiceTask.class); - private BpmnEngine.RegisteredTask registeredTask; - private boolean stopping; - @Autowired - private BenchmarkCompleteJobExceptionHandlingStrategy exceptionHandlingStrategy; - - public RunScenarioFlowServiceTask(TaskScheduler scheduler, - ScenarioStep scenarioStep, - RunScenario runScenario, - RunResult runResult) { - super(scenarioStep, runScenario, runResult); - this.scheduler = scheduler; - this.semaphore = new Semaphore(Math.max(1, scenarioStep.getNbTokens())); - } - - @Override - public String getTopic() { - return getScenarioStep().getTopic(); - } - - @Override - public void execute() { - registerWorker(); - } - - @Override - public void pleaseStop() { - logger.info("Ask Stopping [" + getId() + "]"); - stopping = true; - if (registeredTask == null || (registeredTask.isNull())) - return; - if (registeredTask.isClosed()) { - return; + private static final TrackActiveWorker trackActiveWorkers = new TrackActiveWorker(); + private static final TrackActiveWorker trackAsynchronousWorkers = new TrackActiveWorker(); + private final TaskScheduler scheduler; + private final Semaphore semaphore; + Logger logger = LoggerFactory.getLogger(RunScenarioFlowServiceTask.class); + private BpmnEngine.RegisteredTask registeredTask; + private boolean stopping; + + private BenchmarkCompleteJobExceptionHandlingStrategy exceptionHandlingStrategy=null; + + public RunScenarioFlowServiceTask(TaskScheduler scheduler, + ScenarioStep scenarioStep, + RunScenario runScenario, + RunResult runResult) { + super(scenarioStep, runScenario, runResult); + this.scheduler = scheduler; + this.semaphore = new Semaphore(Math.max(1, scenarioStep.getNbTokens())); } - registeredTask.close(); - - Duration durationSleep = getScenarioStep().getWaitingTimeDuration(Duration.ZERO); - long expectedEndTime = System.currentTimeMillis() + durationSleep.toMillis(); - while (!registeredTask.isClosed() && System.currentTimeMillis() < expectedEndTime) { - registeredTask.close(); - try { - Thread.sleep(500); - } catch (Exception e) { - // do nothing - } - } - logger.info("[" + getId() + "] " + (registeredTask.isClosed() ? "stopped" : "Fail to stop")); - - registeredTask = null; - } - - @Override - public STATUS getStatus() { - if (registeredTask == null) - return STATUS.STOPPED; - if (stopping) - return STATUS.STOPPING; - return STATUS.RUNNING; - } - - @Override - public int getCurrentNumberOfThreads() { - return trackActiveWorkers.getCounter() + trackAsynchronousWorkers.getCounter(); - } - - /** - * Register the worker - */ - - private void registerWorker() { - BpmnEngine bpmnEngine = getRunScenario().getBpmnEngine(); - - Duration durationSleep = getScenarioStep().getWaitingTimeDuration(Duration.ZERO); - durationSleep = durationSleep.plusSeconds(10); - - if (getRunScenario().getRunParameters().showLevelMonitoring()) { - logger.info("Start service TaskId[{}] Topic[{}] StreamEnabled:{} DurationSleep[{} ms]", - getScenarioStep().getTaskId(), getScenarioStep().getTopic(), getScenarioStep().isStreamEnabled(), - durationSleep.toMillis()); - } - - registeredTask = bpmnEngine.registerServiceTask(getId(), // workerId - getScenarioStep().getTopic(), // topic - getScenarioStep().isStreamEnabled(), // stream - durationSleep, // lock time - new SimpleDelayHandler(this), new FixedBackoffSupplier(getScenarioStep().getFixedBackOffDelay())); - } - private static class TrackActiveWorker { - public int counter = 0; - - public synchronized void movement(int movement) { - counter += movement; + @Override + public String getTopic() { + return getScenarioStep().getTopic(); } - public int getCounter() { - return counter; - } - } - - /** - * C7, C8 Handler - */ - public class SimpleDelayHandler implements ExternalTaskHandler, JobHandler { - private final RunScenarioFlowServiceTask flowServiceTask; - private final Duration durationSleep; - - public SimpleDelayHandler(RunScenarioFlowServiceTask flowServiceTask) { - this.flowServiceTask = flowServiceTask; - durationSleep = flowServiceTask.getScenarioStep().getWaitingTimeDuration(Duration.ZERO); + @Override + public void execute() { + registerWorker(); } - /* C7 Management */ @Override - public void execute(org.camunda.bpm.client.task.ExternalTask externalTask, - ExternalTaskService externalTaskService) { - switch (getScenarioStep().getModeExecution()) { - case CLASSICAL, WAIT -> - manageWaitExecution(externalTask, externalTaskService, null, null, durationSleep.toMillis()); - case THREAD, ASYNCHRONOUS -> manageAsynchronousExecution(externalTask, externalTaskService, null, null); - case THREADTOKEN, ASYNCHRONOUSLIMITED -> - manageAsynchronousLimitedExecution(externalTask, externalTaskService, null, null); - } + public void pleaseStop() { + logger.info("Ask Stopping [" + getId() + "]"); + stopping = true; + if (registeredTask == null || (registeredTask.isNull())) + return; + if (registeredTask.isClosed()) { + return; + } + registeredTask.close(); + + Duration durationSleep = getScenarioStep().getWaitingTimeDuration(Duration.ZERO); + long expectedEndTime = System.currentTimeMillis() + durationSleep.toMillis(); + while (!registeredTask.isClosed() && System.currentTimeMillis() < expectedEndTime) { + registeredTask.close(); + try { + Thread.sleep(500); + } catch (Exception e) { + // do nothing + } + } + logger.info("[" + getId() + "] " + (registeredTask.isClosed() ? "stopped" : "Fail to stop")); + + registeredTask = null; } - /* C8 management */ @Override - public void handle(JobClient jobClient, ActivatedJob activatedJob) throws Exception { - switch (getScenarioStep().getModeExecution()) { - case CLASSICAL, WAIT -> manageWaitExecution(null, null, jobClient, activatedJob, durationSleep.toMillis()); - case THREAD, ASYNCHRONOUS -> manageAsynchronousExecution(null, null, jobClient, activatedJob); - case THREADTOKEN, ASYNCHRONOUSLIMITED -> manageAsynchronousLimitedExecution(null, null, jobClient, activatedJob); - } + public STATUS getStatus() { + if (registeredTask == null) + return STATUS.STOPPED; + if (stopping) + return STATUS.STOPPING; + return STATUS.RUNNING; } - private void manageWaitExecution(org.camunda.bpm.client.task.ExternalTask externalTask, - ExternalTaskService externalTaskService, - JobClient jobClient, - ActivatedJob activatedJob, - long waitTimeInMs) { - long begin = System.currentTimeMillis(); - Map<String, Object> variables = new HashMap<>(); - Map<String, Object> currentVariables = new HashMap<>(); - try { - if (getRunScenario().getRunParameters().isDeepTracking()) - trackActiveWorkers.movement(1); - - if (waitTimeInMs > 0) - Thread.sleep(waitTimeInMs); - - variables = RunZeebeOperation.getVariablesStep(flowServiceTask.getRunScenario(), - flowServiceTask.getScenarioStep(), 0); - - /** This should be moved to the Camunda Engine implementation */ - /* C7 */ - if (externalTask != null) { - currentVariables = externalTask.getAllVariables(); - externalTaskService.complete(externalTask, variables); - } - /* C8 */ - if (jobClient != null) { - currentVariables = activatedJob.getVariablesAsMap(); - CompleteJobCommandStep1 completeCommand = jobClient.newCompleteCommand(activatedJob.getKey()); - CommandWrapper command = new RefactoredCommandWrapper((FinalCommandStep) completeCommand, - activatedJob.getDeadline(), activatedJob.toString(), exceptionHandlingStrategy); - - command.executeAsync(); - } + @Override + public int getCurrentNumberOfThreads() { + return trackActiveWorkers.getCounter() + trackAsynchronousWorkers.getCounter(); + } - flowServiceTask.runResult.registerAddStepExecution(); + /** + * Register the worker + */ - } catch (Exception e) { - logger.error("Error task[{}] PI[{}] : {}", flowServiceTask.getId(), - (externalTask != null ? externalTask.getProcessDefinitionKey() : activatedJob.getProcessInstanceKey()), - e.getMessage()); + private void registerWorker() { + BpmnEngine bpmnEngine = getRunScenario().getBpmnEngine(); - flowServiceTask.runResult.registerAddErrorStepExecution(); + Duration durationSleep = getScenarioStep().getWaitingTimeDuration(Duration.ZERO); + durationSleep = durationSleep.plusSeconds(10); - } - long end = System.currentTimeMillis(); + if (getRunScenario().getRunParameters().showLevelMonitoring()) { + logger.info("Start service TaskId[{}] Topic[{}] StreamEnabled:{} DurationSleep[{} ms]", + getScenarioStep().getTaskId(), getScenarioStep().getTopic(), getScenarioStep().isStreamEnabled(), + durationSleep.toMillis()); + } - if (getRunScenario().getRunParameters().isDeepTracking()) - trackActiveWorkers.movement(-1); + registeredTask = bpmnEngine.registerServiceTask(getId(), // workerId + getScenarioStep().getTopic(), // topic + getScenarioStep().isStreamEnabled(), // stream + durationSleep, // lock time + new SimpleDelayHandler(this), new FixedBackoffSupplier(getScenarioStep().getFixedBackOffDelay())); + } - if (getRunScenario().getRunParameters().showLevelInfo()) { - logger.info("Executed task[{}] in {} ms PI[{}] CurrentVariable {} Variable {} Sleep [{} s]", getId(), - end - begin, - (externalTask != null ? externalTask.getProcessDefinitionKey() : activatedJob.getProcessInstanceKey()), - currentVariables, variables, durationSleep.getSeconds()); + private static class TrackActiveWorker { + public int counter = 0; - } + public synchronized void movement(int movement) { + counter += movement; + } + public int getCounter() { + return counter; + } } - private void manageAsynchronousExecution(org.camunda.bpm.client.task.ExternalTask externalTask, - ExternalTaskService externalTaskService, - JobClient jobClient, - ActivatedJob activatedJob) { - if (getRunScenario().getRunParameters().isDeepTracking()) - trackAsynchronousWorkers.movement(1); - flowServiceTask.scheduler.schedule(new Runnable() { - @Override - public void run() { - manageWaitExecution(externalTask, externalTaskService, jobClient, activatedJob, 0); - if (getRunScenario().getRunParameters().isDeepTracking()) - trackAsynchronousWorkers.movement(-1); + /** + * C7, C8 Handler + */ + public class SimpleDelayHandler implements ExternalTaskHandler, JobHandler { + private final RunScenarioFlowServiceTask flowServiceTask; + private final Duration durationSleep; + + public SimpleDelayHandler(RunScenarioFlowServiceTask flowServiceTask) { + this.flowServiceTask = flowServiceTask; + durationSleep = flowServiceTask.getScenarioStep().getWaitingTimeDuration(Duration.ZERO); } - }, Instant.now().plusMillis(durationSleep.toMillis())); - } - private void manageAsynchronousLimitedExecution(org.camunda.bpm.client.task.ExternalTask externalTask, - ExternalTaskService externalTaskService, - JobClient jobClient, - ActivatedJob activatedJob) { - // we register - try { - flowServiceTask.semaphore.acquire(); - if (getRunScenario().getRunParameters().showLevelMonitoring()) { - logger.info("task[{}] Semaphore acquire", getId()); + /* C7 Management */ + @Override + public void execute(org.camunda.bpm.client.task.ExternalTask externalTask, + ExternalTaskService externalTaskService) { + switch (getScenarioStep().getModeExecution()) { + case CLASSICAL, WAIT -> + manageWaitExecution(externalTask, externalTaskService, null, null, durationSleep.toMillis()); + case THREAD, ASYNCHRONOUS -> manageAsynchronousExecution(externalTask, externalTaskService, null, null); + case THREADTOKEN, ASYNCHRONOUSLIMITED -> + manageAsynchronousLimitedExecution(externalTask, externalTaskService, null, null); + } } - } catch (Exception e) { - return; - } - // Ok, now we can run that asynchronous - flowServiceTask.scheduler.schedule(new Runnable() { + + /* C8 management */ @Override - public void run() { - manageWaitExecution(externalTask, externalTaskService, jobClient, activatedJob, 0); - flowServiceTask.semaphore.release(); - if (getRunScenario().getRunParameters().showLevelMonitoring()) { - logger.info("task[{}] Semaphore release", getId()); - } + public void handle(JobClient jobClient, ActivatedJob activatedJob) throws Exception { + switch (getScenarioStep().getModeExecution()) { + case CLASSICAL, WAIT -> + manageWaitExecution(null, null, jobClient, activatedJob, durationSleep.toMillis()); + case THREAD, ASYNCHRONOUS -> manageAsynchronousExecution(null, null, jobClient, activatedJob); + case THREADTOKEN, ASYNCHRONOUSLIMITED -> + manageAsynchronousLimitedExecution(null, null, jobClient, activatedJob); + } } - }, Instant.now().plusMillis(durationSleep.toMillis())); - } + private void manageWaitExecution(org.camunda.bpm.client.task.ExternalTask externalTask, + ExternalTaskService externalTaskService, + JobClient jobClient, + ActivatedJob activatedJob, + long waitTimeInMs) { + long begin = System.currentTimeMillis(); + Map<String, Object> variables = new HashMap<>(); + Map<String, Object> currentVariables = new HashMap<>(); + try { + if (getRunScenario().getRunParameters().isDeepTracking()) + trackActiveWorkers.movement(1); + + if (waitTimeInMs > 0) + Thread.sleep(waitTimeInMs); + + variables = RunZeebeOperation.getVariablesStep(flowServiceTask.getRunScenario(), + flowServiceTask.getScenarioStep(), 0); + + /** This should be moved to the Camunda Engine implementation */ + /* C7 */ + if (externalTask != null) { + currentVariables = externalTask.getAllVariables(); + externalTaskService.complete(externalTask, variables); + } + /* C8 */ + if (jobClient != null) { + currentVariables = activatedJob.getVariablesAsMap(); + CompleteJobCommandStep1 completeCommand = jobClient.newCompleteCommand(activatedJob.getKey()); + CommandWrapper command = new RefactoredCommandWrapper((FinalCommandStep) completeCommand, + activatedJob.getDeadline(), activatedJob.toString(), exceptionHandlingStrategy); + + command.executeAsync(); + } + + flowServiceTask.runResult.registerAddStepExecution(); + + } catch (Exception e) { + logger.error("Error task[{}] PI[{}] : {}", flowServiceTask.getId(), + (externalTask != null ? externalTask.getProcessDefinitionKey() : activatedJob.getProcessInstanceKey()), + e.getMessage()); + + flowServiceTask.runResult.registerAddErrorStepExecution(); + + } + long end = System.currentTimeMillis(); + + if (getRunScenario().getRunParameters().isDeepTracking()) + trackActiveWorkers.movement(-1); + + if (getRunScenario().getRunParameters().showLevelInfo()) { + logger.info("Executed task[{}] in {} ms PI[{}] CurrentVariable {} Variable {} Sleep [{} s]", getId(), + end - begin, + (externalTask != null ? externalTask.getProcessDefinitionKey() : activatedJob.getProcessInstanceKey()), + currentVariables, variables, durationSleep.getSeconds()); + + } - } + } + + private void manageAsynchronousExecution(org.camunda.bpm.client.task.ExternalTask externalTask, + ExternalTaskService externalTaskService, + JobClient jobClient, + ActivatedJob activatedJob) { + if (getRunScenario().getRunParameters().isDeepTracking()) + trackAsynchronousWorkers.movement(1); + flowServiceTask.scheduler.schedule(new Runnable() { + @Override + public void run() { + manageWaitExecution(externalTask, externalTaskService, jobClient, activatedJob, 0); + if (getRunScenario().getRunParameters().isDeepTracking()) + trackAsynchronousWorkers.movement(-1); + } + }, Instant.now().plusMillis(durationSleep.toMillis())); + } + + private void manageAsynchronousLimitedExecution(org.camunda.bpm.client.task.ExternalTask externalTask, + ExternalTaskService externalTaskService, + JobClient jobClient, + ActivatedJob activatedJob) { + // we register + try { + flowServiceTask.semaphore.acquire(); + if (getRunScenario().getRunParameters().showLevelMonitoring()) { + logger.info("task[{}] Semaphore acquire", getId()); + } + } catch (Exception e) { + return; + } + // Ok, now we can run that asynchronous + flowServiceTask.scheduler.schedule(new Runnable() { + @Override + public void run() { + manageWaitExecution(externalTask, externalTaskService, jobClient, activatedJob, 0); + flowServiceTask.semaphore.release(); + if (getRunScenario().getRunParameters().showLevelMonitoring()) { + logger.info("task[{}] Semaphore release", getId()); + } + } + }, Instant.now().plusMillis(durationSleep.toMillis())); + + } + + } } \ No newline at end of file diff --git a/src/main/java/org/camunda/automator/engine/flow/RunScenarioFlowStartEvent.java b/src/main/java/org/camunda/automator/engine/flow/RunScenarioFlowStartEvent.java index c1cbbe2..c172353 100644 --- a/src/main/java/org/camunda/automator/engine/flow/RunScenarioFlowStartEvent.java +++ b/src/main/java/org/camunda/automator/engine/flow/RunScenarioFlowStartEvent.java @@ -19,186 +19,186 @@ import java.util.stream.Collectors; public class RunScenarioFlowStartEvent extends RunScenarioFlowBasic { - private final TaskScheduler scheduler; - Logger logger = LoggerFactory.getLogger(RunScenarioFlowStartEvent.class); - StartEventRunnable startEventRunnable; - private boolean stopping; - private boolean isRunning; - /** - * Each time we run a batch of start, execution Number increase - */ - private int executionBatchNumber = 1; - - public RunScenarioFlowStartEvent(TaskScheduler scheduler, - ScenarioStep scenarioStep, - RunScenario runScenario, - RunResult runResult) { - super(scenarioStep, runScenario, runResult); - this.scheduler = scheduler; - } - - @Override - public String getTopic() { - return getScenarioStep().getTaskId(); - } - - @Override - public void execute() { - stopping = false; - isRunning = true; - - startEventRunnable = new StartEventRunnable(scheduler, getScenarioStep(), getRunScenario(), this, runResult); - - startEventRunnable.start(); - } - - @Override - public void pleaseStop() { - this.stopping = true; - } - - public RunScenarioFlowBasic.STATUS getStatus() { - if (!isRunning) - return RunScenarioFlowBasic.STATUS.STOPPED; - if (stopping) { - return RunScenarioFlowBasic.STATUS.STOPPING; + private final TaskScheduler scheduler; + Logger logger = LoggerFactory.getLogger(RunScenarioFlowStartEvent.class); + StartEventRunnable startEventRunnable; + private boolean stopping; + private boolean isRunning; + /** + * Each time we run a batch of start, execution Number increase + */ + private int executionBatchNumber = 1; + + public RunScenarioFlowStartEvent(TaskScheduler scheduler, + ScenarioStep scenarioStep, + RunScenario runScenario, + RunResult runResult) { + super(scenarioStep, runScenario, runResult); + this.scheduler = scheduler; } - return RunScenarioFlowBasic.STATUS.RUNNING; - } - - @Override - public int getCurrentNumberOfThreads() { - try { - return startEventRunnable == null ? 0 : startEventRunnable.getNumberOfRunningThreads(); - } catch (Exception e) { - // do nothing - logger.error("During getCurrentNumberOfThreads : {}", e); - return 0; + + @Override + public String getTopic() { + return getScenarioStep().getTaskId(); } - } - @Override - public RunResult getRunResult() { - return runResult; - } + @Override + public void execute() { + stopping = false; + isRunning = true; - public enum STATUS {RUNNING, STOPPING, STOPPED} + startEventRunnable = new StartEventRunnable(scheduler, getScenarioStep(), getRunScenario(), this, runResult); - /** - * StartEventRunnable - */ - class StartEventRunnable implements Runnable { + startEventRunnable.start(); + } - private final TaskScheduler scheduler; - private final ScenarioStep scenarioStep; - private final RunResult runResult; - private final RunScenario runScenario; - private final RunScenarioFlowStartEvent flowStartEvent; - - private int nbOverloaded = 0; - private int totalCreation = 0; - private int totalFailed = 0; - - private CreateProcessInstanceThread createProcessInstanceThread = null; - - public StartEventRunnable(TaskScheduler scheduler, - ScenarioStep scenarioStep, - RunScenario runScenario, - RunScenarioFlowStartEvent flowStartEvent, - RunResult runResult) { - this.scheduler = scheduler; - this.scenarioStep = scenarioStep; - this.runResult = runResult; - this.runScenario = runScenario; - this.flowStartEvent = flowStartEvent; + @Override + public void pleaseStop() { + this.stopping = true; } - /** - * Start it in a new tread - */ - public void start() { - scheduler.schedule(this, Instant.now()); + public RunScenarioFlowBasic.STATUS getStatus() { + if (!isRunning) + return RunScenarioFlowBasic.STATUS.STOPPED; + if (stopping) { + return RunScenarioFlowBasic.STATUS.STOPPING; + } + return RunScenarioFlowBasic.STATUS.RUNNING; } @Override - public void run() { - if (flowStartEvent.stopping) { - if (runScenario.getRunParameters().showLevelMonitoring()) { - logger.info("Stop now [" + getId() + "]"); - if (nbOverloaded > 0) - runResult.addError(scenarioStep, - - "Overloaded:" + nbOverloaded + " TotalCreation:" + totalCreation // total creation we see - + " TheoricNumberExpectred:" + (scenarioStep.getNumberOfExecutions() * executionBatchNumber) - // expected - - + " Process[" + scenarioStep.getProcessId() + "] Can't create PI at the required frequency"); - if (totalFailed > 0) - runResult.addError(scenarioStep, - "Failed " + totalFailed + " Process[" + scenarioStep.getProcessId() + "] Can't create PI "); - + public int getCurrentNumberOfThreads() { + try { + return startEventRunnable == null ? 0 : startEventRunnable.getNumberOfRunningThreads(); + } catch (Exception e) { + // do nothing + logger.error("During getCurrentNumberOfThreads : {}", e); + return 0; } - // notify my parent that I stop now - flowStartEvent.isRunning = false; - return; - } - executionBatchNumber++; - - Duration durationToCreateProcessInstances = Duration.parse(scenarioStep.getFrequency()); - - long begin = System.currentTimeMillis(); - boolean isOverloadSection = false; - - // generate process instance in multiple threads - - createProcessInstanceThread = new CreateProcessInstanceThread(executionBatchNumber, scenarioStep, runScenario, - runResult); - - // creates all process instances, return when finish OR when duration is reach - createProcessInstanceThread.createProcessInstances(durationToCreateProcessInstances); - - // Now collect data for the running time - totalCreation += createProcessInstanceThread.getTotalCreation(); - totalFailed += createProcessInstanceThread.getTotalFailed(); - List<String> listProcessInstances = createProcessInstanceThread.getListProcessInstances(); - long end = System.currentTimeMillis(); - - // do we have to stop the execution? - if (createProcessInstanceThread.isOverload()) { - // take too long to create the required process instance, so stop now. - nbOverloaded++; - isOverloadSection = true; - } - - // calculate the time to wait now - Duration durationToWait = durationToCreateProcessInstances.minusMillis(end - begin); - if (durationToWait.isNegative()) { - durationToWait = Duration.ZERO; - - } - - // report now - if (runScenario.getRunParameters().showLevelMonitoring() || createProcessInstanceThread.isOverload()) { - logger.info("Step #{}-{}" + " Create (real/scenario)[{}/{} {}]" // Overload marker - + " Failed[{}] in {} ms " // time of operation - + " Sleep[{} s] ", // end message - executionBatchNumber, getId(), createProcessInstanceThread.getTotalCreation(), - scenarioStep.getNumberOfExecutions(), (isOverloadSection ? "OVERLOAD" : ""), - createProcessInstanceThread.getTotalFailed(), (end - begin), durationToWait.getSeconds()); - } - if (runScenario.getRunParameters().showLevelInfo()) { - logger.info(" listPI(first20): " + listProcessInstances.stream().collect(Collectors.joining(","))); - - } - - // Wait to restart - scheduler.schedule(this, Instant.now().plusMillis(durationToWait.toMillis())); + } + @Override + public RunResult getRunResult() { + return runResult; } - public int getNumberOfRunningThreads() { - return createProcessInstanceThread == null ? 0 : createProcessInstanceThread.getNumberOfRunningThreads(); + public enum STATUS {RUNNING, STOPPING, STOPPED} + + /** + * StartEventRunnable + */ + class StartEventRunnable implements Runnable { + + private final TaskScheduler scheduler; + private final ScenarioStep scenarioStep; + private final RunResult runResult; + private final RunScenario runScenario; + private final RunScenarioFlowStartEvent flowStartEvent; + + private int nbOverloaded = 0; + private int totalCreation = 0; + private int totalFailed = 0; + + private CreateProcessInstanceThread createProcessInstanceThread = null; + + public StartEventRunnable(TaskScheduler scheduler, + ScenarioStep scenarioStep, + RunScenario runScenario, + RunScenarioFlowStartEvent flowStartEvent, + RunResult runResult) { + this.scheduler = scheduler; + this.scenarioStep = scenarioStep; + this.runResult = runResult; + this.runScenario = runScenario; + this.flowStartEvent = flowStartEvent; + } + + /** + * Start it in a new tread + */ + public void start() { + scheduler.schedule(this, Instant.now()); + } + + @Override + public void run() { + if (flowStartEvent.stopping) { + if (runScenario.getRunParameters().showLevelMonitoring()) { + logger.info("Stop now [" + getId() + "]"); + if (nbOverloaded > 0) + runResult.addError(scenarioStep, + + "Overloaded:" + nbOverloaded + " TotalCreation:" + totalCreation // total creation we see + + " TheoricNumberExpectred:" + (scenarioStep.getNumberOfExecutions() * executionBatchNumber) + // expected + + + " Process[" + scenarioStep.getProcessId() + "] Can't create PI at the required frequency"); + if (totalFailed > 0) + runResult.addError(scenarioStep, + "Failed " + totalFailed + " Process[" + scenarioStep.getProcessId() + "] Can't create PI "); + + } + // notify my parent that I stop now + flowStartEvent.isRunning = false; + return; + } + executionBatchNumber++; + + Duration durationToCreateProcessInstances = Duration.parse(scenarioStep.getFrequency()); + + long begin = System.currentTimeMillis(); + boolean isOverloadSection = false; + + // generate process instance in multiple threads + + createProcessInstanceThread = new CreateProcessInstanceThread(executionBatchNumber, scenarioStep, runScenario, + runResult); + + // creates all process instances, return when finish OR when duration is reach + createProcessInstanceThread.createProcessInstances(durationToCreateProcessInstances); + + // Now collect data for the running time + totalCreation += createProcessInstanceThread.getTotalCreation(); + totalFailed += createProcessInstanceThread.getTotalFailed(); + List<String> listProcessInstances = createProcessInstanceThread.getListProcessInstances(); + long end = System.currentTimeMillis(); + + // do we have to stop the execution? + if (createProcessInstanceThread.isOverload()) { + // take too long to create the required process instance, so stop now. + nbOverloaded++; + isOverloadSection = true; + } + + // calculate the time to wait now + Duration durationToWait = durationToCreateProcessInstances.minusMillis(end - begin); + if (durationToWait.isNegative()) { + durationToWait = Duration.ZERO; + + } + + // report now + if (runScenario.getRunParameters().showLevelMonitoring() || createProcessInstanceThread.isOverload()) { + logger.info("Step #{}-{}" + " Create (real/scenario)[{}/{} {}]" // Overload marker + + " Failed[{}] in {} ms " // time of operation + + " Sleep[{} s] ", // end message + executionBatchNumber, getId(), createProcessInstanceThread.getTotalCreation(), + scenarioStep.getNumberOfExecutions(), (isOverloadSection ? "OVERLOAD" : ""), + createProcessInstanceThread.getTotalFailed(), (end - begin), durationToWait.getSeconds()); + } + if (runScenario.getRunParameters().showLevelInfo()) { + logger.info(" listPI(first20): " + listProcessInstances.stream().collect(Collectors.joining(","))); + + } + + // Wait to restart + scheduler.schedule(this, Instant.now().plusMillis(durationToWait.toMillis())); + + } + + public int getNumberOfRunningThreads() { + return createProcessInstanceThread == null ? 0 : createProcessInstanceThread.getNumberOfRunningThreads(); + } } - } } diff --git a/src/main/java/org/camunda/automator/engine/flow/RunScenarioFlowUserTask.java b/src/main/java/org/camunda/automator/engine/flow/RunScenarioFlowUserTask.java index 2e37042..f9044c7 100644 --- a/src/main/java/org/camunda/automator/engine/flow/RunScenarioFlowUserTask.java +++ b/src/main/java/org/camunda/automator/engine/flow/RunScenarioFlowUserTask.java @@ -15,124 +15,124 @@ public class RunScenarioFlowUserTask extends RunScenarioFlowBasic { - private final TaskScheduler scheduler; - Logger logger = LoggerFactory.getLogger(RunScenarioFlowUserTask.class); - private STATUS status = STATUS.RUNNING; - - public RunScenarioFlowUserTask(TaskScheduler scheduler, - ScenarioStep scenarioStep, - int index, - RunScenario runScenario, - RunResult runResult) { - super(scenarioStep, runScenario, runResult); - this.scheduler = scheduler; - - } - - @Override - public String getTopic() { - return getScenarioStep().getTaskId(); - } - - @Override - public void execute() { - RunScenarioFlowUserTask.UserTaskRunnable startEventRunnable = new RunScenarioFlowUserTask.UserTaskRunnable( - scheduler, getScenarioStep(), runResult, getRunScenario(), this); - scheduler.schedule(startEventRunnable, Instant.now()); - } - - @Override - public STATUS getStatus() { - return status; - } - - @Override - public int getCurrentNumberOfThreads() { - return 1; - } - - @Override - public void pleaseStop() { - logger.info("Ask Stopping [" + getId() + "]"); - - status = STATUS.STOPPING; - // wait 1 second - try { - Thread.sleep(1000); - } catch (Exception e) { - // do nothing + private final TaskScheduler scheduler; + Logger logger = LoggerFactory.getLogger(RunScenarioFlowUserTask.class); + private STATUS status = STATUS.RUNNING; + + public RunScenarioFlowUserTask(TaskScheduler scheduler, + ScenarioStep scenarioStep, + int index, + RunScenario runScenario, + RunResult runResult) { + super(scenarioStep, runScenario, runResult); + this.scheduler = scheduler; + + } + + @Override + public String getTopic() { + return getScenarioStep().getTaskId(); } - } - /** - * StartEventRunnable - */ - class UserTaskRunnable implements Runnable { + @Override + public void execute() { + RunScenarioFlowUserTask.UserTaskRunnable startEventRunnable = new RunScenarioFlowUserTask.UserTaskRunnable( + scheduler, getScenarioStep(), runResult, getRunScenario(), this); + scheduler.schedule(startEventRunnable, Instant.now()); + } - private final TaskScheduler scheduler; - private final ScenarioStep scenarioStep; - private final RunResult runResult; - private final RunScenario runScenario; - private final RunScenarioFlowUserTask flowUserTask; - - private final int nbOverloaded = 0; - private final int totalCreation = 0; - private final int totalCreationGoal = 0; - private final int totalFailed = 0; - - public UserTaskRunnable(TaskScheduler scheduler, - ScenarioStep scenarioStep, - RunResult runResult, - RunScenario runScenario, - RunScenarioFlowUserTask flowUserTask) { - this.scheduler = scheduler; - this.scenarioStep = scenarioStep; - this.runResult = runResult; - this.runScenario = runScenario; - this.flowUserTask = flowUserTask; + @Override + public STATUS getStatus() { + return status; } @Override - public void run() { - Long waitingTimeInMs = null; - if (getScenarioStep().getWaitingTime() != null) { - Duration duration = Duration.parse(getScenarioStep().getWaitingTime()); - waitingTimeInMs = duration.toMillis(); - } - if (waitingTimeInMs == null) - waitingTimeInMs = 1L; - - long beginTimeWait = System.currentTimeMillis(); - while (flowUserTask.status == STATUS.RUNNING) { + public int getCurrentNumberOfThreads() { + return 1; + } + + @Override + public void pleaseStop() { + logger.info("Ask Stopping [" + getId() + "]"); + + status = STATUS.STOPPING; + // wait 1 second try { - List<String> listActivities; - do { + Thread.sleep(1000); + } catch (Exception e) { + // do nothing + } + } - listActivities = getRunScenario().getBpmnEngine().searchUserTasks(getScenarioStep().getTaskId(), 10); + /** + * StartEventRunnable + */ + class UserTaskRunnable implements Runnable { + + private final TaskScheduler scheduler; + private final ScenarioStep scenarioStep; + private final RunResult runResult; + private final RunScenario runScenario; + private final RunScenarioFlowUserTask flowUserTask; + + private final int nbOverloaded = 0; + private final int totalCreation = 0; + private final int totalCreationGoal = 0; + private final int totalFailed = 0; + + public UserTaskRunnable(TaskScheduler scheduler, + ScenarioStep scenarioStep, + RunResult runResult, + RunScenario runScenario, + RunScenarioFlowUserTask flowUserTask) { + this.scheduler = scheduler; + this.scenarioStep = scenarioStep; + this.runResult = runResult; + this.runScenario = runScenario; + this.flowUserTask = flowUserTask; + } - if (listActivities.isEmpty()) { - try { - Thread.sleep(10000); - } catch (InterruptedException e) { - // nothing to do here - } + @Override + public void run() { + Long waitingTimeInMs = null; + if (getScenarioStep().getWaitingTime() != null) { + Duration duration = Duration.parse(getScenarioStep().getWaitingTime()); + waitingTimeInMs = duration.toMillis(); } - } while (listActivities.isEmpty() && System.currentTimeMillis() - beginTimeWait < waitingTimeInMs); - - if (!listActivities.isEmpty()) { - for (String taskInstanceId : listActivities) { - getRunScenario().getBpmnEngine() - .executeUserTask(taskInstanceId, getScenarioStep().getUserId(), - RunZeebeOperation.getVariablesStep(getRunScenario(), getScenarioStep(), 0)); + if (waitingTimeInMs == null) + waitingTimeInMs = 1L; + + long beginTimeWait = System.currentTimeMillis(); + while (flowUserTask.status == STATUS.RUNNING) { + try { + List<String> listActivities; + do { + + listActivities = getRunScenario().getBpmnEngine().searchUserTasks(getScenarioStep().getTaskId(), 10); + + if (listActivities.isEmpty()) { + try { + Thread.sleep(10000); + } catch (InterruptedException e) { + // nothing to do here + } + } + } while (listActivities.isEmpty() && System.currentTimeMillis() - beginTimeWait < waitingTimeInMs); + + if (!listActivities.isEmpty()) { + for (String taskInstanceId : listActivities) { + getRunScenario().getBpmnEngine() + .executeUserTask(taskInstanceId, getScenarioStep().getUserId(), + RunZeebeOperation.getVariablesStep(getRunScenario(), getScenarioStep(), 0)); + } + } + } catch (AutomatorException e) { + logger.error("Error task[" + getScenarioStep().getTaskId() + " : " + e.getMessage()); + + getRunResult().registerAddErrorStepExecution(); + } } - } - } catch (AutomatorException e) { - logger.error("Error task[" + getScenarioStep().getTaskId() + " : " + e.getMessage()); - - getRunResult().registerAddErrorStepExecution(); + flowUserTask.status = STATUS.STOPPED; } - } - flowUserTask.status = STATUS.STOPPED; } - } } diff --git a/src/main/java/org/camunda/automator/engine/flow/RunScenarioFlows.java b/src/main/java/org/camunda/automator/engine/flow/RunScenarioFlows.java index 6692cd3..62ce0a5 100644 --- a/src/main/java/org/camunda/automator/engine/flow/RunScenarioFlows.java +++ b/src/main/java/org/camunda/automator/engine/flow/RunScenarioFlows.java @@ -16,378 +16,372 @@ import org.slf4j.LoggerFactory; import java.time.Duration; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; +import java.util.*; public class RunScenarioFlows { - private final ServiceAccess serviceAccess; - private final RunScenario runScenario; - private final Map<String, Long> previousValueMap = new HashMap<>(); - Logger logger = LoggerFactory.getLogger(RunScenarioFlows.class); - - public RunScenarioFlows(ServiceAccess serviceAccess, RunScenario runScenario) { - this.serviceAccess = serviceAccess; - this.runScenario = runScenario; - } - - /** - * Execute the scenario flow - * - * @param runResult result to populate - */ - public void execute(RunResult runResult) { - // Create one executor per flow - RunScenarioWarmingUp runScenarioWarmingUp = new RunScenarioWarmingUp(serviceAccess, runScenario); - Map<String, RunResult.RecordCreationPI> recordCreationPIMap = new HashMap<>(); - if (runScenario.getScenario().getFlowControl() == null) { - runResult.addError(null, - "Scenario does not declare a [FlowControl] section. This section is mandatory for a Flow Scenario"); - return; + private final ServiceAccess serviceAccess; + private final RunScenario runScenario; + private final Map<String, Long> previousValueMap = new HashMap<>(); + Logger logger = LoggerFactory.getLogger(RunScenarioFlows.class); + + public RunScenarioFlows(ServiceAccess serviceAccess, RunScenario runScenario) { + this.serviceAccess = serviceAccess; + this.runScenario = runScenario; } - List<ScenarioFlowControl.Objective> listObjectives = runScenario.getScenario().getFlowControl().getObjectives(); - if (listObjectives == null) - listObjectives = Collections.emptyList(); - - RunObjectives runObjectives = new RunObjectives(listObjectives, runScenario.getBpmnEngine(), recordCreationPIMap); - - logger.info("ScenarioFlow: ------ WarmingUp"); - runScenarioWarmingUp.warmingUp(runResult); - - Date startTestDate = new Date(); - runObjectives.setStartDate(startTestDate); - - logger.info("ScenarioFlow: ------ Start"); - List<RunScenarioFlowBasic> listFlows = startExecution(runScenarioWarmingUp.getListWarmingUpTask()); - - waitEndExecution(runObjectives, startTestDate, listFlows); - - Date endTestDate = new Date(); - runObjectives.setEndDate(endTestDate); - logger.info("ScenarioFlow: ------ Stop"); - - stopExecution(listFlows); - - logger.info("ScenarioFlow: ------ CollectData"); - collectInformation(listFlows, runResult, recordCreationPIMap); - - // Check with Objective now - logger.info("ScenarioFlow: ------ CheckObjectives"); - checkObjectives(runObjectives, startTestDate, endTestDate, runResult); - - logger.info("ScenarioFlow: ------ TheEnd"); - } - - /** - * Start execution - * - * @return list of Flow started - */ - private List<RunScenarioFlowBasic> startExecution(List<RunScenarioFlowBasic> listWarmingTask) { - List<RunScenarioFlowBasic> listFlows = new ArrayList<>(); - for (ScenarioStep scenarioStep : runScenario.getScenario().getFlows()) { - switch (scenarioStep.getType()) { - case STARTEVENT -> { - if (!runScenario.getRunParameters().isCreation()) { - logger.info("According configuration, STARTEVENT[" + scenarioStep.getProcessId() + "] is fully disabled"); - } else { - RunScenarioFlowStartEvent runStartEvent = new RunScenarioFlowStartEvent( - serviceAccess.getTaskScheduler(scenarioStep.getProcessId()), scenarioStep, runScenario, - new RunResult(runScenario)); - runStartEvent.execute(); - listFlows.add(runStartEvent); + /** + * Execute the scenario flow + * + * @param runResult result to populate + */ + public void execute(RunResult runResult) { + // Create one executor per flow + RunScenarioWarmingUp runScenarioWarmingUp = new RunScenarioWarmingUp(serviceAccess, runScenario); + Map<String, RunResult.RecordCreationPI> recordCreationPIMap = new HashMap<>(); + if (runScenario.getScenario().getFlowControl() == null) { + runResult.addError(null, + "Scenario does not declare a [FlowControl] section. This section is mandatory for a Flow Scenario"); + return; } - } - - case SERVICETASK -> { - Optional<RunScenarioFlowBasic> runServiceTaskOp = getFromList(listWarmingTask, scenarioStep.getTopic()); - - if (!runScenario.getRunParameters().isServiceTask()) { - logger.info("According configuration, SERVICETASK[{}] is fully disabled", scenarioStep.getTopic()); - if (runServiceTaskOp.isPresent()) - runServiceTaskOp.get().pleaseStop(); - } else if (runScenario.getRunParameters().blockExecutionServiceTask(scenarioStep.getTopic())) { - logger.info("According configuration, SERVICETASK[{}] is disabled (only acceptable {})", - scenarioStep.getTopic(), runScenario.getRunParameters().getFilterServiceTask()); - if (runServiceTaskOp.isPresent()) - runServiceTaskOp.get().pleaseStop(); - } else { - if (runServiceTaskOp.isEmpty()) { - - RunScenarioFlowServiceTask runServiceTask = new RunScenarioFlowServiceTask( - serviceAccess.getTaskScheduler("serviceTask"), scenarioStep, runScenario, new RunResult(runScenario)); - - runServiceTask.execute(); - listFlows.add(runServiceTask); - } else { - listFlows.add(runServiceTaskOp.get()); - } - } - } - - case USERTASK -> { - Optional<RunScenarioFlowBasic> runUserTaskOpt = getFromList(listWarmingTask, scenarioStep.getTaskId()); - - if (!runScenario.getRunParameters().isUserTask()) { - logger.info("According configuration, USERTASK[{}] is fully disabled", scenarioStep.getTaskId()); - if (runUserTaskOpt.isPresent()) - runUserTaskOpt.get().pleaseStop(); - } else { - if (runUserTaskOpt.isEmpty()) { - - RunScenarioFlowUserTask runUserTask = new RunScenarioFlowUserTask( - serviceAccess.getTaskScheduler("userTask"), scenarioStep, 0, runScenario, new RunResult(runScenario)); - - runUserTask.execute(); - listFlows.add(runUserTask); - } else { - listFlows.add(runUserTaskOpt.get()); - } - } - } - } - } - return listFlows; - } - - private Optional<RunScenarioFlowBasic> getFromList(List<RunScenarioFlowBasic> listTasks, String topic) { - return listTasks.stream().filter(t -> t.getTopic().equals(topic)).findFirst(); - } - - /** - * Wait end of execution. according to the time in the scenario, wait this time - * - * @param runObjectives checkObjectif: we may have a Flow Objectives - * @param listFlows list of flows to monitor the execution - */ - private void waitEndExecution(RunObjectives runObjectives, Date startTestDate, List<RunScenarioFlowBasic> listFlows) { - // Then wait the delay, and kill everything after - Duration durationExecution = runScenario.getScenario().getFlowControl().getDuration(); - Duration durationWarmingUp = Duration.ZERO; - // if this server didn't do the warmingUp, then other server did it: we have to keep this time into account - if (!runScenario.getRunParameters().isWarmingUp()) { - // is the scenario has a warming up defined? - if (runScenario.getScenario().getWarmingUp() != null) - durationWarmingUp = runScenario.getScenario().getWarmingUp().getDuration(); + + List<ScenarioFlowControl.Objective> listObjectives = runScenario.getScenario().getFlowControl().getObjectives(); + if (listObjectives == null) + listObjectives = Collections.emptyList(); + + RunObjectives runObjectives = new RunObjectives(listObjectives, runScenario.getBpmnEngine(), recordCreationPIMap); + + logger.info("ScenarioFlow: ------ WarmingUp"); + runScenarioWarmingUp.warmingUp(runResult); + + Date startTestDate = new Date(); + runObjectives.setStartDate(startTestDate); + + logger.info("ScenarioFlow: ------ Start"); + List<RunScenarioFlowBasic> listFlows = startExecution(runScenarioWarmingUp.getListWarmingUpTask()); + + waitEndExecution(runObjectives, startTestDate, listFlows); + + Date endTestDate = new Date(); + runObjectives.setEndDate(endTestDate); + logger.info("ScenarioFlow: ------ Stop"); + + stopExecution(listFlows); + + logger.info("ScenarioFlow: ------ CollectData"); + collectInformation(listFlows, runResult, recordCreationPIMap); + + // Check with Objective now + logger.info("ScenarioFlow: ------ CheckObjectives"); + checkObjectives(runObjectives, startTestDate, endTestDate, runResult); + + logger.info("ScenarioFlow: ------ TheEnd"); } - long endTimeExpected = - startTestDate.getTime() + durationExecution.getSeconds() * 1000 + durationWarmingUp.getSeconds() * 1000; - - logger.info("Start: FixedWarmingUp {} s ExecutionDuration {} s (total {} s)", durationWarmingUp.getSeconds(), - durationExecution.getSeconds(), durationWarmingUp.getSeconds() + durationExecution.getSeconds()); - - while (System.currentTimeMillis() < endTimeExpected) { - long currentTime = System.currentTimeMillis(); - long sleepTime = Math.min(30 * 1000L, endTimeExpected - currentTime); - try { - Thread.sleep(sleepTime); - } catch (InterruptedException e) { - } - int advancement = (int) (100.0 * (currentTime - startTestDate.getTime()) / (endTimeExpected - - startTestDate.getTime())); - runObjectives.heartBeat(); - logRealTime(listFlows, endTimeExpected - System.currentTimeMillis(), advancement); + /** + * Start execution + * + * @return list of Flow started + */ + private List<RunScenarioFlowBasic> startExecution(List<RunScenarioFlowBasic> listWarmingTask) { + List<RunScenarioFlowBasic> listFlows = new ArrayList<>(); + for (ScenarioStep scenarioStep : runScenario.getScenario().getFlows()) { + switch (scenarioStep.getType()) { + case STARTEVENT -> { + if (!runScenario.getRunParameters().isCreation()) { + logger.info("According configuration, STARTEVENT[" + scenarioStep.getProcessId() + "] is fully disabled"); + } else { + RunScenarioFlowStartEvent runStartEvent = new RunScenarioFlowStartEvent( + serviceAccess.getTaskScheduler(scenarioStep.getProcessId()), scenarioStep, runScenario, + new RunResult(runScenario)); + runStartEvent.execute(); + listFlows.add(runStartEvent); + } + } + + case SERVICETASK -> { + Optional<RunScenarioFlowBasic> runServiceTaskOp = getFromList(listWarmingTask, scenarioStep.getTopic()); + + if (!runScenario.getRunParameters().isServiceTask()) { + logger.info("According configuration, SERVICETASK[{}] is fully disabled", scenarioStep.getTopic()); + if (runServiceTaskOp.isPresent()) + runServiceTaskOp.get().pleaseStop(); + } else if (runScenario.getRunParameters().blockExecutionServiceTask(scenarioStep.getTopic())) { + logger.info("According configuration, SERVICETASK[{}] is disabled (only acceptable {})", + scenarioStep.getTopic(), runScenario.getRunParameters().getFilterServiceTask()); + if (runServiceTaskOp.isPresent()) + runServiceTaskOp.get().pleaseStop(); + } else { + if (runServiceTaskOp.isEmpty()) { + + RunScenarioFlowServiceTask runServiceTask = new RunScenarioFlowServiceTask( + serviceAccess.getTaskScheduler("serviceTask"), scenarioStep, runScenario, new RunResult(runScenario)); + + runServiceTask.execute(); + listFlows.add(runServiceTask); + } else { + listFlows.add(runServiceTaskOp.get()); + } + } + } + + case USERTASK -> { + Optional<RunScenarioFlowBasic> runUserTaskOpt = getFromList(listWarmingTask, scenarioStep.getTaskId()); + + if (!runScenario.getRunParameters().isUserTask()) { + logger.info("According configuration, USERTASK[{}] is fully disabled", scenarioStep.getTaskId()); + if (runUserTaskOpt.isPresent()) + runUserTaskOpt.get().pleaseStop(); + } else { + if (runUserTaskOpt.isEmpty()) { + + RunScenarioFlowUserTask runUserTask = new RunScenarioFlowUserTask( + serviceAccess.getTaskScheduler("userTask"), scenarioStep, 0, runScenario, new RunResult(runScenario)); + + runUserTask.execute(); + listFlows.add(runUserTask); + } else { + listFlows.add(runUserTaskOpt.get()); + } + } + } + } + } + return listFlows; } - } - - /** - * Stop the execution - * - * @param listFlows list of flows to stop - */ - private void stopExecution(List<RunScenarioFlowBasic> listFlows) { - logger.info("End - wait end FlowBasic"); - // now, stop all executions - for (RunScenarioFlowBasic flowBasic : listFlows) { - flowBasic.pleaseStop(); + + private Optional<RunScenarioFlowBasic> getFromList(List<RunScenarioFlowBasic> listTasks, String topic) { + return listTasks.stream().filter(t -> t.getTopic().equals(topic)).findFirst(); } - // wait the end of all executions - long numberOfActives = listFlows.size(); - int count = 0; - while (numberOfActives > 0 && count < 100) { - count++; - numberOfActives = listFlows.stream() - .filter(t -> !t.getStatus().equals(RunScenarioFlowBasic.STATUS.STOPPED)) - .count(); - if (numberOfActives > 0) - try { - Thread.sleep(2000); - } catch (Exception e) { - numberOfActives = 0; + + /** + * Wait end of execution. according to the time in the scenario, wait this time + * + * @param runObjectives checkObjectif: we may have a Flow Objectives + * @param listFlows list of flows to monitor the execution + */ + private void waitEndExecution(RunObjectives runObjectives, Date startTestDate, List<RunScenarioFlowBasic> listFlows) { + // Then wait the delay, and kill everything after + Duration durationExecution = runScenario.getScenario().getFlowControl().getDuration(); + Duration durationWarmingUp = Duration.ZERO; + // if this server didn't do the warmingUp, then other server did it: we have to keep this time into account + if (!runScenario.getRunParameters().isWarmingUp()) { + // is the scenario has a warming up defined? + if (runScenario.getScenario().getWarmingUp() != null) + durationWarmingUp = runScenario.getScenario().getWarmingUp().getDuration(); + } + + long endTimeExpected = + startTestDate.getTime() + durationExecution.getSeconds() * 1000 + durationWarmingUp.getSeconds() * 1000; + + logger.info("Start: FixedWarmingUp {} s ExecutionDuration {} s (total {} s)", durationWarmingUp.getSeconds(), + durationExecution.getSeconds(), durationWarmingUp.getSeconds() + durationExecution.getSeconds()); + + while (System.currentTimeMillis() < endTimeExpected) { + long currentTime = System.currentTimeMillis(); + long sleepTime = Math.min(30 * 1000L, endTimeExpected - currentTime); + try { + Thread.sleep(sleepTime); + } catch (InterruptedException e) { + } + int advancement = (int) (100.0 * (currentTime - startTestDate.getTime()) / (endTimeExpected + - startTestDate.getTime())); + runObjectives.heartBeat(); + logRealTime(listFlows, endTimeExpected - System.currentTimeMillis(), advancement); } } - } - - /** - * Collect multiple information - * - * @param listFlows list of flow - * @param runResult runResult to populate - * @param recordCreationPIMap statistics - */ - private void collectInformation(List<RunScenarioFlowBasic> listFlows, - RunResult runResult, - Map<String, RunResult.RecordCreationPI> recordCreationPIMap) { - // Collect information - logger.info("CollectData : listFlows[{}]", listFlows.size()); - for (RunScenarioFlowBasic flowBasic : listFlows) { - RunResult runResultFlow = flowBasic.getRunResult(); - runResult.add(runResultFlow); - if (flowBasic instanceof RunScenarioFlowStartEvent) { - String processId = flowBasic.getScenarioStep().getProcessId(); - RunResult.RecordCreationPI recordFlow = runResultFlow.getRecordCreationPI().get(processId); - RunResult.RecordCreationPI recordCreationPI = recordCreationPIMap.getOrDefault(processId, - new RunResult.RecordCreationPI(processId)); - - recordCreationPI.add(recordFlow); - recordCreationPIMap.put(processId, recordCreationPI); - logger.info("CollectData : StartEvent, processId[{}] PICreated[{}] PIFailed[{}]", processId, - recordFlow.nbCreated, recordFlow.nbFailed); - } - } - } - - /** - * Check the objective of the scenario - * - * @param startTestDate date when the test start - * @param endTestDate date when the test end - * @param runResult result to populate - */ - private void checkObjectives(RunObjectives runObjectives, Date startTestDate, Date endTestDate, RunResult runResult) { - - // Objectives ask Operate, which get the result with a delay. So, wait 1 mn - logger.info("CollectingData... (sleep 30s)"); - try { - Thread.sleep(30 * 1000L); - } catch (InterruptedException e) { - // do nothing + + /** + * Stop the execution + * + * @param listFlows list of flows to stop + */ + private void stopExecution(List<RunScenarioFlowBasic> listFlows) { + logger.info("End - wait end FlowBasic"); + // now, stop all executions + for (RunScenarioFlowBasic flowBasic : listFlows) { + flowBasic.pleaseStop(); + } + // wait the end of all executions + long numberOfActives = listFlows.size(); + int count = 0; + while (numberOfActives > 0 && count < 100) { + count++; + numberOfActives = listFlows.stream() + .filter(t -> !t.getStatus().equals(RunScenarioFlowBasic.STATUS.STOPPED)) + .count(); + if (numberOfActives > 0) + try { + Thread.sleep(2000); + } catch (Exception e) { + numberOfActives = 0; + } + } } - List<RunObjectives.ObjectiveResult> listCheckResult = runObjectives.check(); - for (RunObjectives.ObjectiveResult checkResult : listCheckResult) { - if (checkResult.success) { - logger.info("Objective: SUCCESS type[{}] label[{}} processId[{}] reach/objective {}/{} analysis [{}}", - checkResult.objective.type, checkResult.objective.label, checkResult.objective.processId, - checkResult.recordedSuccessValue, checkResult.objective.value, checkResult.analysis); - } else { - // do not need to log the error, already done - runResult.addError(null, - "Objective: FAIL " + checkResult.objective.getInformation() + " type[" + checkResult.objective.type - + "] processId[" + checkResult.objective.processId // ProcessID - + "] reach/objective " + checkResult.recordedSuccessValue // Reach - + "/" + checkResult.objective.value // Objective - + " " + checkResult.analysis); - } + /** + * Collect multiple information + * + * @param listFlows list of flow + * @param runResult runResult to populate + * @param recordCreationPIMap statistics + */ + private void collectInformation(List<RunScenarioFlowBasic> listFlows, + RunResult runResult, + Map<String, RunResult.RecordCreationPI> recordCreationPIMap) { + // Collect information + logger.info("CollectData : listFlows[{}]", listFlows.size()); + for (RunScenarioFlowBasic flowBasic : listFlows) { + RunResult runResultFlow = flowBasic.getRunResult(); + runResult.merge(runResultFlow); + if (flowBasic instanceof RunScenarioFlowStartEvent) { + String processId = flowBasic.getScenarioStep().getProcessId(); + RunResult.RecordCreationPI recordFlow = runResultFlow.getRecordCreationPI().get(processId); + RunResult.RecordCreationPI recordCreationPI = recordCreationPIMap.getOrDefault(processId, + new RunResult.RecordCreationPI(processId)); + + recordCreationPI.add(recordFlow); + recordCreationPIMap.put(processId, recordCreationPI); + logger.info("CollectData : StartEvent, processId[{}] PICreated[{}] PIFailed[{}]", processId, + recordFlow.nbCreated, recordFlow.nbFailed); + } + } } - } - - /** - * Log to see the advancement - * - * @param listFlows list flows running - * @param percentAdvancement percentAdvancement of the test, according the timeframe - */ - private void logRealTime(List<RunScenarioFlowBasic> listFlows, long timeToFinishInMs, int percentAdvancement) { - logger.info("------------ Log advancement at {} ----- {} %, end in {} s", new Date(), percentAdvancement, - timeToFinishInMs / 1000); - - for (RunScenarioFlowBasic flowBasic : listFlows) { - - RunResult runResultFlow = flowBasic.getRunResult(); - int currentNumberOfThreads = flowBasic.getCurrentNumberOfThreads(); - // logs only flow with a result or currently active - if (runResultFlow.getRecordCreationPIAllProcesses() + runResultFlow.getNumberOfSteps() - + runResultFlow.getNumberOfErrorSteps() == 0 && currentNumberOfThreads == 0) - continue; - long previousValue = previousValueMap.getOrDefault(flowBasic.getId(), 0L); - - ScenarioStep scenarioStep = flowBasic.getScenarioStep(); - String key = "[" + flowBasic.getId() + "] " + flowBasic.getStatus().toString() + " currentNbThreads[" - + currentNumberOfThreads + "] "; - key += switch (scenarioStep.getType()) { - case STARTEVENT -> "PI[" + runResultFlow.getRecordCreationPI() + "] delta[" + ( - runResultFlow.getRecordCreationPI().get(flowBasic.getScenarioStep().getProcessId()).nbCreated - - previousValue) + "]"; - case SERVICETASK -> - "StepsExecuted[" + runResultFlow.getNumberOfSteps() + "] delta [" + (runResultFlow.getNumberOfSteps() - - previousValue) + "] StepsErrors[" + runResultFlow.getNumberOfErrorSteps() + "]"; - case USERTASK -> - "StepsExecuted[" + runResultFlow.getNumberOfSteps() + "] delta [" + (runResultFlow.getNumberOfSteps() - - previousValue) + "] StepsErrors[" + runResultFlow.getNumberOfErrorSteps() + "]"; - - default -> "]"; - }; - logger.info(key); - switch (scenarioStep.getType()) { - case STARTEVENT -> previousValueMap.put(flowBasic.getId(), - runResultFlow.getRecordCreationPI().get(flowBasic.getScenarioStep().getProcessId()).nbCreated); - - case SERVICETASK -> previousValueMap.put(flowBasic.getId(), (long) runResultFlow.getNumberOfSteps()); - - case USERTASK -> previousValueMap.put(flowBasic.getId(), (long) runResultFlow.getNumberOfSteps()); - - default -> { - } - } + /** + * Check the objective of the scenario + * + * @param startTestDate date when the test start + * @param endTestDate date when the test end + * @param runResult result to populate + */ + private void checkObjectives(RunObjectives runObjectives, Date startTestDate, Date endTestDate, RunResult runResult) { + + // Objectives ask Operate, which get the result with a delay. So, wait 1 mn + logger.info("CollectingData... (sleep 30s)"); + try { + Thread.sleep(30 * 1000L); + } catch (InterruptedException e) { + // do nothing + } + + List<RunObjectives.ObjectiveResult> listCheckResult = runObjectives.check(); + for (RunObjectives.ObjectiveResult checkResult : listCheckResult) { + if (checkResult.success) { + logger.info("Objective: SUCCESS type[{}] label[{}} processId[{}] reach/objective {}/{} analysis [{}}", + checkResult.objective.type, checkResult.objective.label, checkResult.objective.processId, + checkResult.recordedSuccessValue, checkResult.objective.value, checkResult.analysis); + } else { + // do not need to log the error, already done + runResult.addError(null, + "Objective: FAIL " + checkResult.objective.getInformation() + " type[" + checkResult.objective.type + + "] processId[" + checkResult.objective.processId // ProcessID + + "] reach/objective " + checkResult.recordedSuccessValue // Reach + + "/" + checkResult.objective.value // Objective + + " " + checkResult.analysis); + } + } } - int nbThreadsServiceTask = 0; - int nbThreadsAutomator = 0; - int nbThreadsTimeWaiting = 0; - int nbThreadsWaiting = 0; - int nbThreadsTimeRunnable = 0; - for (Map.Entry<Thread, StackTraceElement[]> entry : Thread.getAllStackTraces().entrySet()) { - boolean isZeebe = false; - boolean isServiceTask = false; - boolean isAutomator = false; - for (StackTraceElement ste : entry.getValue()) { - if (ste.getClassName().contains("io.camunda")) - isZeebe = true; - else if (ste.getClassName().contains(RunScenarioFlowServiceTask.SimpleDelayHandler.class.getName())) - isServiceTask = true; - else if (ste.getClassName().contains(".automator.")) - isAutomator = true; - - // org.camunda.automator.engine.flow.RunScenarioFlowServiceTask$SimpleDelayCompletionHandler - } - if (!isZeebe && !isServiceTask && !isAutomator) - continue; - - if (isServiceTask) - nbThreadsServiceTask++; - else if (isAutomator) - nbThreadsAutomator++; - else - // TIME_WAITING: typical for the FlowServiceTask with a sleep - if (entry.getKey().getState().equals(Thread.State.TIMED_WAITING)) { - // is the thread is running the service task (with a Thread.sleep? - nbThreadsTimeWaiting++; - } else if (entry.getKey().getState().equals(Thread.State.WAITING)) { - nbThreadsTimeWaiting++; - } else if (entry.getKey().getState().equals(Thread.State.RUNNABLE)) { - nbThreadsTimeRunnable++; - } else { - logger.info(" {} {}", entry.getKey(), entry.getKey().getState()); - for (StackTraceElement ste : entry.getValue()) { - logger.info("\tat {}", ste); - } + /** + * Log to see the advancement + * + * @param listFlows list flows running + * @param percentAdvancement percentAdvancement of the test, according the timeframe + */ + private void logRealTime(List<RunScenarioFlowBasic> listFlows, long timeToFinishInMs, int percentAdvancement) { + logger.info("------------ Log advancement at {} ----- {} %, end in {} s", new Date(), percentAdvancement, + timeToFinishInMs / 1000); + + for (RunScenarioFlowBasic flowBasic : listFlows) { + + RunResult runResultFlow = flowBasic.getRunResult(); + int currentNumberOfThreads = flowBasic.getCurrentNumberOfThreads(); + // logs only flow with a result or currently active + if (runResultFlow.getRecordCreationPIAllProcesses() + runResultFlow.getNumberOfSteps() + + runResultFlow.getNumberOfErrorSteps() == 0 && currentNumberOfThreads == 0) + continue; + long previousValue = previousValueMap.getOrDefault(flowBasic.getId(), 0L); + + ScenarioStep scenarioStep = flowBasic.getScenarioStep(); + String key = "[" + flowBasic.getId() + "] " + flowBasic.getStatus().toString() + " currentNbThreads[" + + currentNumberOfThreads + "] "; + key += switch (scenarioStep.getType()) { + case STARTEVENT -> "PI[" + runResultFlow.getRecordCreationPI() + "] delta[" + ( + runResultFlow.getRecordCreationPI().get(flowBasic.getScenarioStep().getProcessId()).nbCreated + - previousValue) + "]"; + case SERVICETASK -> + "StepsExecuted[" + runResultFlow.getNumberOfSteps() + "] delta [" + (runResultFlow.getNumberOfSteps() + - previousValue) + "] StepsErrors[" + runResultFlow.getNumberOfErrorSteps() + "]"; + case USERTASK -> + "StepsExecuted[" + runResultFlow.getNumberOfSteps() + "] delta [" + (runResultFlow.getNumberOfSteps() + - previousValue) + "] StepsErrors[" + runResultFlow.getNumberOfErrorSteps() + "]"; + + default -> "]"; + }; + logger.info(key); + switch (scenarioStep.getType()) { + case STARTEVENT -> previousValueMap.put(flowBasic.getId(), + runResultFlow.getRecordCreationPI().get(flowBasic.getScenarioStep().getProcessId()).nbCreated); + + case SERVICETASK -> previousValueMap.put(flowBasic.getId(), (long) runResultFlow.getNumberOfSteps()); + + case USERTASK -> previousValueMap.put(flowBasic.getId(), (long) runResultFlow.getNumberOfSteps()); + + default -> { + } + } + + } + int nbThreadsServiceTask = 0; + int nbThreadsAutomator = 0; + int nbThreadsTimeWaiting = 0; + int nbThreadsWaiting = 0; + int nbThreadsTimeRunnable = 0; + for (Map.Entry<Thread, StackTraceElement[]> entry : Thread.getAllStackTraces().entrySet()) { + boolean isZeebe = false; + boolean isServiceTask = false; + boolean isAutomator = false; + for (StackTraceElement ste : entry.getValue()) { + if (ste.getClassName().contains("io.camunda")) + isZeebe = true; + else if (ste.getClassName().contains(RunScenarioFlowServiceTask.SimpleDelayHandler.class.getName())) + isServiceTask = true; + else if (ste.getClassName().contains(".automator.")) + isAutomator = true; + + // org.camunda.automator.engine.flow.RunScenarioFlowServiceTask$SimpleDelayCompletionHandler + } + if (!isZeebe && !isServiceTask && !isAutomator) + continue; + + if (isServiceTask) + nbThreadsServiceTask++; + else if (isAutomator) + nbThreadsAutomator++; + else + // TIME_WAITING: typical for the FlowServiceTask with a sleep + if (entry.getKey().getState().equals(Thread.State.TIMED_WAITING)) { + // is the thread is running the service task (with a Thread.sleep? + nbThreadsTimeWaiting++; + } else if (entry.getKey().getState().equals(Thread.State.WAITING)) { + nbThreadsTimeWaiting++; + } else if (entry.getKey().getState().equals(Thread.State.RUNNABLE)) { + nbThreadsTimeRunnable++; + } else { + logger.info(" {} {}", entry.getKey(), entry.getKey().getState()); + for (StackTraceElement ste : entry.getValue()) { + logger.info("\tat {}", ste); + } + + } } + BpmnEngine bpmnEngine = runScenario.getBpmnEngine(); + int workerExecutionThreads = bpmnEngine.getWorkerExecutionThreads(); + if (nbThreadsServiceTask + nbThreadsTimeWaiting + nbThreadsWaiting + nbThreadsTimeRunnable + nbThreadsAutomator > 0) + logger.info( + "Threads: ServiceTaskExecution (ThreadService/maxJobActive) [{}/{}] {} % Automator[{}] TIME_WAITING[{}] WAITING[{}] RUNNABLE[{}] ", + nbThreadsServiceTask, workerExecutionThreads, + workerExecutionThreads == 0 ? 0 : (int) (100.0 * nbThreadsServiceTask / workerExecutionThreads), + nbThreadsAutomator, nbThreadsTimeWaiting, nbThreadsWaiting, nbThreadsTimeRunnable); } - BpmnEngine bpmnEngine = runScenario.getBpmnEngine(); - int workerExecutionThreads = bpmnEngine.getWorkerExecutionThreads(); - if (nbThreadsServiceTask + nbThreadsTimeWaiting + nbThreadsWaiting + nbThreadsTimeRunnable + nbThreadsAutomator > 0) - logger.info( - "Threads: ServiceTaskExecution (ThreadService/maxJobActive) [{}/{}] {} % Automator[{}] TIME_WAITING[{}] WAITING[{}] RUNNABLE[{}] ", - nbThreadsServiceTask, workerExecutionThreads, - workerExecutionThreads == 0 ? 0 : (int) (100.0 * nbThreadsServiceTask / workerExecutionThreads), - nbThreadsAutomator, nbThreadsTimeWaiting, nbThreadsWaiting, nbThreadsTimeRunnable); - } } diff --git a/src/main/java/org/camunda/automator/engine/flow/RunScenarioWarmingUp.java b/src/main/java/org/camunda/automator/engine/flow/RunScenarioWarmingUp.java index f010767..5d23b79 100644 --- a/src/main/java/org/camunda/automator/engine/flow/RunScenarioWarmingUp.java +++ b/src/main/java/org/camunda/automator/engine/flow/RunScenarioWarmingUp.java @@ -27,307 +27,307 @@ import java.util.stream.Stream; public class RunScenarioWarmingUp { - private final ServiceAccess serviceAccess; - private final RunScenario runScenario; - Logger logger = LoggerFactory.getLogger(RunScenarioWarmingUp.class); - - List<RunScenarioFlowServiceTask> listWarmingUpServiceTask = new ArrayList<>(); - List<RunScenarioFlowUserTask> listWarmingUpUserTask = new ArrayList<>(); - - RunScenarioWarmingUp(ServiceAccess serviceAccess, RunScenario runScenario) { - this.serviceAccess = serviceAccess; - this.runScenario = runScenario; - } - - /** - * warmingUp - * Do it! - * - * @param runResult populate the runResult - */ - public void warmingUp(RunResult runResult) { - ScenarioWarmingUp warmingUp = runScenario.getScenario().getWarmingUp(); - if (warmingUp == null) { - logger.info("WarmingUp not present in scenario"); - return; - } - if (!runScenario.getRunParameters().isWarmingUp()) { - logger.info("WarmingUp present, but not allowed to start"); - return; - } - long beginTime = System.currentTimeMillis(); - - // If no duration is set, then 10 Mn max - long endWarmingUp = - beginTime + (warmingUp.getDuration().toMillis() > 0 ? warmingUp.getDuration().toMillis() : 1000 * 60 * 10); - - listWarmingUpServiceTask.clear(); - listWarmingUpUserTask.clear(); - List<StartEventWarmingUpRunnable> listWarmingUpStartEvent = new ArrayList<>(); - List<ScenarioStep> listOperationWarmingUp = warmingUp.getOperations(); - if (warmingUp.useServiceTasks && runScenario.getRunParameters().isServiceTask()) { - listOperationWarmingUp.addAll(runScenario.getScenario() - .getFlows() - .stream() - .filter(t -> t.getType().equals(ScenarioStep.Step.SERVICETASK)) - .toList()); - } - if (warmingUp.useUserTasks && runScenario.getRunParameters().isUserTask()) { - listOperationWarmingUp.addAll(runScenario.getScenario() - .getFlows() - .stream() - .filter(t -> t.getType().equals(ScenarioStep.Step.USERTASK)) - .toList()); - } + private final ServiceAccess serviceAccess; + private final RunScenario runScenario; + Logger logger = LoggerFactory.getLogger(RunScenarioWarmingUp.class); - logger.info("WarmingUp: Start ---- {} operations (Scenario/Policy: serviceTask:{}/{} userTask: {}/{})", - listOperationWarmingUp.size(), // size of operations - warmingUp.useServiceTasks, // scenario allow service task? - runScenario.getRunParameters().isServiceTask(), // pod can run service task? - warmingUp.useUserTasks, runScenario.getRunParameters().isUserTask() // pod can run User Task? - ); - - for (ScenarioStep scenarioStep : listOperationWarmingUp) { - switch (scenarioStep.getType()) { - case STARTEVENT -> { - logger.info("WarmingUp: StartEvent GeneratePI[{}] Frequency[{}] EndWarmingUp[{}]", - scenarioStep.getNumberOfExecutions(), scenarioStep.getFrequency(), scenarioStep.getEndWarmingUp()); - StartEventWarmingUpRunnable startEventWarmingUpRunnable = new StartEventWarmingUpRunnable( - serviceAccess.getTaskScheduler("warmingUp"), scenarioStep, 0, runScenario, runResult); - listWarmingUpStartEvent.add(startEventWarmingUpRunnable); - startEventWarmingUpRunnable.start(); - } - case SERVICETASK -> { - logger.info("WarmingUp: Start Service Task topic[{}]", scenarioStep.getTopic()); - RunScenarioFlowServiceTask task = new RunScenarioFlowServiceTask(serviceAccess.getTaskScheduler("serviceTask"), - scenarioStep, runScenario, new RunResult(runScenario)); - task.execute(); - listWarmingUpServiceTask.add(task); - } - case USERTASK -> { - logger.info("WarmingUp: Start User Task taskId[{}]", scenarioStep.getTaskId()); - RunScenarioFlowUserTask userTask = new RunScenarioFlowUserTask(serviceAccess.getTaskScheduler("userTask"), - scenarioStep, 0, runScenario, new RunResult(runScenario)); - userTask.execute(); - listWarmingUpUserTask.add(userTask); - } - default -> logger.info("WarmingUp: Unknown [{}]", scenarioStep.getType()); - - } + List<RunScenarioFlowServiceTask> listWarmingUpServiceTask = new ArrayList<>(); + List<RunScenarioFlowUserTask> listWarmingUpUserTask = new ArrayList<>(); + + RunScenarioWarmingUp(ServiceAccess serviceAccess, RunScenario runScenario) { + this.serviceAccess = serviceAccess; + this.runScenario = runScenario; } - // check if we reach the end of the warming up - boolean warmingUpIsFinish = false; - while (!warmingUpIsFinish) { - long currentTime = System.currentTimeMillis(); - String analysis = "Limit warmupDuration in " + (endWarmingUp - currentTime) / 1000 + " s, "; - if (currentTime >= endWarmingUp) { - analysis += "OVER_MAXIMUM"; - warmingUpIsFinish = true; - } - boolean allIsFinished = true; - for (StartEventWarmingUpRunnable startRunnable : listWarmingUpStartEvent) { - analysis += "/ warmingUp[" + startRunnable.scenarioStep.getTaskId() + "] instanceCreated[" - + startRunnable.nbInstancesCreated + "]"; - - // the warmup finished boolean is not made here: each runnable (separate thread) check it. - if (startRunnable.warmingUpFinished) { - analysis += " FINISH " + startRunnable.warmingUpFinishedAnalysis; - } else { - analysis += " NOT_FINISH " + startRunnable.warmingUpNotFinishedAnalysis; - allIsFinished = false; + /** + * warmingUp + * Do it! + * + * @param runResult populate the runResult + */ + public void warmingUp(RunResult runResult) { + ScenarioWarmingUp warmingUp = runScenario.getScenario().getWarmingUp(); + if (warmingUp == null) { + logger.info("WarmingUp not present in scenario"); + return; } - - } - if (allIsFinished) { - warmingUpIsFinish = true; - } - logger.info("WarmingUpFinished? {} analysis:[{}]", warmingUpIsFinish, analysis); - if (!warmingUpIsFinish) { - try { - Thread.sleep(1000L * 15); - } catch (InterruptedException e) { - // do not care + if (!runScenario.getRunParameters().isWarmingUp()) { + logger.info("WarmingUp present, but not allowed to start"); + return; + } + long beginTime = System.currentTimeMillis(); + + // If no duration is set, then 10 Mn max + long endWarmingUp = + beginTime + (warmingUp.getDuration().toMillis() > 0 ? warmingUp.getDuration().toMillis() : 1000 * 60 * 10); + + listWarmingUpServiceTask.clear(); + listWarmingUpUserTask.clear(); + List<StartEventWarmingUpRunnable> listWarmingUpStartEvent = new ArrayList<>(); + List<ScenarioStep> listOperationWarmingUp = warmingUp.getOperations(); + if (warmingUp.useServiceTasks && runScenario.getRunParameters().isServiceTask()) { + listOperationWarmingUp.addAll(runScenario.getScenario() + .getFlows() + .stream() + .filter(t -> t.getType().equals(ScenarioStep.Step.SERVICETASK)) + .toList()); + } + if (warmingUp.useUserTasks && runScenario.getRunParameters().isUserTask()) { + listOperationWarmingUp.addAll(runScenario.getScenario() + .getFlows() + .stream() + .filter(t -> t.getType().equals(ScenarioStep.Step.USERTASK)) + .toList()); } - } - } - - // stop everything - for (StartEventWarmingUpRunnable startRunnable : listWarmingUpStartEvent) { - startRunnable.pleaseStop(true); - } - // now warmup is finished - logger.info("WarmingUp: Complete ----"); - } + logger.info("WarmingUp: Start ---- {} operations (Scenario/Policy: serviceTask:{}/{} userTask: {}/{})", + listOperationWarmingUp.size(), // size of operations + warmingUp.useServiceTasks, // scenario allow service task? + runScenario.getRunParameters().isServiceTask(), // pod can run service task? + warmingUp.useUserTasks, runScenario.getRunParameters().isUserTask() // pod can run User Task? + ); + + for (ScenarioStep scenarioStep : listOperationWarmingUp) { + switch (scenarioStep.getType()) { + case STARTEVENT -> { + logger.info("WarmingUp: StartEvent GeneratePI[{}] Frequency[{}] EndWarmingUp[{}]", + scenarioStep.getNumberOfExecutions(), scenarioStep.getFrequency(), scenarioStep.getEndWarmingUp()); + StartEventWarmingUpRunnable startEventWarmingUpRunnable = new StartEventWarmingUpRunnable( + serviceAccess.getTaskScheduler("warmingUp"), scenarioStep, 0, runScenario, runResult); + listWarmingUpStartEvent.add(startEventWarmingUpRunnable); + startEventWarmingUpRunnable.start(); + } + case SERVICETASK -> { + logger.info("WarmingUp: Start Service Task topic[{}]", scenarioStep.getTopic()); + RunScenarioFlowServiceTask task = new RunScenarioFlowServiceTask(serviceAccess.getTaskScheduler("serviceTask"), + scenarioStep, runScenario, new RunResult(runScenario)); + task.execute(); + listWarmingUpServiceTask.add(task); + } + case USERTASK -> { + logger.info("WarmingUp: Start User Task taskId[{}]", scenarioStep.getTaskId()); + RunScenarioFlowUserTask userTask = new RunScenarioFlowUserTask(serviceAccess.getTaskScheduler("userTask"), + scenarioStep, 0, runScenario, new RunResult(runScenario)); + userTask.execute(); + listWarmingUpUserTask.add(userTask); + } + default -> logger.info("WarmingUp: Unknown [{}]", scenarioStep.getType()); + + } + } - public List<RunScenarioFlowServiceTask> getListWarmingUpServiceTask() { - return listWarmingUpServiceTask; - } + // check if we reach the end of the warming up + boolean warmingUpIsFinish = false; + while (!warmingUpIsFinish) { + long currentTime = System.currentTimeMillis(); + String analysis = "Limit warmupDuration in " + (endWarmingUp - currentTime) / 1000 + " s, "; + if (currentTime >= endWarmingUp) { + analysis += "OVER_MAXIMUM"; + warmingUpIsFinish = true; + } + boolean allIsFinished = true; + for (StartEventWarmingUpRunnable startRunnable : listWarmingUpStartEvent) { + analysis += "/ warmingUp[" + startRunnable.scenarioStep.getTaskId() + "] instanceCreated[" + + startRunnable.nbInstancesCreated + "]"; + + // the warmup finished boolean is not made here: each runnable (separate thread) check it. + if (startRunnable.warmingUpFinished) { + analysis += " FINISH " + startRunnable.warmingUpFinishedAnalysis; + } else { + analysis += " NOT_FINISH " + startRunnable.warmingUpNotFinishedAnalysis; + allIsFinished = false; + } + + } + if (allIsFinished) { + warmingUpIsFinish = true; + } + logger.info("WarmingUpFinished? {} analysis:[{}]", warmingUpIsFinish, analysis); + if (!warmingUpIsFinish) { + try { + Thread.sleep(1000L * 15); + } catch (InterruptedException e) { + // do not care + } + } + } - public List<RunScenarioFlowUserTask> getListWarmingUpUserTask() { - return listWarmingUpUserTask; - } + // stop everything + for (StartEventWarmingUpRunnable startRunnable : listWarmingUpStartEvent) { + startRunnable.pleaseStop(true); + } - public List<RunScenarioFlowBasic> getListWarmingUpTask() { - return Stream.concat(listWarmingUpServiceTask.stream(), listWarmingUpUserTask.stream()) - .collect(Collectors.toList()); - } + // now warmup is finished + logger.info("WarmingUp: Complete ----"); + } - /** - * StartEventRunnable - * Must be runnable because we will schedule it. - */ - class StartEventWarmingUpRunnable implements Runnable { + public List<RunScenarioFlowServiceTask> getListWarmingUpServiceTask() { + return listWarmingUpServiceTask; + } - private final TaskScheduler scheduler; - private final ScenarioStep scenarioStep; - private final RunScenario runScenario; - private final RunResult runResult; - public boolean stop = false; - public boolean warmingUpFinished = false; - public String warmingUpFinishedAnalysis = ""; - public String warmingUpNotFinishedAnalysis = "Not verified yet"; - public int nbInstancesCreated = 0; - private int nbOverloaded = 0; - private int executionBatchNumber = 1; - - public StartEventWarmingUpRunnable(TaskScheduler scheduler, - ScenarioStep scenarioStep, - int index, - RunScenario runScenario, - RunResult runResult) { - this.scheduler = scheduler; - this.scenarioStep = scenarioStep; - this.runScenario = runScenario; - this.runResult = runResult; + public List<RunScenarioFlowUserTask> getListWarmingUpUserTask() { + return listWarmingUpUserTask; } - public void pleaseStop(boolean stop) { - this.stop = stop; + public List<RunScenarioFlowBasic> getListWarmingUpTask() { + return Stream.concat(listWarmingUpServiceTask.stream(), listWarmingUpUserTask.stream()) + .collect(Collectors.toList()); } /** - * Start it in a new tread + * StartEventRunnable + * Must be runnable because we will schedule it. */ - public void start() { - scheduler.schedule(this, Instant.now()); - - } - - @Override - public void run() { - if (stop) { - return; - } - executionBatchNumber++; - // check if the condition is reach - CheckFunctionResult checkFunctionResult = null; - if (scenarioStep.getEndWarmingUp() != null) { - checkFunctionResult = endCheckFunction(scenarioStep.getEndWarmingUp(), runResult); - if (checkFunctionResult.goalReach) { - warmingUpFinishedAnalysis += "GoalReach[" + checkFunctionResult.analysis + "]"; - warmingUpNotFinishedAnalysis = ""; - warmingUpFinished = true; - return; - } else { - warmingUpNotFinishedAnalysis = checkFunctionResult.analysis(); + class StartEventWarmingUpRunnable implements Runnable { + + private final TaskScheduler scheduler; + private final ScenarioStep scenarioStep; + private final RunScenario runScenario; + private final RunResult runResult; + public boolean stop = false; + public boolean warmingUpFinished = false; + public String warmingUpFinishedAnalysis = ""; + public String warmingUpNotFinishedAnalysis = "Not verified yet"; + public int nbInstancesCreated = 0; + private int nbOverloaded = 0; + private int executionBatchNumber = 1; + + public StartEventWarmingUpRunnable(TaskScheduler scheduler, + ScenarioStep scenarioStep, + int index, + RunScenario runScenario, + RunResult runResult) { + this.scheduler = scheduler; + this.scenarioStep = scenarioStep; + this.runScenario = runScenario; + this.runResult = runResult; } - } - // continue to generate PI - long begin = System.currentTimeMillis(); - CreateProcessInstanceThread createProcessInstanceThread = new CreateProcessInstanceThread(executionBatchNumber, - scenarioStep, runScenario, runResult); - - Duration durationWarmup; - if (scenarioStep.getFrequency() == null || scenarioStep.getFrequency().isEmpty()) { - durationWarmup = Duration.ofHours(1); - } else { - durationWarmup = Duration.parse(scenarioStep.getFrequency()); - } - - createProcessInstanceThread.createProcessInstances(durationWarmup); - - long end = System.currentTimeMillis(); - // one step generation? - if (scenarioStep.getFrequency() == null || scenarioStep.getFrequency().isEmpty()) { - if (runScenario.getRunParameters().showLevelMonitoring()) { - logger.info("WarmingUp:StartEvent Create[{}] in {} ms (oneShoot) listPI(max20): ", - scenarioStep.getNumberOfExecutions(), (end - begin), - createProcessInstanceThread.getListProcessInstances().stream().collect(Collectors.joining(","))); + + public void pleaseStop(boolean stop) { + this.stop = stop; } - warmingUpFinishedAnalysis += "GoalOneShoot"; - warmingUpFinished = true; - return; - } - - if (createProcessInstanceThread.isOverload()) { - nbOverloaded++; - } - Duration durationToWait; - if (scenarioStep.getFrequency() == null || scenarioStep.getFrequency().isEmpty()) { - durationToWait = Duration.ZERO; - } else { - durationToWait = durationWarmup.minusMillis(end - begin); - if (durationToWait.isNegative()) { - durationToWait = Duration.ZERO; + + /** + * Start it in a new tread + */ + public void start() { + scheduler.schedule(this, Instant.now()); + } - } - if (runScenario.getRunParameters().showLevelMonitoring()) { - logger.info("Warmingup batch_#{} Create real/scenario[{}/{}] in {} ms Sleep[{} s] {}", // log - executionBatchNumber, // batch - createProcessInstanceThread.getTotalCreation(), scenarioStep.getNumberOfExecutions(), - // Number of creation request - (end - begin), // duration - durationToWait.getSeconds(), // Sleep for the frequency - (checkFunctionResult == null ? "" : "EndWarmingUp:" + checkFunctionResult.analysis)); - } - scheduler.schedule(this, Instant.now().plusMillis(durationToWait.toMillis())); - } - /** - * Check the function - * - * @param function function to check - * @param runResult runResult to fulfill information - * @return status - */ - private CheckFunctionResult endCheckFunction(String function, RunResult runResult) { - try { - int posParenthesis = function.indexOf("("); - String functionName = function.substring(0, posParenthesis); - String parameters = function.substring(posParenthesis + 1); - parameters = parameters.substring(0, parameters.length() - 1); - StringTokenizer st = new StringTokenizer(parameters, ","); - if ("UserTaskThreshold".equalsIgnoreCase(functionName)) { - String taskId = st.hasMoreTokens() ? st.nextToken() : ""; - Integer threshold = st.hasMoreTokens() ? Integer.valueOf(st.nextToken()) : 0; - long value = runScenario.getBpmnEngine().countNumberOfTasks(runScenario.getScenario().getProcessId(), taskId); - return new CheckFunctionResult(value >= threshold, - "Task[" + taskId + "] value [" + value + "] / threshold[" + threshold + "]"); - } else if ("EndEventThreshold".equalsIgnoreCase(functionName)) { - String endId = st.hasMoreTokens() ? st.nextToken() : ""; - Integer threshold = st.hasMoreTokens() ? Integer.valueOf(st.nextToken()) : 0; - - long value = runScenario.getBpmnEngine() - .countNumberOfProcessInstancesEnded(runScenario.getScenario().getProcessId(), - new DateFilter(runResult.getStartDate()), new DateFilter(new Date())); - return new CheckFunctionResult(value >= threshold, - "End[" + endId + "] value [" + value + "] / threshold[" + threshold + "]"); + @Override + public void run() { + if (stop) { + return; + } + executionBatchNumber++; + // check if the condition is reach + CheckFunctionResult checkFunctionResult = null; + if (scenarioStep.getEndWarmingUp() != null) { + checkFunctionResult = endCheckFunction(scenarioStep.getEndWarmingUp(), runResult); + if (checkFunctionResult.goalReach) { + warmingUpFinishedAnalysis += "GoalReach[" + checkFunctionResult.analysis + "]"; + warmingUpNotFinishedAnalysis = ""; + warmingUpFinished = true; + return; + } else { + warmingUpNotFinishedAnalysis = checkFunctionResult.analysis(); + } + } + // continue to generate PI + long begin = System.currentTimeMillis(); + CreateProcessInstanceThread createProcessInstanceThread = new CreateProcessInstanceThread(executionBatchNumber, + scenarioStep, runScenario, runResult); + + Duration durationWarmup; + if (scenarioStep.getFrequency() == null || scenarioStep.getFrequency().isEmpty()) { + durationWarmup = Duration.ofHours(1); + } else { + durationWarmup = Duration.parse(scenarioStep.getFrequency()); + } + + createProcessInstanceThread.createProcessInstances(durationWarmup); + + long end = System.currentTimeMillis(); + // one step generation? + if (scenarioStep.getFrequency() == null || scenarioStep.getFrequency().isEmpty()) { + if (runScenario.getRunParameters().showLevelMonitoring()) { + logger.info("WarmingUp:StartEvent Create[{}] in {} ms (oneShoot) listPI(max20): ", + scenarioStep.getNumberOfExecutions(), (end - begin), + createProcessInstanceThread.getListProcessInstances().stream().collect(Collectors.joining(","))); + } + warmingUpFinishedAnalysis += "GoalOneShoot"; + warmingUpFinished = true; + return; + } + + if (createProcessInstanceThread.isOverload()) { + nbOverloaded++; + } + Duration durationToWait; + if (scenarioStep.getFrequency() == null || scenarioStep.getFrequency().isEmpty()) { + durationToWait = Duration.ZERO; + } else { + durationToWait = durationWarmup.minusMillis(end - begin); + if (durationToWait.isNegative()) { + durationToWait = Duration.ZERO; + } + } + if (runScenario.getRunParameters().showLevelMonitoring()) { + logger.info("Warmingup batch_#{} Create real/scenario[{}/{}] in {} ms Sleep[{} s] {}", // log + executionBatchNumber, // batch + createProcessInstanceThread.getTotalCreation(), scenarioStep.getNumberOfExecutions(), + // Number of creation request + (end - begin), // duration + durationToWait.getSeconds(), // Sleep for the frequency + (checkFunctionResult == null ? "" : "EndWarmingUp:" + checkFunctionResult.analysis)); + } + scheduler.schedule(this, Instant.now().plusMillis(durationToWait.toMillis())); + } + /** + * Check the function + * + * @param function function to check + * @param runResult runResult to fulfill information + * @return status + */ + private CheckFunctionResult endCheckFunction(String function, RunResult runResult) { + try { + int posParenthesis = function.indexOf("("); + String functionName = function.substring(0, posParenthesis); + String parameters = function.substring(posParenthesis + 1); + parameters = parameters.substring(0, parameters.length() - 1); + StringTokenizer st = new StringTokenizer(parameters, ","); + if ("UserTaskThreshold".equalsIgnoreCase(functionName)) { + String taskId = st.hasMoreTokens() ? st.nextToken() : ""; + Integer threshold = st.hasMoreTokens() ? Integer.valueOf(st.nextToken()) : 0; + long value = runScenario.getBpmnEngine().countNumberOfTasks(runScenario.getScenario().getProcessId(), taskId); + return new CheckFunctionResult(value >= threshold, + "Task[" + taskId + "] value [" + value + "] / threshold[" + threshold + "]"); + } else if ("EndEventThreshold".equalsIgnoreCase(functionName)) { + String endId = st.hasMoreTokens() ? st.nextToken() : ""; + Integer threshold = st.hasMoreTokens() ? Integer.valueOf(st.nextToken()) : 0; + + long value = runScenario.getBpmnEngine() + .countNumberOfProcessInstancesEnded(runScenario.getScenario().getProcessId(), + new DateFilter(runResult.getStartDate()), new DateFilter(new Date())); + return new CheckFunctionResult(value >= threshold, + "End[" + endId + "] value [" + value + "] / threshold[" + threshold + "]"); + + } + logger.error("Unknown function [{}]", functionName); + return new CheckFunctionResult(false, "Unknown function"); + } catch (AutomatorException e) { + logger.error("Error during warmingup {}", e.getMessage()); + return new CheckFunctionResult(false, "Exception " + e.getMessage()); + } } - logger.error("Unknown function [{}]", functionName); - return new CheckFunctionResult(false, "Unknown function"); - } catch (AutomatorException e) { - logger.error("Error during warmingup {}", e.getMessage()); - return new CheckFunctionResult(false, "Exception " + e.getMessage()); - } - } - /** - * UserTaskTask(<taskId>,<numberOfTaskExpected>) - */ - public record CheckFunctionResult(boolean goalReach, String analysis) { + /** + * UserTaskTask(<taskId>,<numberOfTaskExpected>) + */ + public record CheckFunctionResult(boolean goalReach, String analysis) { + } } - } } diff --git a/src/main/java/org/camunda/automator/engine/unit/RunScenarioUnit.java b/src/main/java/org/camunda/automator/engine/unit/RunScenarioUnit.java index 3932074..d4c20f2 100644 --- a/src/main/java/org/camunda/automator/engine/unit/RunScenarioUnit.java +++ b/src/main/java/org/camunda/automator/engine/unit/RunScenarioUnit.java @@ -21,210 +21,216 @@ * one ExecutionStep in a runScenario */ public class RunScenarioUnit { - private final Logger logger = LoggerFactory.getLogger(RunScenarioUnit.class); - private final RunScenario runScenario; - private final ScenarioExecution scnExecution; - private String agentName = ""; - - public RunScenarioUnit(RunScenario runScenario, ScenarioExecution scnExecution) { - this.runScenario = runScenario; - this.scnExecution = scnExecution; - } - - public void setAgentName(String name) { - this.agentName = name; - } - - /** - * Execute the scenario. - * Note: this method is multi thread safe. - * Each execution has its own Thread - * - * @return the execution - */ - public RunResult runExecution() { - RunResult resultExecution = new RunResult(runScenario); - - if (runScenario.getRunParameters().showLevelMonitoring()) { - logger.info("ScnRunExecution." + agentName + ": Start Execution [" + scnExecution.getName() + "] "); + private final Logger logger = LoggerFactory.getLogger(RunScenarioUnit.class); + private final RunScenario runScenario; + private final ScenarioExecution scnExecution; + private String agentName = ""; + + public RunScenarioUnit(RunScenario runScenario, ScenarioExecution scnExecution) { + this.runScenario = runScenario; + this.scnExecution = scnExecution; } - ExecutorService executor = Executors.newFixedThreadPool(scnExecution.getNumberOfThreads()); - List<Future<?>> listFutures = new ArrayList<>(); - - for (int i = 0; i < scnExecution.getNumberProcessInstances(); i++) { - ScnThreadExecutionCallable scnExecutionCallable = new ScnThreadExecutionCallable("AutomatorThread-" + i, this, - runScenario.getRunParameters()); - - listFutures.add(executor.submit(scnExecutionCallable)); + public void setAgentName(String name) { + this.agentName = name; } - // wait the end of all executions - try { - for (Future<?> f : listFutures) { - Object scnRunResult = f.get(); - resultExecution.add((RunResult) scnRunResult); - - } + /** + * Execute one execution on the scenario + * Note: this method is multi thread safe. + * Each execution has its own newFixedThreadPool + * + * @return the execution + */ + public RunResult runExecution() { + RunResult resultExecution = new RunResult(runScenario, scnExecution); - } catch (Exception e) { - resultExecution.addError(null, "Error during executing in parallel " + e.getMessage()); - } + if (runScenario.getRunParameters().showLevelMonitoring()) { + logger.info("ScnRunExecution.{} Start Execution [{}]", agentName, scnExecution.getName()); + } + ExecutorService executor = Executors.newFixedThreadPool(scnExecution.getNumberOfThreads()); - if (runScenario.getRunParameters().showLevelMonitoring()) { - logger.info("ScnRunExecution." + agentName + ": End Execution [" + scnExecution.getName() + "] success? " - + resultExecution.isSuccess()); - } - return resultExecution; - } + List<Future<?>> listFutures = new ArrayList<>(); + for (int i = 0; i < scnExecution.getNumberProcessInstances(); i++) { + ScnThreadExecutionCallable scnExecutionCallable = new ScnThreadExecutionCallable("AutomatorThread-" + scnExecution.getName() + "-" + i, this, + runScenario.getRunParameters()); + listFutures.add(executor.submit(scnExecutionCallable)); + } + // wait the end of all executions + try { + for (Future<?> f : listFutures) { + Object scnRunResult = f.get(); + resultExecution.merge((RunResult) scnRunResult); + } + } catch (Exception e) { + resultExecution.addError(null, "Error during executing in parallel " + e.getMessage()); + } - /* ******************************************************************** */ - /* */ - /* ScnThreadCallable : execute one Execution per thread */ - /* */ - /* ******************************************************************** */ + if (runScenario.getRunParameters().showLevelMonitoring()) { + logger.info("ScnRunExecution.{}: End Execution [{}] success? {}", + agentName, + scnExecution.getName(), + resultExecution.isSuccess()); + } + return resultExecution; + } - private class ScnThreadExecutionCallable implements Callable { - private final String agentName; - private final RunScenarioUnit scnRunExecution; - private final RunParameters runParameters; - private RunResult scnRunResult; - ScnThreadExecutionCallable(String agentName, RunScenarioUnit scnRunExecution, RunParameters runParameters) { - this.agentName = agentName; - this.scnRunExecution = scnRunExecution; - this.runParameters = runParameters; - } - /** - * run one execution. - * - * @return the result object - * @throws Exception in case of error - */ - public Object call() throws Exception { - scnRunResult = new RunResult(scnRunExecution.runScenario); - if (runParameters.isExecution()) - runExecution(); - - // two uses case here: - // Execution AND verifications: for each process Instance created, a verification is running - // Only VERIFICATION: the verification ojbect define a filter to search existing process instance. Verification is perform againts this list - if (runParameters.isVerification() && (scnExecution.getVerifications() != null)) { - if (runParameters.isExecution()) { - // we just finish executing process instance, so wait 30 S to let the engine finish - try { - Thread.sleep(30 * 1000); - } catch (Exception e) { - // nothing to do - } - runVerifications(); - } else { - // use the search criteria - if (scnExecution.getVerifications().getSearchProcessInstanceByVariable().isEmpty()) { - scnRunResult.addVerification(null, false, "No Search Instance by Variable is defined"); - } else { - List<BpmnEngine.ProcessDescription> listProcessInstances = runScenario.getBpmnEngine() - .searchProcessInstanceByVariable(scnExecution.getScnHead().getProcessId(), - scnExecution.getVerifications().getSearchProcessInstanceByVariable(), 100); - - for (BpmnEngine.ProcessDescription processInstance : listProcessInstances) { - scnRunResult.addProcessInstanceId(scnExecution.getScnHead().getProcessId(), - processInstance.processInstanceId); - } - runVerifications(); - } - } - } - // we finish with this process instance - if (scnRunResult.getFirstProcessInstanceId() != null && runParameters.isClearAllAfter()) - runScenario.getBpmnEngine() - .endProcessInstance(scnRunResult.getFirstProcessInstanceId(), runParameters.isClearAllAfter()); - return scnRunResult; - } - public void runExecution() { + /* ******************************************************************** */ + /* */ + /* ScnThreadCallable : execute one Execution per thread */ + /* */ + /* ******************************************************************** */ - RunScenarioUnitServiceTask serviceTask = new RunScenarioUnitServiceTask(runScenario); - RunScenarioUnitUserTask userTask = new RunScenarioUnitUserTask(runScenario); - RunScenarioUnitStartEvent startEvent = new RunScenarioUnitStartEvent(runScenario); + private class ScnThreadExecutionCallable implements Callable { + private final String agentName; + private final RunScenarioUnit scnRunExecution; + private final RunParameters runParameters; - if (scnRunExecution.runScenario.getRunParameters().showLevelMonitoring()) - logger.info( - "ScnRunExecution.StartExecution [" + scnRunExecution.runScenario.getScenario().getName() + "] agent[" - + agentName + "]"); + private RunResult scnRunResult; - for (ScenarioStep step : scnExecution.getSteps()) { + ScnThreadExecutionCallable(String agentName, RunScenarioUnit scnRunExecution, RunParameters runParameters) { + this.agentName = agentName; + this.scnRunExecution = scnRunExecution; + this.runParameters = runParameters; + } - if (scnRunExecution.runScenario.getRunParameters().showLevelDebug()) - logger.info( - "ScnRunExecution.StartExecution.Execute [" + scnRunExecution.runScenario.getScenario().getName() + "." - + step.getTaskId() + " agent[" + agentName + "]"); + /** + * run one execution. + * + * @return the result object + * @throws Exception in case of error + */ + public Object call() throws Exception { + scnRunResult = new RunResult(scnRunExecution.runScenario); + if (runParameters.isExecution()) + runExecution(); + + // two uses case here: + // Execution AND verifications: for each process Instance created, a verification is running + // Only VERIFICATION: the verification ojbect define a filter to search existing process instance. Verification is perform againts this list + if (runParameters.isVerification() && (scnExecution.getVerifications() != null)) { + if (runParameters.isExecution()) { + // we just finish executing process instance, so wait 30 S to let the engine finish + try { + logger.info("Wait 10 s to let Operate collect data"); + Thread.sleep(10 * 1000); + } catch (Exception e) { + // nothing to do + } + runVerifications(); + } else { + // use the search criteria + if (scnExecution.getVerifications().getSearchProcessInstanceByVariable().isEmpty()) { + scnRunResult.addVerification(null, false, "No Search Instance by Variable is defined"); + } else { + List<BpmnEngine.ProcessDescription> listProcessInstances = runScenario.getBpmnEngine() + .searchProcessInstanceByVariable(scnExecution.getScnHead().getProcessId(), + scnExecution.getVerifications().getSearchProcessInstanceByVariable(), 100); + + for (BpmnEngine.ProcessDescription processInstance : listProcessInstances) { + scnRunResult.addProcessInstanceId(scnExecution.getScnHead().getProcessId(), + processInstance.processInstanceId); + } + runVerifications(); + } + } - try { - step.checkConsistence(); - } catch (AutomatorException e) { - scnRunResult.addError(step, e.getMessage()); - continue; - } - long timeBegin = System.currentTimeMillis(); - if (step.getType() == null) { - scnRunResult.addError(step, "Unknown type"); - continue; - } - switch (step.getType()) { - case STARTEVENT -> { - if (scnRunExecution.runScenario.getRunParameters().isCreation()) - scnRunResult = startEvent.startEvent(scnRunResult, step); - } - case USERTASK -> { - // wait for the user Task - if (scnRunExecution.runScenario.getRunParameters().isUserTask()) - scnRunResult = userTask.executeUserTask(step, scnRunResult); - } - case SERVICETASK -> { - // wait for the user Task - if (scnRunExecution.runScenario.getRunParameters().isServiceTask()) { - scnRunResult = serviceTask.executeServiceTask(step, scnRunResult); - } + } + // we finish with this process instance + if (scnRunResult.getFirstProcessInstanceId() != null && runParameters.isClearAllAfter()) + runScenario.getBpmnEngine() + .endProcessInstance(scnRunResult.getFirstProcessInstanceId(), runParameters.isClearAllAfter()); + return scnRunResult; } - case ENDEVENT -> { + public void runExecution() { + + RunScenarioUnitServiceTask serviceTask = new RunScenarioUnitServiceTask(runScenario); + RunScenarioUnitUserTask userTask = new RunScenarioUnitUserTask(runScenario); + RunScenarioUnitStartEvent startEvent = new RunScenarioUnitStartEvent(runScenario); + + if (scnRunExecution.runScenario.getRunParameters().showLevelMonitoring()) + logger.info( + "ScnRunExecution.StartExecution [{}] agent[{}]", + scnRunExecution.runScenario.getScenario().getName(), + agentName); + + for (ScenarioStep step : scnExecution.getSteps()) { + + if (scnRunExecution.runScenario.getRunParameters().showLevelDebug()) + logger.info( + "ScnRunExecution.StartExecution.Execute [{}.{} agent[{}]", + scnRunExecution.runScenario.getScenario().getName(), + step.getTaskId(), + agentName); + + try { + step.checkConsistence(); + } catch (AutomatorException e) { + scnRunResult.addError(step, e.getMessage()); + continue; + } + long timeBegin = System.currentTimeMillis(); + if (step.getType() == null) { + scnRunResult.addError(step, "Unknown type"); + continue; + } + switch (step.getType()) { + case STARTEVENT -> { + if (scnRunExecution.runScenario.getRunParameters().isCreation()) + scnRunResult = startEvent.startEvent(scnRunResult, step); + } + case USERTASK -> { + // wait for the user Task + if (scnRunExecution.runScenario.getRunParameters().isUserTask()) + scnRunResult = userTask.executeUserTask(step, scnRunResult); + } + case SERVICETASK -> { + // wait for the user Task + if (scnRunExecution.runScenario.getRunParameters().isServiceTask()) { + scnRunResult = serviceTask.executeServiceTask(step, scnRunResult); + } + } + + case ENDEVENT -> { + } + + case MESSAGE -> { + } + } + long timeEnd = System.currentTimeMillis(); + scnRunResult.addStepExecution(step, timeEnd - timeBegin); + + if (!scnRunResult.isSuccess() && ScenarioExecution.Policy.STOPATFIRSTERROR.equals(scnExecution.getPolicy())) + return; + } + if (scnRunExecution.runScenario.getRunParameters().showLevelMonitoring()) + logger.info("ScnRunExecution.EndExecution [" + scnExecution.getName() + "] agent[" + agentName + "]"); } - case MESSAGE -> { - } + /** + * Run the verification just after the execution, on the process instances created + */ + public void runVerifications() { + RunScenarioVerification verifications = new RunScenarioVerification(scnExecution); + for (String processInstanceId : scnRunResult.getProcessInstanceId()) { + scnRunResult.merge(verifications.runVerifications(scnRunExecution.runScenario, processInstanceId)); + } } - long timeEnd = System.currentTimeMillis(); - scnRunResult.addStepExecution(step, timeEnd - timeBegin); - - if (!scnRunResult.isSuccess() && ScenarioExecution.Policy.STOPATFIRSTERROR.equals(scnExecution.getPolicy())) - return; - } - if (scnRunExecution.runScenario.getRunParameters().showLevelMonitoring()) - logger.info("ScnRunExecution.EndExecution [" + scnExecution.getName() + "] agent[" + agentName + "]"); - } - /** - * Run the verification just after the execution, on the process instances created - */ - public void runVerifications() { - RunScenarioVerification verifications = new RunScenarioVerification(scnExecution); - for (String processInstanceId : scnRunResult.getProcessInstanceId()) { - scnRunResult.add(verifications.runVerifications(scnRunExecution.runScenario, processInstanceId)); - } - } + public RunResult getScnRunResult() { + return scnRunResult; + } - public RunResult getScnRunResult() { - return scnRunResult; } - - } } diff --git a/src/main/java/org/camunda/automator/engine/unit/RunScenarioUnitServiceTask.java b/src/main/java/org/camunda/automator/engine/unit/RunScenarioUnitServiceTask.java index 3430f2e..3773877 100644 --- a/src/main/java/org/camunda/automator/engine/unit/RunScenarioUnitServiceTask.java +++ b/src/main/java/org/camunda/automator/engine/unit/RunScenarioUnitServiceTask.java @@ -13,75 +13,75 @@ public class RunScenarioUnitServiceTask { - private final Logger logger = LoggerFactory.getLogger(RunScenarioUnitServiceTask.class); + private final Logger logger = LoggerFactory.getLogger(RunScenarioUnitServiceTask.class); - private final RunScenario runScenario; + private final RunScenario runScenario; - protected RunScenarioUnitServiceTask(RunScenario runScenario) { - this.runScenario = runScenario; - } - - /** - * Execute User task - * - * @param result result to complete and return - * @param step step to execute - * @return result completed - */ - public RunResult executeServiceTask(ScenarioStep step, RunResult result) { - if (runScenario.getRunParameters().showLevelMonitoring()) { - logger.info("Service TaskId[{}]", step.getTaskId()); - } - - if (step.getDelay() != null) { - Duration duration = Duration.parse(step.getDelay()); - try { - Thread.sleep(duration.toMillis()); - } catch (InterruptedException e) { - // nothing to do - } + protected RunScenarioUnitServiceTask(RunScenario runScenario) { + this.runScenario = runScenario; } - Long waitingTimeInMs = null; - if (step.getWaitingTime() != null) { - Duration duration = Duration.parse(step.getWaitingTime()); - waitingTimeInMs = duration.toMillis(); - } - if (waitingTimeInMs == null) - waitingTimeInMs = 5L * 60 * 1000; - - for (int index = 0; index < step.getNumberOfExecutions(); index++) { - long beginTimeWait = System.currentTimeMillis(); - try { - List<String> listActivities; - do { - listActivities = runScenario.getBpmnEngine() - .searchServiceTasks(result.getFirstProcessInstanceId(), step.getTaskId(), step.getTopic(), 1); + /** + * Execute User task + * + * @param result result to complete and return + * @param step step to execute + * @return result completed + */ + public RunResult executeServiceTask(ScenarioStep step, RunResult result) { + if (runScenario.getRunParameters().showLevelMonitoring()) { + logger.info("Service TaskId[{}]", step.getTaskId()); + } - if (listActivities.isEmpty()) { + if (step.getDelay() != null) { + Duration duration = Duration.parse(step.getDelay()); try { - Thread.sleep(500); + Thread.sleep(duration.toMillis()); } catch (InterruptedException e) { + // nothing to do } - } - } while (listActivities.isEmpty() && System.currentTimeMillis() - beginTimeWait < waitingTimeInMs); + } + Long waitingTimeInMs = null; + if (step.getWaitingTime() != null) { + Duration duration = Duration.parse(step.getWaitingTime()); + waitingTimeInMs = duration.toMillis(); + } + if (waitingTimeInMs == null) + waitingTimeInMs = 5L * 60 * 1000; - if (listActivities.isEmpty()) { - result.addError(step, "No service task show up task[" + step.getTaskId() + "] processInstance[" - + result.getFirstProcessInstanceId() + "]"); - return result; + for (int index = 0; index < step.getNumberOfExecutions(); index++) { + long beginTimeWait = System.currentTimeMillis(); + try { + List<String> listActivities; + do { + + listActivities = runScenario.getBpmnEngine() + .searchServiceTasks(result.getFirstProcessInstanceId(), step.getTaskId(), step.getTopic(), 1); + + if (listActivities.isEmpty()) { + try { + Thread.sleep(500); + } catch (InterruptedException e) { + } + } + } while (listActivities.isEmpty() && System.currentTimeMillis() - beginTimeWait < waitingTimeInMs); + + if (listActivities.isEmpty()) { + result.addError(step, "No service task show up task[" + step.getTaskId() + "] processInstance[" + + result.getFirstProcessInstanceId() + "]"); + return result; + } + // this is a unit test : there is only one thread, index=1 + runScenario.getBpmnEngine() + .executeServiceTask(listActivities.get(0), step.getUserId(), + RunZeebeOperation.getVariablesStep(runScenario, step, 1)); + } catch (AutomatorException e) { + result.addError(step, e.getMessage()); + return result; + } } - // this is a unit test : there is only one thread, index=1 - runScenario.getBpmnEngine() - .executeServiceTask(listActivities.get(0), step.getUserId(), - RunZeebeOperation.getVariablesStep(runScenario, step, 1)); - } catch (AutomatorException e) { - result.addError(step, e.getMessage()); - return result; - } - } - return result; + return result; - } + } } diff --git a/src/main/java/org/camunda/automator/engine/unit/RunScenarioUnitStartEvent.java b/src/main/java/org/camunda/automator/engine/unit/RunScenarioUnitStartEvent.java index 8353349..4129e7d 100644 --- a/src/main/java/org/camunda/automator/engine/unit/RunScenarioUnitStartEvent.java +++ b/src/main/java/org/camunda/automator/engine/unit/RunScenarioUnitStartEvent.java @@ -12,38 +12,38 @@ public class RunScenarioUnitStartEvent { - private final Logger logger = LoggerFactory.getLogger(RunScenarioUnitStartEvent.class); - - private final RunScenario runScenario; - - protected RunScenarioUnitStartEvent(RunScenario runScenario) { - this.runScenario = runScenario; - } - - /** - * Start Event - * - * @param result result to complete and return - * @param step step to execute - * @return result completed - */ - public RunResult startEvent(RunResult result, ScenarioStep step) { - try { - if (runScenario.getRunParameters().showLevelMonitoring()) { - logger.info("StartEvent EventId[{}]", step.getTaskId()); - } - String processId = step.getScnExecution().getScnHead().getProcessId(); - // There is no multithreading: index=1 - Map<String, Object> processVariables = RunZeebeOperation.getVariablesStep(runScenario, step, 1); - - String processInstanceId = runScenario.getBpmnEngine() - .createProcessInstance(processId, step.getTaskId(), processVariables); - - result.addProcessInstanceId(processId, processInstanceId); - } catch (AutomatorException e) { - result.addError(step, "Error at creation " + e.getMessage()); + private final Logger logger = LoggerFactory.getLogger(RunScenarioUnitStartEvent.class); + + private final RunScenario runScenario; + + protected RunScenarioUnitStartEvent(RunScenario runScenario) { + this.runScenario = runScenario; + } + + /** + * Start Event + * + * @param result result to complete and return + * @param step step to execute + * @return result completed + */ + public RunResult startEvent(RunResult result, ScenarioStep step) { + try { + if (runScenario.getRunParameters().showLevelMonitoring()) { + logger.info("StartEvent EventId[{}]", step.getTaskId()); + } + String processId = step.getScnExecution().getScnHead().getProcessId(); + // There is no multithreading: index=1 + Map<String, Object> processVariables = RunZeebeOperation.getVariablesStep(runScenario, step, 1); + + String processInstanceId = runScenario.getBpmnEngine() + .createProcessInstance(processId, step.getTaskId(), processVariables); + + result.addProcessInstanceId(processId, processInstanceId); + } catch (AutomatorException e) { + result.addError(step, "Error at creation " + e.getMessage()); + } + return result; } - return result; - } } diff --git a/src/main/java/org/camunda/automator/engine/unit/RunScenarioUnitUserTask.java b/src/main/java/org/camunda/automator/engine/unit/RunScenarioUnitUserTask.java index cb4efaf..4904ef6 100644 --- a/src/main/java/org/camunda/automator/engine/unit/RunScenarioUnitUserTask.java +++ b/src/main/java/org/camunda/automator/engine/unit/RunScenarioUnitUserTask.java @@ -13,78 +13,78 @@ public class RunScenarioUnitUserTask { - private final Logger logger = LoggerFactory.getLogger(RunScenarioUnitUserTask.class); + private final Logger logger = LoggerFactory.getLogger(RunScenarioUnitUserTask.class); - private final RunScenario runScenario; + private final RunScenario runScenario; - protected RunScenarioUnitUserTask(RunScenario runScenario) { - this.runScenario = runScenario; - } - - /** - * Execute User task - * - * @param step step to execute - * @param result result to complete and return - * @return result completed - */ - public RunResult executeUserTask(ScenarioStep step, RunResult result) { - - if (runScenario.getRunParameters().showLevelMonitoring()) { - logger.info("UserTask TaskId[{}]", step.getTaskId()); - } - - if (step.getDelay() != null) { - Duration duration = Duration.parse(step.getDelay()); - try { - Thread.sleep(duration.toMillis()); - } catch (InterruptedException e) { - // don't need to do anything here - } + protected RunScenarioUnitUserTask(RunScenario runScenario) { + this.runScenario = runScenario; } - Long waitingTimeInMs = null; - if (step.getWaitingTime() != null) { - Duration duration = Duration.parse(step.getWaitingTime()); - waitingTimeInMs = duration.toMillis(); - } - if (waitingTimeInMs == null) - waitingTimeInMs = 5L * 60 * 1000; - - for (int index = 0; index < step.getNumberOfExecutions(); index++) { - long beginTimeWait = System.currentTimeMillis(); - try { - List<String> listActivities; - do { - listActivities = runScenario.getBpmnEngine() - .searchUserTasksByProcessInstance(result.getFirstProcessInstanceId(), step.getTaskId(), 1); + /** + * Execute User task + * + * @param step step to execute + * @param result result to complete and return + * @return result completed + */ + public RunResult executeUserTask(ScenarioStep step, RunResult result) { + + if (runScenario.getRunParameters().showLevelMonitoring()) { + logger.info("UserTask TaskId[{}]", step.getTaskId()); + } - if (listActivities.isEmpty()) { + if (step.getDelay() != null) { + Duration duration = Duration.parse(step.getDelay()); try { - Thread.sleep(500); + Thread.sleep(duration.toMillis()); } catch (InterruptedException e) { - // nothing to do here + // don't need to do anything here } - } - } while (listActivities.isEmpty() && System.currentTimeMillis() - beginTimeWait < waitingTimeInMs); + } + Long waitingTimeInMs = null; + if (step.getWaitingTime() != null) { + Duration duration = Duration.parse(step.getWaitingTime()); + waitingTimeInMs = duration.toMillis(); + } + if (waitingTimeInMs == null) + waitingTimeInMs = 5L * 60 * 1000; - if (listActivities.isEmpty()) { - result.addError(step, "No user task show up task[" + step.getTaskId() + "] processInstance[" - + result.getFirstProcessInstanceId() + "]"); - return result; + for (int index = 0; index < step.getNumberOfExecutions(); index++) { + long beginTimeWait = System.currentTimeMillis(); + try { + List<String> listActivities; + do { + + listActivities = runScenario.getBpmnEngine() + .searchUserTasksByProcessInstance(result.getFirstProcessInstanceId(), step.getTaskId(), 1); + + if (listActivities.isEmpty()) { + try { + Thread.sleep(500); + } catch (InterruptedException e) { + // nothing to do here + } + } + } while (listActivities.isEmpty() && System.currentTimeMillis() - beginTimeWait < waitingTimeInMs); + + if (listActivities.isEmpty()) { + result.addError(step, "No user task show up task[" + step.getTaskId() + "] processInstance[" + + result.getFirstProcessInstanceId() + "]"); + return result; + } + // unit test: there is no multi thread executing this part, index=1 + runScenario.getBpmnEngine() + .executeUserTask(listActivities.get(0), step.getUserId(), + RunZeebeOperation.getVariablesStep(runScenario, step, 1)); + } catch (AutomatorException e) { + result.addError(step, e.getMessage()); + return result; + } } - // unit test: there is no multi thread executing this part, index=1 - runScenario.getBpmnEngine() - .executeUserTask(listActivities.get(0), step.getUserId(), - RunZeebeOperation.getVariablesStep(runScenario, step, 1)); - } catch (AutomatorException e) { - result.addError(step, e.getMessage()); - return result; - } - } - return result; + return result; - } + } } diff --git a/src/main/java/org/camunda/automator/engine/unit/RunScenarioVerification.java b/src/main/java/org/camunda/automator/engine/unit/RunScenarioVerification.java index 07f064f..93e3520 100644 --- a/src/main/java/org/camunda/automator/engine/unit/RunScenarioVerification.java +++ b/src/main/java/org/camunda/automator/engine/unit/RunScenarioVerification.java @@ -1,103 +1,205 @@ package org.camunda.automator.engine.unit; import org.camunda.automator.bpmnengine.BpmnEngine; -import org.camunda.automator.definition.ScenarioExecution; -import org.camunda.automator.definition.ScenarioVerification; -import org.camunda.automator.definition.ScenarioVerificationTask; -import org.camunda.automator.definition.ScenarioVerificationVariable; +import org.camunda.automator.definition.*; import org.camunda.automator.engine.AutomatorException; import org.camunda.automator.engine.RunResult; import org.camunda.automator.engine.RunScenario; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.Date; import java.util.List; +import java.util.Map; +import java.util.Optional; public class RunScenarioVerification { - private final ScenarioExecution scnExecution; - private final Logger logger = LoggerFactory.getLogger(RunScenarioVerification.class); + private final ScenarioExecution scnExecution; + private final Logger logger = LoggerFactory.getLogger(RunScenarioVerification.class); - public RunScenarioVerification(ScenarioExecution scnExecution) { - this.scnExecution = scnExecution; - } + public RunScenarioVerification(ScenarioExecution scnExecution) { + this.scnExecution = scnExecution; + } + + public RunResult runVerifications(RunScenario runScenario, String processInstanceId) { + RunResult runResult = new RunResult(runScenario); - public RunResult runVerifications(RunScenario runScenario, String processInstanceId) { - RunResult result = new RunResult(runScenario); + // we get a processInstanceId now + ScenarioVerification verifications = scnExecution.getVerifications(); + for (ScenarioVerificationTask activity : verifications.getActivities()) { + checkTask(runScenario, processInstanceId, activity, runResult); + } + for (ScenarioVerificationVariable variable : verifications.getVariables()) { + checkVariable(runScenario, processInstanceId, variable, runResult); + } + for (ScenarioVerificationPerformance performance : verifications.getPerformances()) { + checkPerformance(runScenario, processInstanceId, performance, runResult); + } + return runResult; - // we get a processInstanceId now - ScenarioVerification verifications = scnExecution.getVerifications(); - for (ScenarioVerificationTask activity : verifications.getActivities()) { - checkTask(runScenario, processInstanceId, activity, result); } - for (ScenarioVerificationVariable variable : verifications.getVariables()) { - checkVariable(runScenario, processInstanceId, variable, result); + + /** + * Check to see if verificationActivity is correct or not + * + * @param runScenario scenario to pilot the verification + * @param processInstanceId ProcessInstanceId to check + * @param verificationActivity activity to check + * @param result the result object + */ + private void checkTask(RunScenario runScenario, + String processInstanceId, + ScenarioVerificationTask verificationActivity, + RunResult result) { + try { + StringBuilder message = new StringBuilder(); + + List<BpmnEngine.TaskDescription> listTaskDescriptions = runScenario.getBpmnEngine() + .searchTasksByProcessInstanceId(processInstanceId, verificationActivity.taskId, 100); + message.append("CheckTask: PID["); + message.append(processInstanceId); + message.append("] VerifTaskName["); + message.append(verificationActivity.taskId); + + // Does a type is expected? + if (verificationActivity.getType() != null) { + message.append("] type["); + message.append(verificationActivity.getType()); + listTaskDescriptions = listTaskDescriptions.stream() + .filter(t -> (verificationActivity.getType().toString().equalsIgnoreCase(t.type.toString()))) // + .toList(); + } + + // Does a state is expected? + if (verificationActivity.state != null) { + message.append("] State["); + message.append(verificationActivity.state); + listTaskDescriptions = listTaskDescriptions.stream() + .filter(t -> ((t.isCompleted && ScenarioVerificationTask.StepState.COMPLETED.toString() + .equals(verificationActivity.state.toString())) || (!t.isCompleted + && ScenarioVerificationTask.StepState.ACTIVE.toString().equals(verificationActivity.state.toString())))) + .toList(); + } + + // Now, check the result + + boolean isSuccess = listTaskDescriptions.size() == verificationActivity.getNumberOfTasks(); + + message.append("] NumberExpectedTask: "); + message.append(verificationActivity.getNumberOfTasks()); + message.append(" Found: "); + message.append(listTaskDescriptions.size()); + message.append(" status: "); + message.append(isSuccess); + result.addVerification(verificationActivity, isSuccess, message.toString()); + + if (runScenario.getRunParameters().showLevelMonitoring()) + logger.info("ScnScenarioVerification.CheckActivity [{}] Success {} - {} ", verificationActivity.getTaskId(), + isSuccess, message); + } catch (AutomatorException e) { + result.addVerification(verificationActivity, false, "Error " + e.getMessage()); + } + } - return result; - - } - - /** - * Check to see if verificationActivity is correct or not - * - * @param runScenario scenario to pilot the verification - * @param processInstanceId ProcessInstanceId to check - * @param verificationActivity activity to check - * @param result the result object - */ - private void checkTask(RunScenario runScenario, - String processInstanceId, - ScenarioVerificationTask verificationActivity, - RunResult result) { - - try { - StringBuilder message = new StringBuilder(); - - List<BpmnEngine.TaskDescription> listTaskDescriptions = runScenario.getBpmnEngine() - .searchTasksByProcessInstanceId(processInstanceId, verificationActivity.taskId, 100); - if (listTaskDescriptions.size() != verificationActivity.getNumberOfTasks()) { - message.append("CheckTask: FAILED_NOTASK Search Task PID["); - message.append(processInstanceId); - message.append("] expected Task Name["); - message.append(verificationActivity.taskId); - message.append("] Number of tasks expected: "); - message.append(verificationActivity.getNumberOfTasks()); - message.append(", found "); - message.append(listTaskDescriptions.size()); - } - // check the type for each taskDescription - List<BpmnEngine.TaskDescription> listNotExpected = listTaskDescriptions.stream() - .filter(t -> !(verificationActivity.getType() != null && verificationActivity.getType() - .toString() - .equalsIgnoreCase(t.type.toString()))) - .filter(t -> ((t.isCompleted && ScenarioVerificationTask.StepState.COMPLETED.toString() - .equals(verificationActivity.state.toString())) || (!t.isCompleted - && ScenarioVerificationTask.StepState.ACTIVE.toString().equals(verificationActivity.state.toString())))) - .toList(); - if (!listNotExpected.isEmpty()) { - message.append("CheckTask: FAILED_BADTYPE PID["); - message.append(processInstanceId); - message.append("] Task["); - message.append(verificationActivity.taskId); - message.append("] type expected ["); - message.append(verificationActivity.type.toString()); - message.append("] FAILED, received "); - message.append(listNotExpected.stream().map(t -> t.taskId + ":" + t.type.toString()).toList()); - } - result.addVerification(verificationActivity, message.isEmpty(), message.toString()); - - if (runScenario.getRunParameters().showLevelDebug()) - logger.info("ScnScenarioVerification.CheckActivity [{}] Success {} ", verificationActivity.getTaskId(), - message.isEmpty() + " - " + message); - } catch (AutomatorException e) { - result.addVerification(verificationActivity, false, "Error " + e.getMessage()); + + private void checkVariable(RunScenario runScenario, + String processInstanceId, + ScenarioVerificationVariable verificationActivity, + RunResult result) { + try { + StringBuilder message = new StringBuilder(); + + Map<String, Object> variables = runScenario.getBpmnEngine().getVariables(processInstanceId); + message.append("CheckVariable: PID["); + message.append(processInstanceId); + message.append("] ExpectVariable["); + message.append(verificationActivity.name); + message.append("] ExpectedValue["); + message.append(verificationActivity.value); + + boolean isSuccess = false; + if (variables.containsKey(verificationActivity.name)) { + Object value = variables.get(verificationActivity.name); + message.append("] value["); + message.append(value); + if (value == null && verificationActivity.value == null) + isSuccess = true; + else if (value == null || verificationActivity.value == null) { + isSuccess = false; + } else { + // None of them is null here + isSuccess = value.toString().equals(verificationActivity.value.toString()); + } + } else + isSuccess = false; + + message.append("] status: "); + message.append(isSuccess); + + result.addVerification(verificationActivity, isSuccess, message.toString()); + + if (runScenario.getRunParameters().showLevelDebug()) + logger.info("ScnScenarioVerification.CheckVariable [{}] Success {} - {} ", verificationActivity.name, + isSuccess, message); + } catch (AutomatorException e) { + result.addVerification(verificationActivity, false, "Error " + e.getMessage()); + } } - } - private void checkVariable(RunScenario runScenario, - String processInstanceId, - ScenarioVerificationVariable activity, - RunResult result) { - } + /** + * checkPerformance + * + * @param runScenario scenario to check + * @param processInstanceId processInstanceId + * @param verificationActivity verificationActivity + * @param result complete the result + */ + private void checkPerformance(RunScenario runScenario, + String processInstanceId, + ScenarioVerificationPerformance verificationActivity, + RunResult result) { + try { + StringBuilder message = new StringBuilder(); + + List<BpmnEngine.TaskDescription> listTaskDescriptions = runScenario.getBpmnEngine() + .searchTasksByProcessInstanceId(processInstanceId, null, 100); + message.append("CheckPerformance: PID["); + message.append(processInstanceId); + message.append(" :"); + message.append(verificationActivity.getSynthesis()); + + Optional<BpmnEngine.TaskDescription> taskFrom = listTaskDescriptions.stream().filter(t -> (t.taskId.equals(verificationActivity.fromFlowNode))).findFirst(); + Optional<BpmnEngine.TaskDescription> taskTo = listTaskDescriptions.stream().filter(t -> (t.taskId.equals(verificationActivity.toFlowNode))).findFirst(); + + boolean isSuccess = true; + + if (!taskFrom.isPresent() || !taskTo.isPresent()) { + isSuccess = false; + message.append("Missing task: From [" + taskFrom.isPresent() + "] To [" + taskTo.isPresent() + "]"); + } else { + Date dateFrom = verificationActivity.getFromMarker() == ScenarioVerificationPerformance.Marker.BEGIN ? taskFrom.get().startDate : taskFrom.get().endDate; + Date endFrom = verificationActivity.getToMarker() == ScenarioVerificationPerformance.Marker.BEGIN ? taskTo.get().startDate : taskTo.get().endDate; + long durationExecution = Math.abs(endFrom.getTime() - dateFrom.getTime()); + + isSuccess = durationExecution < verificationActivity.getDurationInMs(); + message.append("ExpectExecution(ms): "); + message.append(verificationActivity.getDurationInMs()); + message.append(" Execution(ms): "); + message.append(durationExecution); + } + message.append(" status: "); + message.append(isSuccess); + + result.addVerification(verificationActivity, isSuccess, message.toString()); + + if (runScenario.getRunParameters().showLevelMonitoring()) + logger.info("ScnScenarioVerification.CheckActivity [{}] Success {} - {} ", verificationActivity.getSynthesis(), + isSuccess, message); + } catch (AutomatorException e) { + result.addVerification(verificationActivity, false, "Error " + e.getMessage()); + } + } + } diff --git a/src/main/java/org/camunda/automator/services/AutomatorStartup.java b/src/main/java/org/camunda/automator/services/AutomatorStartup.java index 2610063..bf189b7 100644 --- a/src/main/java/org/camunda/automator/services/AutomatorStartup.java +++ b/src/main/java/org/camunda/automator/services/AutomatorStartup.java @@ -20,254 +20,257 @@ import java.time.Instant; import java.util.ArrayList; import java.util.List; +import java.util.stream.Collectors; @Service public class AutomatorStartup { - static Logger logger = LoggerFactory.getLogger(AutomatorStartup.class); + static Logger logger = LoggerFactory.getLogger(AutomatorStartup.class); - @Autowired - ConfigurationStartup configurationStartup; + @Autowired + ConfigurationStartup configurationStartup; - @Autowired - AutomatorAPI automatorAPI; + @Autowired + AutomatorAPI automatorAPI; - @Autowired - AutomatorCLI automatorCLI; + @Autowired + AutomatorCLI automatorCLI; - @Autowired - BpmnEngineList engineConfiguration; + @Autowired + BpmnEngineList engineConfiguration; - @Autowired - ServiceAccess serviceAccess; + @Autowired + ServiceAccess serviceAccess; - @PostConstruct - public void init() { - if (AutomatorCLI.isRunningCLI) - return; + @PostConstruct + public void init() { + if (AutomatorCLI.isRunningCLI) + return; - logger.info("AutomatorStartup-start"); - AutomatorSetupRunnable automatorSetupRunnable = new AutomatorSetupRunnable(configurationStartup, automatorAPI, - automatorCLI, engineConfiguration); + logger.info("AutomatorStartup-start"); + AutomatorSetupRunnable automatorSetupRunnable = new AutomatorSetupRunnable(configurationStartup, automatorAPI, + automatorCLI, engineConfiguration); - // start the automator startup immediately, and Spring can continue to start the application - serviceAccess.getTaskScheduler("AutomatorSetup").schedule(automatorSetupRunnable, Instant.now()); + // start the automator startup immediately, and Spring can continue to start the application + serviceAccess.getTaskScheduler("AutomatorSetup").schedule(automatorSetupRunnable, Instant.now()); - } + } - private void runFixedWarmup() { - // Fixed Warmup - if (configurationStartup.getWarmingUpServer().getSeconds() > 30) { - logger.info("WarmupFixedTime: wait.... {} s", configurationStartup.getWarmingUpServer().getSeconds()); + private void runFixedWarmup() { + // Fixed Warmup + if (configurationStartup.getWarmingUpServer().getSeconds() > 30) { + logger.info("WarmupFixedTime: wait.... {} s", configurationStartup.getWarmingUpServer().getSeconds()); - try { - Thread.sleep(configurationStartup.getWarmingUpServer().toMillis()); - } catch (Exception e) { - // do nothing - } - logger.info("WarmupFixedTime: end"); - } - } - - /** - * Load all scenario. List of File or Resource - * - * @return list of scenario - */ - private List<Object> registerScenario() { - List<Object> scenarioList = new ArrayList<>(); - // File - if (configurationStartup.getScenarioFileAtStartup().isEmpty()) { - logger.info("No scenario [File] from variable {} given", configurationStartup.getScenarioFileAtStartupName()); - } else { - logger.info("Detect {} scenario [File] from variable [{}] ScenarioPath[{}]", - configurationStartup.getScenarioFileAtStartup().size(), configurationStartup.getScenarioFileAtStartupName(), - configurationStartup.scenarioPath); - - for (String scenarioFileName : configurationStartup.getScenarioFileAtStartup()) { - logger.info("Register scenario [File] [{}]", scenarioFileName); - - File scenarioFile = new File(configurationStartup.scenarioPath + "/" + scenarioFileName); - if (!scenarioFile.exists()) { - scenarioFile = new File(scenarioFileName); - } - if (!scenarioFile.exists()) { - logger.error("ScenarioFile: Can't find File [{}/{}] or [{}]", configurationStartup.scenarioPath, - scenarioFileName, scenarioFileName); - continue; - } - scenarioList.add(scenarioFile); - } - } - // Resource - if (configurationStartup.getScenarioResourceAtStartup().isEmpty()) { - logger.info("No scenario [Resource] from variable {} given", - configurationStartup.getScenarioResourceAtStartupName()); - } else { - logger.info("Detect {} scenario [Resource] from variable [{}]", - configurationStartup.getScenarioResourceAtStartup().size(), - configurationStartup.getScenarioResourceAtStartupName()); - - for (Resource resource : configurationStartup.getScenarioResourceAtStartup()) { - if (resource != null) { - logger.info("Load scenario [Resource] from [{}]", resource.getDescription()); - scenarioList.add(resource); + try { + Thread.sleep(configurationStartup.getWarmingUpServer().toMillis()); + } catch (Exception e) { + // do nothing + } + logger.info("WarmupFixedTime: end"); } - } } - return scenarioList; - } + /** + * Load all scenario. List of File or Resource + * + * @return list of scenario + */ + private List<Object> registerScenario() { + List<Object> scenarioList = new ArrayList<>(); + // File + if (configurationStartup.getScenarioFileAtStartup().isEmpty()) { + logger.info("No scenario [File] from variable {} given", configurationStartup.getScenarioFileAtStartupName()); + } else { + logger.info("Detect {} scenario [File] from variable [{}] ScenarioPath[{}]", + configurationStartup.getScenarioFileAtStartup().size(), configurationStartup.getScenarioFileAtStartupName(), + configurationStartup.scenarioPath); + + for (String scenarioFileName : configurationStartup.getScenarioFileAtStartup()) { + logger.info("Register scenario [File] [{}]", scenarioFileName); + + File scenarioFile = new File(configurationStartup.scenarioPath + "/" + scenarioFileName); + if (!scenarioFile.exists()) { + scenarioFile = new File(scenarioFileName); + } + if (!scenarioFile.exists()) { + logger.error("ScenarioFile: Can't find File [{}/{}] or [{}]", configurationStartup.scenarioPath, + scenarioFileName, scenarioFileName); + continue; + } + scenarioList.add(scenarioFile); + } + } + // Resource + if (configurationStartup.getScenarioResourceAtStartup().isEmpty()) { + logger.info("No scenario [Resource] from variable {} given", + configurationStartup.getScenarioResourceAtStartupName()); + } else { + List<Resource> scenarioResource = configurationStartup.getScenarioResourceAtStartup().stream() + .filter(t -> t != null) + .collect(Collectors.toList()); + + logger.info("Detect {} scenario [Resource] from variable [{}]", + scenarioResource.size(), + configurationStartup.getScenarioResourceAtStartupName()); + + for (Resource resource : scenarioResource) { + logger.info("Load scenario [Resource] from [{}]", resource.getDescription()); + scenarioList.add(resource); + } + } - /** - * AutomatorSetupRunnable - run in parallel - */ - class AutomatorSetupRunnable implements Runnable { + return scenarioList; + } - ConfigurationStartup configurationStartup; + /** + * AutomatorSetupRunnable - run in parallel + */ + class AutomatorSetupRunnable implements Runnable { - AutomatorAPI automatorAPI; + ConfigurationStartup configurationStartup; - AutomatorCLI automatorCLI; + AutomatorAPI automatorAPI; - BpmnEngineList engineConfiguration; + AutomatorCLI automatorCLI; - public AutomatorSetupRunnable(ConfigurationStartup configurationStartup, - AutomatorAPI automatorAPI, - AutomatorCLI automatorCLI, - BpmnEngineList engineConfiguration) { - this.configurationStartup = configurationStartup; - this.automatorAPI = automatorAPI; - this.automatorCLI = automatorCLI; - this.engineConfiguration = engineConfiguration; - } + BpmnEngineList engineConfiguration; - @Override - public void run() { - - RunParameters runParameters = new RunParameters(); - runParameters.setExecution(true) - .setServerName(configurationStartup.getServerName()) - .setLogLevel(configurationStartup.getLogLevelEnum()) - .setCreation(configurationStartup.isPolicyExecutionCreation()) - .setServiceTask(configurationStartup.isPolicyExecutionServiceTask()) - .setUserTask(configurationStartup.isPolicyExecutionUserTask()) - .setWarmingUp(configurationStartup.isPolicyExecutionWarmingUp()) - .setDeploymentProcess(configurationStartup.isPolicyDeployProcess()) - .setDeepTracking(configurationStartup.deepTracking()) - .setStartEventNbThreads(configurationStartup.getStartEventNbThreads()); - List<String> filterService = configurationStartup.getFilterService(); - if (filterService != null) { - runParameters.setFilterExecutionServiceTask(filterService); - } - - logger.info( - "AutomatorStartup parameters serverName[{}] warmingUp[{}] creation:[{}] serviceTask:[{}] userTask:[{}] ScenarioPath[{}] logLevel[{}] waitWarmingUpServer[{} s]", - runParameters.getServerName(), runParameters.isWarmingUp(), runParameters.isCreation(), - runParameters.isServiceTask(), runParameters.isUserTask(), configurationStartup.scenarioPath, - configurationStartup.logLevel, configurationStartup.getWarmingUpServer().toMillis() / 1000); - - try { - String currentPath = new java.io.File(".").getCanonicalPath(); - logger.info("Local Path[{}]", currentPath); - } catch (Exception e) { - logger.error("Can't access Local Path : {} ", e.getMessage()); - } - - runFixedWarmup(); - - // Load scenario - List<Object> scenarioList = registerScenario(); - - // now proceed all scenario - for (Object scenarioObject : scenarioList) { - Scenario scenario = null; - if (scenarioObject instanceof File scenarioFile) - try { - scenario = automatorAPI.loadFromFile(scenarioFile); - } catch (Exception e) { - logger.error("Error during accessing InputStream from File [{}]: {}", scenarioFile.getAbsolutePath(), - e.getMessage()); - } - else if (scenarioObject instanceof Resource scenarioResource) { - try { - scenario = automatorAPI.loadFromInputStream(scenarioResource.getInputStream(), - scenarioResource.getDescription()); - } catch (Exception e) { - logger.error("Error during accessing InputStream from resource [{}]: {}", scenarioResource.getDescription(), - e.getMessage()); - } + public AutomatorSetupRunnable(ConfigurationStartup configurationStartup, + AutomatorAPI automatorAPI, + AutomatorCLI automatorCLI, + BpmnEngineList engineConfiguration) { + this.configurationStartup = configurationStartup; + this.automatorAPI = automatorAPI; + this.automatorCLI = automatorCLI; + this.engineConfiguration = engineConfiguration; } - if (scenario == null) - continue; - logger.info("Start scenario [{}] on (1)ScenarioServerName[{}] (2)ConfigurationServerName[{}]", - scenario.getName(), scenario.getServerName(), runParameters.getServerName()); - - // BpmnEngine: find the correct one referenced in the scenario - int countEngineIsNotReady = 0; - BpmnEngine bpmnEngine = null; - boolean pleaseTryAgain; - String message = ""; - do { - pleaseTryAgain = false; - countEngineIsNotReady++; - try { - if (scenario.getServerName() != null && !scenario.getServerName().isEmpty()) { - message += "ScenarioServerName[" + scenario.getServerName() + "];"; - bpmnEngine = automatorAPI.getBpmnEngineFromScenario(scenario, engineConfiguration); - } else { - if (runParameters.getServerName() == null) - throw new AutomatorException("No Server define in configuration"); - message += "ConfigurationServerName[" + runParameters.getServerName() + "];"; - BpmnEngineList.BpmnServerDefinition serverDefinition = engineConfiguration.getByServerName( - runParameters.getServerName()); - if (serverDefinition == null) - throw new AutomatorException( - "Server [" + runParameters.getServerName() + "] does not exist in the list"); - - if (runParameters.showLevelMonitoring()) { - logger.info("Run scenario with Server {}", serverDefinition.getSynthesis()); - } - bpmnEngine = automatorAPI.getBpmnEngine(serverDefinition, true); - } - if (runParameters.showLevelDashboard()) { - logger.info("Scenario [{}] Connect to BpmnEngine {}", scenario.getName(), message); - } - if (!bpmnEngine.isReady()) { - bpmnEngine.connection(); + @Override + public void run() { + + RunParameters runParameters = new RunParameters(); + runParameters.setExecution(true) + .setServerName(configurationStartup.getServerName()) + .setLogLevel(configurationStartup.getLogLevelEnum()) + .setCreation(configurationStartup.isPolicyExecutionCreation()) + .setServiceTask(configurationStartup.isPolicyExecutionServiceTask()) + .setUserTask(configurationStartup.isPolicyExecutionUserTask()) + .setWarmingUp(configurationStartup.isPolicyExecutionWarmingUp()) + .setDeploymentProcess(configurationStartup.isPolicyDeployProcess()) + .setDeepTracking(configurationStartup.deepTracking()) + .setStartEventNbThreads(configurationStartup.getStartEventNbThreads()); + List<String> filterService = configurationStartup.getFilterService(); + if (filterService != null) { + runParameters.setFilterExecutionServiceTask(filterService); } - } catch (AutomatorException e) { - pleaseTryAgain = true; - message += "EXCEPT " + e.getMessage(); - } - if (pleaseTryAgain && countEngineIsNotReady < 10) { + logger.info( - "Scenario [{}] file[{}] No BPM ENGINE running [{}] tentative:{}/10. Sleep 30s. Scenario reference serverName[{}]", - message, countEngineIsNotReady, scenario.getName(), scenario.getName(), scenario.getServerName()); + "AutomatorStartup parameters serverName[{}] warmingUp[{}] creation:[{}] serviceTask:[{}] userTask:[{}] ScenarioPath[{}] logLevel[{}] waitWarmingUpServer[{} s]", + runParameters.getServerName(), runParameters.isWarmingUp(), runParameters.isCreation(), + runParameters.isServiceTask(), runParameters.isUserTask(), configurationStartup.scenarioPath, + configurationStartup.logLevel, configurationStartup.getWarmingUpServer().toMillis() / 1000); + try { - Thread.sleep(((long) 1000) * 30); - } catch (InterruptedException e) { - // nothing to do + String currentPath = new java.io.File(".").getCanonicalPath(); + logger.info("Local Path[{}]", currentPath); + } catch (Exception e) { + logger.error("Can't access Local Path : {} ", e.getMessage()); } - } - } while (pleaseTryAgain && countEngineIsNotReady < 10); - if (bpmnEngine == null) { - logger.error("Scenario [{}] file[{}] Server {} No BPM ENGINE running.", scenario.getName(), - scenario.getName(), message); - continue; - } + runFixedWarmup(); + + // Load scenario + List<Object> scenarioList = registerScenario(); + + // now proceed all scenario + for (Object scenarioObject : scenarioList) { + Scenario scenario = null; + if (scenarioObject instanceof File scenarioFile) + try { + scenario = automatorAPI.loadFromFile(scenarioFile); + } catch (Exception e) { + logger.error("Error during accessing InputStream from File [{}]: {}", scenarioFile.getAbsolutePath(), + e.getMessage()); + } + else if (scenarioObject instanceof Resource scenarioResource) { + try { + scenario = automatorAPI.loadFromInputStream(scenarioResource.getInputStream(), + scenarioResource.getDescription()); + } catch (Exception e) { + logger.error("Error during accessing InputStream from resource [{}]: {}", scenarioResource.getDescription(), + e.getMessage()); + } + } + if (scenario == null) + continue; + logger.info("Start scenario [{}] on (1)ScenarioServerName[{}] (2)ConfigurationServerName[{}]", + scenario.getName(), scenario.getServerName(), runParameters.getServerName()); + + // BpmnEngine: find the correct one referenced in the scenario + int countEngineIsNotReady = 0; + BpmnEngine bpmnEngine = null; + boolean pleaseTryAgain; + String message = ""; + do { + pleaseTryAgain = false; + countEngineIsNotReady++; + try { + if (scenario.getServerName() != null && !scenario.getServerName().isEmpty()) { + message += "ScenarioServerName[" + scenario.getServerName() + "];"; + bpmnEngine = automatorAPI.getBpmnEngineFromScenario(scenario, engineConfiguration); + } else { + if (runParameters.getServerName() == null) + throw new AutomatorException("No Server define in configuration"); + message += "ConfigurationServerName[" + runParameters.getServerName() + "];"; + BpmnEngineList.BpmnServerDefinition serverDefinition = engineConfiguration.getByServerName( + runParameters.getServerName()); + if (serverDefinition == null) + throw new AutomatorException( + "Server [" + runParameters.getServerName() + "] does not exist in the list"); + + if (runParameters.showLevelMonitoring()) { + logger.info("Run scenario with Server {}", serverDefinition.getSynthesis()); + } + bpmnEngine = automatorAPI.getBpmnEngine(serverDefinition, true); + } + if (runParameters.showLevelDashboard()) { + logger.info("Scenario [{}] Connect to BpmnEngine {}", scenario.getName(), message); + } + + if (!bpmnEngine.isReady()) { + bpmnEngine.connection(); + } + } catch (AutomatorException e) { + pleaseTryAgain = true; + message += "EXCEPT " + e.getMessage(); + } + if (pleaseTryAgain && countEngineIsNotReady < 10) { + logger.info( + "Scenario [{}] file[{}] No BPM ENGINE running [{}] tentative:{}/10. Sleep 30s. Scenario reference serverName[{}]", + message, countEngineIsNotReady, scenario.getName(), scenario.getName(), scenario.getServerName()); + try { + Thread.sleep(((long) 1000) * 30); + } catch (InterruptedException e) { + // nothing to do + } + } + } while (pleaseTryAgain && countEngineIsNotReady < 10); + + if (bpmnEngine == null) { + logger.error("Scenario [{}] file[{}] Server {} No BPM ENGINE running.", scenario.getName(), + scenario.getName(), message); + continue; + } + + bpmnEngine.turnHighFlowMode(true); + logger.info("Scenario [{}] file[{}] use BpmnEngine {}", scenario.getName(), scenario.getName(), + bpmnEngine.getSignature()); + RunResult scenarioExecutionResult = automatorAPI.executeScenario(bpmnEngine, runParameters, scenario); + logger.info("AutomatorStartup: end scenario [{}] in {} ms", scenario.getName(), + scenarioExecutionResult.getTimeExecution()); + bpmnEngine.turnHighFlowMode(false); - bpmnEngine.turnHighFlowMode(true); - logger.info("Scenario [{}] file[{}] use BpmnEngine {}", scenario.getName(), scenario.getName(), - bpmnEngine.getSignature()); - RunResult scenarioExecutionResult = automatorAPI.executeScenario(bpmnEngine, runParameters, scenario); - logger.info("AutomatorStartup: end scenario [{}] in {} ms", scenario.getName(), - scenarioExecutionResult.getTimeExecution()); - bpmnEngine.turnHighFlowMode(false); - - } + } + } } - } } diff --git a/src/main/java/org/camunda/automator/services/ServiceAccess.java b/src/main/java/org/camunda/automator/services/ServiceAccess.java index f529d35..08a9dbd 100644 --- a/src/main/java/org/camunda/automator/services/ServiceAccess.java +++ b/src/main/java/org/camunda/automator/services/ServiceAccess.java @@ -16,20 +16,20 @@ @Configuration public class ServiceAccess { - private final Logger logger = LoggerFactory.getLogger(ServiceAccess.class); - @Autowired - public ServiceDataOperation serviceDataOperation; - @Value("${scheduler.poolSize}") - private int schedulerPoolSize; + private final Logger logger = LoggerFactory.getLogger(ServiceAccess.class); + @Autowired + public ServiceDataOperation serviceDataOperation; + @Value("${scheduler.poolSize}") + private int schedulerPoolSize; - /** - * Executor to run everything that is scheduled (also @Scheduled) - */ - public TaskScheduler getTaskScheduler(String schedulerName) { - ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler(); - scheduler.setPoolSize(schedulerPoolSize); - scheduler.setThreadNamePrefix(schedulerName); - scheduler.initialize(); - return scheduler; - } + /** + * Executor to run everything that is scheduled (also @Scheduled) + */ + public TaskScheduler getTaskScheduler(String schedulerName) { + ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler(); + scheduler.setPoolSize(schedulerPoolSize); + scheduler.setThreadNamePrefix(schedulerName); + scheduler.initialize(); + return scheduler; + } } diff --git a/src/main/java/org/camunda/automator/services/ServiceDataOperation.java b/src/main/java/org/camunda/automator/services/ServiceDataOperation.java index dcfa511..80d2944 100644 --- a/src/main/java/org/camunda/automator/services/ServiceDataOperation.java +++ b/src/main/java/org/camunda/automator/services/ServiceDataOperation.java @@ -13,39 +13,39 @@ @Component public class ServiceDataOperation { - static Logger logger = LoggerFactory.getLogger(ServiceDataOperation.class); - - @Autowired - private List<DataOperation> listDataOperation; - - /** - * please use the getInstance() - */ - private ServiceDataOperation() { - } - - /** - * Execute the DataOperation - * - * @param value value to process - * @param runScenario scenario to get information - * @param context give context in the exception in case of error - * @param index when multiple worker does the same operation, this is the index - * @return the value calculated - * @throws AutomatorException in case of error - */ - public Object execute(String value, RunScenario runScenario, String context, int index) throws AutomatorException { - for (DataOperation dataOperation : listDataOperation) { - if (dataOperation.match(value)) { - if (runScenario.getRunParameters().showLevelDebug()) - logger.info("Execute {} value[{}]", dataOperation.getName(), value); - return dataOperation.execute(value, runScenario, index); - } - } + static Logger logger = LoggerFactory.getLogger(ServiceDataOperation.class); + + @Autowired + private List<DataOperation> listDataOperation; - String helpOperations = listDataOperation.stream().map(DataOperation::getHelp).collect(Collectors.joining(", ")); + /** + * please use the getInstance() + */ + private ServiceDataOperation() { + } - throw new AutomatorException(context + "No operation for [" + value + "] - operationExpected " + helpOperations); - } + /** + * Execute the DataOperation + * + * @param value value to process + * @param runScenario scenario to get information + * @param context give context in the exception in case of error + * @param index when multiple worker does the same operation, this is the index + * @return the value calculated + * @throws AutomatorException in case of error + */ + public Object execute(String value, RunScenario runScenario, String context, int index) throws AutomatorException { + for (DataOperation dataOperation : listDataOperation) { + if (dataOperation.match(value)) { + if (runScenario.getRunParameters().showLevelDebug()) + logger.info("Execute {} value[{}]", dataOperation.getName(), value); + return dataOperation.execute(value, runScenario, index); + } + } + + String helpOperations = listDataOperation.stream().map(DataOperation::getHelp).collect(Collectors.joining(", ")); + + throw new AutomatorException(context + "No operation for [" + value + "] - operationExpected " + helpOperations); + } } diff --git a/src/main/java/org/camunda/automator/services/dataoperation/DataOperation.java b/src/main/java/org/camunda/automator/services/dataoperation/DataOperation.java index ed8c3cc..7d17284 100644 --- a/src/main/java/org/camunda/automator/services/dataoperation/DataOperation.java +++ b/src/main/java/org/camunda/automator/services/dataoperation/DataOperation.java @@ -11,52 +11,52 @@ public abstract class DataOperation { - public abstract boolean match(String value); - - /** - * return the name of the operation - * - * @return name - */ - public abstract String getName(); - - /** - * @param value value from the function - * @param runScenario scenario to run - * @param index when multiple workers run the same operation, each worker has a uniq index - * @return the result of the operation - * @throws AutomatorException in case of error - */ - public abstract Object execute(String value, RunScenario runScenario, int index) throws AutomatorException; - - protected boolean matchFunction(String value, String function) { - return value.toUpperCase(Locale.ROOT).startsWith(function.toUpperCase(Locale.ROOT) + "("); - } - - protected List<String> extractArgument(String value, boolean resolveValue) throws AutomatorException { - List<String> listResult = new ArrayList<>(); - value = value.trim(); - // format is function(arg1, args2, arg3 - int pos = value.indexOf("("); - if (pos == -1 || !value.endsWith(")")) - throw new AutomatorException("Format must be function(args), received [" + value + "]"); - String args = value.substring(pos); - args = args.substring(1, args.length() - 1); - StringTokenizer st = new StringTokenizer(args, ","); - while (st.hasMoreTokens()) - listResult.add(st.nextToken()); - - // each args, if it start by a " or ', remove them - if (resolveValue) { - listResult = listResult.stream().map(t -> { - if (t.startsWith("\"") || t.startsWith("'")) - return t.substring(1, t.length() - 1); - else - return t; - }).collect(Collectors.toList()); + public abstract boolean match(String value); + + /** + * return the name of the operation + * + * @return name + */ + public abstract String getName(); + + /** + * @param value value from the function + * @param runScenario scenario to run + * @param index when multiple workers run the same operation, each worker has a uniq index + * @return the result of the operation + * @throws AutomatorException in case of error + */ + public abstract Object execute(String value, RunScenario runScenario, int index) throws AutomatorException; + + protected boolean matchFunction(String value, String function) { + return value.toUpperCase(Locale.ROOT).startsWith(function.toUpperCase(Locale.ROOT) + "("); } - return listResult; - } - public abstract String getHelp(); + protected List<String> extractArgument(String value, boolean resolveValue) throws AutomatorException { + List<String> listResult = new ArrayList<>(); + value = value.trim(); + // format is function(arg1, args2, arg3 + int pos = value.indexOf("("); + if (pos == -1 || !value.endsWith(")")) + throw new AutomatorException("Format must be function(args), received [" + value + "]"); + String args = value.substring(pos); + args = args.substring(1, args.length() - 1); + StringTokenizer st = new StringTokenizer(args, ","); + while (st.hasMoreTokens()) + listResult.add(st.nextToken()); + + // each args, if it start by a " or ', remove them + if (resolveValue) { + listResult = listResult.stream().map(t -> { + if (t.startsWith("\"") || t.startsWith("'")) + return t.substring(1, t.length() - 1); + else + return t; + }).collect(Collectors.toList()); + } + return listResult; + } + + public abstract String getHelp(); } diff --git a/src/main/java/org/camunda/automator/services/dataoperation/DataOperationGenerateList.java b/src/main/java/org/camunda/automator/services/dataoperation/DataOperationGenerateList.java index 0fe64fb..a6ffe81 100644 --- a/src/main/java/org/camunda/automator/services/dataoperation/DataOperationGenerateList.java +++ b/src/main/java/org/camunda/automator/services/dataoperation/DataOperationGenerateList.java @@ -12,38 +12,38 @@ @Component public class DataOperationGenerateList extends DataOperation { - Logger logger = LoggerFactory.getLogger(DataOperationGenerateList.class); - - @Override - public String getName() { - return "GenerateList"; - } - - @Override - public boolean match(String value) { - return matchFunction(value, "generaterandomlist"); - } - - @Override - public String getHelp() { - return "generaterandomlist(<sizeOfTheList-integer>)"; - } - - @Override - public Object execute(String value, RunScenario runScenario, int index) throws AutomatorException { - - List<String> args = extractArgument(value, true); - List<String> listValues = new ArrayList<>(); - try { - Integer sizeList = Integer.valueOf(args.get(0)); - for (int i = 0; i < sizeList; i++) { - listValues.add("I" + i); - } - } catch (Exception e) { - throw new AutomatorException( - "can't generate a list: second parameters must be a Integer[" + args + "] : " + e.getMessage()); + Logger logger = LoggerFactory.getLogger(DataOperationGenerateList.class); + @Override + public String getName() { + return "GenerateList"; + } + + @Override + public boolean match(String value) { + return matchFunction(value, "generaterandomlist"); + } + + @Override + public String getHelp() { + return "generaterandomlist(<sizeOfTheList-integer>)"; + } + + @Override + public Object execute(String value, RunScenario runScenario, int index) throws AutomatorException { + + List<String> args = extractArgument(value, true); + List<String> listValues = new ArrayList<>(); + try { + Integer sizeList = Integer.valueOf(args.get(0)); + for (int i = 0; i < sizeList; i++) { + listValues.add("I" + i); + } + } catch (Exception e) { + throw new AutomatorException( + "can't generate a list: second parameters must be a Integer[" + args + "] : " + e.getMessage()); + + } + return listValues; } - return listValues; - } } diff --git a/src/main/java/org/camunda/automator/services/dataoperation/DataOperationGenerateUniqueID.java b/src/main/java/org/camunda/automator/services/dataoperation/DataOperationGenerateUniqueID.java index 3833c1c..859a33f 100644 --- a/src/main/java/org/camunda/automator/services/dataoperation/DataOperationGenerateUniqueID.java +++ b/src/main/java/org/camunda/automator/services/dataoperation/DataOperationGenerateUniqueID.java @@ -11,35 +11,35 @@ @Component public class DataOperationGenerateUniqueID extends DataOperation { - private final long baseTimer = System.currentTimeMillis(); - private final Map<String, Long> mapUniqueId = new HashMap<>(); - - @Override - public String getName() { - return "GenerateUniqueId"; - } - - @Override - public boolean match(String value) { - return matchFunction(value, "generateuniqueid"); - } - - @Override - public String getHelp() { - return "generateuniqueid(<prefix-String>)"; - } - - @Override - public Object execute(String value, RunScenario runScenario, int index) throws AutomatorException { - List<String> args = extractArgument(value, true); - String prefix = args.get(0); - if (prefix == null) - prefix = "default"; - - Long uniqueId = mapUniqueId.getOrDefault(prefix, 0L); - uniqueId++; - mapUniqueId.put(prefix, uniqueId); - return index + "-" + uniqueId + "-" + baseTimer; - - } + private final long baseTimer = System.currentTimeMillis(); + private final Map<String, Long> mapUniqueId = new HashMap<>(); + + @Override + public String getName() { + return "GenerateUniqueId"; + } + + @Override + public boolean match(String value) { + return matchFunction(value, "generateuniqueid"); + } + + @Override + public String getHelp() { + return "generateuniqueid(<prefix-String>)"; + } + + @Override + public Object execute(String value, RunScenario runScenario, int index) throws AutomatorException { + List<String> args = extractArgument(value, true); + String prefix = args.get(0); + if (prefix == null) + prefix = "default"; + + Long uniqueId = mapUniqueId.getOrDefault(prefix, 0L); + uniqueId++; + mapUniqueId.put(prefix, uniqueId); + return index + "-" + uniqueId + "-" + baseTimer; + + } } diff --git a/src/main/java/org/camunda/automator/services/dataoperation/DataOperationLoadFile.java b/src/main/java/org/camunda/automator/services/dataoperation/DataOperationLoadFile.java index 1847d6a..e4fd652 100644 --- a/src/main/java/org/camunda/automator/services/dataoperation/DataOperationLoadFile.java +++ b/src/main/java/org/camunda/automator/services/dataoperation/DataOperationLoadFile.java @@ -12,42 +12,42 @@ @Component public class DataOperationLoadFile extends DataOperation { - @Override - public boolean match(String value) { - return matchFunction(value, "loadfile"); - } - - @Override - public String getName() { - return "LoadFile"; - } - - @Override - public String getHelp() { - return "loadfile(<CompletePathToTheFile>)"; - } - - @Override - public Object execute(String value, RunScenario runScenario, int index) throws AutomatorException { - File fileLoad = loadFile(value, runScenario); - - FileValue typedFileValue = Variables.fileValue(fileLoad.getName()).file(fileLoad) - // .mimeType("text/plain") - // .encoding("UTF-8") - .create(); - return typedFileValue; - - } - - private File loadFile(String value, RunScenario runScenario) throws AutomatorException { - List<String> args = extractArgument(value, true); - - if (args.size() != 1) { - throw new AutomatorException("Bad argument: loadfile(<fileName>)"); + @Override + public boolean match(String value) { + return matchFunction(value, "loadfile"); } - String formatArgs = args.get(0); - return ScenarioTool.loadFile(formatArgs, runScenario); + @Override + public String getName() { + return "LoadFile"; + } + + @Override + public String getHelp() { + return "loadfile(<CompletePathToTheFile>)"; + } - } + @Override + public Object execute(String value, RunScenario runScenario, int index) throws AutomatorException { + File fileLoad = loadFile(value, runScenario); + + FileValue typedFileValue = Variables.fileValue(fileLoad.getName()).file(fileLoad) + // .mimeType("text/plain") + // .encoding("UTF-8") + .create(); + return typedFileValue; + + } + + private File loadFile(String value, RunScenario runScenario) throws AutomatorException { + List<String> args = extractArgument(value, true); + + if (args.size() != 1) { + throw new AutomatorException("Bad argument: loadfile(<fileName>)"); + } + String formatArgs = args.get(0); + + return ScenarioTool.loadFile(formatArgs, runScenario); + + } } diff --git a/src/main/java/org/camunda/automator/services/dataoperation/DataOperationStringToDate.java b/src/main/java/org/camunda/automator/services/dataoperation/DataOperationStringToDate.java index c8ffbd6..4e332c6 100644 --- a/src/main/java/org/camunda/automator/services/dataoperation/DataOperationStringToDate.java +++ b/src/main/java/org/camunda/automator/services/dataoperation/DataOperationStringToDate.java @@ -17,64 +17,64 @@ @Component public class DataOperationStringToDate extends DataOperation { - public static final String FCT_LOCALDATETIME = "LOCALDATETIME"; - public static final String FCT_DATETIME = "DATETIME"; - public static final String FCT_DATE = "DATE"; - public static final String FCT_ZONEDATETIME = "ZONEDATETIME"; - public static final String FCT_LOCALDATE = "LOCALDATE"; - // visit https://docs.camunda.io/docs/components/modeler/bpmn/timer-events/#time-date - // 2019-10-01T12:00:00Z - public static final String ISO_8601_DATETIME_FORMAT = "yyyy-MM-dd'T'HH:mm:ss'Z'"; - public static final String ISO_8601_DATE_FORMAT = "yyyy-MM-dd"; + public static final String FCT_LOCALDATETIME = "LOCALDATETIME"; + public static final String FCT_DATETIME = "DATETIME"; + public static final String FCT_DATE = "DATE"; + public static final String FCT_ZONEDATETIME = "ZONEDATETIME"; + public static final String FCT_LOCALDATE = "LOCALDATE"; + // visit https://docs.camunda.io/docs/components/modeler/bpmn/timer-events/#time-date + // 2019-10-01T12:00:00Z + public static final String ISO_8601_DATETIME_FORMAT = "yyyy-MM-dd'T'HH:mm:ss'Z'"; + public static final String ISO_8601_DATE_FORMAT = "yyyy-MM-dd"; - @Override - public boolean match(String value) { - return matchFunction(value, "stringtodate"); - } + @Override + public boolean match(String value) { + return matchFunction(value, "stringtodate"); + } + + @Override + public String getName() { + return "StringToDate"; + } - @Override - public String getName() { - return "StringToDate"; - } + @Override + public String getHelp() { + return "stringtodate(" + FCT_LOCALDATETIME + "|" + FCT_DATETIME + "|" + FCT_DATE + "|" + FCT_ZONEDATETIME + "|" + + FCT_LOCALDATE + ", dateSt)"; + } - @Override - public String getHelp() { - return "stringtodate(" + FCT_LOCALDATETIME + "|" + FCT_DATETIME + "|" + FCT_DATE + "|" + FCT_ZONEDATETIME + "|" - + FCT_LOCALDATE + ", dateSt)"; - } + @Override + public Object execute(String value, RunScenario runScenario, int index) throws AutomatorException { + List<String> args = extractArgument(value, true); - @Override - public Object execute(String value, RunScenario runScenario, int index) throws AutomatorException { - List<String> args = extractArgument(value, true); + if (args.size() != 2) { + throw new AutomatorException("Bad argument: " + getHelp()); + } + String formatArgs = args.get(0).toUpperCase(Locale.ROOT); + String valueArgs = args.get(1); + try { + if (FCT_LOCALDATETIME.equals(formatArgs)) + return LocalDateTime.parse(valueArgs); - if (args.size() != 2) { - throw new AutomatorException("Bad argument: " + getHelp()); - } - String formatArgs = args.get(0).toUpperCase(Locale.ROOT); - String valueArgs = args.get(1); - try { - if (FCT_LOCALDATETIME.equals(formatArgs)) - return LocalDateTime.parse(valueArgs); + else if (FCT_DATETIME.equals(formatArgs)) { + SimpleDateFormat isoFormat = new SimpleDateFormat(ISO_8601_DATETIME_FORMAT); + return isoFormat.parse(valueArgs); // Date + } else if (FCT_DATE.equals(formatArgs)) { + SimpleDateFormat dateFormat = new SimpleDateFormat(ISO_8601_DATE_FORMAT); + dateFormat.setLenient(false); + dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); + return dateFormat.parse(valueArgs, new ParsePosition(0)); + } else if (FCT_ZONEDATETIME.equals(formatArgs)) { + DateTimeFormatter formatter = DateTimeFormatter.ofPattern(ISO_8601_DATETIME_FORMAT); + return ZonedDateTime.parse(valueArgs, formatter); + } else if (FCT_LOCALDATE.equals(formatArgs)) { + return LocalDate.parse(valueArgs, DateTimeFormatter.ofPattern(ISO_8601_DATE_FORMAT)); + } else + throw new AutomatorException("Unknown date formatter [" + formatArgs + "]"); + } catch (Exception e) { + throw new AutomatorException( + "parsing error function[" + formatArgs + "] value[" + valueArgs + "] : " + e.getMessage()); + } - else if (FCT_DATETIME.equals(formatArgs)) { - SimpleDateFormat isoFormat = new SimpleDateFormat(ISO_8601_DATETIME_FORMAT); - return isoFormat.parse(valueArgs); // Date - } else if (FCT_DATE.equals(formatArgs)) { - SimpleDateFormat dateFormat = new SimpleDateFormat(ISO_8601_DATE_FORMAT); - dateFormat.setLenient(false); - dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); - return dateFormat.parse(valueArgs, new ParsePosition(0)); - } else if (FCT_ZONEDATETIME.equals(formatArgs)) { - DateTimeFormatter formatter = DateTimeFormatter.ofPattern(ISO_8601_DATETIME_FORMAT); - return ZonedDateTime.parse(valueArgs, formatter); - } else if (FCT_LOCALDATE.equals(formatArgs)) { - return LocalDate.parse(valueArgs, DateTimeFormatter.ofPattern(ISO_8601_DATE_FORMAT)); - } else - throw new AutomatorException("Unknown date formatter [" + formatArgs + "]"); - } catch (Exception e) { - throw new AutomatorException( - "parsing error function[" + formatArgs + "] value[" + valueArgs + "] : " + e.getMessage()); } - - } } diff --git a/src/main/resources/application.yaml b/src/main/resources/application.yaml index c0a2aeb..61fe1d6 100644 --- a/src/main/resources/application.yaml +++ b/src/main/resources/application.yaml @@ -2,9 +2,12 @@ automator: scheduler: + content: + repositoryPath: "c:/temp/processautomator" + uploadPath: "C:/dev/intellij/community/process-execution-automator/doc/unittestscenario/resources" startup: # give the server to run all tests at startup. The name must be registered in the list of server after - serverName: + serverName: Camunda8Ruby scenarioPath: # list of scenario separate by ;