Commits (3)
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
4. [Create Process](#create-process) 4. [Create Process](#create-process)
5. [Run Application (MAVEN)](#run-application-maven) 5. [Run Application (MAVEN)](#run-application-maven)
6. [Run Application (DOCKER)](#run-application-docker) 6. [Run Application (DOCKER)](#run-application-docker)
6. [How to use Application](#how-to-use-application) 7. [How to use Application](#how-to-use-application)
## Set up Application ## Set up Application
Camunda Spring Boot Application created with [Camunda Platform Initializr]. Camunda Spring Boot Application created with [Camunda Platform Initializr].
...@@ -43,7 +43,7 @@ Also added [GSON] dependency for parsing JSON objects to `pom.xml`. ...@@ -43,7 +43,7 @@ Also added [GSON] dependency for parsing JSON objects to `pom.xml`.
> **_INFO:_** Used version `2.8.4`, because other failed with spring boot. > **_INFO:_** Used version `2.8.4`, because other failed with spring boot.
### Additional Settings ### Additional Settings
Enabled process application to disables the `SpringProcessEngineConfiguration` auto-deploy feature. Enabled process application to disable the `SpringProcessEngineConfiguration` auto-deploy feature.
> **_INFO:_** Without `@EnableProcessApplication` using embedded forms always failed. > **_INFO:_** Without `@EnableProcessApplication` using embedded forms always failed.
```sh ```sh
...@@ -64,32 +64,32 @@ Got free [Alpha Vantage] API Key: ...@@ -64,32 +64,32 @@ Got free [Alpha Vantage] API Key:
## Create Process ## Create Process
Created camunda BPMN process as described in [BPT Moodle Course]. Created camunda BPMN process as described in [BPT Moodle Course].
- Start Event - Start Event `End of Month`
- End of month as manually triggered Start-Event - End of month as manually triggered Start-Event
- First User Task - First User Task `Set Company Name`
- User enters into a dialog (HTML form: [company_form.html]) a company name, of which their company own stocks. - User enters into a dialog (HTML form: [company_form.html]) a company name, of which their company own stocks.
- The step stores the name in a process variable `stock`. - The step stores the name in a process variable `stock`.
- First Service Task - First Service Task `Get Symbol`
- System queries a REST-WebService at https://www.alphavantage.co/query?function=SYMBOL_SEARCH&keywords=IBM&apikey=VPNHOQPE0AOJ8BEP - System queries a REST-WebService at https://www.alphavantage.co/query?function=SYMBOL_SEARCH&keywords=IBM&apikey=VPNHOQPE0AOJ8BEP
- The Search Endpoint for `stock`. - The Search Endpoint for `stock`.
- The step stores the resulting symbol in a process variable `symbol`. - The step stores the resulting symbol in a process variable `symbol`.
- Used the `Java Delegate` class for implementation. - Used the `Java Delegate` class for implementation.
- Connecting the delegate class [SymbolSearchDelegate.java] with the service task takes place selecting `Java Class` instead of `Expression` and entering the full classpath. - Connecting the delegate class [SymbolSearchDelegate.java] with the service task takes place selecting `Java Class` instead of `Expression` and entering the full classpath.
- Second Service Task - Second Service Task `Get Price and Change`
- System queries a REST-WebService at https://www.alphavantage.co/query?function=GLOBAL_QUOTE&symbol=IBM&apikey=VPNHOQPE0AOJ8BEP - System queries a REST-WebService at https://www.alphavantage.co/query?function=GLOBAL_QUOTE&symbol=IBM&apikey=VPNHOQPE0AOJ8BEP
- The Quote Endpoint stores the current price in a process variable `price` and the change in a process variable `change`. - The Quote Endpoint stores the current price in a process variable `price` and the change in a process variable `change`.
- Used the `Java Delegate` class for implementation. - Used the `Java Delegate` class for implementation.
- Connecting the delegate class [GlobalQuoteDelegate.java] with the service task takes place selecting `Java Class` instead of `Expression` and entering the full classpath. - Connecting the delegate class [GlobalQuoteDelegate.java] with the service task takes place selecting `Java Class` instead of `Expression` and entering the full classpath.
- Gateway - Gateway `Sell?`
- Gateway decides by price and change for a sell recommendation - Gateway decides by price and change for a sell recommendation
- if `price<1 and change negative`, the system should execute the second user task. - if `price<1 and change negative`, the system should execute the second user task.
- else, the system leads to second end event - else, the system leads to second end event
- Second User Task - Second User Task `Sell Stock`
- System displays to the user a dialog (HTML form: [sell_form.html]) with `symbol`, `price`, `change` and a button `Sell` and a button `Cancel`. - System displays to the user a dialog (HTML form: [sell_form.html]) with `symbol`, `price`, `change` and a button `Sell` and a button `Cancel`.
- There are no functions implemented for the buttons! - There are no functions implemented for the buttons!
- First End Event - First End Event `Stock sold`
- The process terminates. - The process terminates.
- Second End Event - Second End Event `Stock kept`
- The process terminates. - The process terminates.
- Set to `default` sequence flow. - Set to `default` sequence flow.
...@@ -230,4 +230,4 @@ OS/ARCH: `linux/amd64` ...@@ -230,4 +230,4 @@ OS/ARCH: `linux/amd64`
[disable-real-data]: assets/dummy-data_01_disable-real-data.png "disable real data" [disable-real-data]: assets/dummy-data_01_disable-real-data.png "disable real data"
[show-user-task-2]: assets/dummy-data_02_show-user-task2.png "show user task 2" [show-user-task-2]: assets/dummy-data_02_show-user-task2.png "show user task 2"
[complete-user-task-2]: assets/dummy-data_03_complete-user-task2.png "complete user task 2" [complete-user-task-2]: assets/dummy-data_03_complete-user-task2.png "complete user task 2"
[dummy-data-logs]: assets/dummy-data_04_logs.png "application dummy data logs" [dummy-data-logs]: assets/dummy-data_04_logs.png "application dummy data logs"
\ No newline at end of file
assets/dummy-data_04_logs.png

24.5 KB | W: | H:

assets/dummy-data_04_logs.png

28.5 KB | W: | H:

assets/dummy-data_04_logs.png
assets/dummy-data_04_logs.png
assets/dummy-data_04_logs.png
assets/dummy-data_04_logs.png
  • 2-up
  • Swipe
  • Onion skin
assets/real-data_09_logs.png

24.4 KB | W: | H:

assets/real-data_09_logs.png

29.9 KB | W: | H:

assets/real-data_09_logs.png
assets/real-data_09_logs.png
assets/real-data_09_logs.png
assets/real-data_09_logs.png
  • 2-up
  • Swipe
  • Onion skin
...@@ -27,8 +27,8 @@ public class GlobalQuoteDelegate implements JavaDelegate { ...@@ -27,8 +27,8 @@ public class GlobalQuoteDelegate implements JavaDelegate {
public void execute(DelegateExecution execution) throws Exception { public void execute(DelegateExecution execution) throws Exception {
// process variables // process variables
String stock_process = "stock"; String symbol_process = "symbol";
String stock_value = (String) execution.getVariable(stock_process); String symbol_value = (String) execution.getVariable(symbol_process);
String quote_value = ""; String quote_value = "";
String price_process = "price"; String price_process = "price";
String change_process = "change"; String change_process = "change";
...@@ -45,7 +45,7 @@ public class GlobalQuoteDelegate implements JavaDelegate { ...@@ -45,7 +45,7 @@ public class GlobalQuoteDelegate implements JavaDelegate {
// https://www.alphavantage.co/support/#api-key // https://www.alphavantage.co/support/#api-key
String key = "VPNHOQPE0AOJ8BEP"; String key = "VPNHOQPE0AOJ8BEP";
LOGGER.info("Processing request by '" + stock_value + "'..."); LOGGER.info("Processing request by '" + symbol_value + "'...");
// build GET Request // build GET Request
// GET https://www.alphavantage.co/query?function=GLOBAL_QUOTE&symbol=IBM&apikey=VPNHOQPE0AOJ8BEP // GET https://www.alphavantage.co/query?function=GLOBAL_QUOTE&symbol=IBM&apikey=VPNHOQPE0AOJ8BEP
...@@ -53,7 +53,7 @@ public class GlobalQuoteDelegate implements JavaDelegate { ...@@ -53,7 +53,7 @@ public class GlobalQuoteDelegate implements JavaDelegate {
String queryEndpoint = "query?function=GLOBAL_QUOTE&symbol="; String queryEndpoint = "query?function=GLOBAL_QUOTE&symbol=";
String apiKey = "&apikey=" + key; String apiKey = "&apikey=" + key;
String uri_string = apiURL + queryEndpoint + stock_value + apiKey; String uri_string = apiURL + queryEndpoint + symbol_value + apiKey;
// set HTTP Client // set HTTP Client
HttpClient vClient = HttpClient.newBuilder().connectTimeout(Duration.ofSeconds(20)) HttpClient vClient = HttpClient.newBuilder().connectTimeout(Duration.ofSeconds(20))
...@@ -140,7 +140,7 @@ public class GlobalQuoteDelegate implements JavaDelegate { ...@@ -140,7 +140,7 @@ public class GlobalQuoteDelegate implements JavaDelegate {
} else { } else {
// symbol item is null // symbol item is null
LOGGER.info("JSON is empty... Sorry your Key is just for demo purposes. Use symbol=\"IBM\" instead!"); LOGGER.info("JSON is empty...");
LOGGER.info(quote_value); LOGGER.info(quote_value);
} }
} }
......
...@@ -12,6 +12,11 @@ import java.time.Duration; ...@@ -12,6 +12,11 @@ import java.time.Duration;
import java.util.logging.Logger; import java.util.logging.Logger;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.gson.JsonArray;
import org.camunda.bpm.engine.delegate.DelegateExecution; import org.camunda.bpm.engine.delegate.DelegateExecution;
import org.camunda.bpm.engine.delegate.JavaDelegate; import org.camunda.bpm.engine.delegate.JavaDelegate;
...@@ -23,10 +28,12 @@ public class SymbolSearchDelegate implements JavaDelegate { ...@@ -23,10 +28,12 @@ public class SymbolSearchDelegate implements JavaDelegate {
public void execute(DelegateExecution execution) throws Exception { public void execute(DelegateExecution execution) throws Exception {
// process variables // process variables
//String stock_process = "stock"; String stock_process = "stock";
String stock_value = (String) execution.getVariable("stock"); String stock_value = (String) execution.getVariable(stock_process);
String symbol_process = "symbol"; String symbol_process = "symbol";
String symbol_value = ""; String symbol_value = "";
String name_process = "name";
String name_value = "";
// set alphavantage key here // set alphavantage key here
// https://www.alphavantage.co/support/#api-key // https://www.alphavantage.co/support/#api-key
...@@ -67,15 +74,84 @@ public class SymbolSearchDelegate implements JavaDelegate { ...@@ -67,15 +74,84 @@ public class SymbolSearchDelegate implements JavaDelegate {
// requested resource is available (200) // requested resource is available (200)
// get symbol value from REST API // get symbol resonse from REST API -> save to best matches string
symbol_value = vResponse.body(); String best_matches = vResponse.body();
// set symbol value to process variable /* parse SYMBOL_SEARCH JSON
execution.setVariable(symbol_process, symbol_value);
Example:
// log success and symbol value
LOGGER.info("HttpServletResponse succeed...");
//LOGGER.info("Set variable symbol = " + symbol_value); {
"bestMatches": [
{
"1. symbol": "IBM",
"2. name": "International Business Machines Corp",
"3. type": "Equity",
"4. region": "United States",
"5. marketOpen": "09:30",
"6. marketClose": "16:00",
"7. timezone": "UTC-04",
"8. currency": "USD",
"9. matchScore": "1.0000"
},
{
...
}
}
*/
// parse JSON object
JsonParser jsonParser = new JsonParser();
JsonElement jsonTree = jsonParser.parse(best_matches);
if(jsonTree.isJsonObject()) {
JsonObject jsonObject = jsonTree.getAsJsonObject();
//LOGGER.info("jsonObject=" + jsonObject);
JsonElement best_maches_element = jsonObject.get("bestMatches");
//LOGGER.info("best_maches_element=" + best_maches_element);
if(best_maches_element.isJsonArray()){
// get json object (bestMatches) as json array
JsonArray symbol_array = best_maches_element.getAsJsonArray();
//LOGGER.info("JSON Parser: symbol_array=" + symbol_array);
// get first array item as json object
JsonObject symbol_json_object = symbol_array.get(0).getAsJsonObject();
//LOGGER.info("JSON Parser: symbol_json_object=" + symbol_json_object);
// get symbol value from REST API
symbol_value = symbol_json_object.get("1. symbol").getAsString();
LOGGER.info("JSON Parser: symbol=" + symbol_value);
// get company name value from REST API
name_value = symbol_json_object.get("2. name").getAsString();
LOGGER.info("JSON Parser: name=" + name_value);
// set symbol value to process variable
execution.setVariable(symbol_process, symbol_value);
// set company name value to process variable
execution.setVariable(name_process, name_value);
// log success and symbol value
LOGGER.info("HttpServletResponse succeed...");
} else {
// not a json array
LOGGER.info("NOT a JSON Array...");
LOGGER.info(best_maches_element.toString());
}
} else {
// quote_value is not a JSON object
LOGGER.info("JSON Parser failed...");
LOGGER.info("Not a JSON Object");
LOGGER.info(best_matches);
}
} }
} catch (IOException | InterruptedException e) { } catch (IOException | InterruptedException e) {
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<div class="form-group"> <div class="form-group">
<label for="symbol">Company Name</label> <label for="symbol">Company Name</label>
<input id="symbol" required <input id="symbol" required
cam-variable-name="stock" cam-variable-name="name"
cam-variable-type="String" cam-variable-type="String"
class="form-control"><br> class="form-control"><br>
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<div class="form-group"> <div class="form-group">
<label for="symbol">Company Name</label> <label for="symbol">Company Name</label>
<input id="symbol" required <input id="symbol" required
cam-variable-name="stock" cam-variable-name="name"
cam-variable-type="String" cam-variable-type="String"
class="form-control"><br> class="form-control"><br>
......
#Generated by Maven #Generated by Maven
#Tue Nov 23 02:26:49 CET 2021 #Wed Dec 01 00:32:44 CET 2021
groupId=de.kebidge.camunda groupId=de.kebidge.camunda
artifactId=stock-asset-review artifactId=stock-asset-review
version=1.0.0-SNAPSHOT version=1.0.0-SNAPSHOT