# Integration Management

Integration is crucial for insurance transactions. For example, in policy transactions, carriers may need to connect with channels through integration, or channels with carriers. Each integration can be very specific to each channel or carrier. 

Based on our experience, such integration usually follow a standard pattern and there's always technical need to capture some of the data during the integration process. 

We hope that by using our integration management, the technical team does not need to conduct repetitive work to capture such integration data, and it will make it easier for technical teams to implement and accelerate the integration process.


## Concept

### Standard Integration Pattern

Although integration implementations can vary, most integrations follow a standard pattern with several steps:

1. Prepare Request

    This step involves preparing the request to be sent to other systems. For example, in policy integration, we need to transform our policy data into the format required by the third-party system.

2. Send Request

    Upon preparing the request, we need to send it to the third-party system for real connection. This step is vital and might involve extensive network preparation or authentication.

3. Set response

    Once we receive the response from the third-party system, we need to transform it in a manner similar to the sent request. The response may be in the third-party system's policy format. In such cases, we need to perform a process similar to sending a request, converting it back into a policy format that our system can read before proceeding with the rest of our internal operations.  


### Key Characteristics

#### Benefit

The key benefit of the integration management is to automatically capture the integration request and response bodies within all above-mentioned integration steps. 

By leveraging the integration management, there's no need for technical teams to create all kinds of similar integration-related tables for reconciliation. 

Additionally, users can access our out-of-box integration management history UI to view all these historical records and trigger automatic retries in case of integration failures due to issues like network connection errors.

#### Compared with iHub

iHub, as another key offering within InsureMO, focuses on the detailed integration mapping logic to transform the request and response body among different integration parties. Consequently, the key is to achieve the transformation and validation logic, while our integration management assists by persistently storing this information and initiating automatic retries in case of failures. 

To implement an integration, users can employ both iHub and the integration management within their applications, accelerating development efforts.

#### Compared with MQ

Integrations can follow different patterns. Some integrations can be achieved in a synchronous way, while some APIs require asynchronous calls. Common asynchronous calls include email, SMS, print generation, or BCP integration.

Normally, applications will use MQ to do such integrations by sending integration messages to a queue, where a receiver application will receive the message and process them. With our integration management, there comes a new option. Take print as an example:

1. **MQ Implementation**: If we use MQ for asynchronous, the BFF will initially send a message to BFF and there’s a BFF code to listen to message and trigger print.
2. **Integration Management**: If we use integration management, during prepare request, we can save the request first. (This ensures the request is always available as the process is synchronous.) Then during the send request, the process is made asynchronous. If it’s successful, no further action is required. If it fails, an alert email will be sent, prompting a system administrator to manually retry the request through the system interface. 

Therefore, by using the integration management, we can achieve almost the same features as what MQ does.

For integrations involving high volumes of transactions, MQ is still the most reliable choice. We recommend that partner teams assess their business scenario and pick the right choice. If MQ is chosen, you'll need to procure your own cloud MQ or other messaging services from cloud providers.

## Implementation with Code Examples

### Basics

Firstly, integration Management adoption requires the following two prerequisites:

1. Users must adopt either of the following methods to achieve integration:

    * InsureMO app framework to write BFF
    * InsureMO iComposer

2. Users must separate the integration implementation into the three steps outlined above, as illustrated below: 

    * Prepare Request
    * Send Request
    * Set Response

Based on the InsureMO framework, our platform provides a standard interface (`...platform.inteadapter.clientservice.TransactionSyncAdapterService`) which includes three main methods: `prepareRequest`, `sendRequest`, and `setResponse`.

The tenant team can implement this interface and register it as a Spring Bean by configuring the bean name in our data table. The framework will subsequently invoke these three methods in sequence.

### Configuration

There is one data table related to the integration management:

* `AdapterServiceCfg`

    This is to define the detailed service implementation based on which each integration transaction is triggered.
        
    Please note that when calling a third-party API, users need to configure the srvUrl to be the name of `SrvImpl` plus `.url`. Then, the system will use the same key to look it up in the Config Center to find the relevant URL.

    | id | transactionType |TransactionTypeDescription  | providerCode |countryCode| srvImpl                           | srvUrl                                   | retryEnable | retryLimit |
    |----|-----------------|----------------------------|--------------|-----------|----------------------------------|------------------------------------------------------|-------------|------------|
    | 2  | 2               |sendmailwithappframeworkcode| Container    |US         |sendMailAdapterService            | http://gateway.ebao/eBao/1.0/email/send              | Y           | 3          |
    | 3  | 3               |sendmailwithiComposer       | Container    |US         |iComposer.EmailServiceWithAdapter | http://gateway.ebao/eBao/1.0/email/send             | Y           | 3          |
    | 4  | 4               |sendmailwiththirdparty      | ThirdParty   |US         |iComposer.EmailServiceWithAdapterByThirdParty | iComposer.EmailServiceWithAdapterByThirdParty.url | N           | 3          |

### Source Code to Invoke

To help users understand, we will use the InsureMO email service as an example integration party and demonstrate how to use our integration management to implement the email sending function.

#### iComposer Example

1. Add a new `sendMailwithiComposer` transactionType in the `AdapterServiceCfg` data table.
2. Add a new service function named `EmailServiceWithAdapter` in iComposer.


```java
import org.springframework.web.client.RestTemplate;
import com.insuremo.icomposer.utils.IComposerJsonUtils;
import com.insuremo.icomposer.utils.IComposerRestTemplateManager;
import com.insuremo.icomposer.sdk.inteadapter.IComposerTransactionSyncRequest;
import com.insuremo.icomposer.sdk.inteadapter.IComposerTransactionSyncResponse;
import com.insuremo.icomposer.sdk.inteadapter.IComposerIntegrationAdapterRequest;
import com.insuremo.icomposer.sdk.inteadapter.IComposerIntegrationAdapterService;

IComposerIntegrationAdapterService integrationAdapterService = (IComposerIntegrationAdapterService)getBean("com.insuremo.icomposer.sdk.inteadapter.IComposerIntegrationAdapterService");

// template method, never change any of the method definition
def prepareRequest(IComposerTransactionSyncRequest request) {
    Map policyInfo = request.getInputData();
    //pre define  
    String subject = "InsureMO Policy Number {0}";
    String templateCode = "IssuePolicy";

    List<String> consigneeList = new ArrayList<>();
    consigneeList.add("sascha.slevin@insuremo.com");
    String account = "insuremo-ptdev@insuremo.com";

    Map map = new HashMap<>();
    map.put("subject", java.text.MessageFormat.format(subject, policyInfo.get("PolicyNo")));
    map.put("templateCode", templateCode);
    map.put("templateParams", policyInfo);
    map.put("account", account);
    map.put("consignee", consigneeList);
    // debug("Sending mail. data:{}", map);

    return IComposerJsonUtils.toJSON(map);
}

// template method, never change any of the method definition
def sendRequest(IComposerTransactionSyncRequest transactionSyncRequest, String sendRequestString, String syncUrl) {
    RestTemplate restTemplateContainer = IComposerRestTemplateManager.gatewayCall();
    debug("sendRequest syncUrl:{},restTemplateContainer:{}", syncUrl, restTemplateContainer);
    Map resp = restTemplateContainer.postForObject(syncUrl, IComposerJsonUtils.fromJSON(sendRequestString, Map.class), Map.class);
    debug("sendRequest. resp:{}", resp);
    return IComposerJsonUtils.toJSON(resp);
}

// template method, never change any of the method definition
def setResponse(IComposerTransactionSyncRequest transactionSyncRequest, String responseStr, IComposerTransactionSyncResponse transactionSyncResponse) {
    Map responseMap = IComposerJsonUtils.fromJSON(responseStr, Map.class);
    transactionSyncResponse.setResult(responseMap);
}

```

3. Configure this service function into the same data table.
4. Instantiate `IntegrationAdapterRequest` and call `integrationAdapterService.callProviderAdapter`.

```java
import com.insuremo.icomposer.sdk.inteadapter.IComposerIntegrationAdapterRequest;
import com.insuremo.icomposer.sdk.inteadapter.IComposerIntegrationAdapterService;

IComposerIntegrationAdapterService integrationAdapterService = (IComposerIntegrationAdapterService)getBean("com.insuremo.icomposer.sdk.inteadapter.IComposerIntegrationAdapterService");

// biz  method for invoke 
def prepareEmail(Map policyInfo) {
    IComposerIntegrationAdapterRequest request = new IComposerIntegrationAdapterRequest();
    request.setInputData(policyInfo);
    request.setClientRequestId("Policy_Issue_Mail" + policyInfo.get("PolicyNo"));
    request.setProviderCode("Container");
    request.setCountryCode("CN");
    request.setTransactionType(3);
    integrationAdapterService.callProviderAdapter(request);
}

```

#### Asynchronous Call

All the examples presented above demonstrate the process of making synchronous integration calls. 

If this integration requires an asynchronous call, users can replace `integrationAdapterService.callProviderAdapter(request)` with `integrationAdapterService.callProviderAdapterAsync(request)`.


## UI Operation

User can find the menu by clicking **Public Setting** > **Integration Management**.

### Search & Retry

On the search page, users can:

1. Search out the historical integration log information.
2. Perform retry on failure records.
3. View integration details.

![integration_adapter_search](./image/integration_adapter/integration_adapter_search.png)

### View Details

![integration_adapter_detail](./image/integration_adapter/integration_adapter_detail.png)


## Failure Notification

If there's any failure during integration management, you will receive notification email like below:

![integration_adapter_failure_email](./image/integration_adapter/integration_adapter_failure_email.png)

This email will be sent to your tenant's alarm email group. Upon receipt, visit the integration management menu, locate your case, and perform a manual retry.

## Log Archive

Current integration log is stored in the database with below table:

* t_transaction
* t_trasaction_sync_log

Integration API calls can be very often. If there's any high-frequency integration happening, the generation of integration log can be very huge which might lead to infra issue.

At platform level, we provide a batch - integrationAdapterArchiveBatch for user to archive integration log into S3. It's suggested that user can override the platform batch to regularly archive the previous log older than certain days.

Once log is archived, user will not be able to search it out and need to check directly on S3 folder.

![integration_adapter_failure_email](./image/integration_adapter/integration_adapter_failure_email.png)

