Skip to content

Commit 17f4bdc

Browse files
committed
feat(emtp): add new plugin entity-task-mapper-plugin
1 parent c424784 commit 17f4bdc

File tree

6 files changed

+422
-0
lines changed

6 files changed

+422
-0
lines changed
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
name: 'Check Pull Request for plugin: entity-mapper-task-plugin'
2+
3+
on:
4+
pull_request:
5+
types: [opened, synchronize, reopened]
6+
paths:
7+
- 'emtp/**'
8+
9+
jobs:
10+
tests:
11+
name: Unit tests
12+
runs-on: ubuntu-latest
13+
steps:
14+
- uses: actions/checkout@v4
15+
- name: Set up JDK 21 for x64
16+
uses: actions/setup-java@v4
17+
with:
18+
java-version: '21'
19+
distribution: 'temurin'
20+
architecture: x64
21+
22+
- name: Install Pandoc
23+
run: sudo apt-get update && sudo apt-get install -y pandoc
24+
25+
- name: Execute unit tests
26+
run: mvn -ntp -pl emtp test
27+
28+
- name: Execute mutation tests
29+
run: mvn -ntp -pl emtp org.pitest:pitest-maven:mutationCoverage
30+
31+
- name: Extract summary from pitest
32+
run: |
33+
echo "<html><head></head><body><h1>Pit Test Coverage Report: entity-mapper-task-plugin</h1><h3>Project Summary</h3>" > pitest.html
34+
perl -0777 -ne 'print "$1\n" if /(<table>.*?<\/table>)/s' emtp/target/pit-reports/index.html >> pitest.html
35+
echo "</body></html>" >> pitest.html
36+
37+
- name: Convert pitest report to markdown
38+
run: pandoc --from html --to markdown_github --no-highlight pitest.html
39+
40+
- name: Post comment
41+
uses: luukkemp/pr-comment@2024.1
42+
env:
43+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
44+
with:
45+
path: pitest.html

emtp/README.md

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
# 🌐 Entity Mapper Task Plugin (emtp)
2+
3+
The `emtp` module provides a task plugin for mapping values from the execution context into dynamic entities. It is part of the LinID task engine and allows flexible mapping configuration using Jinja templates.
4+
5+
## EntityMapperTaskPlugin
6+
7+
The `EntityMapperTaskPlugin` is a task plugin that populates entity attributes dynamically based on the execution context. It retrieves values defined in the task configuration and assigns them to corresponding fields in the dynamic entity.
8+
9+
### ✅ Use Case
10+
11+
Use this plugin when you need to:
12+
13+
* Map values from the execution context to entity attributes.
14+
* Dynamically compute entity fields using templates.
15+
* Simplify the integration of external data or precomputed values into entities.
16+
17+
### 🔧 Configuration
18+
19+
#### Minimal Example
20+
21+
```yaml
22+
task:
23+
- name: X
24+
type: entity-mapper
25+
mapping:
26+
id: '{{context.response.id}}'
27+
```
28+
29+
### Configuration Fields
30+
31+
| Key | Required | Description |
32+
| --------- | -------- |---------------------------------------------------|
33+
| `name` | ✅ | Name of the task |
34+
| `type` | ✅ | Must be `entity-mapper` |
35+
| `mapping` | ✅ | Entity fields mapping, supports Jinja templating. |
36+
37+
### 🛠 Behavior
38+
39+
* For each entry in `mapping`, the plugin renders the Jinja template using the `JinjaService` with the current execution context and entity.
40+
* The result is assigned to the corresponding attribute in the `DynamicEntity`.
41+
* If the `mapping` option is missing, the plugin throws an `ApiException` with a descriptive error message.
42+
43+
### Example Mapping
44+
45+
```yaml
46+
task:
47+
- name: MapResponseId
48+
type: entity-mapper
49+
mapping:
50+
id: '{{context.response.id}}'
51+
name: '{{context.response.name}}'
52+
status: '{{context.response.status}}'
53+
```
54+
55+
In this example, the entity's `id`, `name`, and `status` attributes will be populated dynamically based on the values in `context.response`.
56+
57+
### 🔑 Notes
58+
59+
* Templates support any values available in the `TaskExecutionContext` and the entity itself.
60+
* This plugin is purely a **task plugin**; it does not call external APIs or transform responses—use in combination with other plugins (like HTTP or JSON parsing) if needed.
61+
* Missing mappings or invalid templates will result in a runtime exception.

emtp/pom.xml

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
2+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
3+
<modelVersion>4.0.0</modelVersion>
4+
<parent>
5+
<groupId>io.github.linagora.linid.im</groupId>
6+
<artifactId>linid-im-api-community-plugins</artifactId>
7+
<version>0.1.0</version>
8+
</parent>
9+
10+
<groupId>io.github.linagora.linid.im</groupId>
11+
<artifactId>emtp</artifactId>
12+
<packaging>jar</packaging>
13+
14+
<version>0.1.0</version>
15+
<name>entity-mapper-task-plugin</name>
16+
<description>Plugin for mapping values from the execution context into an entity, allowing flexible configuration to extract and assign data to corresponding entity fields.</description>
17+
<url>https://github.com/linagora/linid-im-api-community-plugins</url>
18+
19+
<licenses>
20+
<license>
21+
<name>GNU Affero General Public License v3.0</name>
22+
<url>https://www.gnu.org/licenses/agpl-3.0.html</url>
23+
<distribution>repo</distribution>
24+
<comments>This project is licensed under the GNU AGPL v3.0</comments>
25+
</license>
26+
</licenses>
27+
28+
<developers>
29+
<developer>
30+
<id>Zorin95670</id>
31+
<name>Vincent MOITTIE</name>
32+
<email>moittie.vincent@gmail.com</email>
33+
</developer>
34+
</developers>
35+
36+
<scm>
37+
<connection>scm:git:git://github.com/linagora/linid-im-api-community-plugins.git</connection>
38+
<developerConnection>scm:git:ssh://git@github.com:linagora/linid-im-api-community-plugins.git</developerConnection>
39+
<url>https://github.com/linagora/linid-im-api-community-plugins</url>
40+
</scm>
41+
<properties>
42+
<sonar.projectBaseDir>emtp</sonar.projectBaseDir>
43+
</properties>
44+
45+
<build>
46+
<plugins>
47+
<plugin>
48+
<artifactId>maven-shade-plugin</artifactId>
49+
<version>3.6.2</version>
50+
<executions>
51+
<execution>
52+
<phase>package</phase>
53+
<goals>
54+
<goal>shade</goal>
55+
</goals>
56+
<configuration>
57+
<shadedArtifactAttached>false</shadedArtifactAttached>
58+
<createDependencyReducedPom>false</createDependencyReducedPom>
59+
</configuration>
60+
</execution>
61+
</executions>
62+
</plugin>
63+
</plugins>
64+
</build>
65+
</project>
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
/*
2+
* Copyright (C) 2020-2026 Linagora
3+
*
4+
* This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General
5+
* Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option)
6+
* any later version, provided you comply with the Additional Terms applicable for LinID Identity Manager software by
7+
* LINAGORA pursuant to Section 7 of the GNU Affero General Public License, subsections (b), (c), and (e), pursuant to
8+
* which these Appropriate Legal Notices must notably (i) retain the display of the "LinID™" trademark/logo at the top
9+
* of the interface window, the display of the “You are using the Open Source and free version of LinID™, powered by
10+
* Linagora © 2009–2013. Contribute to LinID R&D by subscribing to an Enterprise offer!” infobox and in the e-mails
11+
* sent with the Program, notice appended to any type of outbound messages (e.g. e-mail and meeting requests) as well
12+
* as in the LinID Identity Manager user interface, (ii) retain all hypertext links between LinID Identity Manager
13+
* and https://linid.org/, as well as between LINAGORA and LINAGORA.com, and (iii) refrain from infringing LINAGORA
14+
* intellectual property rights over its trademarks and commercial brands. Other Additional Terms apply, see
15+
* <http://www.linagora.com/licenses/> for more details.
16+
*
17+
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
18+
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
19+
* details.
20+
*
21+
* You should have received a copy of the GNU Affero General Public License and its applicable Additional Terms for
22+
* LinID Identity Manager along with this program. If not, see <http://www.gnu.org/licenses/> for the GNU Affero
23+
* General Public License version 3 and <http://www.linagora.com/licenses/> for the Additional Terms applicable to the
24+
* LinID Identity Manager software.
25+
*/
26+
27+
package io.github.linagora.linid.im.emtp;
28+
29+
import io.github.linagora.linid.im.corelib.exception.ApiException;
30+
import io.github.linagora.linid.im.corelib.i18n.I18nMessage;
31+
import io.github.linagora.linid.im.corelib.plugin.config.JinjaService;
32+
import io.github.linagora.linid.im.corelib.plugin.config.dto.TaskConfiguration;
33+
import io.github.linagora.linid.im.corelib.plugin.entity.DynamicEntity;
34+
import io.github.linagora.linid.im.corelib.plugin.task.TaskExecutionContext;
35+
import io.github.linagora.linid.im.corelib.plugin.task.TaskPlugin;
36+
import java.util.Map;
37+
import lombok.NonNull;
38+
import org.springframework.beans.factory.annotation.Autowired;
39+
import org.springframework.stereotype.Component;
40+
import tools.jackson.core.type.TypeReference;
41+
42+
/**
43+
* Task plugin that maps values from the execution context into a dynamic entity.
44+
*
45+
* <p>This plugin uses templates defined in the task configuration to populate entity attributes dynamically.
46+
* It supports tasks of type "entity-mapping".
47+
*/
48+
@Component
49+
public class EntityMappingTaskPlugin implements TaskPlugin {
50+
51+
/**
52+
* Service used to render Jinja templates with the task execution context and entity attributes.
53+
*/
54+
private final JinjaService jinjaService;
55+
56+
/**
57+
* Constructs an EntityMappingTaskPlugin with the specified JinjaService.
58+
*
59+
* @param jinjaService the service responsible for rendering Jinja templates
60+
*/
61+
@Autowired
62+
public EntityMappingTaskPlugin(final JinjaService jinjaService) {
63+
this.jinjaService = jinjaService;
64+
}
65+
66+
@Override
67+
public boolean supports(final @NonNull String type) {
68+
return "entity-mapper".equals(type);
69+
}
70+
71+
@Override
72+
public void execute(final TaskConfiguration taskConfiguration,
73+
final DynamicEntity dynamicEntity,
74+
final TaskExecutionContext taskExecutionContext) {
75+
Map<String, String> mapping = taskConfiguration.getOption(
76+
"mapping",
77+
new TypeReference<Map<String, String>>() {})
78+
.orElseThrow(() -> new ApiException(500, I18nMessage.of(
79+
"error.plugin.default.missing.option",
80+
Map.of("option", "mapping")
81+
)));
82+
83+
mapping.forEach((String key, String template) -> {
84+
String value = jinjaService.render(taskExecutionContext, dynamicEntity, template);
85+
dynamicEntity.getAttributes().put(key, value);
86+
});
87+
}
88+
}

0 commit comments

Comments
 (0)