Using Hosted Transparent Decision Service Interface (HTDS) in IBM Operational Decision Manager

IBM® Operational Decision Manager (ODM), IBM's business rule management system (BRMS) product, offers an easy way to expose rulesets as web services through Hosted Transparent Decision Services (HTDS). This article briefly introduces HTDS and discusses the approaches to building an HTDS client and using the RESTful interface that is new to IBM ODM V8.5. The primary focus of the article is potential issues and pitfalls in using HTDS, mostly related to controlling its service interface, and some practical, hands-on approaches to resolve these issues. This content is part of the IBM Business Process Management Journal.

Share:

Rajesh Rao, BRMS Architect, IBM

Raj Rao photoRajesh (Raj) Rao has been working in the area of expert systems and business rule management systems for over 20 years, during which time he has applied business rules technology to build diagnostic, scheduling, qualification, and configuration applications across various domains such as manufacturing, transportation, and finance. He has been with IBM since 2009. With a background in Artificial Intelligence, his interests include Natural Language Processing and Semantic Web.



Matt Voss ( mattvoss@us.ibm.com), ODM Consultant, IBM

Matt Voss photoMatthew (Matt) Voss has worked with expert systems and decision management technologies for nearly 10 years, building applications for healthcare, manufacturing, finance and mortgage. He joined IBM in 2013 after several years consulting for ODM engagements.



Matt Voss ( mattvoss@us.ibm.com), ODM Consultant, IBM

Matt Voss photoMatthew (Matt) Voss has worked with expert systems and decision management technologies for nearly 10 years, building applications for healthcare, manufacturing, finance and mortgage. He joined IBM in 2013 after several years consulting for ODM engagements.



July 2014 (First published 21 November 2013)

Also available in Chinese

What is Hosted Transparent Decision (HTDS)?

Hosted Transparent Decision Service (HTDS) is a predefined application deployed to an application server that enables rulesets to be automatically exposed as web services. Additionally, it offers access to decision service metadata and runtime statistics using the JMX MBean protocol. It is a standard execution component provided as part of the IBM ODM Decision Server in an enterprise archive (EAR) file located in the following directory: <InstallDir>/executionserver/applicationservers/<app-server>/jrules-res-htds-<app_server>.ear. HTDS integrates with the local ODM Rule Execution Server and must reside in the same application server as the eXecution Unit (XU).

Why HTDS?

Using HTDS, a ruleset can be invoked as a web service as soon as it is deployed to the Rule Execution Server. No additional coding or deployment is necessary in order to expose a ruleset as a web service. This aids in the integration of rules with remote rule clients and saves considerable development time and effort.

Rule service WSDLs

HTDS exposes rulesets as web services, or rule services, with no developer coding besides building the ruleset. This means that the developer does not have to construct a Web Services Description Language (WSDL) file for the web service. So how are the rule service WSDLs generated? Quite simply, the WSDLs are generated by HTDS.

In ODM, the input and output ruleset parameters dictate the signature of a ruleset. Not surprisingly, these input and output parameters are the elements used by HTDS to generate the WSDL. The WSDL for a ruleset may be retrieved through the Rule Execution Server console. Alternatively, the WSDL file can be accessed at: http://<HOST>:<PORT>/DecisionService/ws/<RULESETPATH>?wsdl, where <HOST>:<PORT> identifies the location of the application server instance and <RULESETPATH> is the identifier of the ruleset formed by concatenation of the RuleApp name/version with the ruleset name/version; e.g.: /miniloanruleapp/1.0/miniloanrules/1.0.

The input and output parameters of a ruleset are part of the Execution Object Model (XOM). The XOM may be defined as Java™ classes or as XML Schema Definition (XSD). Until ODM V7.5, only XSD XOM and basic Java primitive types could be used with HTDS. However, this limitation is no longer applicable and a Java XOM can be used with HTDS. Using a Java XOM results in better performance and also allows for behavior and methods to be attached to objects, and is therefore preferred. The Java XOM must be deployed to the Rule Execution Server prior to using it with HTDS.


Invoking HTDS with a Java client

The classes defined in the XOM are parsed by HTDS to generate the WSDL. With a Java XOM, and to a more limited extent with an XSD XOM, there are occasions where the default WSDL generated by HTDS is either insufficient or has certain issues when invoked from a Java client. In this section, we introduce a simple business scenario to highlight the potential pitfalls and issues related to invoking HTDS from a service consumer. In particular, our focus will be on Java client integration with a HTDS ruleset that uses a Java XOM.

Scenario description

Consider a simple rule application that determines which customer accounts are upgradable based on a series of business policies. We won't delve into the business policies in this article, but instead focus on integration of the client with the rule service. The signature of the rule service is determined by the ruleset parameters. In this scenario, we use the request/response pattern to identify the data passed into, and returned from, the rule service. The domain model used here is rather simplistic and is designed to highlight the potential issues in integrating with HTDS. Briefly, as illustrated in the UML class diagram in Figure 1, the request contains a customer with a collection of accounts, while the response contains a collection of upgradable accounts.

Figure 1. Domain model for the scenario
Domain model for the scenario

This model is implemented as Java classes that constitute the XOM for the ruleset.

HTDS web service

Investigating the WSDL

As noted earlier, HTDS can generate the WSDL for a ruleset once it is deployed to the Rule Execution Server. This WSDL contains all of the XSD versions of the domain classes that make up our XOM. In addition, HTDS uses the ruleset name and ruleset parameter names to generate some HTDS specific elements:

  1. Elements are defined by HTDS that correspond to the ruleset parameter names.
  2. XML wrapper elements corresponding to the ruleset name are created by HTDS. Specifically, <rulesetName>Request and <rulesetName>Response are created.
  3. The default namespaces use the RuleApp and ruleset names: http://www.ibm.com/rules/decisionservice/<RuleApp name>/<ruleset name>

Testing with a rule service client

Now that the rule service is deployed, we can generate a client to invoke it. This can be done using wizards in IDEs or using command line scripts that invoke wsimport. For this article, we'll use Rational Software Architect V8.5. Rational Software Architect provides a simple Web Service Client wizard (Figure 2) to generate a JAX-WS web service client that starts by prompting for the location of the WSDL.

Figure 2. Web Service Client wizard in Rational Software Architect
Web Service Client wizard in Rational Software Architect

Click to see larger image

Figure 2. Web Service Client wizard in Rational Software Architect

Web Service Client wizard in Rational Software Architect

Upon successful execution of the wizard, two projects are generated: DetermineUpgradeableAccountsClient and DetermineUpgradeableAccountsClient EAR. The EAR project can be used to export the application archive (.ear) or to deploy it directly to the configured WebSphere Application Server in Rational Software Architect. Once the enterprise archive is deployed to the server, it can be tested using one of the test methods provided with Rational Software Architect, such as Test with Generic Service Client, as shown in Figure 3. With this test client, you start by editing a request, followed by invoking the service and finally viewing the response.

Figure 3. Testing HTDS with the generated client
Testing HTDS with the generated client

Click to see larger image

Figure 3. Testing HTDS with the generated client

Testing HTDS with the generated client

HTDS REST service

Starting with IBM ODM 8.5, it is possible to invoke HTDS with a RESTful interface, too. The Web Application Description File (WADL) for the REST service can be obtained by selecting REST when retrieving the HTDS description file, as shown in Figure 4.

Figure 4. Retrieving the REST WADL
Retrieving the REST WADL

Alternatively, it can directly be obtained at: http://<HOST>:<PORT>/DecisionService/rest/v1/<RULESETPATH>/WADL. For example, the URL for our locally deployed RuleApp is: http://localhost:9080/DecisionService/rest/v1/determineupgradeableaccountsruleapp/1.0/DetermineUpgradeableAccountsRules/1.0/WADL.

Note: When retrieving the WADL through the RES console, you can use the Test to easily execute and validate requests.

Investigating the WADL

The WADL contains one resource with three methods:

  • post method to process a rule request and return a response
  • get method with a resource path of /xml to obtain a sample request.
  • post method with a resource path of /validate to perform validation on a request.

Note that at this time, only XML content is allowed and JSON cannot be used.

Building a REST client

Building a Java client to invoke the HTDS REST service is not as straightforward as building the web service client because there is no wizard to do so. Instead, we'll build the REST client manually starting from the WADL generated by HTDS. We employ a tool called wadl2java to generate the Java stubs from the WADL. You can download this tool at http://search.maven.org/remotecontent?filepath=org/jvnet/ws/wadl/wadl-dist/1.1.5/wadl-dist-1.1.5-bin.zip.

To generate the Java client, run the following batch script to generate the stubs: <path to wadl2java>\wadl2java -o .\src -p com.example.client http://localhost:9080/DecisionService/rest/v1/determineupgradeableaccountsruleapp/DetermineUpgradeableAccountsRules/WADL

This generates the Java stubs shown in Figure 5. In addition to the stubs that map to the domain classes in the XOM, you'll see the following classes:

  • Request and Response, which are the HTDS wrapper classes
  • Localhost_DecisionServiceRestV1DetermineupgradeableaccountsruleappDetermineUpgradeableAccountsRules, which is a proxy to invoke the service
Figure 5. Stubs generated by wadl2java
Stubs generated by wadl2java

Note: The generated class Localhost_DecisionServiceRestV1DetermineupgradeableaccountsruleappDetermineUpgradeableAccountsRules has compile errors due to duplication of method parameters. This has to be fixed manually by deleting the duplicate parameters.

To compile and execute the client code, you must add several wadl2java library dependencies to the lib directory (and the client's Java build path), as shown in Figure 6. wadl2java does not generate the code to invoke the client; you must do this manually. An example client runner is listed below. Notice that it builds the request by making use of the /xml resource method and then executes HTDS with this request payload using index.

Click to see code listing

import com.example.client.Localhost_
DecisionServiceRestV1DetermineupgradeableaccountsruleappDetermineUpgradeableAccountsRules;
import com.example.client.Localhost_
DecisionServiceRestV1DetermineupgradeableaccountsruleappDetermineUpgradeableAccountsRules.Index;
import com.example.client.Localhost_
DecisionServiceRestV1DetermineupgradeableaccountsruleappDetermineUpgradeableAccountsRules.Xml;
import com.example.client.Request;
import com.example.client.Response;


public class ClientRunner {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		XmlFormatter formatter = new XmlFormatter();
		com.sun.jersey.api.client.Client client = Localhost_
DecisionServiceRestV1DetermineupgradeableaccountsruleappDetermineUpgradeableAccountsRules.createClient();
		Xml xml = 
Localhost_
DecisionServiceRestV1DetermineupgradeableaccountsruleappDetermineUpgradeableAccountsRules.xml(client);
		Request request = xml.getAsRequest();
		String reqXml = formatter.marshalToString(request);
		System.out.println("Req=" + reqXml);

		Index index = Localhost_
DecisionServiceRestV1DetermineupgradeableaccountsruleappDetermineUpgradeableAccountsRules.index(client);
		Response response = index.postXmlAsResponse(request);
		System.out.println
(response.getDetermineUpgradeableAccountsResponse().getUpgradeableAccounts().iterator().next().getAccountId());
	}
}

Alternatively, once the stubs are generated, you can use regular HTTP client code to invoke the REST service. For instance, the client runner code using Apache HTTP Components is listed below. This too uses the /xml GET method to build the base request and then posts the modified request to HTDS to execute the rules. This uses regular HTTP GET and HTTP POST commands.

Click to see code listing

import java.io.InputStream;
import java.net.URL;

import javax.xml.bind.Unmarshaller;

import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;

import com.example.client.Request;
import com.example.client.Response;

public class Main {

	private static String url = "http://localhost:9080/DecisionService/rest/v1/determineupgradeableaccountsruleapp/1.0/DetermineUpgradeableAccountsRules/1.0";

	/**
	 * @param args
	 */
	public static void main(String[] args) {

		XmlFormatter formatter = new XmlFormatter();
		Unmarshaller u = XmlFormatter.unmarshaller;

		CloseableHttpClient httpclient = HttpClients.createDefault();
		String result = "";
		try {
			Request req = (Request) u.unmarshal(new URL(url + "/xml"));
			req.getDetermineUpgradeableAccountsRequest().getCustomer().setFirstName("James");
			req.getDetermineUpgradeableAccountsRequest().getCustomer().setLastName("Bond");
			String reqXml = formatter.marshalToString(req);
			System.out.println("Req=" + reqXml);
			
			StringEntity reqEntity = new StringEntity(reqXml, ContentType.create(
					"application/xml", "UTF-8"));

			HttpPost httppost = new HttpPost(url);
			httppost.setEntity(reqEntity);
			CloseableHttpResponse response = httpclient.execute(httppost);
			try {
				HttpEntity entity = response.getEntity();
				if (entity != null) {
					InputStream instream = entity.getContent();
					try {
						 Response resp = (Response) u.unmarshal(instream);
						 result = formatter.marshalToString(resp);
					} finally {
						instream.close();
					}
				}
			} finally {
				response.close();
			}
		} catch (Exception e) {
			e.printStackTrace();
		} 
		System.out.println("Response = " + result);
	}
}

This approach has the advantage that it does not make use of the Localhost_DecisionServiceRestV1DetermineupgradeableaccountsruleappDetermineUpgradeableAccountsRules class that, as was previously noted, is generated with some compile errors.


Architectural issues and pitfalls

The beguiling ease of remote invocation of rulesets through web services exposed by HTDS tempts one to promote them as business services that can be used across several enterprise clients. However, very often the reality is that these web services should not be directly consumed by the enterprise client applications, but instead by a reusable decision service (see Resources) that serves as a gateway. There are several reasons for this:

  • The ruleset object model is likely to be different from the enterprise integration model, in keeping with best practices, and the decision service would have to perform model transformation and request enrichment, possibly by accessing external data sources, before invoking the rule engine.
  • When invoking HTDS a ruleset path is known from the client, which strictly speaking is a violation of the business interface design in that the client knows that the service is a rule-based implementation.
  • The desired granularity of the service operation, which is an important facet of SOA service design, can be different from the service signature exposed by HTDS. In fact, it is not uncommon to have multiple service operations at different granularity levels for the same ruleset.

For these reasons, HTDS typically should not be considered a reusable business decision service to be directly invoked by business rule clients, but instead a rule service to be invoked by service integration components (which we'll call business decision services) or by dedicated one-off clients such as BPM process tasks.

When designing this business decision service, the typical use case is to invoke the Rule Execution Server from the business decision service using a POJORuleSession if they are on the same server. However, there are a number of situations where owing to licensing restrictions or other administrative constraints, it's necessary for the rule execution environment to be separate and distinct from the business decision service. In such situations, it is possible to leverage HTDS for remote rule execution from the Business Decision Service, as illustrated in Figure 6. For the sake of completeness, it must be pointed out that remote invocation may also be achieved by using the rule execution EJB component that is provided with ODM; however, that does inject some additional ODM library dependencies into the Business Decision Service.

Figure 6. Invoking HTDS from a decision service
Invoking HTDS from a decision service

Click to see larger image

Figure 6. Invoking HTDS from a decision service

Invoking HTDS from a decision service

Integration issues and pitfalls

When invoking the HTDS ruleset using a Java client, through either SOAP or REST, several issues may crop up. This section describes those issues and the steps to resolve them.

Name collisions

Issue:

When the Web Service Client wizard is run with the downloadable base projects, you encounter errors, as shown in Figure 7:

Figure 7. Web Service client generation errors
Web Service client generation errors

The same HTDS rule service can be successfully invoked from clients such as SoapUI, which points to the code generation (wsimport) as the culprit.

The errors displayed in Figure 7 are a result of name collisions. This happens when a class name used in the domain model collides with a name generated by HTDS for its wrapper classes and elements. As you saw earlier, HTDS generates wrapper classes by adding Request and Response as a suffix to the ruleset name. For example, the wrapper request class created by HTDS is:

Click to see code listing

<xsd:element name="DetermineUpgradeableAccountsRequest">
        <xsd:complexType>
          <xsd:sequence>
            <xsd:element form="qualified" maxOccurs="1" minOccurs="0" name="DecisionID" type="xsd:string"/>
            <xsd:element ref="param:determineUpgradeableAccountsRequest"/>
          </xsd:sequence>
        </xsd:complexType>
      </xsd:element>

During code generation, this collides with the request class defined in the domain:

<xs:complexType name="determineUpgradeableAccountsRequest">
    <xs:sequence>
      <xs:element minOccurs="0" name="asOfDate" type="xs:dateTime"/>
      <xs:element minOccurs="0" name="customer" type="tns:customer"/>
    </xs:sequence>
</xs:complexType>

Note that these names are not the same case, and therefore they are separate entities in the XSD. However, when running wsimport, these names get converted to Java class names, with the first letter capitalized, which causes the collision.

Similarly, when using the REST interface, there will be name collision if you have a class named Request or Response in your domain model.

Resolution:

There are two approaches to resolving this issue.

  • Use JAXB annotation to change the name of the domain class names. With this approach, the Request and Response domain class names are changed by using @XmlType annotations. For example, the request class name is changed to DetermineUpgradeableAccountsAnnotatedRequest by:
    @XmlAccessorType(XmlAccessType.FIELD)
    @XmlType(name="DetermineUpgradeableAccountsAnnotatedRequest")
    public class DetermineUpgradeableAccountsRequest {
    …
    }

    The Java classes generated by the Web Service Client wizard are shown in Figure 8. Notice that the domain request class is now called DetermineUpgradeableAccountsAnnotatedRequest.

    Figure 8. Generated Java client source
    Generated Java client source

    This resolution technique applies to handling collisions when dealing with HTDS REST interface as well.

    Note that refactoring the project to rename the domain class name is also an option, but that requires refactoring of the rule project, which will take more development time and effort. Therefore, it's simpler to use JAXB annotations to change the name of the generated classes.

  • Change the ruleset name using the Ruleset Archive editor, as shown in Figure 9. Instead of calling the ruleset DetermineUpgradableAccounts, name it DetermineUpgradableAccountsRules.
    Figure 9. Ruleset Archive editor
    Ruleset Archive editor

    Now the wrapper classes generated by HTDS will be called DetermineUpgradableAccountsRulesRequest and DetermineUpgradableAccountsRulesResponse, which do not collide with any domain class names.

Duplication of domain classes

Issue:

The namespace used in the WSDL is translated to Java packages for the generated source for the web service client. For instance, the default target namespace of http://www.ibm.com/rules/decisionservice/Determineupgradeableaccountsruleapp/DetermineUpgradeableAccounts in the WSDL results in the Java classes generated in the package com.ibm.rules.decisionservice.determineupgradeableaccountsruleapp.determineupgradeableaccounts, as shown in Figure 10. In other words, the default package is based on the RuleApp and ruleset name. Note that this is true as long as you do not choose a compatibility mode of 7.0 or 7.1 when generating the HTDS (in which case the namespace is hardcoded as http://www.ilog.com/rules/DecisionService). If you do not select any compatibility mode, the WSDL code uses dynamic namespaces that start with http://www.ibm.com/.

When the same domain classes are used in multiple HTDS rulesets, as may commonly occur when different decision points act on the same domain model, the default namespace leads to duplication of classes in the generated web service clients because the same classes are generated in different packages, one for each WSDL. This duplication of classes can lead to maintenance and synchronization issues.

Resolution:

To avoid duplication, the WSDLs corresponding to the different rulesets must have the same namespace. You can change the namespace of the generated rule services through the Rule Execution Server Console, as shown in Figure 10.

Figure 10. Change namespace of generated WSDL through RES console
Change namespace of generated WSDL through RES console

Hiding transient attributes

Issue:

Often, there are attributes of a Java class that is part of the XOM that you use strictly for internal rule processing use. For example, in the Account class shown in Figure 11, the eligible attribute is intended to be used internally by the rule engine to mark an Account as eligible or not.

Figure 11. Account class with a transient eligibility attribute

These sorts of derived attributes are of no relevance to the rule client and should not be exposed in the WSDL. However, the WSDL does have this attribute, as shown in the WSDL extract in Figure 12. This is true even when the attribute is declared to be transient, as private transient boolean eligible;.

Figure 12. WSDL extract for Account
WSDL extract for Account

This issue is also applicable when invoking HTDS with a REST interface, as are the remaining issues in this section.

Resolution:

JAXB annotations can be used on the Java class to mark an attribute as transient and hide it from the WSDL. Specifically, use @XmlTransient to hide the attribute. For example:

@XmlAccessorType(XmlAccessType.FIELD)
public class Account {
	@XmlTransient
	private boolean eligible;
	…

Notes:

  1. @XmlTransient cannot be applied to the attribute itself if the attribute has the transient field modifier. Therefore, the Java keyword transient should not be used. You can annotate the getter with @XmlTransient instead if the Java keyword transient is necessary. In this and future examples, the class is annotated with @XmlAccessorType(XmlAccessType.FIELD) to indicate that the attribute will be annotated. By default, JAXB expects the getter to be annotated.
  2. On another side note, the ability to use transient attributes is yet another advantage of using a Java XOM over an XSD XOM.

Marking attributes as mandatory

Issue:

Frequently, there are mandatory data elements in the request. Data validation rules may be written to ensure that these mandatory fields do not have a null value, but it would be preferable if this were enforced by the WSDL. For example, rules may have to make use of the Account Status, and therefore it must be passed in. However, as seen in Figure 13, the accountStatus field has a minOccurs of 0 and therefore may be absent in the request.

Resolution:

JAXB annotations can be used on the Java class to mark an attribute as mandatory. Specifically, use @XmlElement to mark the attribute as mandatory. For example:

@XmlAccessorType(XmlAccessType.FIELD)
public class Account {
	…
	@XmlElement(required=true, nillable=false)
	private AccountStatus status;
	…

Upon redeploying the ruleset after adding this annotation, the generated WSDL (Figure 13) has no minOccurs (default value of 1) and is therefore mandatory.

Figure 13. WSDL extract after AccountStatus is marked with @XmlElement(required=true)
WSDL extract after AccountStatus is marked with @XmlElement(required=true)

The same annotation can be used to make associations mandatory. For example, the accounts attribute of the Customer can be annotated as follows:

@XmlElement(required=true,name="account")
	private Set<Account> accounts;

Controlling attribute names

On occasion, the names of attributes will need some customization. This is particularly true for Collections. The Java best practice for Collections is to name the attribute in the plural. For example:

private Set<Account> accounts;

The SOAP request will have corresponding tags:

<accounts>
	<balanceAmount>?</balanceAmount>
	<id>?</id>
	<openDate>?</openDate>
	<status>?</status>
	<stateWhereOpened>?</stateWhereOpened>
	<type>?</type>
	<tier>?</tier>
</accounts>

Each <accounts> is one account. To make the naming more intuitive, the attribute can be annotated with an alternate name as follows:

@XmlElement(required=true,name="account")
	private Set<Account> accounts;

The corresponding request will be as follows:

<account>
	<balanceAmount>?</balanceAmount>
	<id>?</id>
	<openDate>?</openDate>
	<status>?</status>
	<stateWhereOpened>?</stateWhereOpened>
	<type>?</type>
	<tier>?</tier>
</account>

Controlling subclasses

Issue:

The WSDL generated by HTDS contains definitions of classes that are referenced, directly or transitively through directed associations, by the ruleset parameter classes. If the referenced class happens to be an abstract class or a parent class with subclasses, then by default, subclasses of the parent class will not appear in the generated WSDL. This is an issue when your domain model relies on polymorphism. For instance, if an abstract Customer class can be a CorporateCustomer or an InternationalCustomer and only the Customer is referenced in the ruleset parameters, then CorporateCustomer and InternationalCustomer will not be present in the WSDL.

Resolution:

In the XOM, annotate the parent class with @XmlSeeAlso. For example:

@XmlSeeAlso({CorporateCustomer.class})
publicclass Customer {
...
}

The subclass appears in WSDL as shown in Figure 14.

Figure 14. WSDL with corporateCustomer subclass
WSDL with corporateCustomer subclass

All of the subclasses of the annotated class must be listed within the brackets with each one separated by a comma. For example, to include the InternationalCustomer subclass, the annotation is:

@XmlSeeAlso({CorporateCustomer.class, InternationalCustomer.class })

You can then use the subclass in a SOAP request. Using SoapUI, the request itself needs to be modified slightly to use the subclass by specifying the xsi:type. The following sample request snippet uses the subclass CorporateCustomer:

Click to see code listing

              <customer xsi:type="det:corporateCustomer" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
                  <age>?</age>
                  <isLoyalCustomer>?</isLoyalCustomer>
                  <firstName>?</firstName>
                  <grossIncomeAmount>?</grossIncomeAmount>
                  <!--1 or more repetitions:-->
                  <account>
                     <balanceAmount>?</balanceAmount>
                     <id>?</id>
                     <openDate>?</openDate>
                     <status>?</status>
                     <stateWhereOpened>?</stateWhereOpened>
                     <type>?</type>
                     <tier>?</tier>
                  </account>
                  <address>
                     <city>?</city>
                     <state>?</state>
                     <line1>?</line1>
                     <line2>?</line2>
                  </address>
                  <netIncomeAmount>?</netIncomeAmount>
                  <lastName>?</lastName>
                  <id>?</id>
                  <corporationName>Corporation1</corporationName>
               </customer>

You can move up the xmlns:xsi declaration in the request as needed. Since the HTDS generation puts all the generated XOM classes into the same namespace, prefix the subclass with the appropriate namespace reference such as "det". Lower in the snippet (in bold), this XML request includes an attribute of the subclass, "corporationName".

Controlling data types

Issue:

Frequently, the data types in the generated WSDL and the generated client code are not ideal. XOM attributes of type java.util.Date are marked as xs:dateTime in the WSDL. For example, in Figure 14, openDate is marked as xs:dateTime. Futhermore, in the generated client code, it is typed as XmlGregorianCalendar.

@XmlSchemaType(name = "dateTime")
protected XMLGregorianCalendar openDate;

XmlGregorianCalendar is much harder to deal with than a simple Calendar or Date object. Often, the precision offered by XmlGregorianCalendar is not necessary and it would be preferable to generate the attribute as a simple java.util.Date.

Resolution:

In the XOM, annotate the attribute with @XmlSchemaType. For example:

@XmlSchemaType(name="date")	
private Date openDate;

The generated WSDL for openDate now correctly has xs:date as the type. However, the generated client Java code still uses XmlGregorianCalendar. To fix this, we use a JAXB adapter. First, a binding file must be created that indicates the Java type to use for an XSD type and also specifies the parse method and print method to use during JAXB unmarshaling and marshaling respectively. This JAXB binding file is listed below.

Click to see code listing

<bindings xmlns="http://java.sun.com/xml/ns/jaxb" version="2.0" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <globalBindings>
    <javaType name="java.util.Date" xmlType="xs:date"
      parseMethod="com.example.adapters.DateAdapter.parseDate"
      printMethod="com.example.adapters.DateAdapter.printDate"
    />
    <javaType name="java.util.Date" xmlType="xs:dateTime"
      parseMethod="com.example.adapters.DateAdapter.parseDate"
      printMethod="com.example.adapters.DateAdapter.printDate"
    />    
  </globalBindings>
</bindings>

This binding file is used during the client generation as shown in Figure 15.

Figure 15. Using the JAXB binding file in the Web Service Client wizard
Using the JAXB binding file in the Web Service Client wizard

Click to see larger image

Figure 15. Using the JAXB binding file in the Web Service Client wizard

Using the JAXB binding file in the Web Service Client wizard

In the case of using a REST client, the JAXB binding file must be passed in with a –c option:

wadl2java -o outputDir -p package [-a] [-s jaxrs20] [-c customization]* file.wadl

In the generated web service client project, a class called com.example.adapters.DateAdapter must be created with the parseMethod and printMethod indicated in the binding file. The contents of the file are listed below.

package com.example.adapters;

import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;

import javax.xml.bind.DatatypeConverter;

public class DateAdapter {
	public static Date parseDate(String s) {
		return DatatypeConverter.parseDate(s).getTime();
	}

	public static String printDate(Date dt) {
		Calendar cal = new GregorianCalendar();
		cal.setTime(dt);
		return DatatypeConverter.printDate(cal);
	}
}

Issue:

Attributes in XOM Java classes that are assigned the wrapper class type for a primitive will be generated on the client side as the primitive by default. For example:

@XmlElement(required=true)
private Boolean isLoyalCustomer;

generates the following in the web service client:

@XmlElement(required = true)	
protected boolean isLoyalCustomer;

Resolution:

Attributes with a wrapped primitive type should be annotated with nillable=true. For example:

@XmlElement(required=true,nillable=true)
private Boolean isLoyalCustomer;

The client will generate the following:

@XmlElement(required = true, type = Boolean.class, nillable = true)
protected Boolean isLoyalCustomer;

The following table identifies the default mappings from XOM to WSDL to web service client for several common data types.

XOM data type WSDL data type Web service client generated data type
String xs:string String
Double xs:double double by default or Double when annotated with nillable=true
double xs:double double
int xs:int int
Integer xs:int int or Integer when annotated with nillable=true
BigDecimal xs:decimal BigDecimal
Boolean xs:boolean boolean by default or Boolean when annotated with nillable=true
boolean xs:boolean boolean
Set ex, tns:customerAccount List
Date xs:dateTime XmlGregorianCalendar

Conclusion

In conclusion, HTDS offers developers a slick method to expose rulesets as web services, but with that comes the potential to misuse this power. HTDS should not be treated as a reusable business decision service, but rather as a rule service that makes it easy for a decision service to invoke rules remotely. In this article, you saw some of the common issues in using the WSDL and WADL generated by HTDS and learned how to overcome them through HTDS configurations and by leveraging JAXB annotations.


Downloads

DescriptionNameSize
Base Rule Designer workspace (with issues)wsdl-demo-base-projects.zip39KB
Solution Rule Designer workspace (with fixes)wsdl-demo-modified-projects.zip40KB

Resources

Learn

Get products and technologies

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into Business process management on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Business process management
ArticleID=954431
ArticleTitle=Using Hosted Transparent Decision Service Interface (HTDS) in IBM Operational Decision Manager
publish-date=07212014