Creating data provider extensions
A data provider extension is used to enrich attributes within the business model. An extension is a data provider class that defines how the attribute is enriched.
Before you begin
Before you create a data provider extension, you must create an extension project to store and package the extension, and define the data providers in the business model.
About this task
Use a data provider extension to enrich entities from an external source. An extension can be useful if the data that you need is not in the incoming event or in the object grid. You must define the data provider in your business object model definitions, and then use the definitions to enrich the attributes of entities in your business object model. For more information, see Business model definitions.
In your extension implementation, you must send a request to retrieve the relevant information. An agent can reference the enriched attributes in the same way that it refers to non-enriched attributes. The runtime resolves and loads the enriched data when it is needed by using the specified provider in the business model statements.
A data provider is associated with a request and response type. The generated names for the request and response use the provider name as a prefix. To use a data provider that is defined in the Definitions tab of the BMD editor, you must create one or more enrichment statements in the Statements tab.
The statements define the mapping between the entity that is enriched and the values that are returned by the data provider. When an enrichment statement is defined, an error appears on the solution project until a data provider implementation is created. The names of the data provider elements must match those defined in the Definitions tab.
Procedure
Example
The following Java code shows a data provider extension. The java.naming and java.sql must be added to the extension project bundle manifest. The example uses the customer ID from the request to query an SQL database. It assumes that the server configuration includes a data source for the database that is bound to the JNDI name "jdbc/CustomerProviderDB".
package com.example.extensions.provider;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;
import com.ibm.ia.common.ComponentException;
import com.ibm.ia.extension.DataProvider;
import com.ibm.ia.extension.annotations.DataProviderDescriptor;
import com.example.providers.CustomerProvider;
import com.example.providers.CustomerProviderRequest;
import com.example.providers.CustomerProviderResponse;
import com.example.providers.ConceptFactory;
@DataProviderDescriptor(dataProvider = CustomerProvider.class,
responseCacheTimeout = 300)
public class CustomerDataProvider
extends DataProvider<CustomerProviderRequest, CustomerProviderResponse>
implements CustomerProvider {
// Data source JNDI name
private static final String DATA_SOURCE_JNDI = "jdbc/CustomerProviderDB";
// Select SQL from DB
private final static String SELECT_CUSTOMER =
"SELECT FIRST_NAME, LAST_NAME FROM CUSTOMER WHERE CUSTOMER_ID = ?";
// Cached reference to the DataSource
private ThreadLocal<DataSource> dataSource = new
ThreadLocal<DataSource>();
@Override
public CustomerProviderResponse processRequest(CustomerProviderRequest request)
throws ComponentException {
Connection conn = null;
try {
// Lookup the DataSource for the database if not already cached
if (dataSource.get() == null) {
Context initialContext = new InitialContext();
dataSource.set(
(javax.sql.DataSource) initialContext
.lookup(DATA_SOURCE_JNDI));
}
// Make a connection to the database
conn = dataSource.get().getConnection();
// Prepare the statement to retrieve the data from the database
PreparedStatement prepSt = conn.prepareStatement(SELECT_CUSTOMER);
// Get customer ID from the request
String customerId = request.getCustomerId();
prepSt.setString(1, customerId);
// Execute the query
ResultSet resultSet = prepSt.executeQuery();
// Read the first row from the result set
if (resultSet.next()) {
// Create a response object
ConceptFactory factory = getConceptFactory(ConceptFactory.class);
CustomerProviderResponse response =
factory.createCustomerProviderResponse();
// Set the response fields
response.setFirstName(resultSet.getString(1));
response.setLastName(resultSet.getString(2));
// Return the response
return response;
} else {
throw new ComponentException(
"CustomerDataProvider: No result for " + customerId);
}
} catch (NamingException | SQLException e) {
throw new ComponentException(
"CustomerDataProvider: " + e.getLocalizedMessage(), e);
} finally {
// Always try close the connection
if (conn != null) {
try {
conn.close();
} catch (SQLException e2) {
// Assume it's closed
}
}
}
}
}
The previous example also assumes that the following data is defined in the BMD and has the package name com.example.providers.
The names that you use to reference request and response data in the Java implementation are mapped directly to the definitions in the BMD. For example, the following definition returns a given name ("first name") and a surname ("last name"):
a CustomerProvider is a data provider ,
accepts a customer id,
returns a first name, a last name.
The implementation uses these names in the response fields:
response.setFirstName(resultSet.getString(1));
response.setLastName(resultSet.getString(2));
Input values can be derived from values in the entity, and output values can be derived from both the entity and the results of the data provider execution.
What to do next
Complete the Java file with the information necessary to connect to your external data source and return a value.
Deploy the Extension Project to the server as part of the solution. Entity values that are enriched by a data provider are cached in the memory of the local partition to improve performance the next time they are queried. The response cache timeout that you specified in the wizard is the longest time that a value is stored.
The server grid configuration might cause the value to be released earlier. Verify the timeToLive value in the objectgrid.xml file to see how long a value is held in the map.