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
14 changes: 8 additions & 6 deletions en/docs/guides/guides.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,14 @@ Complete, end-to-end examples you can follow from start to finish.

## Enterprise integration patterns

Reusable integration patterns you can apply across projects:

- **[Message](patterns/message.md)** -- Package business data and metadata for transmission through a message channel
- **[Message Filter](patterns/message-filter.md)** -- Route only messages that match a condition
- **[Content Based Routing](patterns/content-based-routing.md)** -- Route messages by inspecting their content
- **[Channel Adapter](patterns/channel-adapter.md)** -- Connect applications, services, or broker channels to an integration flow
Reusable integration patterns you can apply across projects. Start with the [Enterprise Integration Patterns overview](patterns/overview.md), or jump to a category:

- **Messaging Systems** -- The basic building blocks: [Message](patterns/message.md), [Pipes and Filters](patterns/pipes-and-filters.md), [Message Router](patterns/message-router.md), [Message Translator](patterns/message-translator.md), [Message Endpoint](patterns/message-endpoint.md)
- **Messaging Channels** -- How messages move between applications: [Point-to-Point Channel](patterns/point-to-point-channel.md), [Channel Adapter](patterns/channel-adapter.md), [Messaging Bridge](patterns/messaging-bridge.md)
- **Message Construction** -- The intent and form of messages: [Command Message](patterns/command-message.md), [Document Message](patterns/document-message.md), [Event Message](patterns/event-message.md), [Message Sequence](patterns/message-sequence.md), [Format Indicator](patterns/format-indicator.md)
- **Message Routing** -- Getting messages to the right receiver: [Content-Based Router](patterns/content-based-router.md), [Message Filter](patterns/message-filter.md), [Splitter](patterns/splitter.md), [Aggregator](patterns/aggregator.md), [Routing Slip](patterns/routing-slip.md), [Process Manager](patterns/process-manager.md)
- **Message Transformation** -- Changing message content: [Content Enricher](patterns/content-enricher.md), [Content Filter](patterns/content-filter.md), [Normalizer](patterns/normalizer.md)
- **Messaging Endpoints and System Management** -- Consuming and managing messages: [Idempotent Receiver](patterns/idempotent-receiver.md), [Message Store](patterns/message-store.md)

## Migration guides

Expand Down
72 changes: 72 additions & 0 deletions en/docs/guides/patterns/aggregator.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
---
title: Aggregator
description: "Implement the Aggregator pattern with WSO2 Integrator."
---

import TabItem from '@theme/TabItem';
import {
EipReferenceLink,
PatternImage,
PatternImplementationTabs,
} from '@site/src/utils/eipPatternComponents';

# Aggregator

Use an Aggregator to collect individual but related messages and publish a single combined message once the set is complete. <EipReferenceLink href="https://www.enterpriseintegrationpatterns.com/patterns/messaging/Aggregator.html" label="Enterprise Integration Patterns Aggregator reference" />

In WSO2 Integrator, the aggregator keeps the partial messages in a map keyed by a correlation identifier, appends each arriving message to its group, and sends the combined message when the completeness condition is met.

## Example: Combining multi-part survey responses

This example collects survey form submissions that arrive one section at a time. Each submission is correlated by the `userId` header and stored with the user's earlier sections. When all three sections have arrived, the aggregator submits the complete survey to the survey API and clears the stored parts.

<PatternImplementationTabs>
<TabItem value="ui" label="Visual Designer" default>

1. Create an [HTTP service](../../develop/integration-artifacts/service/http.md#creating-an-http-service) with a `post` resource that accepts the survey section payload and the `userId` correlation header.
2. Add an HTTP client connection for the survey submission API. See [adding a connection](../../develop/integration-artifacts/supporting/connections.md#adding-a-connection).
3. In the flow, look up the user's partial submissions in the aggregation map by `userId`.
4. Add an [If node](../../develop/understand-ide/editors/flow-diagram-editor/control.md#if): when no entry exists, store the first section; otherwise append the new section.
5. When the stored sections reach the completeness condition (three sections), post the combined survey to the submission endpoint and remove the entry from the map.

In the flow, the **If** node checks whether this is the user's first survey section; once three sections have accumulated, the combined survey is posted and the stored parts are cleared:

<PatternImage src="/img/eip-patterns/aggregator_flow.png" alt="Aggregator flow in the WSO2 Integrator visual designer" width={760} />

</TabItem>
<TabItem value="code" label="Ballerina Code">

```ballerina
// docs-fold-start: Supporting definitions
import ballerina/http;

final http:Client formSubmitClient = check new ("http://api.surveyme.com.balmock.io");
// docs-fold-end

map<json[]> partialSurveys = {};

listener http:Listener httpListener = new (port = 8080);

service /api/v1 on httpListener {
resource function post survey/[string id](@http:Header string userId, @http:Payload json formData) returns error? {
json[]|() surveyData = partialSurveys[userId];
if surveyData == () {
json[] newSurvey = [formData];
partialSurveys[userId] = newSurvey;
} else {
() var1 = surveyData.push(formData);
if surveyData.length() == 3 {
http:Response response = check formSubmitClient->/survey/[id]/submit.post({userId: surveyData}, targetType = http:Response);
json[] remove = partialSurveys.remove(userId);
}
}
}
}
```

</TabItem>
</PatternImplementationTabs>

## Complete sample

The complete project is available in the [aggregator sample](https://github.com/wso2/integration-samples/tree/main/integrator-default-profile/enterprise-integration-pattern/aggregator) on GitHub.
132 changes: 24 additions & 108 deletions en/docs/guides/patterns/channel-adapter.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,145 +6,61 @@ description: "Implement the Channel Adapter pattern with WSO2 Integrator."
import TabItem from '@theme/TabItem';
import {
EipReferenceLink,
PatternImage,
PatternImplementationTabs,
} from '@site/src/utils/eipPatternComponents';

# Channel Adapter

Use a Channel Adapter to define the boundary between an integration flow and the transport, application, or broker channel that supplies or receives messages. <EipReferenceLink href="https://www.enterpriseintegrationpatterns.com/patterns/messaging/ChannelAdapter.html" label="Enterprise Integration Patterns Channel Adapter reference" />
Use a Channel Adapter to connect an application that was not built for messaging to the messaging system, so the integration can send messages to it and receive messages from it through the application's own API. <EipReferenceLink href="https://www.enterpriseintegrationpatterns.com/patterns/messaging/ChannelAdapter.html" label="Enterprise Integration Patterns Channel Adapter reference" />

The adapter is usually implemented at the edge of the flow. Use connector clients for application APIs, services and listeners for inbound endpoints, and broker connectors only when the channel itself is Kafka, RabbitMQ, or JMS. Keep payloads typed, and keep endpoints and credentials in configurables.
In WSO2 Integrator, connectors are channel adapters. A connector client wraps an external application's API (its authentication, endpoints, and payload formats) and exposes it to the flow as typed operations, so the rest of the integration works with messages instead of API details.

## API/SaaS channel adapter with connector client
## Example: Adapting Jira into the integration

A connector client adapts an external application API into the integration flow. Create the connection with managed connection settings, call the required connector operation, and pass the typed result into the next step.
This example uses the Jira connector as a channel adapter. The connector handles authentication and the Jira REST API details, and the flow simply calls the `getProject` operation to receive a typed `jira:Project` message.

<PatternImplementationTabs>
<TabItem value="ui" label="Visual Designer" default>

1. Add the connector client connection for the application channel. See [adding a connection](../../develop/integration-artifacts/supporting/connections.md#adding-a-connection); for this example, select the Jira connector as shown in [adding the Jira connector](../../connectors/catalog/productivity-collaboration/jira/example.md#adding-the-jira-connector).
2. Configure the endpoint, authentication values, and other connection properties with project configurables. Use the connector-specific [Jira setup guide](../../connectors/catalog/productivity-collaboration/jira/setup-guide.md) and [Jira connection configuration steps](../../connectors/catalog/productivity-collaboration/jira/example.md#configuring-the-jira-connection).
3. Add the connector operation that reads from or writes to the application channel. Use the [Jira action reference](../../connectors/catalog/productivity-collaboration/jira/actions.md#projects) to select the project operation for this example.
4. Map the connector response to the message shape used by the rest of the flow.
The Jira connector is the channel adapter: it exposes the external Jira API to the automation as a typed connection:

</TabItem>
<TabItem value="code" label="Ballerina Code">

```ballerina
// docs-fold-start: Supporting definitions
import ballerinax/jira;

configurable string username = ?;
configurable string password = ?;
configurable string serviceUrl = ?;

jira:ConnectionConfig jiraConfig = {
auth: {
username,
password
}
};

jira:Client jiraAdapter = check new (
jiraConfig,
serviceUrl = serviceUrl
);
// docs-fold-end
<PatternImage src="/img/eip-patterns/channel_adapter_design.png" alt="Channel Adapter integration design view in WSO2 Integrator" width={706} />

public function readProject(string projectKey) returns jira:Project|error {
return jiraAdapter->/api/'3/project/[projectKey];
}
```

</TabItem>
</PatternImplementationTabs>

## HTTP service as inbound channel adapter
1. Create an [automation](../../develop/integration-artifacts/automation.md#creating-an-automation) to run the flow.
2. Add a Jira connection with the username and password kept as [configurable values](../../reference/config/configuration-management.md#configurable-variables). See [adding a connection](../../develop/integration-artifacts/supporting/connections.md#adding-a-connection).
3. In the flow, call the `getProject` operation on the Jira connection to bring the project into the integration as a typed message.

An HTTP service adapts an inbound HTTP channel into an integration flow. Define the service resource as the adapter entry point, receive a typed request payload, and return the typed response expected by the caller. See [creating an HTTP service](../../develop/integration-artifacts/service/http.md#creating-an-http-service) for the service setup flow.
The flow calls the `getProject` operation on the Jira connection; the connector handles the API details and returns a typed result:

<PatternImplementationTabs>
<TabItem value="ui" label="Visual Designer" default>

1. Create an HTTP service for the inbound channel. See [creating an HTTP service](../../develop/integration-artifacts/service/http.md#creating-an-http-service).
2. Add the resource that represents the inbound adapter operation. Use [resource inputs](../../develop/integration-artifacts/service/http.md#defining-inputs) to define the request payload or parameters.
3. Define the response payload type for the resource with [response schemas](../../develop/integration-artifacts/service/http.md#defining-response-schemas).
4. Add the flow logic that transforms or forwards the received message.
<PatternImage src="/img/eip-patterns/channel_adapter_flow.png" alt="Channel Adapter flow in the WSO2 Integrator visual designer" width={530} />

</TabItem>
<TabItem value="code" label="Ballerina Code">

```ballerina
// docs-fold-start: Supporting definitions
import ballerina/http;
import ballerinax/jira;

listener http:Listener projectListener = new (8080);
configurable string username = "admin";
configurable string password = "admin";

type ProjectRequest record {|
string projectKey;
|};

type ProjectResponse record {|
string key;
string name;
|};
final jira:Client jiraAdapter = check new ({
auth: {
username: username,
password: password
}
}, "http://wso2.jira.com.balmock.io");
Comment thread
coderabbitai[bot] marked this conversation as resolved.
// docs-fold-end

service /projects on projectListener {
resource function post lookup(ProjectRequest request) returns ProjectResponse|error {
jira:Project project = check readProject(request.projectKey);
return mapProject(project);
}
public function main() returns error? {
jira:Project result = check jiraAdapter->getProject("EI-Patterns-With-Ballerina");
}
```

</TabItem>
</PatternImplementationTabs>

## Broker-backed channel adapter

Use a broker listener when the channel is a messaging broker rather than an application API or HTTP endpoint. The service receives records from the broker, converts each record into the flow payload, and acknowledges or publishes through the connector according to the channel contract. Use the relevant broker guide, such as [Kafka consumers](../../develop/integration-artifacts/event/kafka.md#creating-a-kafka-listener), [RabbitMQ services](../../develop/integration-artifacts/event/rabbitmq.md#creating-a-rabbitmq-service), or the [JMS listener](../../connectors/catalog/messaging/java.jms/triggers.md#listener).

<PatternImplementationTabs>
<TabItem value="ui" label="Visual Designer" default>

1. Create the broker listener for the channel. For Kafka, see [creating a Kafka consumer](../../develop/integration-artifacts/event/kafka.md#creating-a-kafka-listener); for RabbitMQ, see [creating a RabbitMQ service](../../develop/integration-artifacts/event/rabbitmq.md#creating-a-rabbitmq-service); for JMS, see the [JMS listener](../../connectors/catalog/messaging/java.jms/triggers.md#listener).
2. Configure the broker endpoint, topic or queue, and credentials with configurables. For Kafka, use [service configuration](../../develop/integration-artifacts/event/kafka.md#service-configuration); for RabbitMQ, use [listener configuration](../../develop/integration-artifacts/event/rabbitmq.md#listener-configuration).
3. Add the message-handling function for the broker event. For Kafka, use [service configuration](../../develop/integration-artifacts/event/kafka.md#service-configuration); for RabbitMQ, use [event handlers](../../develop/integration-artifacts/event/rabbitmq.md#event-handlers).
4. Convert the broker record to the typed payload used inside the flow.

</TabItem>
<TabItem value="code" label="Ballerina Code">

```ballerina
// docs-fold-start: Supporting definitions
import ballerinax/kafka;

configurable string brokerUrl = ?;

type ProjectEvent record {|
string projectKey;
string source;
|};

listener kafka:Listener projectEventListener = new ({
bootstrapServers: brokerUrl,
groupId: "project-adapter"
});

function handleProjectEvent(ProjectEvent event) returns error? {
}
// docs-fold-end

service on projectEventListener {
remote function onConsumerRecord(ProjectEvent[] events) returns error? {
foreach ProjectEvent event in events {
check handleProjectEvent(event);
}
}
}
```
## Complete sample

</TabItem>
</PatternImplementationTabs>
The complete project is available in the [channel adapter sample](https://github.com/wso2/integration-samples/tree/main/integrator-default-profile/enterprise-integration-pattern/channel_adapter) on GitHub.
90 changes: 90 additions & 0 deletions en/docs/guides/patterns/command-message.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
---
title: Command Message
description: "Implement the Command Message pattern with WSO2 Integrator."
---

import TabItem from '@theme/TabItem';
import {
EipReferenceLink,
PatternImage,
PatternImplementationTabs,
} from '@site/src/utils/eipPatternComponents';

# Command Message

Use a Command Message to invoke a procedure in another application through messaging. The message carries the command and its parameters, and the receiver executes it. <EipReferenceLink href="https://www.enterpriseintegrationpatterns.com/patterns/messaging/CommandMessage.html" label="Enterprise Integration Patterns Command Message reference" />

In WSO2 Integrator, a command message is a typed record sent to the operation endpoint of the receiving application. The record fields are the procedure's parameters, and the response confirms the command's outcome.

## Example: Creating a Slack user group

This example receives a user group creation request and sends it as a command message to the Slack `usergroups.create` API. The `UserGroupCreateRequest` record carries the command parameters, and Slack executes the procedure and returns the created group.

<PatternImplementationTabs>
<TabItem value="ui" label="Visual Designer" default>

1. Create an [HTTP service](../../develop/integration-artifacts/service/http.md#creating-an-http-service) with a `post` resource that accepts the `UserGroupCreateRequest` payload.
2. Add an HTTP client connection for the Slack API. See [adding a connection](../../develop/integration-artifacts/supporting/connections.md#adding-a-connection).
3. In the flow, post the command message to the `usergroups.create` operation with the `x-www-form-urlencoded` media type.
4. Return the `UserGroupCreationResponse` to the caller.

The `UserGroupCreateRequest` record is the command message, and its fields (`name`, `description`, and `team_id`) are the parameters of the procedure to invoke:

<PatternImage src="/img/eip-patterns/command_message_types.png" alt="UserGroupCreateRequest command message type in WSO2 Integrator" width={285} />

The flow forwards the command message to Slack's `usergroups.create` operation and returns the result:

<PatternImage src="/img/eip-patterns/command_message_flow.png" alt="Command Message flow in the WSO2 Integrator visual designer" width={530} />

</TabItem>
<TabItem value="code" label="Ballerina Code">

```ballerina
// docs-fold-start: Supporting definitions
import ballerina/http;

type UserGroupCreateRequest record {|
string name;
string description;
string team_id;
|};

type UserGroup record {
string id;
boolean is_usergroup;
string 'handle;
boolean is_external;
int date_create;
string created_by;
string user_count;
string name;
string description;
string team_id;
};

type UserGroupCreationResponse record {
boolean ok;
UserGroup usergroup?;
string 'error?;
};

final http:Client slackClient = check new ("http://api.slack.com.balmock.io");
// docs-fold-end

listener http:Listener httpListener = new (port = 8080);

service /api/v1 on httpListener {
isolated resource function post createUserGroup(UserGroupCreateRequest userGroup)
returns UserGroupCreationResponse|error {
UserGroupCreationResponse userGroupCreateRequest = check slackClient->/api/usergroups\.create.post(userGroup, mediaType = "x-www-form-urlencoded");
return userGroupCreateRequest;
}
}
```

</TabItem>
</PatternImplementationTabs>

## Complete sample

The complete project is available in the [command message sample](https://github.com/wso2/integration-samples/tree/main/integrator-default-profile/enterprise-integration-pattern/command_message) on GitHub.
Loading
Loading