Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 81 additions & 17 deletions exercises/exercise-1.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,25 +23,60 @@ FHIR resources used in the DSF are formatted as XML. You can find them in the `t
When creating your own FHIR resources for DSF process plugins you also want to put them in a fitting subdirectory of `tutorial-process/src/main/resources/fhir`.

# Exercise 1 - Simple Process
In this exercise you will add functionality to a service task in the already existing process called `exampleorg_dicProcess` and learn how to start
processes in the DSF. The BPMN model for the `exampleorg_dicProcess` is located in `tutorial-process/src/main/resources/bpe`.

Documentation topics related to this exercise are [FHIR Task](https://dsf.dev/process-development/api-v2/fhir/task.html),
[The Process Plugin Definition](https://dsf.dev/process-development/api-v2/dsf/process-plugin-definition.html),
[Spring Integration](https://dsf.dev/process-development/api-v2/dsf/spring-framework-integration.html),
[Activities](https://dsf.dev/process-development/api-v2/dsf/activities.html),
[BPMN Process Execution](https://dsf.dev/process-development/api-v2/dsf/bpmn-process-execution.html),
[BPMN Process Variables](https://dsf.dev/process-development/api-v2/dsf/bpmn-process-variables.html),
[Accessing BPMN Process Variables](https://dsf.dev/process-development/api-v2/guides/accessing-bpmn-process-variables.html),
[Versions, Placeholders and URLs](https://dsf.dev/process-development/api-v2/dsf/versions-placeholders-urls.html)
and [Starting a Process via Task Resources](https://dsf.dev/process-development/api-v2/guides/starting-a-process-via-task-resources.html).
In this exercise you will wire up a Java service task to an already existing BPMN process and start it for the first time. The goal is simple: the process runs, your Java code executes, and a log message appears.

The BPMN model for the `exampleorg_dicProcess` is located in `tutorial-process/src/main/resources/bpe/dic-process.bpmn`.
The Java service task class you will fill in is `tutorial-process/src/main/java/org/tutorial/process/tutorial/service/DicTask.java`.

Solutions to this exercise are found on the branch `solutions/exercise-1`.

<details>
<summary>Background reading (documentation links for this exercise)</summary>

You do not need to read all of these before starting. Use them as a reference when something is unclear:

- [FHIR Task](https://dsf.dev/process-development/api-v2/fhir/task.html)
- [The Process Plugin Definition](https://dsf.dev/process-development/api-v2/dsf/process-plugin-definition.html)
- [Spring Integration](https://dsf.dev/process-development/api-v2/dsf/spring-framework-integration.html)
- [Activities](https://dsf.dev/process-development/api-v2/dsf/activities.html)
- [BPMN Process Execution](https://dsf.dev/process-development/api-v2/dsf/bpmn-process-execution.html)
- [BPMN Process Variables](https://dsf.dev/process-development/api-v2/dsf/bpmn-process-variables.html)
- [Accessing BPMN Process Variables](https://dsf.dev/process-development/api-v2/guides/accessing-bpmn-process-variables.html)
- [Versions, Placeholders and URLs](https://dsf.dev/process-development/api-v2/dsf/versions-placeholders-urls.html)
- [Starting a Process via Task Resources](https://dsf.dev/process-development/api-v2/guides/starting-a-process-via-task-resources.html)
</details>

## Exercise Tasks
1. Set the `DicTask` class as the service implementation of the appropriate service task within the `dic-process.bpmn` process model.
2. Register the `DicTask` class as a prototype bean in the `TutorialConfig` class.

**What:** Open `tutorial-process/src/main/resources/bpe/dic-process.bpmn` and set the `camunda:class` attribute on the `<bpmn:serviceTask>` element to the fully qualified class name of `DicTask`.
**Why:** Camunda needs to know which Java class to instantiate and call when it reaches this task during process execution.
**How it looks in XML:**
<details>
<summary>How it looks in XML?</summary>

```xml
<bpmn:serviceTask id="Activity_1tegofl" name="Dic Task"
camunda:class="org.tutorial.process.tutorial.service.DicTask">
```
The value follows the pattern `<package>.<ClassName>`, which matches the folder structure under `tutorial-process/src/main/java/`. If you use the **Camunda Modeler**, switch the task's implementation type to **"Java Class"** and enter the same fully qualified name in the field that appears.

</details>

<details>
<summary>What does the fully qualified class name look like in other processes?</summary>

For orientation: the `CosTask` class lives at `tutorial-process/src/main/java/org/tutorial/process/tutorial/service/CosTask.java`, so its fully qualified name is `org.tutorial.process.tutorial.service.CosTask`. `DicTask` sits in the same package.
</details>

2. Register the `DicTask` class as a prototype bean in the `TutorialConfig` class located at `tutorial-process/src/main/java/org/tutorial/process/tutorial/spring/config/TutorialConfig.java`.

<details>
<summary>Why prototype scope?</summary>

The DSF BPE engine creates a new instance of a service task class for every process execution. Spring's default scope is singleton, so we must explicitly declare the bean as `@Scope("prototype")` to prevent shared state between concurrent executions.
</details>

<details>
<summary>Don't know how to register prototype beans?</summary>

Expand All @@ -53,25 +88,54 @@ Solutions to this exercise are found on the branch `solutions/exercise-1`.
<details>
<summary>Don't know where to get a logger?</summary>

This project uses slf4j. So use `LoggerFactory` to get yourself a logger instance.
This project uses slf4j. Use `LoggerFactory` to get yourself a logger instance.
</details>

<details>
<summary>Can't find a way to get the start task?</summary>

The `execute` method provides a `Variables` instance. Try it through this one.
The `execute` method provides a `Variables` instance. It might provide a fitting method.
</details>

<details>
<summary>Don't know where to look for the identifier?</summary>

Take a look at the official [FHIR Task](https://hl7.org/fhir/R4/task.html) resource, find elements that have a recipient and maneuver your way to those elements using the right getters. Then test which of them has the correct value.

Try to navigate to the identifier value with the equivalent getters according to the following:
The FHIR Task resource has a `restriction` element that lists the allowed recipients. Its structure looks like this:

```xml
<Task>
<!-- ... other elements ... -->
<restriction>
<recipient>
<identifier>
<value value="dic.dsf.test"/> <!-- this is what we want -->
</identifier>
</recipient>
</restriction>
</Task>
```

Hint: Don't iterate over the list of all recipients. `getRecipientFirstRep()` is a HAPI convenience method that returns the first element of the recipient list. In practice a Task can have more than one recipient, but for this simple example there is always exactly one.
</details>

4. In order to start your process you need to either create a regular [Task](https://dsf.dev/process-development/api-v2/fhir/task.html) resource
or a [Draft Task Resource](https://dsf.dev/process-development/api-v2/dsf/draft-task-resources.html). Based on whether you would like
to use cURL or the DSF FHIR server's web interface for starting processes you can do one of the following
assignments (although we invite you to do both):

<details>

<summary>Special DSF FHIR Task Elements</summary>
FHIR Task that starts a DSF process have the following fields with special meaning:

| Element | Purpose |
|---|--------------------------------------------------------------------------------------------------------------------------------------------|
| `instantiatesCanonical` | Which process (and version) should be started. Points to the process URI defined in the `ActivityDefinition`. |
| `requester` / `restriction.recipient` | Who sends the request (requester) and to which organization it is addressed (recipient). Uses organization identifiers. |
| `input` (message-name) | Which BPMN Message Start Event should be triggered. The value must match the message name in the BPMN file (here: `startDicProcess`), and be defined as an expected input within the linked ActivityDefinition. |
</details>

* Create a [Task](https://dsf.dev/process-development/api-v2/fhir/task.html) resource in `tutorial-process/src/main/resources/fhir/example-task.xml` based on the [Task](https://dsf.dev/process-development/api-v2/fhir/task.html)
profile `tutorial-process/src/main/resources/fhir/StructureDefinition/task-start-dic-process.xml`.
You will need it to start your process via cURL.
Expand Down
30 changes: 17 additions & 13 deletions exercises/exercise-2.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,22 @@
___

# Exercise 2 - Environment Variables and Input Parameters
BPMN processes might require additional information during execution, e.g. for configuration purposes.
We will take a look at two possibilities on how to pass additional information to a BPMN process: Environment Variables and Input Parameters.
The goal of this exercise is to enhance the `exampleorg_dicProcess` by trying them both.
In both cases the information will be available in the `execute` method of your service class.

In order to solve this exercise, you should have solved the first exercise and read the topics on
[Environment Variables](https://dsf.dev/process-development/api-v2/dsf/environment-variables.html),
[Task Input Parameters](https://dsf.dev/process-development/api-v2/fhir/task.html#task-input-parameters),
[Accessing Task Resources During Execution](https://dsf.dev/process-development/api-v2/guides/accessing-task-resources-during-execution.html),
[Placeholders](https://dsf.dev/process-development/api-v2/dsf/versions-placeholders-urls.html) and
[Read Access Tag](https://dsf.dev/process-development/api-v2/dsf/read-access-tag.html).
In this exercise you will pass additional information into a running process in two different ways: via an **environment variable** (configured outside the process, at deployment time) and via a **FHIR Task Input Parameter** (supplied at the start of every process).

Both values will be accessible inside the `execute` method of your `DicTask` service class.

Solutions to this exercise are found on the branch `solutions/exercise-2`.

<details>
<summary>Background reading (documentation links for this exercise)</summary>

- [Environment Variables](https://dsf.dev/process-development/api-v2/dsf/environment-variables.html)
- [Task Input Parameters](https://dsf.dev/process-development/api-v2/fhir/task.html#task-input-parameters)
- [Accessing Task Resources During Execution](https://dsf.dev/process-development/api-v2/guides/accessing-task-resources-during-execution.html)
- [Placeholders](https://dsf.dev/process-development/api-v2/dsf/versions-placeholders-urls.html)
- [Read Access Tag](https://dsf.dev/process-development/api-v2/dsf/read-access-tag.html)
</details>


## Exercise Tasks
1. Add a new boolean variable to the `TutorialConfig` class. It will enable/disable logging and have its value injected from an environment variable. Add the annotation and specify the default value as `false`. You may freely choose a name for your environment variable here. Just make sure you follow the naming convention explained in [Environment Variables](https://dsf.dev/process-development/api-v2/dsf/environment-variables.html).
Expand Down Expand Up @@ -54,14 +56,16 @@ Solutions to this exercise are found on the branch `solutions/exercise-2`.
`tutorial-process/src/main/resources/fhir/ValueSet`.
</details>

7. Add a new input parameter of type `tutorial-input` with `Task.input.value[x]` as a `string` to the `task-start-dic-process.xml` [Task](https://dsf.dev/process-development/api-v2/fhir/task.html) profile.
7. Add a new input parameter of type `tutorial-input` with `Task.input.value[x]` as a `string` to the StructureDefinition profile file `tutorial-process/src/main/resources/fhir/StructureDefinition/task-start-dic-process.xml`.

> **Note:** The `task-start-dic-process.xml` exists both under the `StructureDefinition` and `Task` directories under `resources`. In terms of Object Oriented Programming, the StructureDefinition is the class and the Task resource is an instance.
<details>
<summary>Don't know how to add a new input parameter?</summary>

Check out [this guide](https://dsf.dev/process-development/api-v2/guides/adding-task-parameters-to-task-profiles.html).
</details>

8. `task-start-dic-process` and by extension the process `exampleorg_dicProcess` now requires additional FHIR resources. Make sure the return value for `TutorialProcessPluginDefinition#getFhirResourcesByProcessId` also includes the new [CodeSystem](https://dsf.dev/process-development/api-v2/fhir/codesystem.html) and [ValueSet](https://dsf.dev/process-development/api-v2/fhir/valueset.html) resources for the `exampleorg_dicProcess`.
8. Make sure the return value for `TutorialProcessPluginDefinition#getFhirResourcesByProcessId` also includes the new [CodeSystem](https://dsf.dev/process-development/api-v2/fhir/codesystem.html) and [ValueSet](https://dsf.dev/process-development/api-v2/fhir/valueset.html) resources for the `exampleorg_dicProcess`. The process `exampleorg_dicProcess` now requires these additional FHIR resources because `task-start-dic-process` references them — without registering them here, the DSF BPE server will reject the StructureDefinition (and thus process deployment) because it can't find the resources referenced in it.
9. Read the new input parameter in the `DicTask` class from the start [Task](https://dsf.dev/process-development/api-v2/fhir/task.html) and add the value to the log message from exercise 1.
<details>
<summary>Don't know how to get the input parameter?</summary>
Expand Down