Overview
When building an agent, you will have to implement a few interfaces. The XMPro IoT Framework provides a number of interfaces, but the interfaces that you need to implement depends on the type of agent you are writing. The available interfaces are as follows:
- IAgent
- IPollingAgent
- IReceivingAgent
- IPublishesError
Please look at the table below, which explains which interfaces need to be implemented for each type of agent:
IAgent | IPollingAgent | IReceivingAgent | IPublishesError | |
Listener | Required | Required | Not Required | Not Required |
Context Provider | Required | Required | Not Required | Not Required |
Transformation | Required | Not Required | Required | Not Required |
Action Agent/ Function | Required | Not Required | Required | Not Required |
Each of these interfaces will be explained in more detail below.
Interfaces
IAgent
IAgent is the primary interface which has to be implemented by all agents as it provides the structure for the workings of an XMPro Agent. When implementing this interface, please note that there are several methods that you need to add for the agent to function properly. We will discuss each of these methods and features of the IAgent interface in the section below.
An agent may need some settings which needs to be provided by a user when building a stream. A template for these settings should be created along with the agent using the XMPro Stream Integration Manager.
An example of the settings template (generated using the Stream Integration Manager) after it has been rendered in XMPro IoT on the UI is shown in the image on the right. The settings in this example consists of the following:
- Group (Data)
- File Upload
- Group (Payload)
- Grid
Each control needs to have a Key field defined in the template. This key uniquely identifies it in the template and allows the agent, which you will write, to access its value at any time. To get the value contained in a setting, use the following code:
string mySetting = parameters[“myUniqueKey”];
Before a template is rendered on the screen, or if a post back occurs on any control in the template, the method below would be called to allow the agent an opportunity to make any necessary runtime changes to the template, for example, verifying user credentials, displaying all tables of a selected database in a drop down list, etc. In this example, no changes are being made to the template but, if needed, they can be added to the todo section.
public string GetConfigurationTemplate(string template, IDictionary<string, string> parameters)
{
//parse settings JSON into Settings object
var settings = Settings.Parse(template);
//populate the settings/configuration controls with the user selected values
new Populator(parameters).Populate(settings);
// ToDo: update the controls/values or the data sources here
//return the updated settings xml
return settings.ToString();
}
If a user tries to run an Integrity Check on a use case in XMPro IoT, all agents will be requested to validate the defined configurations. An agent has to, if needed, use this opportunity to inform the user about any configurations that are incorrect, for example, credentials that have expired, required values that are missing, etc.
To validate the configurations/ settings in an agent, the Validate method needs to be implemented. This method would, if errors occurred, return an array of errors. If validation was successful, an empty array would be returned. Please see the example below:
public string[] Validate(IDictionary<string, string> parameters)
{
int i = 1;
var errors = new List<string>();
this.config = new Configuration() { Parameters = parameters };
if (String.IsNullOrWhiteSpace(this.Broker))
errors.Add($”Error {i++}: Broker is not specified.”);
if (String.IsNullOrWhiteSpace(this.Topic))
errors.Add($”Error {i++}: Topic is not specified.”);
var grid = new Grid();
grid.Value = this.config[“PayloadDefinition”];
if (grid.Rows.Any() == false)
errors.Add($”Error {i++}: Payload Definition is not specified.”);
return errors.ToArray();
}
Each agent has the responsibility to inform the Engine about the structure of the payload that will be produced by the agent. To do this, implement the following method:
IEnumerable<Attribute> GetOutputAttributes(string endpoint, IDictionary<string, string> parameters)
This method returns a collection that has an Attribute type, which is a type that represents the name and type of a given attribute in the outgoing payload. As from XMPro.IOT.Framework version 3.0.2, comparison/ equality operations are also supported in Attribute, for example:
new XMIoT.Framework.Attribute(“Name1”, Types.DateTime).Equals(new XMIoT.Framework.Attribute(“Name2”, Types.String));
Each agent needs to implement a method called Create, which will be invoked when your agent is being hosted. User defined configuration is passed as a parameter to this method and should mostly be stored in a class variable for later use. This is a good point to provision any resources needed for the working of your agent.
void Create(Configuration configuration)
{
this.config = configuration;
// ToDo: Provision any resources or write Startup logic.
}
The Start method is invoked when your agent is hosted and starts to work.
void Start()
Each agent needs to implement a Destroy method, which will be invoked when a use case is being unpublished. Use this method to release any resources or memory that your agent may have acquired during its life time.
void Destroy()
To push the events to the next agent, your agent should invoke the OnPublish event with the events passed as arguments:
this.OnPublish?.Invoke(this, new OnPublishArgs(new JArray(), “EndpointName”));
If an agent’s configuration contains a Secure/Password Textbox, its value will automatically be encrypted. To decrypt the value, use following set of instructions:
var request = new OnDecryptRequestArgs(value);
this.OnDecryptRequestArgs?.Invoke(this, request);
var decryptedVal = request.DecryptedValue;
If your agent requires some third-party event subscriptions, the event handlers must handle the exceptions and do not let it bubble up.
IPollingAgent
The IPollingAgent interface allows time-based operations. Implementing this interface will automatically add a PollingInterval setting to the configuration template of your agent, which can be used by the user to specify the time for polling. The following method will be invoked every time the poll interval expires:
void Poll()
This method can be used to listed to a third-party system for changes every x seconds.
IReceivingAgent
If your agent is required to receive inputs from other agents, you should implement the IReceivingAgent interface.
Each agent is responsible to inform the Engine about the structure of the payload it consumes. To achieve this in your agent, implement the following method:
IEnumerable<Attribute> GetInputAttributes(string endpoint, IDictionary<string, string> parameters)
This method returns a collection consisting of Attribute, which is a type that represents the name and type of a given attribute in the incoming payload.
Input Mapping
In most cases, if an incoming payload structure is supposed to be different to what the parent is sending, i.e. the Input Payload has been specified above, the user will have to map parent outputs to current agent’s inputs. To enable this, mark the Require Input Map flag as true in the XMPro Stream Integration Manager when packaging the agent.
Endpoint
Each agent can have a number of input and output endpoints. Endpoints are where incoming or outgoings arrows are connected. Each endpoint consists of a Name<String> attribute. You will be passed an endpoint name when queried for an Input payload definition. Be sure to specify the endpoint name when querying the parent’s output payload definition.
All receiving agents can query the structure of parent agent outputs connected at a given endpoint by invoking an event, as demonstrated in the example below:
var args = new OnRequestParentOutputAttributesArgs(this.UniqueId, “Input”);
this.OnRequestParentOutputAttributes.Invoke(this, args);
var pOuts = args.ParentOutputs;
Events published to a receiving agent can be received by implementing the following method:
void Receive(string endpointName, JArray events)
The endpointName parameter will identify which endpoint the events have been received at.
IPublishesError
An agent can publish messages to an error endpoint by implementing the IPublishesError interface. Any unhandled error in an agent will be captured and error information will be published to the error endpoint.
Implement the interface member:
public event EventHandler<OnErrorArgs> OnPublishError;
To push the error to the next agent, the OnPublishError event should be invoked and the error information should be passed as arguments:
this.OnPublishError?.Invoke(this, new OnErrorArgs(AgentId, Timestamp, Source, Error, DetailedError, Data));
Comments are closed.