# Use o poder do Java no DMN

<p align="right">Credits to: <img src="/files/3Hh0PbPrTzaRah8cbwGi" alt="" data-size="line"></p>

### Modelação de Decisões com **DMN**

Esta secção inclui laboratórios para te ajudar a familiarizar-te com a automatização de decisões utilizando o padrão **DMN** e a linguagem de expressões **FEEL**.

As instruções dos guias propõem-te tarefas de automatização com objetivos específicos. Deves explorar o **Kogito** e o **Quarkus**, desenvolver, testar e executar os cenários de decisão.

{% hint style="info" %} <img src="/files/87pEYtFGUUaxxe2m0fIH" alt="" data-size="line">

**Alguns exercícios foram inspirados em exemplos do livro** [*<mark style="color:blue;">**DMN Cookbook**</mark>*](https://www.amazon.com/dp/0982368186) **e nos exemplos gratuitos disponibilizados com o mesmo.**
{% endhint %}

### **Usa o poder do Java no DMN**

O DMN permite que utilizadores ao nível do negócio criem a maior parte dos diagramas de decisão e da sua lógica central. Uma das grandes vantagens desta especificação é que **não está limitada a um único perfil de utilizador**, promovendo a colaboração com equipas técnicas.

Uma prática comum é a utilização de lógica desacoplada e funções reutilizáveis, onde o analista delega, quando necessário, parte da implementação da lógica a um programador — por exemplo, usando um **BKM (Business Knowledge Model)** para realizar uma operação.

A linguagem **FEEL (Friendly Enough Expression Language)** oferece várias operações para suportar a implementação da lógica. Por outro lado, também temos à disposição as extensas funcionalidades das classes Java para suportar a execução da lógica. Neste laboratório, vais praticar como usar o nó BKM em conjunto com o poder das classes Java e os seus métodos para suportar decisões DMN.

Vai começar por criar um **DMN básico** e alguns **testes unitários**. O objetivo pode ser alcançado de diferentes formas, mas, para este exercício, deverá criar a lógica utilizando um **método da classe String do Java**.

***

### **Objetivo**

A tua decisão deve ser capaz de receber uma **lista de strings** e devolver uma **única string concatenada**, separada por vírgulas ",".

Por exemplo:\
Entrada: `["John Doe", "Ash"]`\
Saída: `"John Doe, Ash"`

### **Criação do Projeto**

O primeiro passo é criar um projeto para conter as tuas decisões. Vamos usar **Kogito** e **Quarkus** para tirar partido das capacidades de geração automática de código.

Cria uma nova aplicação Quarkus usando o arquétipo Quarkus. Certifica-te de que adicionas:

* Extensão **Kogito Decision** para capacidades de execução de decisões;
* **Quarkus Smallrye OpenAPI** para permitir o uso do Swagger e facilitar a interação REST via interface gráfica;
* **Kogito Scenario Simulation** para permitir o uso de cenários de teste (`scesim`) no teu serviço;
* ```shell
  mvn io.quarkus.platform:quarkus-maven-plugin:2.8.2.Final:create \
      -DprojectGroupId=org.acme \
      -DprojectArtifactId=practicing-dmn-lab03 \
      -Dextensions="kogito-quarkus-decisions,quarkus-smallrye-openapi,quarkus-resteasy-jackson" \
      -DnoCode
  ```

### **Definição básica do Diagrama de Decisão**

1. Cria uma nova decisão em `src/main/resources/DecisionWithJava.dmn`.
2. Nos **Tipos de Dados** da tua decisão, adiciona uma nova lista de strings com o nome `tNameList`.

{% hint style="info" %} <img src="/files/wmqi1MayT2ojSPXEqOnQ" alt="" data-size="line">

Ao adicionares o novo tipo, seleciona Tipo `String` e certifica-te de que clicas no seletor de lista para o categorizar como um tipo de lista.
{% endhint %}

3. No editor, arrasta e larga um nó de entrada e chama-o **`Names`**;
4. Configura o input **Names** com o tipo de dados `tNameList`;
5. Adiciona um nó de decisão chamado **Final Name** com tipo de dados `string`.

> Agora, antes de implementar a lógica, cria um teste unitário> \
> Vamos usar um cenário de teste para implementar testes unitários para esta decisão.

### Comece pelos testes

Ao desenvolver uma decisão, uma forma de verificar se está a funcionar é iniciar o seu serviço **Quarkus** em modo de desenvolvimento (`mvn quarkus:dev`) e invocar o respetivo **endpoint REST**, passando uma entrada e observando a saída, até estar satisfeito. Quando o resultado corresponder ao esperado, pode avançar e começar a escrever o **teste unitário**.

Outra abordagem é começar logo pelos **testes unitários**, validando o maior número possível de entradas válidas e inválidas, bem como os resultados da execução. Assim que o teste estiver concluído, implementa a sua decisão e verifica a validade através de testes automatizados. Com esta abordagem, quando conseguir executar os testes com sucesso, terá concluído tanto a **implementação** como o respetivo **teste unitário**.

{% hint style="info" %} <img src="/files/wmqi1MayT2ojSPXEqOnQ" alt="" data-size="line">

Para saber mais sobre as práticas de **Test Driven Development (TDD)**, consulte o **Manifesto TDD**.
{% endhint %}

2. Abra o ficheiro **pom.xml** e adicione a dependência da biblioteca **test scenario**, para que possamos utilizar as funcionalidades de **Test Scenario**.

```xml
<dependency>
  <groupId>org.kie.kogito</groupId>
  <artifactId>kogito-scenario-simulation</artifactId>
  <scope>test</scope>
</dependency>
```

3. Adicione duas novas estruturas de diretórios de teste:

* `src/test/resources`
* `src/test/java/testscenario`

4. Crie uma nova **classe Java** que permitirá que os nossos cenários de teste façam parte do **ciclo de testes do Maven** dentro do âmbito do **JUnit**.  No diretório `src/main/java/testscenario`, adicione a nova classe Java **KogitoScenarioJunitActivatorTest.java** com o seguinte conteúdo:

```java
package testscenario;

/**
 * KogitoJunitActivator is a custom JUnit runner that enables the execution of Test Scenario files (*.scesim).
 * This activator class, when executed, will load all scesim files available in the project and run them.
 * Each row of the scenario will generate a test JUnit result.
 */
@org.junit.runner.RunWith(org.kogito.scenariosimulation.runner.KogitoJunitActivator.class)
public class KogitoScenarioJunitActivatorTest {
}
```

5. Agora, em `src/test/resources/`, adicione um novo **Test Scenario** chamado **DecisionWithJavaTest.scesim**.
6. A decisão deverá receber um **Array de Strings** e devolver uma **String** resultante da concatenação de todos os elementos.
7. Quando abrir o novo ficheiro de cenário de teste (caso tenha instalada a extensão **Red Hat Business Automation Bundle** no VSCode), deverá conseguir escolher **DMN** e selecionar o seu ficheiro DMN na lista de decisões disponíveis.
8. Clique em **Create** quando terminar. O cenário de teste já deverá estar configurado utilizando as **Entradas e Saídas** do ficheiro de decisão que selecionou.

***

#### 9. Adicione os seguintes cenários de validação:

* Deve devolver uma **String vazia** para uma lista com zero elementos (ex.: `""`).
* Deve devolver uma **String** para uma lista com um elemento (string). (ex.: `"Karina"`)
* Deve devolver uma **String com palavras separadas por vírgula** para uma lista com dois elementos (ex.: `"Karina,Varela"`).

Veja abaixo algumas dicas sobre a configuração da lista de entradas fornecidas e a implementação final do teste:

* Lista de entrada configurada com o formulário guiado **"Create List"**.

{% hint style="info" %} <img src="/files/wmqi1MayT2ojSPXEqOnQ" alt="" data-size="line">

Também pode usar a opção **"Define List"**, com um valor como `["John Doe","Ash"]`.
{% endhint %}

<figure><img src="/files/AyodAAclbPmRBpK2R0d0" alt=""><figcaption></figcaption></figure>

* Exemplo de cenário de teste:

<figure><img src="/files/Cs068psg86c1EYGxeuSW" alt=""><figcaption></figcaption></figure>

Se abrir o seu projeto numa **linha de comandos** e executar os testes utilizando o **Maven**, deverá conseguir ver os testes que falharam. Algo semelhante a:

```shell
$ mvn test
(...)

[INFO]
[INFO] Results:
[INFO]
[ERROR] Errors:
[ERROR]   #1 Should return an empty string for empty list: Failure reason: The decision Final Name has not been successfully evaluated: SKIPPED (DecisionWithJavaTest)
[ERROR]   #2 Should return a string for one element list: Failure reason: The decision Final Name has not been successfully evaluated: SKIPPED (DecisionWithJavaTest)
[ERROR]   #3 Should return string with the concatenated elements separated by comma: Failure reason: The decision Final Name has not been successfully evaluated: SKIPPED (DecisionWithJavaTest)
[INFO]
[ERROR] Tests run: 3, Failures: 0, Errors: 3, Skipped: 0
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
```

#### Implementação da Lógica da Decisão

Com o projeto, um **DMN básico** e alguns **testes unitários**, já temos uma boa estrutura de base para começar a programar a nossa lógica de decisão.

O mesmo resultado poderia ser obtido de várias formas, mas, para este exercício, deverá criar a lógica utilizando a **classe Java String**.

***

#### Objetivos

Corrigir o **DecisionWithJava.dmn** para **concatenar a lista de strings recebida** e devolver uma única **String**.

A saída da decisão deve ser uma **string única** contendo todas as strings da lista, separadas por um espaço.\
Exemplo: `["John","Doe","Ash"]` → `"John Doe Ash"`

***

#### O que deve fazer na sua solução:

1. O nó de decisão **Final Name** deve depender de um **BKM Node**: isto irá desacoplar e externalizar os aspetos técnicos da implementação da lógica de decisão.
2. Ao invocar a solução fornecida pelo **BKM**, o nó de decisão **Final Name** deve enviar a lista **Names** e **" "** (um espaço) como delimitador a ser usado na concatenação da lista de strings.
3. Utilize a classe **java.lang.String**.
   * Esta possui o método estático **`join`**, que pode ser útil.
   * Este método espera, de forma simples, dois parâmetros: o **delimitador** usado entre os elementos concatenados e uma **lista**.

***

#### Antes de ver as dicas abaixo, tente implementar e ajustar a sua decisão até que todos os testes passem com sucesso.

***

#### Dicas de Solução

* Utilize um **Business Knowledge Model (BKM) node** para criar a lógica reutilizável que será invocada pelo nó de decisão **Final Name**.
* O BKM deve ser do tipo **Function**, e o **Function Kind** deve ser **Java (J)**.
* Adicione dois parâmetros:
  * **delimiter** (tipo *string*)
  * **names list** (tipo *tNamesList*)\
    Estes parâmetros serão enviados pelo nó que invoca o BKM e usados como entrada no método Java.
* Configure a classe como **`java.lang.String`**.
* Configure a assinatura do método como **`join(java.lang.CharSequence,java.lang.Iterable)`**.
* O nó de decisão **Final Name** pode ser implementado com uma **boxed expression** do tipo **Invocation**.
* Na segunda célula da tabela (com o valor por defeito *Enter function*), escreva o nome do seu **BKM**.
* Adicione duas linhas:
  * Uma com o parâmetro **delimiter** e valor literal **" "** (um espaço).
  * Outra com o parâmetro **list** e valor literal **Names**.

Assim, estará a configurar os valores a enviar para o BKM, onde o parâmetro **list** referencia a entrada **Names**.

###


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://ulht-jcb.gitbook.io/fundamentals-of-information-systems/lab-11/lab-11.2-dmn-and-low-code-exercicios-praticos-guiados/use-o-poder-do-java-no-dmn.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
