Creation of a new inbound message
For the sake of explanation, this manual will implement a fake message "Tutorial Inbound Integration". We will abbreviate this in code as "TUTInIntegration".
Enum value
Each integration is uniquely identified by a value in the enum SMRIFMessageTypes. In order to create a new message, we have to create a new value in the enum. In this case, we add an enum value TUTInIntegration with the label "Tutorial Inbound Integration".
Staging data
All staging tables are centered around the framework table SMRIFMessage. The staging tables form a hierarchical tree structure below this generic message table.
It is important that each staging table
- has the save data per company property set to no.
- is related to a parent table, with a cascade delete action.
- has an index on the parent relation field.
For the sake of this demo, we can create two staging tables:
-
TUTInIntegrationHeader
- Has a field message that relates to the SMRIFMessageTable.RecId field.
- Has integration specific fields HeaderField1, HeaderField2, ...
-
TUTInIntegrationLine
- Has a field Header that relates to the TUTInIntegrationHeader.RecId field.
- Has integration specific fields LineField1, LineField2, ...
The appropriate incoming json file that matches this staging table structure can be found here.
Type class
Once we have created our staging tables, we can move on to the creation of our Type class. This class relates all code and tables involved in this integration together.
We can create this class by extending from the framework class SMRIFAbstractMessageInType. The name for this class in our case would be TUTInIntegrationType. This class should be attributed with the SMRIFMessageTypeAttribute corresponding to the enum value we created earlier.
At the very basis, the class declaration of our type class should now look like this:
[SMRIFMessageTypeAttribute(SMRIFMessageTypes::TUTInIntegration)]
public class TUTInIntegrationType extends SMRIFAbstractMessageInType
{
}
This class should implement a couple of abstract methods from the superclass it extends.
detailMenuItem
This method should return a display menu item that opens a details form. This new-to-be-created details form should have the SMRIFMessage table as a root datasource. It should offer a detailed view of one instance of your incoming message. All fields in every staging table should be visible on this form. Consider if you want fields to be editable on this form. On one hand, this recudes tracability, while on the other hand, it improves error handling.
doProcess
This method will do the actual processing of the staging data. This is done by calling the processing class that we will create in a next step. We can call this processing class using the framework as follows:
SMRIFAbstractProcessInMessage::process(message)
The message variable that is passed on will be inherited from the superclass.
validate
This method will return a boolean if the data in the staging tables is valid. We can look up the data in the staging tables by refering to the message variable from the super class, to which the staging tables should have a relation. If the data is valid, we return true. If the data is invalid, we return false and we issue a warning in an infolog (using checkFailed). The framework will pick up these warnings and log them.
tableRelationsMap
This method defines the hierarchical structure of our staging data. It does this by building and returning a map that maps strings to table relations. These string match 1:1 with what is in the inbound json file, while the table relations match with the relations between the staging tables. In order to represent a table relation, we use the framework class SMRIFTableField.
In our case, consider the following map, to which indentation has been added for clarity:
Map map = new Map(Types::String, Types::Class);
map.insert(
SMRIFConstants::Content, // The string 'content' as found in the json file
SMRIFTableField::construct( // A table relation
tableNum(TUTInIntegrationHeader), // The table 'TUTInIntegrationHeader' uses ....
fieldNum(TUTInIntegrationHeader, Message), // .... the field 'Message' to relate to ....
tableNum(SMRIFMessage))); // .... the table 'SMRIFMessage'.
map.insert(
tableStr(TUTInIntegrationLine), // The string 'TUTInIntegrationLine' as found in the json file
SMRIFTableField::construct( // A table relation
tableNum(TUTInIntegrationLine), // The table 'TUTInIntegrationLine' uses ....
fieldNum(TUTInIntegrationLine, Header), // .... the field 'Header' to relate to ....
tableNum(TUTInIntegrationHeader))); // .... the table 'TUTInIntegrationHeader'.
Processing class
The processing class is responsible for persisting the data in the staging tables into the system.
We can create this class by extending from the framework class SMRIFAbstractProcessInMessage. The name for this class in our case would be TUTProcessInIntegration. This class should be attributed with the SMRIFMessageTypeAttribute corresponding to the enum value we created earlier.
At the very basis, the class declaration of our type class should now look like this:
[SMRIFMessageTypeAttribute(SMRIFMessageTypes::TUTInIntegration)]
public class TUTProcessInIntegration extends SMRIFAbstractProcessInMessage
{
}
This class should implement an abstract methods from the superclass it extends.
doProcess
This method performs the actual business logic of the integration. For example, in the case of a customer creation interface, this method would create a customer based on the staging tables.
Some general guidelines for implementing this class:
- You do not need to start a transaction. This method will already be in a transaction scope.
- The superclass provides a message variable that is already instantiated to the message we are currently processing. This serves as an entry point to find all other related staging tables.
- If any error happens in this method, the interface message will be marked as failed and the error will be logged. If for some reasone processing can not succeed, simply throw a meaningful error. Do not try to recover using try-catch.