Adapter Services

Overview

An adapter service defines an operation that the adapter performs on an adapter resource. Adapter services operate like Integration Server flow services or Java services. Adapter services have input and output signatures, can be invoked within flow services, and can be audited from the Integration Server's audit system.

Like a connection, an adapter service consists of a Java class component and a namespace node in which design time settings are stored in the metadata parameters. Adapter services support:

  • Basic metadata constructs supported by connections.
  • Additional data types.
  • More sophisticated widgets.
  • Ability to define the signature of the adapter service node.

    This means that the users of the adapter can specify what data to search for in the flow service pipeline when the adapter service is called, and what data to place in the pipeline during the execution of the service. Using these signatures, you can link the adapter services to other Integration Server elements as part of a total integration solution.

Designer provides the facilities for the users of the adapter to create, configure, and test adapter service nodes.

Adapter Service Classes

The following figure shows the classes provided by the ADK to support adapter service templates. It also shows the com.wm.adk.cci.interaction.WmAdapterService implementation class MockDbUpdate.

Adapter Services Implementation Classes

Create an adapter service class by extending the com.wm.adk.cci.interaction.WmAdapterService base class. The adapters include several adapter service template classes, so it is common to place them in their own package. You must override the following base class methods in your WmAdapterService implementation class:

Method Description
execute Receives a WmManagedConnection implementation object from the adapter implementation, and a WmRecord containing the pipeline data.
Note: This is an abstract method in the base class, so failing to override it results in a compilation error.

For more information, see Adapter Service Execution.

fillWmTemplateDescriptor Receives a WmTemplateDescriptor object and a Locale object. Serves to modify how metadata parameters are handled during data entry.
Note: Failing to override this method results in a runtime error.

For more information, see WmTemplateDescriptor Interface.

metadataVersion Returns the current version of the metadata.
Note: If the template has multiple metadata versions, override this method.
fieldsToIgnoreInMetadataDefinition Uses metadata version as input and returns an array of the fields that are not applicable to the metadata version provided.
Note: If the template has multiple metadata versions, failing to override this method results in breaking the old services.

Metadata Model for Adapter Services

The following sections describe the basics of the metadata model for adapter services.

Metadata Parameters for Adapter Services

Metadata parameters for adapter services use the same model that connections use.
  • The restriction on sequence parameters (arrays) does not apply to adapter services. The adapter service editor supports widgets that allow the users of the adapter to view and manipulate array values in several ways, as described in the next section.
  • Providing default values to parameters through a "get" method is not as valuable in the context of adapter services. This functionality is largely replaced by the use of resource domains. Some functionalities, such as the specification of the run time signature of the service, require values to be provided through the resource domain facilities. For more information, see Resource Domains.
For more information, see Metadata Model for Connection.

WmTemplateDescriptor Interface

The WmTemplateDescriptor interface extends the com.wm.adk.metadata.WmDescriptor interface. The WmTemplateDescriptor controls how metadata parameters appear, and defines rules for data entry. Include the method fillWmTemplateDescriptor in your adapter service to populate WmTemplateDescriptor.

Important: Do not call the base class version of the method (by calling super()).

WmTemplateDescriptor introduces new methods and concepts. In addition, it also modifies the behavior of some of the methods inherited from WmDescriptor.

Table 1. WmDescriptor Methods
Method Description
createGroup Specifies the order in which parameters must appear in Designer. Unlike with connections, you can create multiple groups for adapter services. Each group corresponds to a tab in the adapter service editor, with the group name becoming the key. The key is used to identify the display name. Each group has a resource bundle entry that provides the display name shown on the screen. Group names are only displayed if you do not provide a display name in your resource bundle.

Parameters can be assigned to only one group. If some or all of a service's metadata parameters are not assigned to a group, a default group is created and the unassigned parameters are added to it. This is true even if the parameter is hidden. Each group can have a display name and a description specified in the resource bundle.

setValidValues Use the resource domain facilities (recommended) instead of this method. For more information, see Resource Domains.
setPassword Displays asterisks when the users of the adapter enter passwords.
Note: The adapter service editor does not support the automated password confirmation facilities described for connections.
setDescriptions Searches the resource bundle for display names, and descriptions for the service, metadata parameters, and any groups that have been created at the point setDescriptions is called. If you want group display fields to be loaded from the resource bundle, call setDescriptions at the end of the fillWmTemplateDescriptor implementation.
setHidden Designates properties as hidden. A hidden property does not appear in the adapter service editor.
Note: Some of these methods have implicit order requirements because the methods build on the activities performed in previous method calls.

By default, the adapter service editor displays each metadata parameter in its own widget, based on the parameter's data type. These widgets include:

Widget Data Type
Text box String parameter
Table widget Array
Check box Boolean
A text box with scrollable values Numeric

Use the following WmTemplateDescriptor methods to modify and enhance the default behavior.

WmTemplateDescriptor Methods

Method Description
createFieldMap Organizes parameters into columns of a single table widget.
createTuple Grouping mechanism that you can use to modify the behavior of a resource domain lookup, and how resource domain values are applied in a field map.
setMultiline Changes the widget from a standard text box to a multi-line text box. This widget also supports text import from files. The resulting parameter value may include embedded returns.
setResourceDomain Associates a metadata parameter of an adapter service with a resource domain supported by the service's connection.

For more information about FieldMaps and Tuples, see FieldMaps, Tuples.

For more information about setting resource domains, see Resource Domains and Associating Metadata Parameters with Resource Domains.

Order of WmTemplateDescriptor and WmDescriptor Methods Called

Some of these methods have implicit order requirements because they build on activities performed in the previous methods calls. For example, call setDescriptions after the final call to createGroup so that the resource bundle lookups can include all groups defined in the service. Use the calls in the following order:

  1. createGroup
  2. createFieldMap
  3. createTuple
  4. setResourceDomain
  5. setDescriptions
Note: If you create tuples, make setResourceDomain calls for tuple parameters in the order in which the parameters are set in the tuple.

Metadata Parameter Groups, FieldMaps and Tuples

Groups

Call the WmTemplateDescriptor.createGroup method to perform the following:
  1. Organize parameters into different tabs.
  2. Specify the order in which the parameters appear.

FieldMaps

Call the WmTemplateDescriptor.createFieldMap method to organize various sequence parameters (within the same group) into a single table widget in the adapter service editor. The full signature for createFieldMap is:
void createFieldMap(String[] members,  
                    boolean variable,  
                    boolean fillAll);
The following table describes the parameters of WmTemplateDescriptor.createFieldMap:
Parameter Name Description
members Specifies a list of the parameter names that make up the field map. A field map can contain one or more member parameters, but a parameter must not be a member of more than one field map.
  • The members argument is not an ordered list.
  • The members argument has no impact on the order in which the columns appear in a field map.
  • The order of the columns in a field map is dictated entirely by the order in which the parameters appear in the group.
  • The first member to appear in the group list appears in the first column of the field map.
  • The remaining columns follow the order in which they appear in the group.
  • If there is more than one field map in a group, then the relative positions of the first column parameters in the group dictates the order in which the field map tables appear.
Note: Using the parameters from different groups in a field map results in an exception.
variable Enables the users of the adapter to add rows to the table. Possible values are:
  • true. The values are not populated by default. However the users of the adapter must click on the add row icon to populate each value row in the table.
  • false. The values are populated by default, and the add row icon is disabled, thereby disabling the users of the adapter from adding rows to the table.

In this case, the field map is considered to be a variable field map because the number of fields that appear in the adapter service editor may vary.

By default, each time the user of the adapter adds a row to the field map, each column is populated based on the associated parameter's data type and the contents of the associated resource domain. Typically, the column contains a dropdown list of string values from the resource domain. In other cases, either a check box appears (for Boolean parameters) or the column is empty.

fillAll Populates the table with all the available data. Possible values are:
  • true. Populates the table with all the available data.
  • false. The user of the adapter must add the rows in the table.
  • If the fillAll argument is true and the variable argument is false, then :
    • The table is expanded to contain one row for each value provided for the parameter in the first column of the field map.
    • The values for this first column are provided by the associated resource domain, and cannot be changed or manipulated by the user. This is true even when the associated resource domain's setComplete method is false; the users of the adapter cannot directly update this column. The users of the adapter can still make changes to other parameters that might impact the content of the resource domain of the first column's parameter. For more information about dependencies, see Associating Metadata Parameters with Resource Domains.
    • The remaining columns contain the same value and user interface widget that would be employed if the user manually inserted the row.
Note:
  • If variable is false, then fillAll is assumed to be true, regardless of the value passed in the argument.
  • Do not set both fillAll and variable to true; the resulting behavior is unpredictable.

Tuples

The WmTemplateDescriptor.createTuple method is an another grouping mechanism that you can use to modify:

  • The behavior of a resource domain lookup.
  • How the resource domain values are applied to parameters in the tuple.

Members of a tuple are linked when:

  • The resource domain values are retrieved.
  • The values are updated on the user interface.

When the adapter service editor performs a resource domain lookup for a parameter in a tuple, it expects the response array to contain a ResourceDomainValues object for each parameter in the tuple. Thus, changes resulting from the resource domain lookup is applied simultaneously to each parameter in the tuple. This mechanism is particularly useful when two or more sequence parameters in a field map are closely related. For example, when one parameter contains a column name and the other parameter contains the column format.

Requirements for reliable tuple operation are as follows:

  • The parameters of a tuple must be sequence parameters of the same field map. If parameters are in separate field maps, the resource domain lookup functions properly, but the user interface characteristics do not function as described below.

    In the user interface, the first parameter in a tuple serves as the primary parameter, and all other parameters are secondary parameters. In the adapter service editor:

    • Users of the adapter can directly manipulate the primary parameter, but not secondary parameters.
    • The secondary parameter contains the value from its resource domain that corresponds to the value selected from the primary parameter. For example, if the fourth member of the primary parameter's resource domain is selected, then the fourth member of the secondary parameter's resource domain appears in the secondary parameter's column.
    • If a secondary parameter value is not specified in the position corresponding to the primary parameter's value, then the secondary parameter is left blank in that row.
  • A tuple must be declared (in the code) before a setResourceDomain method.
  • The first parameter of a tuple must be assigned to a resource domain before any other member of the tuple.
  • Each parameter of a tuple must have the same parameter dependencies listed in the setResourceDomain call that you used to assign the metadata parameters of the adapter service to a resource domain.
  • For each ResourceDomainValues object returned in the lookup, the setComplete method must be true in which the users of the adapter cannot supply parameter values.
  • The first parameter in the tuple must appear first in its group.
For more information, see Associating Metadata Parameters with Resource Domains, and Populating Resource Domains with Values.

Resource Domains

A resource domain defines the domain of valid values for metadata parameters, based on rules and/or data that are specific to the adapter resource. Resource domains can have properties that affect the behavior of the resource domain, and associations with the metadata parameters.

You can use resource domain values to:

  • Assign default values for parameters.
  • Enable the adapter to look up parameter values in the adapter resource.
  • Enable the users of the adapter to supply their own parameter values, and enable the adapter to validate these values.
  • Disable parameters, based on specified sets of values in other parameters.

A common use of resource domain values is to create a dropdown list of data values for a parameter, much like the WmDescriptor.setValidValues method in connection factories. However, the resource domain values differ from the setValidValues lists in two important ways:

  • Resource domain values can interact with the adapter service editor.

    As values in one parameter change, callbacks are made to the adapter to update the resource domain values. For example, if parameter A contains a list of database table names, and parameter B contains a list of column names, then when a table is selected in parameter A, the resource domain values used in parameter B can be updated to reflect the columns from the table selected in parameter A.

  • Resource domain values can be retrieved directly from the adapter resource, using a WmManagedConnection instance.

To create a resource domain:

  1. Register the resource domain and its properties in your WmManagedConnection implementation.
  2. Associate the adapter's metadata parameters with the resource domain.
  3. Populate the resource domain with values in your WmManagedConnection implementation.

Registering Resource Domains

You must register resource domains in your WmManagedConnection implementation using the WmManagedConnection.registerResourceDomain method. This method has a single argument of the type WmAdapterAccess. For more information, seeCreating a WmManagedConnection Implementation Class.

Registering a resource domain name establishes the definition of the resource domain within a given scope. That is, you can register one resource domain to be used by all adapter services that use the connection, or you can register multiple resource domains on a service-by-service basis. You must register the name of each resource domain supported by the connection (and by extension, each resource domain used by any service supported by the connection).

In the WmManagedConnection.registerResourceDomain method, you must perform the following:

  • Create a ResourceDomainValues object, which represents a list of values for a resource domain.
  • Specify whether the resource domain is fixed or dynamic.
    Method Description
    WmAdapterAccess.addResourceDomain Defines a fixed resource domain with one or more values. A fixed resource domain displays default values that you provide for the resource domain parameters. This method expects one or more ResourceDomainValues objects. For more information about resource domain values and their settings, see Populating Resource Domains with Values.
    WmAdapterAccess.addResourceDomainLookup Defines a dynamic resource domain. A dynamic resource domain enables the adapter to look up values for the parameters, based on changes to dependency parameters.
    This method supplies a reference to an object that the adapter service editor uses to make callbacks when the adapter service node is configured. Resource domain lookups can only be performed against WmManagedConnection objects, so the "this" reference is generally used as the object reference argument. For example:
    access.addResourceDomainLookup(
    "aSampleResourceDomainName", this);
    For more information, see Resource Domain Lookups.
  • Specify whether the users of the adapter can provide their own parameter values, and enable the adapter to validate these values. To do this, you use the following methods:
    Method Description
    ResourceDomainValues.setComplete(false)
    • Allows the users of the adapter to supply values.
    • Sets a flag named complete.

    When using both fixed resource domains and dynamic resource domains, you can allow the users of the adapter to enter their own values, allowing them to add to the current list of values for the resource domain.

    ResourceDomainValues.setCanValidate(true)
    • Enables the adapter to validate the user supplied values using adapter check values callbacks. The WmManagedConnection.adapterCheckValue method validates the user supplied values.
    • Sets the canValidate flag
    WmAdapterAccess.addCheckValue Calls the WmManagedConnection.adapterCheckValue method.
    Note: WmAdapterAccess.addCheckValue must appear after WmAdapterAccess.addResourceDomain or WmAdapterAccess.addResourceDomainLookup.

The following example registers two resource domains:

101. public void registerResourceDomain(WmAdapterAccess access)  
102.    throws AdapterException  
103. {  
104.    ResourceDomainValues tableRdvs = new ResourceDomainValues(  
105.       MockDbUpdate.TABLES_RD, mockTableNames);  
106.    tableRdvs.setComplete(true);  
107.    access.addResourceDomain(tableRdvs);  
108.  
109.    access.addResourceDomainLookup(MockDbUpdate.COLUMN_NAMES_RD,this);  
110.    access.addResourceDomainLookup(MockDbUpdate.COLUMN_TYPES_RD,this);  
111.  
112.    ResourceDomainValues rdvs = new ResourceDomainValues(  
113.       MockDbUpdate.OVERRIDE_TYPES_RD, new String[] {""});  
114.    rdvs.setComplete(false);  
115.    rdvs.setCanValidate(true);  
116.    access.addResourceDomain(rdvs);  
117.    access.addCheckValue(MockDbUpdate.OVERRIDE_TYPES_RD,this);  
...  
121. }

In this example, note that:

  • Lines 104-105 create a ResourceDomainValues object (identified by the constant MockDbUpdate.TABLES_RD).
  • Line 106 indicates that the users of the adapter may not supply their own values to the resource domain.
  • Line 107 adds a resource domain to this object.
  • Lines 109-110 add lookups for this object, indicating that the resource domain is dynamic. For these lookups, you must pass an instance of the connection that can satisfy the lookup. This is accomplished by using the "this" reference.
  • Lines 112-113 create an empty ResourceDomainValues object.
  • Line 114-115 indicate that the users of the adapter may supply their own values, and the adapter validates these values. setCanValidate(true) calls the adapterCheckValue method (line 117) for each value that is not already in the resource domain.
  • Line 116 adds a resource domain to this object. This is a fixed resource domain because no lookups are performed.

Associating Metadata Parameters with Resource Domains

The metadata parameters of an adapter service must be assigned to a resource domain supported by the service's connection. The interface WmTemplateDescriptor, provides setResourceDomain with the following signature:
void setResourceDomain(String name,  
                       String resourceDomainName,  
                       String[] dependencies)
Parameter Name Description
name Name of the parameter being assigned.
resourceDomainName Resource domain name that matches the name registered in the connection.
dependencies List of any other metadata parameter names in the current adapter service upon which the value of the parameter in the first argument depends.

Dependencies are important to dynamic resource domain lookups. When the user of an adapter changes the value of a parameter in the dependency list, a lookup retrieves a new set of resource domain values.

For example, for the parameters named columns and tables, you might assign the columns parameter to a resource domain called columnsLookup, with a dependency on the tables parameter as follows:
d.setResourceDomain("columns", "columnsLookup",
																new String[] {"tables"});
When the tables parameter changes, WmManagedConnection.adapterResourceDomainLookup determines the new value or values that can be applied to the columns parameter. Depending on the properties of a resource domain, the lookup may be used to set the value of a parameter, or to provide a list of possibilities from which the user of the adapter may select a value.
For more information, see Resource Domain Lookups.

For more information about the variant forms of setResourceDomain, including the concept of useColumns, see The useParam Argument of setResourceDomain.

Populating Resource Domains with Values

To populate a fixed or dynamic resource domain with values, implement the ResourceDomainValues class in your WmManagedConnection implementation.

This class is the primary container for controlling the behavior of the adapter service parameters. It is used during the registration process when you register a fixed resource domain, and it is returned from the adapterResourceDomainLookup method in response to a dynamic callback. For more information, see Resource Domain Lookups.

A ResourceDomainValues object contains the following:

  • Name of the resource domain.
  • Current list of values for the resource domain.

    The current list of values can contain an array of strings or an array of ResourceDomainValue objects. This array constitutes the list of values that appears in the appropriate widgets in the adapter service editor. The displayed values are communicated as strings, regardless of the data type of the parameter associated with the resource domain.

    Note: Using a list of values that cannot be converted to the parameter's data type results in a runtime error. Null and empty strings are not accepted in numeric parameters.
  • The following methods:
    Method Description
    ResourceDomainValues.setComplete(false)
    • Allows the users of the adapter to supply values.
    • Sets a flag named complete.

    When using both fixed resource domains and dynamic resource domains, you can allow the users of the adapter to enter their own values, allowing them to add to the current list of values for the resource domain.

    ResourceDomainValues.setCanValidate(true)
    • Enables the adapter to validate the user supplied values using adapter check values callbacks. The WmManagedConnection.adapterCheckValue method validates the user supplied values.
    • Sets the canValidate flag
    ResourceDomainValues.setDisabled Disables the parameter in the adapter service editor.

For example, assume that a parameter named portNumber has a data type of int. When constructing the associated resource domain values, limit the list of values to numeric strings as follows:

new ResourceDomainValues("portNumberLookup", new String[] 
{"6048","8088","9090"});

This example shows a ResourceDomainValues object with a set list. You have the option to define a range of values, by providing a minimum/maximum value. In this case, a single ResourceDomainValues object is used to define the minimum and maximum values of a numeric parameter. The following conditions must be met for defining a range of values:

  • The parameter must be of a numeric data type (such as int or long).
  • The parameter cannot be a sequence parameter (array).
  • The ResourceDomainValues object must contain exactly one value that is constructed from a ResourceDomainValue object.
  • ResourceDomainValues.setComplete must be false. You must set this method explicitly if you used the ResourceDomainValue[] constructor; otherwise, changes to the parameter are not saved.
  • The embedded ResourceDomainValue object must have a name representing a numeric value, and an endName representing a number value greater than the value of the name.
    Note: This is the only defined use for ResourceDomainValue.endName. In all other cases, only ResourceDomainValue.name is used. All other ResourceDomainValue attributes are placeholders, and are not currently implemented. Using a String[] to construct ResourceDomainValues is equivalent to using a ResourceDomainValue[] where only the ResourceDomainValue.name attributes are populated.

Resource Domain Lookups

A dynamic resource domain uses resource domain lookups. The method addResourceDomainLookup is used to enable the adapter to look up parameter values in the adapter resource.

When the users of the adapter create an adapter service node, they select a connection in which the adapter service executes. That connection also provides data from the resource domain that you registered with the connection.

When a node is created, the adapter service editor initiates a resource domain lookup to the connection class for each of the adapter's metadata parameters that are associated with dynamic resource domains. Additional lookups are made as the users of the adapter modify the values of parameters upon which other parameters depend.

All resource domain lookups invoke the method adapterResourceDomainLookup in the WmManagedConnection implementation class:

ResourceDomainValues[] adapterResourceDomainLookup(String serviceName,  
 String resourceDomainName,  
 String[][] values)
Parameter Name Description
serviceName Class name of the adapter service.
resourceDomainName Registered name of the resource domain.
values A multi-dimensional array that is populated with the current value of the parameters upon which the current lookup depends, as specified in the WmTemplateDescriptor.setResourceDomain call.

For more information, see Associating Metadata Parameters with Resource Domains.

For example:

d.setResourceDomain( "columnsArg", "columnsLookup", new String[] {"tablesArg"});
This call creates a dependency on tablesArg. When the lookup for the columnsLookup resource domain is made, the values argument contains the current settings for the tablesArg parameter. Data in the values argument is organized such that:
  • The first dimension of the array determines the dependent parameter.
  • The second dimension iterates the data in the parameter.
Thus, values[0][0] contains the value of the first dependent parameter. If it is a sequence parameter, then values[0][1] would contain the next value in the sequence, values[0][2] the next, and so on. If there were more than one dependency, the contents of the second parameter on which the lookup depends would be contained in values[1][].
Note: Placing a sequence parameter in a field map has several effects on the resource domain lookup process (seeTuples).

The signature of adapterResourceDomainLookup indicates that an array of ResourceDomainValues objects must be returned. Unless your implementation includes tuples, there must be exactly one object in the response array, and the name attribute of that ResourceDomainValues object must always be the same as the resourceDomainName argument passed into the method.

When the adapter service editor receives the lookup response data, it is evaluated against any data in the "current" parameter (the parameter for which the lookup was performed). An entry in the current parameter is considered valid if any one of the following is true:

  • The parameter value matches a value in the ResourceDomainValues list.
  • ResourceDomainValues.setComplete(false) and ResourceDomainValues.setCanValidate(false).
  • ResourceDomainValues.setComplete(false) and ResourceDomainValues.setCanValidate(true) and the value was successfully validated through the adapter check values facility.

If the current parameter settings are considered valid, then the parameter values remain unchanged. However, any current parameter values are merged with the values in the lookup response when the parameter's dropdown list is opened. (This effectively extends the resource domain to include values that were entered by the user.) If the current parameter settings are not considered valid, then the invalid value is deleted and replaced by a value in the resource domain.

Adapter Check Value Callbacks

When using both fixed resource domains and dynamic resource domains, you may allow the users of the adapter to enter their own parameter values, allowing them to add to the current list of values for the resource domain. To enable the adapter to validate these values, you use callbacks known as adapter check values. Adapter check values are resource domain mechanisms that function very much like resource domain lookups. Any value in a parameter that is not part of the parameter's resource domain list may be validated by an adapter check value. For more information, see Registering Resource Domains.

Adapter check values can also validate resource domain lookups for each unique value that is not part of a resource domain list that is complete (that is, a list that does not accept the values supplied by the users of the adapter). For example, suppose the sequence parameter named colors contains the values "White", "Gray", "Black", and "Red". After a resource domain lookup, the resource domain list contains "Black" and "Gray". Assuming that the resource domain is configured appropriately, the adapter service editor performs an adapter check value callback for "Red" and "White". If it finds either value, it deletes the cell containing that value or overwrites it, if the sequence is in a field map.

To use an adapter check value callback, you must:

  • Set the following methods of the ResourceDomainValues class as follows:

    Method Description
    ResourceDomainValues.setComplete(false)
    • Allows the users of the adapter to supply values.
    • Sets a flag named complete.

    When using both fixed resource domains and dynamic resource domains, you can allow the users of the adapter to enter their own values, allowing them to add to the current list of values for the resource domain.

    ResourceDomainValues.setCanValidate(true)
    • Enables the adapter to validate the user supplied values using adapter check values callbacks. The WmManagedConnection.adapterCheckValue method validates the user supplied values.
    • Sets the canValidate flag
    ResourceDomainValues.setDisabled Disables the parameter in the adapter service editor.

    If both of these flags are set properly, the adapter service editor calls the following method for each value that is not already in the resource domain:

    Boolean adapterCheckValue(String serviceName,  
                              String resourceDomainName,  
                              String[][] values,  
                              String testValue)
    Parameter Name Description
    serviceName Class name of the adapter service.
    resourceDomainName Registered name of the resource domain.
    values A multi-dimensional array that is populated with the current value of the parameters upon which the current lookup depends, as specified in the WmTemplateDescriptor.setResourceDomain call.
    testValue Value being checked.
  • Register the adapter check value callback at the same time you register the resource domain name, using the WmAdapterAccess.addCheckValue method. For more information, see Registering Resource Domains.

Field Maps with Resource Domain Dependencies

The addResourceDomainLookup and adapterCheckValue methods have a values[][] argument that contains the current value(s) of the parameter(s) on which the resource domain association depends. If the dependency parameter is a sequence parameter, the complete list of values is provided in the values argument. However, when a parameter depends on another parameter in the same field map, then by default each row in the field map is handled separately, for resource domain lookup/check value purposes.

For example, assume that with the sequence parameters A and B, the lookup for B depends on A. If the parameters are not in the same field map, then whenever a row in A changes, a lookup is performed for B, to which all values of A are passed. The results list is applied to each row of B, and updates are made to any rows of B that are no longer valid. The rows may be no longer valid because their values are not members of a "complete" resource domain (that is, a resource domain that does not allow the users of the adapter to enter values), or because an adapter check value callback failed to validate the rows.

However, if A and B are in the same field map, then when the value in a row of A changes, only the new value in that row is passed to the resource domain lookup, and the values returned from the lookup apply only to that row of B. For example, if parameter A contains catalog item numbers, and parameter B contains the colors in which the item is available, then for each catalog item number in A, there would be a separate dropdown list of available colors in column B. Also note that if the same catalog item number appeared in multiple rows in column A, then the dropdown list of colors in column B would be the same. There would not be a separate resource domain lookup for each of those rows because the adapter service editor would recognize that it already has the list of colors for that item number. Or, more accurately, that it already has a list of resource domain values based on the given set of dependency parameter values.

If you want to suppress the behavior described above, prefix the name of the parameter in the setResourceDomain dependency list with an asterisk (*). For example, the following method causes Integration Server to treat parameter A like any other parameter, even if it were in a field map with B:

setResourceDomain("B", "bLookup", new String[] {"*A"})

Adapter Service Node Signatures

About this task

In addition to using the metadata model to create parameters for configuring an adapter service node, you can use the model to define the signatures of that node.

An adapter service node has an input signature and an output signature. An input signature describes the data that the service expects to find in the flow service pipeline at run time. An output signature describes the data that the service expects to add to the pipeline when it has successfully executed.

You can view an adapter service node's signature in the Input/Output tab of the adapter service editor in Designer. Rules for defining signatures appear in the following procedure.

Once the signature is complete, users may include an adapter service node in flow constructs. They can route, map, and transform the input and output of the adapter service as needed in the integration solution.

The following procedure provides a basic model that you can use to implement a metadata signature. If you deviate from this model, it is important to understand that signature resource domains are only invoked as a result of a value applied to a dependent parameter. Having a resource domain lookup simply change the list of possible values in the resource domain does not impact the signature unless the current value is changed.

To create the signature of an adapter service node

Procedure

  1. Create metadata input parameters for the field names, data types, and signature. Each parameter must have a data type of String[].

    For example, assume that inputNames, inputTypes, and inputSignature are created as follows:

    public void setInputNames(String[] val);  
    public void setInputTypes(String[] val);  
    public void setInputSignature(String[] val);
  2. Add these parameters to a group in the same order as above.

    For example:

    templateDescriptor.addGroup("group name", new String []  
    { …, "inputNames", "inputTypes", "inputSignature"});
  3. You may hide any or all of the parameters. (Hiding all parameters in a field map hides the map table as well.)

    For example:

    templateDescriptor.setHidden("inputNames");  
    templateDescriptor.setHidden("inputTypes");  
    templateDescriptor.setHidden("inputSignature");
  4. Create a field map containing the three input parameters. In the createFieldMap method, set the variable argument to false, and set the fillAll argument to true.

    For example:

    templateDescriptor.creatFieldMap(new String [] {"inputNames",  
        "inputTypes", "inputSignature"}, false, true);

    In some cases, you can include other parameters in this field map, but this can sometimes be problematic, particularly if these parameters are hidden.

  5. Create a tuple containing the names and types parameters.

    For example:

    templateDescriptor.creatTuple(new String [] {"inputNames",  
        "inputTypes"});
  6. In the associated connection class(es), register two resource domains to support name and type lookups.

    For example, assume that the resource domains inputNamesLookup, and inputTypesLookup are created as follows.

    access.addResourceDomainLookup("inputNamesLookup", this);  
    access.addResourceDomainLookup("inputTypesLookup", this);
  7. Assign the names parameter to the name lookup resource domain, and assign the types parameter to the type lookup resource domain. These assignments must specify the same dependencies because the parameters are in a tuple. If no dependencies are known at this time, specify null.

    For example:

    templateDescriptor.setResourceDomain("inputNames","inputNamesLookup",null);  
    templateDescriptor.setResourceDomain("inputTypes","inputTypesLookup",null);
  8. Assign the signature parameter to one of the reserved resource domain names provided in WmTemplateDescriptor, specifying the names parameter and the types parameter as dependencies.

    For example, INPUT_FIELD_NAMES would be used as follows:

    templateDescriptor.setResourcDomain( "inputSignature",  
        WmTemplateDescriptor.INPUT_FIELD_NAMES, new String[]  
        {"inputNames", "inputTypes"}););
  9. Implement the name and type lookups as described in Implementing Resource Domain Lookups for Signature Names and Data Types.
  10. Create an output signature by repeating this procedure, substituting OUTPUT_FIELD_NAMES for INPUT_FIELD_NAMES in step 8.

Implementing Resource Domain Lookups for Signature Names and Data Types

You can load a signature's name and data type parameters using resource domain lookups. You implement lookups by including an adapterResourceDomainLookup method in your WmManagedConnection implementation class.

These parameters are implemented as string arrays, with the corresponding index in each array used to associate a name with a data type. The following subsections describe the values you supply in your resource domains for the name and data type parameters.

Field Name String Values

A field name string can contain a simple value, such as itemNumber, or a more complex value such as customer.orders[].lineItems[].itemNumber. The complex field name string demonstrates the ability of a signature to specify hierarchy (using a dot ".") and multiplicity (using a pair a square brackets "[]"). Thus, this example shows an aggregate of customer fields containing multiple orders that may contain multiple line items that contain one itemNumber.

Follow these rules when creating resource domain values for containing signature names:

  • A name can be used as a field (containing data) or an aggregate (containing fields), but not both.
  • Each entry must contain a field with any containing aggregates. Do not specify aggregates alone.
  • Both fields and aggregates can be arrays, indicated by square brackets. For example: customer.orders[].lineItems[].itemNumber.
  • Use name restrictions.
For more information, see the IBM webMethods Service Development Help for your release.
Data Type String Values

A data type string must contain the data type corresponding to the field name string at the same index in the field name's resource domain list of values. Data types for the adapter services are similar to the data types for Java services. If the signature item is made accessible from an Integration Server flow, its data type must be java.lang.String, java.util.Date, or one of the "big-letter-primitive" classes (e.g., java.lang.Integer). If the data is made to not be accessible from a flow, then any class type is acceptable.

Multiplicity in the data type string uses a pair of square brackets [] appended to the class name. Data type multiplicity represents the multiplicity across the entire signature hierarchy by adding a set of brackets for each set of brackets in the corresponding name string.

Even though there is only one item number in the lineItems aggregate, there are many in the signature. In this case, the data type would be java.lang.Integer[][] if itemNumber is an integer.

For examples, see Example 1: WmAdapterService Implementation Class. For more information, IBM webMethods Service Development Help for your release and Interacting with the Pipeline.

Adapter Service Execution

When a flow service, or a trigger invokes an adapter service, Designer invokes an adapter service node. The adapter service node calls the WmAdapterService.execute method. The signature is as follows:
public WmRecord execute(WmManagedConnection connection, 
				WmRecord input) throws ResourceException
Input Parameter Description
connection The WmManagedConnection object argument delivers a connection instance from the adapter service's connection node. How the adapter uses this connection object to gain access to the adapter resource is determined by the adapter's design, not by the ADK.
input The inbound WmRecord object contains data based on the input signature as well as any other information that may be in the flow service pipeline at the time the adapter service is invoked. The execute method is responsible for interrogating the inbound WmRecord object to retrieve the data necessary for the adapter service to perform its function. The validation that the fields specified in the signature are actually present in the pipeline is not performed by Integration Server, but the data type for any field present in the pipeline is guaranteed to conform to the data type specified in the signature. The adapter service must determine whether all the required data is present, and how to respond when data elements are missing.
Output Parameter Description
WmRecord object When the execute method completes, the outbound WmRecord object must contain data based on the output signature defined in the metadata. This data is added to the pipeline. (An adapter service may not remove the data from the pipeline because it only works with a copy of the pipeline object, not the original pipeline object.) Once again, the adapter implementation has primary responsibility for determining what portions of the signature is populated. A run time exception might occur if a field that was not populated by the adapter service is mapped within a flow service.

Interacting with the Pipeline

During run time, an adapter service has to perform the following:

  • Retrieve data from the pipeline at the beginning of its execution.

    To retrieve data from the pipeline, the service must interrogate the WmRecord argument of the execute method. Limit the interrogation to fields identified in the service's signature because often there is other information in the pipeline that is not intended for the service.

  • Add data to the pipeline at the end of execution.

    At the end of execution, the execute method must return a WmRecord instance containing the data that must be added to the pipeline. Organize the return data in a way that is consistent with the metadata signature so that other adapter services (or flow or Java services) can access it.

For discussion purposes, assume the following as a sample metadata signature for both input and output of an adapter service:

Field Name Type
customer.id java.lang.Integer
customer.name java.lang.String
customer.orders[].id java.lang.Integer[]
customer.orders[].date java.util.Date[]
customer.orders[].lineItems[].itemNumber java.lang.Integer[][]
customer.orders[].lineItems[].quantity java.lang.Integer[][]
customer.orders[].lineItems[].description java.lang.String [][]

The sample signature describes a hierarchal structure that can be expressed as a tree structure, where the actual field names form the leaves, and the elements preceding the field name are nodes. Thus, the names customer, orders, and lineItems are node names, and id, name, date, itemNumber, quantity, and description are leaves in the tree structure.

The WmRecord class, which is the primary carrier of data into and out of adapter services, is a JCA based wrapper for an IData object. It provides methods that access the IData content. However, when dealing with a hierarchal structure (as is the case with the sample), it is necessary to "drill down" into the IData structure. Therefore, ignore the WmRecord methods except for getIData, and putIData, which is used to access the underlying IData object.

Note: The IData interface is part of the standard IBM webMethods Integration Server Java API. Its structure is based on key/value pairs, where the key is a String and the value is a Java object. For more information, see the Javadoc entries for IData, IDataCursor, IDataFactory, and IDataUtil.
getIData Method

Returns an IData object that contains the entire pipeline at the time the service was invoked. The top-level branch or leaf name(s) in the metadata signature (in this case, customer) is the key used to access data intended for use by the service. The value associated with that key is either another IData object (if the key is a node name) or an object of the type specified by the corresponding type field of the signature. If the name of the branch or leaf includes a pair of square braces "[]", then the value contains an array of the designated object type.

Thus, the fields in the sample would be populated as follows:

  • Returns an IData object with an entry, keyed with the name customer.
  • The value associated with customer is another IData object, with three entries: id, name, and orders.
  • The value corresponding with id is an Integer.
  • The value of name is a String.
  • The value of orders would contain an array of IData objects.
  • The orders IData objects would each contain an id of type Integer, a date of type java.util.Date, and an array of IData objects associated with the lineItems key.
  • The lineItems IData objects would contain entries for itemNumber, quantity, and description, with the data types provided in the signature.

When constructing response data to place in the pipeline at the end of service execution, use the same rules that apply to interpreting the metadata signature. For each node level in the signature, there must be a corresponding layer of IData, keyed with the names from the signature. For each leaf, there must be an IData entry with the corresponding signature name and type.

Note: Signatures are not enforced by Integration Server or the ADK framework. The validity of a request based on the presence or absence of a given field, or the value given to a field, is determined exclusively by the adapter implementation. Similarly, if the service fails to populate the response WmRecord with data organized according to the signature, subsequent services cannot access the data provided by the adapter service.

Adapter Service Template Interactions

Creating Adapter Service Nodes

Designer provides a wizard to guide the user of the adapter through the process of creating adapter service nodes. During this process there are two significant interactions with the adapter. They occur:

  • When the user of the adapter selects the connection node to be used by the service node.
  • After the user of the adapter enters the name and folder of the new adapter service node.

Selecting Connection Nodes

The following diagram shows the adapter calls made when the users of the adapter select a connection node and how the metadata cache is loaded in Designer.

When the user of the adapter selects the connection node to be used by the service node, the Integration Server calls the fillResourceAdapterMetadataInfo method in the connection for the supported adapter service template class names. Integration Server performs the following:

  • Instantiates each of these template classes.
  • Retrieves the default metadata parameter values (by calling the parameter "get" methods).
  • Calls its fillWmTemplateDescriptor method.

All this information is cached in Designer session, and is not requested again for any adapter service activity associated with that connection node. That is, after this information has been gathered from a connection node, the user of the adapter may create multiple adapter service nodes based on any template associated with that connection using the same set of cached information. This is particularly significant during development of metadata-related code.

Note: The cache is not cleared when you recompile the code or reload the package, so it is critical that you refresh the cache manually when loading updated metadata code. Use the Refresh button on the Designer toolbar or select Refresh from the Session menu to refresh the cache.)

Entering Names and Folders for Adapter Service Nodes

The other significant adapter interaction that occurs when creating adapter service nodes occurs after the user of the adapter has entered the name and folder of the new adapter service node.

The following figure describes the parameter interrogation during the creation of an adapter service node:

Before displaying the adapter service editor screens:

  • Integration Server invokes the connection's adapterResourceDomainLookup method for each lookup registered with the service.

    The values argument in these lookups reflect the dependent parameters' default values that are cached when the user of the adapter selects a connection node. If your default value for a dependent parameter is null, make sure your resource domain lookup code can handle a null value in the values argument.

  • After the lookups are complete, Integration Server instantiates the adapter service template class (again), and each of the accessor methods are called.

    Values passed to "set" methods come either from the parameter default, or from the result of a resource domain lookup. These accessor method calls merely validate their operation; the service class instance is not cached. This is the last interaction with the metadata parameter accessor methods during the process of creating an adapter service node. The "set" methods are not called with the final node settings until the service is executed.

Viewing or Editing Adapter Service Nodes

Users may modify the metadata parameter values of an adapter service node using the adapter service editor at any time after the node is created.

When an adapter service node is opened (selected), the adapter service editor performs an adapterResourceDomainLookup call for any resource domain values that it has not already cached. This lookup interaction is shown in steps 1 and 2 of the above figure.

Resource domain values are cached in the adapter service editor based on the values of dependent parameters for the adapter service template/connection type combination (that is, for the class, not the node; thus cached values may be used across nodes that are based on the same template and connection type). Whenever the user of the adapter changes the value of a dependency parameter (a parameter upon which a resource domain lookup depends), the adapter service editor checks its cache for a set of resource domain values based on the new value. If an appropriate set of resource domain values is not found in the cache, then the adapter service editor calls the adapterResourceDomainLookup method again.

Adapter Check Values operate very much like resource domain lookups. When user of the adapter types a value into a parameter configured with an adapter check value, a call is made to the adapterCheckValue method of the corresponding connection class. If the validation succeeds, the adapter service editor caches the checked parameter value as well as the values of any dependent parameters for future use. If a parameter uses the adapter check value feature and is also a dependency parameter for the resource domain lookup of another parameter, the adapter check value validation is performed first. If the validation succeeds, the appropriate lookups are performed. For more information, see Adapter Check Value Callbacks.

Executing Adapter Service Nodes

When an adapter service executes, the Integration Server performs the following:
  • Creates a new instance of the corresponding class, unless it is already cached.
  • Calls the metadata parameter "set" methods, passing the parameter settings stored in the adapter service node.
  • Calls the service's execute method, passing a connection instance and a copy of the pipeline wrapped in a WmRecord object, as shown in the figure.

Adapter Service Implementation

The example provided in this section demonstrates the mechanics of an adapter service implementation by making full use of design-time and runtime interactions while emulating interactions with an external adapter resource.

The example adapter service simulates a simple database update service, allowing the user of the adapter to select table and column names that create the runtime signature for the resulting adapter service node. Table and column names are provided from hard-coded lists in a mock-connection implementation, as if the data were actually retrieved from the adapter resource. The example also includes interactions with the pipeline based on a dynamic service signature. The example is self-contained; it does not actually interact with any external resource.

The model for adapter services forces syntactic and semantic coupling of code in different methods and classes. Because of this, it might be difficult to understand the process of creating an adapter service by looking at the classes (or even methods) as a unit of work in the development process. For example, adding a metadata parameter can require updating two or more methods in the Adapter Service implementation class, updating up to three methods in the associated connection classes, and adding two entries in the resource bundle. Thus, this section approaches the implementation of a service as a series of activities that you perform, each of which may traverse multiple methods and classes.

This section provides examples of the resulting code, and refers to specific lines.

The tasks for creating an adapter service are as follows:

  • Defining a WmAdapterService Implementation Class
  • Specifying Configuration Metadata for Adapter Service
  • Implementing Configuration Resource Domains for Adapter Service
  • Manipulating Adapter Service Signature Properties
  • Specifying Adapter Service Signature Data
  • Specifying Adapter Service Signature Resource Domains
  • Implementing the WmAdapterService.execute Method
  • Updating the Resource Bundle
  • Registering Adapter Service in the Connection Factory Implementation Class
  • Compiling the adapter
  • Reloading Adapter
  • Refreshing the Designer cache
  • Configuring and Testing Adapter Service Nodes

Example 1: WmAdapterService Implementation Class

package com.wm.MyAdapter.services;

import com.wm.adk.cci.interaction.WmAdapterService;
import com.wm.adk.cci.record.WmRecord;
import com.wm.adk.cci.record.WmRecordFactory;
import com.wm.adk.connection.WmManagedConnection;
import com.wm.adk.metadata.WmTemplateDescriptor;
import com.wm.data.IData;
import com.wm.data.IDataCursor;
import com.wm.data.IDataFactory;
import com.wm.data.IDataUtil;

import java.util.Hashtable;
import java.util.Locale;
import javax.resource.ResourceException;

import com.wm.MyAdapter.MyAdapter;

public class MockDbUpdate extends WmAdapterService {
	//MockDB Group
	public static final String UPD_SETTINGS_GRP = "Mock Settings";
	public static final String TABLE_NAME_PARM = "tableName";
	public static final String COLUMN_NAMES_PARM = "columnNames";
	public static final String COLUMN_TYPES_PARM = "columnTypes";
	public static final String REPEATING_PARM = "repeating";
	public static final String OVERRIDE_TYPES_PARM = "overrideTypes";

	private String _tableName;
	private String[] _columnNames;
	private String[] _columnTypes;
	private boolean _repeating;
	private String[] _overrideTypes;

	public void setTableName(String val){ _tableName = val;}
	public void setColumnNames(String[] val){ _columnNames = val;}
	public void setColumnTypes(String[] val){ _columnTypes = val;}
	public void setRepeating(boolean val){ _repeating = val;}
	public void setOverrideTypes(String[] val){_overrideTypes = val;}

	public static final String TABLES_RD = "tablesRD";
	public static final String COLUMN_NAMES_RD = "columnNamesRD";
	public static final String COLUMN_TYPES_RD = "columnTypesRD";
	public static final String OVERRIDE_TYPES_RD = "overrideTypesRD";

	//MockDB Signature Group
	public static final String SIG_SETTINGS_GRP = "Signature";
	public static final String FIELD_NAMES_PARM = "fieldNames";
	public static final String FIELD_TYPES_PARM = "fieldTypes";
	public static final String SIG_IN_PARM = "sigIn";
	public static final String SIG_OUT_PARM = "sigOut";

	private String[] _fieldNames;
	private String[] _fieldTypes;

	public void setFieldNames(String[] val){ _fieldNames = val;}
	public void setFieldTypes(String[] val){ _fieldTypes = val;}
	public void setSigIn(String[] val){}
	public void setSigOut(String[] val){}

	public static final String FIELD_NAMES_RD = "fieldNamesRD";
	public static final String FIELD_TYPES_RD = "fieldTypesRD";

	public void fillWmTemplateDescriptor(WmTemplateDescriptor d,Locale l)
		throws ResourceException
	{
		//MockDB Grouping and resource domain setup
		d.createGroup(UPD_SETTINGS_GRP, new String [] { 
				TABLE_NAME_PARM,
				REPEATING_PARM,
				COLUMN_NAMES_PARM,
				COLUMN_TYPES_PARM,
				OVERRIDE_TYPES_PARM}
			);
		d.createFieldMap(new String[] {
				COLUMN_NAMES_PARM,
				COLUMN_TYPES_PARM,
				OVERRIDE_TYPES_PARM},
			true);
		d.createTuple(new String[]{COLUMN_NAMES_PARM,COLUMN_TYPES_PARM});
		
		d.setResourceDomain(TABLE_NAME_PARM,TABLES_RD,null);
		d.setResourceDomain(COLUMN_NAMES_PARM,COLUMN_NAMES_RD,
			new String[]{TABLE_NAME_PARM});
		d.setResourceDomain(COLUMN_TYPES_PARM,COLUMN_TYPES_RD,
			new String[]{TABLE_NAME_PARM});
		d.setResourceDomain(OVERRIDE_TYPES_PARM,OVERRIDE_TYPES_RD,null);

		//MockDB Signature Grouping and resource domain setup
		d.createGroup(SIG_SETTINGS_GRP, new String [] {
				FIELD_NAMES_PARM,
				FIELD_TYPES_PARM,
				SIG_IN_PARM,
				SIG_OUT_PARM}
			);
		d.createFieldMap(new String [] {
				FIELD_NAMES_PARM,
				FIELD_TYPES_PARM,
				SIG_IN_PARM,
				SIG_OUT_PARM},
			false);
		d.createTuple(new String[]{FIELD_NAMES_PARM,FIELD_TYPES_PARM});
		
		String [] fieldTupleDependencies = {TABLE_NAME_PARM,
			REPEATING_PARM,
			COLUMN_NAMES_PARM,
			COLUMN_TYPES_PARM,
			OVERRIDE_TYPES_PARM};
		d.setResourceDomain(FIELD_NAMES_PARM,FIELD_NAMES_RD, fieldTupleDependencies);
		d.setResourceDomain(FIELD_TYPES_PARM,FIELD_TYPES_RD, fieldTupleDependencies);
		d.setResourceDomain(SIG_IN_PARM,WmTemplateDescriptor.INPUT_FIELD_NAMES,
			new String[] {FIELD_NAMES_PARM, FIELD_TYPES_PARM});
		d.setResourceDomain(SIG_OUT_PARM,WmTemplateDescriptor.OUTPUT_FIELD_NAMES,
			new String[] {FIELD_NAMES_PARM, FIELD_TYPES_PARM});


		//Call to setDescriptions
		d.setDescriptions(MyAdapter.getInstance().
			getAdapterResourceBundleManager(),l);
	}
	public WmRecord execute(WmManagedConnection connection, WmRecord input)
		throws ResourceException
	{
		Hashtable[] request = this.unpackRequest(input);
		return this.packResonse(request);
	}

	private Hashtable[] unpackRequest(WmRecord request) throws ResourceException
	{
		Hashtable data[] = null;
		IData mainIData = request.getIData();
		IDataCursor mainCursor = mainIData.getCursor();

		try
		{
			String tableName = this._tableName;
			String[] columnNames = this._columnNames;

			if(mainCursor.first(tableName))
			{
				IData[] recordIData;
				if(this._repeating)
				{
					recordIData = IDataUtil.getIDataArray (mainCursor,tableName);
					data = new Hashtable[recordIData.length];
				}
				else
				{
					recordIData = new IData[] {IDataUtil.getIData(mainCursor)};
					data = new Hashtable[1];
				}
				for(int rec=0;rec<recordIData.length;rec++)
				{
					IDataCursor recordCursor = recordIData[rec].getCursor();
					data[rec] = new Hashtable();
					for(int c = 0; c < columnNames.length;c++)
					{
						if(recordCursor.first(columnNames[c]))
						{
							data[rec].put(tableName + "." + columnNames[c],
							recordCursor.getValue());
						}
					}
					recordCursor.destroy();
				}
			}
			else
			{
				throw MyAdapter.getInstance().createAdapterException(9999,
					new String[] {"No Request Data"});
			}
		}
		catch (Throwable t)
		{
			throw MyAdapter.getInstance().createAdapterException(9999,
				new String[] {"Error unpacking request data"},t);
		}
		finally
		{
			mainCursor.destroy();
		}
		return data;
	}

	private WmRecord packResonse(Hashtable[] response) throws ResourceException
	{
		WmRecord data = null;
		try
		{
			IData[] recordIData = new IData[response.length];
			String tableName = this._tableName;
			String[] columnNames = this._columnNames;

			for(int rec = 0; rec < response.length; rec++)
			{
				recordIData[rec] = IDataFactory.create();
				IDataCursor recordCursor = recordIData[rec].getCursor();
				for(int col = 0; col < columnNames.length;col++)
				{
					IDataUtil.put(recordCursor,columnNames[col],
						response[rec].get(tableName + "." +
						columnNames[col]));
				}
				recordCursor.destroy();
			}
			IData mainIData = IDataFactory.create();
			IDataCursor mainCursor = mainIData.getCursor();
			if(this._repeating)
			{
				IDataUtil.put(mainCursor,tableName,recordIData);
			}
			else
			{
				IDataUtil.put(mainCursor,tableName,recordIData[0]);
			}
			mainCursor.destroy();
			data = WmRecordFactory.getFactory().createWmRecord("nameNotUsed");
			data.setIData(mainIData);
		}
		catch (Throwable t)
		{
			throw MyAdapter.getInstance().createAdapterException(9999,
				new String[] {"Error packing response data"},t);
		}
		return data;
	}
}

Example 2: WmManagedConnection Implementation Class Updates

package com.wm.MyAdapter.connections;

import com.wm.adk.connection.WmManagedConnection;
import com.wm.adk.metadata.*;
import com.wm.adk.error.AdapterException;

import com.wm.MyAdapter.MyAdapter;
import com.wm.MyAdapter.services.MockDbUpdate;


public class SimpleConnection extends WmManagedConnection {
	String hostName;
	int port;

	//Adapter Services variables
	private String[] mockTableNames ={ "CUSTOMERS","ORDERS","LINE_ITEMS"};
	private String[][] mockColumnNames ={
		{"name","id", "ssn"},
		{"id","date","customer_id"},
		{"order_id","item_number","quantity","description"}
	};

	private String [][] mockDataTypes = {
		{"java.lang.String","java.lang.Integer", "java.lang.String"},
		{"java.lang.Integer", "java.util.Date", "java.lang.Integer"},
		{"java.lang.Integer", "java.lang.Integer", "java.lang.Integer",
		"java.lang.String"}
	};

	public SimpleConnection(String hostNameValue, int portValue)
	{
		super();
		hostName = hostNameValue;
		port = portValue;
		MyAdapter.getInstance().getLogger().logDebug(9999, 
			"Simple Connection created with hostName = "
			+ hostName + "and port = " + Integer.toString(port));
	}
	public void destroyConnection()
	{
		MyAdapter.getInstance().getLogger().logDebug(9999,"Simple Connection Destroyed");
	}
	
	// The remaining methods support metadata for related services, etc.
	// Implement content as needed.
	public Boolean adapterCheckValue(String serviceName,
		String resourceDomainName,
		String[][] values,
		String testValue) throws AdapterException
	{
		Boolean result = new Boolean(false);
		if(resourceDomainName.equals(MockDbUpdate.OVERRIDE_TYPES_RD))
		{
			try
			{
				Object o = Class.forName(testValue).getConstructor(
					new Class[] {String.class}).newInstance(new Object[]{"0"});
				result = new Boolean(true);
			}
			catch (Throwable t){}
		}
		return result;
	}
	public ResourceDomainValues[] adapterResourceDomainLookup(String serviceName,
		String resourceDomainName, String[][] values) throws AdapterException
	{
		ResourceDomainValues[] results = null;
		
		//MockDB Group Lookup
		if(resourceDomainName.equals(MockDbUpdate.COLUMN_NAMES_RD)||
			resourceDomainName.equals(MockDbUpdate.COLUMN_TYPES_RD))
		{
			String tableName = values[0][0];
			for(int x = 0; x < this.mockTableNames.length;x++)
			{
				if(this.mockTableNames[x].equals(tableName))
				{
					ResourceDomainValues columnsRdvs = new ResourceDomainValues(
						MockDbUpdate.COLUMN_NAMES_RD,this.mockColumnNames[x]);
					columnsRdvs.setComplete(true);
					ResourceDomainValues typesRdvs = new ResourceDomainValues(
						MockDbUpdate.COLUMN_TYPES_RD, this.mockDataTypes[x]);
					typesRdvs.setComplete(true);
					results = new ResourceDomainValues[] {columnsRdvs,typesRdvs};
					break;
				}
			}
		}
		//MockDB Signature Group Lookup
		else if (resourceDomainName.equals(MockDbUpdate.FIELD_NAMES_RD)||
			resourceDomainName.equals(MockDbUpdate.FIELD_TYPES_RD))
		{
			String tableName = values[0][0];
			boolean repeating = Boolean.valueOf(values[1][0]).booleanValue();
			String[] columnNames = values[2];
			String[] columnTypes = values[3];
			String[] overrideTypes = values[4];

			String[] fieldNames = new String[columnNames.length];
			String[] fieldTypes = new String[columnTypes.length];
			String optBrackets;

			if(repeating)
				optBrackets ="[]";
			else
				optBrackets = "";


			for (int i = 0; i< fieldNames.length;i++)
			{
				fieldNames[i] = tableName + optBrackets + "." + columnNames[i];
				fieldTypes[i] = columnTypes[i] + optBrackets;

				if(overrideTypes.length > i)
				{
					if (!overrideTypes[i].equals(""))
					{
						fieldTypes[i] = overrideTypes[i] + optBrackets;
					}

				}

			}
			results = new ResourceDomainValues[]{
				new ResourceDomainValues(MockDbUpdate.FIELD_NAMES_RD,fieldNames),
				new ResourceDomainValues(MockDbUpdate.FIELD_TYPES_RD,fieldTypes)};

		}

		return results;
	}

	public void registerResourceDomain(WmAdapterAccess access)
		throws AdapterException
	{
		//MockDB Group Registering Resource Domain
		ResourceDomainValues tableRdvs = new ResourceDomainValues(
			MockDbUpdate.TABLES_RD,mockTableNames);
		tableRdvs.setComplete(true);
		access.addResourceDomain(tableRdvs);

		access.addResourceDomainLookup(MockDbUpdate.COLUMN_NAMES_RD,this);
		access.addResourceDomainLookup(MockDbUpdate.COLUMN_TYPES_RD,this);

		ResourceDomainValues rdvs = new ResourceDomainValues(
			MockDbUpdate.OVERRIDE_TYPES_RD, new String[] {""});
		rdvs.setComplete(false);
		rdvs.setCanValidate(true);
		access.addResourceDomain(rdvs);
		access.addCheckValue(MockDbUpdate.OVERRIDE_TYPES_RD,this);
		
		//MockDB Signature Group Registering Resource Domain
		access.addResourceDomainLookup(MockDbUpdate.FIELD_NAMES_RD,this);
		access.addResourceDomainLookup(MockDbUpdate.FIELD_TYPES_RD,this);

	}
}

Defining WmAdapterService Implementation Class

Procedure

  1. Create a folder structure for the Java package for adapter service implementation. For example: com\mycompany\adapter\myadapter. In the example, the Java package created is com\wm\services.
    Note: You must create your Java package and classes in the adapterPackageName\code\source folder in the IBM webMethods package you created using Designer.
  2. Create a class by extending the base class com.wm.adk.cci.interaction.WmAdapterService.
    In the example, the class created is MockDBUpdate.
  3. Implement the abstract method WmAdapterService.execute.
  4. Override the base class implementation of the WmAdapterService.fillWmTemplateDescriptor method.

Specifying Configuration Metadata for Adapter Service

The next logical step for implementing an adapter service is to create the metadata that enables the users of the adapter to create adapter service nodes. To do this, you perform the following:

  • Create metadata parameters appropriate for the function of the adapter service.
  • Describe presentation for those metadata parameters.
  • Set the data entry rules for those metadata parameters.

Creating Parameters for Data Entry

The sample implementation includes five metadata parameters that the users of the adapter use for data entry when they create adapter service nodes. Each parameter has:

  • An accessor method.
  • A variable to hold the configured values.
  • A String constant containing the name of the parameter.
  • A set of resource bundle entries with a localizable parameter name and description. For information about metadata parameters, see Metadata Model for Connection.

The following table describes the purpose of each of these parameters for data entry:

Parameter Description
tableName Enables the users of the adapter to select a table to update.
columnNames Lists the columns in the selected table for updating. The resource domain lookup for this parameter depends on the value in the tableName parameter.
columnTypes Contains the default type associated with the columnName.
overrideTypes Enables the users of the adapter to type a different data type for the column value.
repeating A Boolean flag indicating whether the service is used to update a single row or multiple rows of the table.

Specifying the Display and Data Entry Attributes of the "Data Entry" Parameters

  • After creating the parameters, specify the display and data entry attributes by calling various methods of the WmTemplateDescriptor interface from the service's fillWmTemplateDescriptor method.
  • The example code places each data entry parameter into a single group (in display order) referenced by the constant UPD_SETTINGS_GRP. A constant instead of a string is used to name the group, because the same value is used in the resource bundle to specify a localizable group name.

Placing the Column Names and Column Data Types Parameters in a Field Map

Next, the example places columnNames and the two types parameters in a field map. The use of two data type columns in the fieldMap warrants further discussion. The desired behavior is to:
  • Automatically update the data type when the column name changes.
  • Allow the users of the adapter to enter an alternative data type for the given field.
  • The adapter must convert the data at run time.
To have the type value change with the columnName, the resource domain associated with the parameter must be "complete" (as specified by the setComplete method being set to true). Users are not allowed to type values into fields of a "complete" resource domain. Because of these conflicting constraints, it is necessary to have two parameters with different resource domain associations: one updated by the adapter service editor, and the other by the users of the adapter.

Placing the Column Names and Column Types Parameters in a Tuple

Finally, the columnNames and columnTypes parameters are placed in a tuple. In a tuple, not only are the resource domain lookups performed together, but the adapter service editor maintains a relationship between the parameter settings such that when value[n] is selected from the resource domain value list for columnNames, then value[n] is automatically selected for the corresponding columnTypes value. Alternatively, you can make a resource domain lookup for columnTypes that depends on the corresponding value of columnNames and then determines the appropriate type in the lookup.

Implementing Configuration Resource Domains for Adapter Service

About this task

The next step for implementing an adapter service is to:

  • Define and implement the resource domains required for the metadata parameters that you created.
  • Identify the values upon which those resource domains depend.

For each parameter that requires either a resource domain to supply a value or that requires a validity check for values supplied by the users of the adapter, you must:

Procedure

  1. In the service's fillWmTemplateDescriptor method, call WmTemplateDescriptor.setResourceDomain method, passing the name of the parameter, the name of the resource domain, and an array of the names of any parameters on which the resource domain depends.
  2. In the associated connection class's WmManagedConnection.registerResourceDomain method, call WmAdapterAccess.addResourceDomain(ResourceDomainValues) to register the resource domain support.
  3. Implement the code to populate the resource domain values and/or the "check values".
  4. In the associated connection class's WmManagedConnection.registerResourceDomain method, call WmAdapterAccess.addResourceDomainLookup(Resource_Domain_Name, WmManagedConnection) method to add the resource domains that have to be looked up.

Results

  • The first parameter, tableName, is associated with a new resource domain called tableNameRD.
    • The list of available tables in this example does not depend on any other parameters, so the dependency list is left null.
    • Furthermore, since the list does not change once it is retrieved from the resource, it can be implemented as a complete resource domain during registration.
    • When a ResourceDomainValues object is provided in registerResourceDomain, there is no need to add support for the resource domain in the lookup method.
  • The resource domains columnNamesRD and columnTypesRD are created to support the columnNames and columnTypes parameters, respectively. The columNamesRD resource domain depends on the value of the tableName parameter. Since columnNames and columnTypes were placed in a tuple, columnTypesRD must also depend on the value of tableName.
  • The lookup implementation for these resource domains checks for the name of the resource domain and returns the values for both resource domains in a single response array. The columnNamesRD resource domain is always passed as the resource domain name in this lookup. Adding the '||' check decouples the lookup implementation from the order in which the parameters were placed in the tuple.
  • The final resource domain, overrideTypesRD associated with the overrideTypes parameter, is used to validate data entered by the users of the adapter into a Java class that contains the data at run time. The specifics of the check implementation are probably unrealistic for a real-world environment, but all the mechanics of doing a check are demonstrated. Remember to set the setCanValidate method to true in the WmManagedConnection.registerResourceDomain method.

Manipulating Adapter Service Signature Properties

In addition to controlling the names and types of the fields in an adapter service signature, the adapter has control over several other aspects of a service's structure and behavior. These aspects can be broadly divided into two categories:

  • Template-based properties which apply to all the adapter service nodes associated with the service implementation class.
  • Signature field properties which are specific to the records and fields that make up the signature of a particular node.

Template-Based Signature Properties

In the implementation of the adapter service's fillWmTemplateDescriptor method, the following signature-related features may be configured using the following methods:

Method Name Description
WmDescriptor.setShowConnectionName(boolean) Includes the reserved string field named $connectionName in the service input signature. Possible Values are:
  • true. Default. Includes the reserved string field named $connectionName in the service input signature. This field allows the flow adapter developers to control the connection pool used during each invocation of the service. The $connectionName field is inserted in the top-level signature record, outside the wrapper.
  • false. Excludes the reserved string field named $connectionName from the service input signature.
For more information about the effect of $connectionName on the run time behavior of the service, see the javadoc for WmDescriptor.showConnectionName().
WmDescriptor.setSignatureWrapped(boolean) Wraps the adapter-defined signature fields in a record called xxxInput for input fields and xxxOutput for output fields, where xxx represents the name of the adapter service node when set to true. Possible Values are:
  • true. Default.
  • false.
WmDescriptor.setPassFullPipeline(boolean) Enables the access to all fields in the pipeline. Possible values are:
  • true. Default. The adapter service can access all the fields in the pipeline.
  • false. The adapter service may only read or write to pipeline fields that are part of the service's defined signature.

Signature Field Properties

All the Integration Server services (including adapter services, flow services, and Java services) contain an input and output signature definition that identifies the names and types of the pipeline fields, read or written by the service. For each of these fields, there are also a number of properties that can be used to document the intended use of the field or to create constraints on what data is valid for that field at run time. For more information on these properties, see the IBM webMethods Service Development Help for your release.

In the flow services and Java services, signature fields and their properties can be modified by the user. For the adapter services, the adapter defines resource domains that act as callbacks from the developer tool that allows the adapter to specify the name, data type, and structure of the service's signature while the service is being configured. A separate callback mechanism allows the adapter to control a limited subset of signature field constraint properties.

The signature field constraints that are controlled by the adapter include:

Signature Field Constraint Field Behavior
Required If true, the field must be present on the pipeline.
Allow null If false, when the field is present, the field cannot hold a null value.
Allow unspecified fields Controls whether the document (record) element can hold fields that are not specifically identified in the signature. This constraint has no effect on non-document-type signature elements.

The controls for these constraints are disabled so the user can view the value, but not modify it. The remaining properties (that are not related to name and type) are enabled and may be managed like any other service.

Note: Like other service types, signature constraints are only enforced at run time if the associated Validate input or Validate output check box is selected by the user.

Adapters gain access to a signature field's constraints by overriding the setSignatureProperties() method in the WmAdapterService implementation class. This method is called whenever the adapter service node is saved, and whenever the user views the input/output panel of an unsaved adapter service. Because this call is made while the adapter service changes are still in progress, the call is made against a temporary object that has all metadata parameter settings as existing in the adapter service editor. This is not the same object that is used for runtime service invocations.

The ADK includes three classes that are used to provide access to signature property information.

PipelineVariableProperties Abstract base class that represents any signature element (field or record). It exposes read access to all common signature element properties (name, data type, comments, etc.) and read/write access to the Required and Allow null constraints.
PipelineFieldProperties Subclass of PipelineVariableProperties that represents a single non-document-type field in the signature. It adds read only access to properties that are specific to non-document elements (pick list choices, content type, etc.)
PipelineRecordProperties Subclass of PipelineVariableProperties that represents a single document-type element in the signature. It adds read/write access to the Allow unspecified fields property, and methods for accessing the member elements of the record.

The WmAdapterService.setSignatureProperties() method receives two PipelineRecordProperties objects as arguments, one for the input signature and the other for the output signature. The adapter must use the accessor/navigation methods available through the two PipelineRecordProperties objects to locate the signature elements for which the constraints have to be managed. Within the setSignatureProperties() implementation, it is frequently useful to use the WmAdapterService.inputRecordName() and WmAdapterService.outputRecordName() methods to get the names of the respective signature wrappers (if wrappers are enabled). If a connection is needed to get the constraint information from a connection target, use the WmAdapterService.retrieveConnection() method.

Note: This is the only place retrieveConnection must be used; using it from the service's execute method causes errors.

The code listing below demonstrates a simple implementation of the signature constraint management.

protected void setSignatureProperties(  
  PipelineRecordProperties inputSigProps,  
  PipelineRecordProperties outputSigProps) throws ResourceException  
  {  
     if(this._tableName != null)  
     {  
       // need a connection to look up info about table being updated  
       MockDbConnection conn = (MockDbConnection)retrieveConnection();  
       TableInfo info = conn.getTableInfo(this._tableName);  
       updateSignatureRecord(inputSigProps, info, _columnNames,  
          inputRecordName());  
       updateSignatureRecord(outputSigProps, info, _columnNames,  
          outputRecordName());  
     }  
  }  
  private void updateSignatureRecord(PipelineRecordProperties inputSigProps,  
    TableInfo tInfo, String[] columnNames, String wrapperName)  
  {  
      PipelineRecordProperties wrapperRec =  
       (PipelineRecordProperties)inputSigProps.findByPath(wrapperName);  
      wrapperRec.setAllowNull(false);  
     wrapperRec.setAllowUnspecifiedFields(false);  
     wrapperRec.setRequired(true);  
     if(columnNames != null)  
     {  
       for(int i = 0; i < columnNames.length; i++)  
       {  
           ColumnInfo cInfo = tInfo.getColumnInfo(columnNames[i]);  
           PipelineVariableProperties fieldProps =  
               wrapperRec.findByPath(columnNames[i]);  
           fieldProps.setAllowNull(false);  
           fieldProps.setRequired(cInfo.isRequired());  
       }  
     }
   }

Specifying Adapter Service Signature Data

After implementing the configuration logic for the adapter service template, implement the logic that defines the runtime signature of a configured adapter service node. To do so, create the following additional metadata parameters:

  • sigIn and sigOut.

    The reserved signature resource domains uses these parameters.

  • fieldNames and fieldTypes

    These parameters are the dependency parameters in which you build the signature data. Because the example update service has the same input and output signature, only one set of name and type parameters is necessary. The relationship between these parameters is established in the WmTemplateDescriptor. The mechanics of signature construction is discussed in Adapter Service Node Signatures.

These parameters do not accept input from the users of the adapter; from the user's perspective, they are largely redundant with information provided elsewhere in the adapter service editor. In most implementations, these parameters are included in the same group with the configuration parameters, but are hidden from the users of the adapter. For demonstration purposes, these parameters remain visible in the example, but they are located in a separate group. Except for that, the metadata constructs for these parameters follow the same basic rules for specifying a signature for any service.

Specifying Adapter Service Signature Resource Domains

The resource domain implementation for the signature parameters is a little more complex. The fieldNamesRD and fieldTypesRD resource domains are designed to depend on the values of each of the configuration parameters as described in Specifying Configuration Metadata for Adapter Service. In the WmManagedConnection lookup implementation, both fieldNamesRD and fieldTypesRD are constructed as "complete" resource domains.

For fieldNamesRD, the tableName and columnName parameter values are used to form a hierarchical signature in which the columnName elements are contained in an aggregate named by the tableName. If the parameter named repeating is set to true, then the tableName aggregate is converted to an array by inserting square brackets ("[]") in the field name.

For fieldTypesRD, a value in the overrideTypes parameter has precedence over a value in columnTypes, and the repeating parameter is used to specify whether the type repeats.

Implementing the WmAdapterService.execute Method

The final step for implementing an adapter service is to implement its execute method. This method is specific to the resource with which the adapter communicates. In most cases, the adapter must interact with the pipeline at the beginning and/or end of the execute method. The methods unpackRequest and packResponse demonstrate an effective method of interacting with the pipeline using the same metadata parameters that were used to create the signature.

Important: The unpackRequest and packResponse methods read class fields, but they never write to them. This is important because of the multi-threaded nature of the adapter service execution. At run time, exactly one WmAdapterService object corresponds to each adapter service node defined in the namespace. All invocations of a given adapter service node call the execute method on the same object. If more than one thread is executing the service at the same time, then updates to the class fields by one thread inevitably collide with those of another thread.

Updating the Resource Bundle

Update the resource bundle with a display name, and description to make the service more usable.
package com.wm.MyAdapter;
..
..
import com.wm.MyAdapter.services.MockDbUpdate;
..
..
public class MyAdapterResource extends ListResourceBundle implements MyAdapterConstants{
   ..
   .. 
 static final Object[][] _contents = {	
   ..
   .. 
		//MockDB Group Resource Domain Values
		,{MockDbUpdate.class.getName() + ADKGLOBAL.RESOURCEBUNDLEKEY_DISPLAYNAME,
			"Mock Update Service"}
		,{MockDbUpdate.class.getName() + ADKGLOBAL.RESOURCEBUNDLEKEY_DESCRIPTION,
			"Simulates a database update service"}
		,{MockDbUpdate.UPD_SETTINGS_GRP + ADKGLOBAL.RESOURCEBUNDLEKEY_GROUP,
			MockDbUpdate.UPD_SETTINGS_GRP}
		,{MockDbUpdate.TABLE_NAME_PARM + ADKGLOBAL.RESOURCEBUNDLEKEY_DISPLAYNAME, 
			"Table Name"}
		,{MockDbUpdate.TABLE_NAME_PARM + ADKGLOBAL.RESOURCEBUNDLEKEY_DESCRIPTION, 
			"Select Table Name"}
		,{MockDbUpdate.COLUMN_NAMES_PARM + ADKGLOBAL.RESOURCEBUNDLEKEY_DISPLAYNAME,
			"Column Names"}
		,{MockDbUpdate.COLUMN_NAMES_PARM + ADKGLOBAL.RESOURCEBUNDLEKEY_DESCRIPTION,
			"Name of column updated by this service"}
		,{MockDbUpdate.COLUMN_TYPES_PARM + ADKGLOBAL.RESOURCEBUNDLEKEY_DISPLAYNAME,
			"Column Types"}
		,{MockDbUpdate.COLUMN_TYPES_PARM + ADKGLOBAL.RESOURCEBUNDLEKEY_DESCRIPTION,
			"Default data type for column"}
		,{MockDbUpdate.OVERRIDE_TYPES_PARM + ADKGLOBAL.RESOURCEBUNDLEKEY_DISPLAYNAME, 
			"Override Data Types"}
		,{MockDbUpdate.OVERRIDE_TYPES_PARM + ADKGLOBAL.RESOURCEBUNDLEKEY_DESCRIPTION, 
			"Type to override column default"}
		,{MockDbUpdate.REPEATING_PARM + ADKGLOBAL.RESOURCEBUNDLEKEY_DISPLAYNAME, 
			"Update Multiple Rows?"}
		,{MockDbUpdate.REPEATING_PARM + ADKGLOBAL.RESOURCEBUNDLEKEY_DESCRIPTION,
			"Select if input will include multiple rows to update"}

		//MockDB Signature Group Resource Domain Values
		,{MockDbUpdate.SIG_SETTINGS_GRP + ADKGLOBAL.RESOURCEBUNDLEKEY_GROUP,
			MockDbUpdate.SIG_SETTINGS_GRP}
		,{MockDbUpdate.FIELD_NAMES_PARM + ADKGLOBAL.RESOURCEBUNDLEKEY_DISPLAYNAME,
			"Field Names"}
		,{MockDbUpdate.FIELD_NAMES_PARM + ADKGLOBAL.RESOURCEBUNDLEKEY_DESCRIPTION,
			"Name of Field"}
		,{MockDbUpdate.FIELD_TYPES_PARM + ADKGLOBAL.RESOURCEBUNDLEKEY_DISPLAYNAME,
			"Field Type"}
		,{MockDbUpdate.FIELD_TYPES_PARM + ADKGLOBAL.RESOURCEBUNDLEKEY_DESCRIPTION,
			"Type of Field"}
		,{MockDbUpdate.SIG_IN_PARM + ADKGLOBAL.RESOURCEBUNDLEKEY_DISPLAYNAME,
			"Input Signature"}
		,{MockDbUpdate.SIG_IN_PARM + ADKGLOBAL.RESOURCEBUNDLEKEY_DESCRIPTION,
			"Input Signature"}
		,{MockDbUpdate.SIG_OUT_PARM + ADKGLOBAL.RESOURCEBUNDLEKEY_DISPLAYNAME,
			"Output Signature"}
		,{MockDbUpdate.SIG_OUT_PARM + ADKGLOBAL.RESOURCEBUNDLEKEY_DESCRIPTION,
			"Output Signature"}
  }
  protected Object[][] getContents() {
		 // TODO Auto-generated method stub
		 return _contents;
  }
}

Registering Adapter Service in the Connection Factory Implementation Class

You must register each adapter service template class in the WmManagedConnectionFactory implementation class. Pass the class name to the ResourceAdapterMetadataInfo.addServiceTemplate method in the SimpleConnectionFactory.fillResourceAdapterMetadataInfo method in the WmManagedConnectionFactory implementation class. In the example, the MockDbUpdate class is registered in the SimpleConnectionFactory connection factory implementation class:

For example: SimpleConnectionFactory class

import com.wm.MyAdapter.services.*;  
.  
.  
public class SimpleConnectionFactory extends WmManagedConnectionFactory implements MyAdapterConstants {
.  
.   
		public void fillResourceAdapterMetadataInfo(
		ResourceAdapterMetadataInfo info, Locale locale)
	{        info.addServiceTemplate(MockDbUpdate.class.getName()); 
	}
}

Refreshing the Designer cache

About this task

Refresh the Designer cache.

Configuring and Testing Adapter Service Nodes

About this task

Before you configure adapter service nodes, ensure that you have configured a connection node as described in Configuring and Testing Connection Nodes. You can use Designer to configure adapter service nodes.

To configure the adapter service nodes

Procedure

  1. Start Designer.
    Note: Make sure that the Integration Server, with which you want to use Designer, is running.
  2. Select a namespace node package where you want to create the adapter service node.
  3. Create a folder in the selected package and navigate to that folder in the Package Navigator section.
  4. Select File > New.
  5. Select Adapter Service from the list of elements.
  6. In the Create a New Adapter Service screen, type a name for your service in the Element name field and click Next.
  7. In the Select Adapter Type screen, select the name of your adapter and click Next.
  8. In the Select an Adapter Connection Alias screen, select the appropriate adapter connection name and click Next.
  9. In the Select a Template screen, select an adapter service template and click Next.
  10. Click Finish.
  11. Specify values for the tab that is specific for your adapter resource (such as Query, Update, Add, or Delete tab).
  12. Specify values for the Input/Output tab and the Settings tab. For more information, see the IBM webMethods Service Development Help for your release.
  13. Select File > Save.