IBM BPM, V8.0.1, All platforms > Authoring services in Integration Designer > Services and service-related functions > Access external services with adapters > Configure and using adapters > IBM WebSphere Adapters > Adapter Toolkit > Implementing code from the IBM WebSphere Adapter Toolkit
Data and metadata
Adapter Foundation Classes (AFC) implement DESPI APIs and support two data formats, service data objects (SDO) and JavaBeans.
The data format-specific implementations are provided in the AFC and are abstracted from the adapters which use the DESPI APIs to process data in a format-independent way.
XSD and JavaBeans structure relationship to DESPI
SDO Structure:
JavaBeanRecord Structure:The JavaBeanRecord data structure is derived from the XML schema defining the SDO. Adapter foundation classes provide an implementation of RecordGenerator which generates JavaBeanRecords for a given SDO/XML schema.
The RecordGenerator class is used by the adapter enterprise metadata to generate the required artifacts for JavaBeans Record data format. See Enterprise metadata implementation details on how to update the adapter enterprise metadata (EMD) implementation to use the RecordGenerator class.
Type mappings: Bean properties map to the attributes of a given complex type. The types of the simple attributes are derived from the XML built-in data types defined in the input schema for each subelement of the complex type. The subelements containing n-cardinality child objects are always defined as an array of the child type while single cardinality subelements are represented as a JavaBeans property with the type of the subelement.
The table below details the mapping between the built-in XML Schema Definition (XSD) types and bean properties generated by the RecordGenerator implementation in the AFC.
Mapping between built-in XSD schema and JavaBeans properties Header Header Boolean boolean String String Int int Integer Integer Decimal BigDecimal Double double Float float Long long Short short hexBinary byte[] (byte array) Byte byte dateTime Calendar Date Calendar Time Calendar anySimpleType String Any String There are cases in which a simple XML data type must be mapped to the corresponding Java™ wrapper class for the Java primitive type:
- an element declaration with the nillable attribute set to True
- an element declaration with the minOccurs attribute set to 0 (zero) and the maxOccurs attribute set to 1 (one) or absent
- an attribute declaration with the use attribute set to optional or absent and carrying either the default or the fixed attribute
The examples of each is as follows:
<xsd:element name="code" type="xsd:int" nillable="true"/> <xsd:element name="code2" type="xsd:int" minOccurs=""></xsd:element> <xsd:element name=""> <xsd:complexType> <xsd:sequence/> <xsd:attribute name=""> </xsd:attribute></xsd:complexType> </xsd:element>The element/attribute declarations for code, code2, code3 are all mapped to the java.lang.Integer type.
JavaBeans Metadata ASI format: The metadata is derived mostly from the structure of the bean. Other metadata, such as containedType and maxLength are not normal parts of a JavaBeans structure, so they must be part of the annotation maps.
Annotation maps:Annotations are not normally part of a JavaBeans structure, so JavaBeanRecords must contain annotations in a specific format to be usable by the metadata API.
The JavaBeanRecord must implement the BeanMetadata interface.
public interface BeanMetadata { public Map getObjectAnnotations(); public Map getPropertyAnnotations(); public Set getSetAttributes();}Each property (if it needs metadata) can have its own Map, which is stored in the propertyAnnotations map, using the property name as key.
Reserved keys in the propertyAnnotations map:
- ContainedType
The class of the object that this property contains
- PrimaryKey:
Whether this property is key
- DefaultValue:
The default value
- MaxLength:
The maximum length of this property.
The notion of whether a property is set is critical to processing null values or values that have not been set in the adapter. If a property has been explicitly set to null, the adapter must be able to detect this and set the associated property to null in the EIS.
If the property has not been set, it might still have a null value, but the adapter ignores the value and not set it in the EIS system.
A list of bean properties for which the setter is called is returned when getSetAttributes() is called. This enables the DESPI implementation to determine if a particular attribute has been set.
Property order:The notion of property order is critical, because the adapter may need to iterate over the properties in the same order that they appear in the EIS system.
Since JavaBeans APIs cannot detect the order present in the class file, there must be a string array called "propertyOrder" in the bean, containing the names of all properties in the preferred order.
public static final String[] propertyOrder = {"property1","property2"};SDO to JavaBeanRecord ASI Mappings: Annotations from the SDO/XML schema are read and stored in a Map structure in the bean. Here is a description of how the RecordGenerator would populate annotation maps. For each element in the metadata annotation, the generator would create an entry in the Map with the name of the element as the key.
- If the element is a simple type with single cardinality then the value of this element is added to the Map.
- If the element is a simple type with n-cardinality, then a List is generated containing one or more values of this element.
The List is then added to the annotation Map.
- If the element is a complex type with single cardinality then a Map is created containing the mappings for elements of this child complex type.
The Map is then added to the annotation Map.
- If the element is a complex type of multiple cardinality then a List is created.
The List would contain one or more Map entries where each Map contains the mapping for the elements of the child complex type.
Here is an example of how the object level metadata annotation would look like in an SDO schema:
<annotation> <appinfo source= "http://www.ibm.com/xmlns/prod/websphere/j2ca/sap/metadata"> <sapasi:sapBAPIBusinessObjectTypeMetadata xmlns:sapasi= "http://www.ibm.com/xmlns/prod/websphere/j2ca/sap/metadata"> <sapasi:Type>BAPI</sapasi:Type> <sapasi:Operation> <sapasi:MethodName>BAPI_CUSTOMER_CREATEFROMDATA1</sapasi:MethodName> <sapasi:Name>Create</sapasi:Name> </sapasi:Operation> <sapasi:Operation> <sapasi:MethodName>BAPI_CUSTOMER_CHANGEFROMDATA1</sapasi:MethodName> <sapasi:Name>Updatewithdelete</sapasi:Name> </sapasi:Operation> </sapasi:sapBAPIBusinessObjectTypeMetadata> </appinfo> </annotation>As defined in the sapBAPIBusinessObjectTypeMetadata schema "Operation" is an n-cardinality complex type. The "MethodName" element of the operation type is a simple type with multiple cardinality:
<complexType name="sapBAPIBusinessObjectTypeMetadata"> <sequence> <element name="Type" type="string"/> <element name="Operation" type="sapasi:sapBAPIOperationTypeMetadata" minOccurs="0" maxOccurs="unbounded"/> <element name="ErrorConfiguration" type= "sapasi:sapRFCErrorConfigurationMetadata" minOccurs="0" maxOccurs="1"/> </sequence> </complexType> <complexType name="sapBAPIOperationTypeMetadata"> <sequence maxOccurs="1" minOccurs="0"> <element name="Name" type="string" minOccurs="0" maxOccurs="1"/> <element name="MethodName" minOccurs="0" maxOccurs="unbounded" type="string"/> </sequence> </complexType> <complexType name="sapRFCErrorConfigurationMetadata"> <sequence maxOccurs="1" minOccurs="0"> <element name="ErrorParameter" type="string" minOccurs="0" maxOccurs="1"/> <element name="ErrorCode" minOccurs="0" maxOccurs="1" type="string"/> <element name="ErrorDetail" minOccurs="0" maxOccurs="1" type="string"/> </sequence> </complexType>For the above metadata, the object level annotations map generated for the JavaBeanRecord would look like the following:
public static LinkedHashMap objectAnnotations = new LinkedHashMap(); static { objectAnnotations.put("Type","BAPI"); LinkedList operationAnnotation = new LinkedList(); LinkedList methodnameList; LinkedHashMap createOperationMap = new LinkedHashMap(); createOperationMap.put("Name", "Create"); methodnameList = new LinkedList(); methodnameList.add("wbiCustomerCreate)"; createOperationMap.put("MethodName", methodnameList); operationAnnotation.add(createOperationMap); LinkedHashMap updateOperationMap = new LinkedHashMap(); updateOperationMap.put("Name", "Update"); methodnameList = new LinkedList(); methodnameList.add("wbiCustomerUpdate)"; updateOperationMap.put("MethodName", methodnameList); operationAnnotation.add(updateOperationMap); objectAnnotations.put("Operation",operationAnnotation);}ObjectAnnotations:Object level metadata in the annotations is read and stored in the 'objectAnnotations' Map. Following diagram shows the structure of objectAnnotations.
The Metadata API
Advanced implementations of adapters are metadata-driven. This implies that the adapter is not hard-coded for each object type in the system, but rather has a form of discovery in which a representation of the object (the metadata) in the EIS is constructed at build time, then at runtime the adapter uses this metadata, along with the data, to process the object. Metadata can be in a preexisting format, such as a standardized schema. Standard metadata includes such information as property name, property type, maximum length, cardinality, and anything else that can be described in a standard schema. Metadata may also be in a format decided by the adapter. This form of metadata is called "Application Specific Information", or ASI. ASI can occur in three places.
- Object level metadata
This includes the information about what type is being processed
- Operation level metadata
This is context-specific object metadata, that is valid for the operation being processed at this time.
- Property level metadata
This is information about the one property in the EIS schema. It may contain such information as the column name as it occurs in the EIS, which may be different than the property name in the object.
In order for the adapters to handle multiple representations of metadata; specifically SDO and JavaBeans, the Foundation classes provide an API for the adapters and abstracts the metadata representation. The intention of this Metadata API is to present both structural and application-specific metadata to the adapter, so the adapter is insulated from the metadata format.
For example, a JavaBeans or an SDO may be used as metadata, but the adapter can use the same metadata APIs to walk over the structure and to extract the required information from it.
Adapter implementations should use the following interfaces when retrieving metadata. Adapters should never cast to an implementation of these interfaces. These interfaces may contain more helper methods than are listed here, see the Javadoc for the additional helpers.
Factory classes
Class TypeFactory:TypeFactory creates an instance of an implementation of Type. The TypeFactory is also capable of detecting whether SDO version 2, SDO version 1, or neither is present in the class path, allowing it to make decisions about what implementation to use.
- Type getType(Object object)
Gets a Type object from existing metadata.
- Type getType(String namespace, String name)
Gets a Type object from a namespace, name combination. For a JavaBeans metadata implementation, the namespace is the package and the name is the class name.
Class SDOFactory:SDOFactory creates an SDO instance, the implementation of which will depend on what version of SDO is in the class path.
- DataObject createDataObject(String namespace, String name)
Creates the data object based on the namespace and name.
- DataObject createDataObject(Type type)
Creates the data object based on an instance of Type
Interfaces
Interface Type:The interface type allows access to object-level metadata, including properties, object-level annotations and key properties.
String getName()retuns the name of the type. Iterator getPropertyIterator() Returns an iterator to allow iteraton over the properties in this type. List getProperties() Returns a list of properties for this type. Property getProperty(String propertyName) Returns the property object for this property name. Map getAnnotations(String source) Returns the object-level annotations for this type. You must pass in the "source" of the annotations, which corresponds to the "source" attribute of the "appinfo" tag of the XML Schema representing this object. Annotations will be returned as a Map, and this Map may contain other maps if the annotation structure is nested. Map getAnnotationsForOperation(String source, String operation) Often operation-specific object metadata is needed.For example, for Create operation there is a specific sequence of APIs that have to be executed, this set could be different for Update and Delete operations. This method returns the metadata for a given operation name as a Map of name - value pairs. List getKeyProperties(String source) Returns the list of key properties in this type.
Interface Type:
Type getContainingType() Returns the type containing this property. Object getDefault() Returns the default value for this property. String getName() Returns the name of this property. Class getPropertyClass() Returns the Class represented by this property.For example, if the property is of String type, this method will return String.class. boolean isContainment() Returns whether or not the property contains a Type (complex object). boolean isMany() Returns whether or not the property contains a List or Array. int getMaxLength() Returns the max length of the property. Map getAnnotations(String source) Returns the annotations for this property. boolean isKey(String source) Returns true if this property is a key, and false if not. Type getType()
If the property is containment, this method will return the contained type.
Enterprise metadata implementation
Selection of artifact typesWebSphere adapters can run against multiple brokers (server run times).
Each broker might require different types of artifacts. The adapter foundation classes can generate artifacts in support of multiple brokers.
The following artifact types are supported by adapter foundation classes:
- Data Bindings
Data Binding classes generated by enterprise metadata discovery to support IBM BPM runtime.
- Generated Records
JavaBeans records generated from SDO to support clients that work with JavaBeans.
- Generic Records
Other DESPI implementations.
The table below provides a matrix for artifact type and their supported server run times.
Artifact types and supported run times Run times Artifact types IBM BPM WebSphere Application Server Other DESPI implementations DataBindings X GeneratedRecords X GenericRecords X While running the external service discovery wizard, adapter users can choose which artifact to generate depending on their runtime environment. Users can select more than one artifact.
Support for GeneratedRecords artifact type: WebSphere adapters may support JavaBeanRecord data representation along with SDO 1.0 and SDO 2.0 data objects. As part of the support for JavaBeans data representation, the adapter foundation classes provides a JavaBeans record generator class that can generate DataBindingDescriptions for the object types discovered and selected through the enterprise metadata discovery (EMD) process.
Each adapter enterprise metadata discovery provides a list of artifact types it supports, allowing the user to select an artifact type that is appropriate for their environment.
For example, to enable the adapters on run times where SDO implementations are not available, users will run the ESD wizards to generate the adapter artifacts for GeneratedRecords type. When the user selects a Generated Records artifact type in the enterprise metadata discovery process, the external service discovery wizard will look for a databinding generator class name on the EMD DataDescription and invokes that class to generate the JavaBeans records.
All adapter enterprise metadata discovery that support the generated records artifact type would need to set the data binding generator class name (on the DataDescription) to the generator implementation provided in the AFC. Here is a code snippet showing how the record generator is set in the service description implementation of an adapter EMD.
WBISingleValuedPropertyImpl property = (WBISingleValuedPropertyImpl) selectionProperties.getProperty (EMDConstants.ARTIFACTS_SUPPORTED); WBIMetadataConnectionImpl.getToolContext().getProgressMonitor() .setIf ("Business object definitions created"); String namespace = getNameSpace(); //Change made for making BG Optional if (property.getValue().equals(EMDConstants.DATA_BINDINGS)) { dataDescription.setName(WBIDataDescriptionImpl.convertNamespaceToUri(namespace + "/" + metadataObj.getBOName().toLowerCase() + "bg" ), metadataObj.getBOName() + "BG"); dataDescription.setDataBindingGeneratorClassName ("com.ibm.j2ca.sample.<AdapterPrefixName>emd.runtime. <AdapterPrefixName>DataBindingGenerator"); dataDescription.setGenericDataBindingClassName(null);} else if (property.getValue().equals(EMDConstants.GENERATED_RECORDS)) { dataDescription.setName(WBIDataDescriptionImpl.convertNamespaceToUri(namespace + "/" + metadataObj.getBOName().toLowerCase()), metadataObj.getBOName()); dataDescription.setDataBindingGeneratorClassName ("com.ibm.j2ca.extension.dataexchange.bean.generator.RecordGenerator"); dataDescription.setGenericDataBindingClassName(null);} else { //Generic Record Scenario dataDescription.setName(WBIDataDescriptionImpl.convertNamespaceToUri(namespace + "/" + metadataObj.getBOName().toLowerCase()), metadataObj.getBOName()); dataDescription.setGenericDataBindingClassName ("com.ibm.j2ca.sample.<AdapterPrefixName>StructuredRecord");New property types supported from WebSphere Adapter Toolkit V6.1:
TableProperty: A property representing a table with rows and columns. Each column is represented by the PropertyDescriptor instance and each cell corresponding to a given row and column is represented by a SingleValuedProperty implementation.
TreeProperty: A property representing a tree of selectable nodes. Each node is represented by a NodeProperty implementation which can be selected, highlighted and can have configuration properties represented by a PropertyGroup instance.