Friday, November 21, 2008

Apache Axis and Arrays





One of the issues that I encountered while using Apache Axis was how it would serialize java beans that contained arrays of another custom bean. When a java object is serialized during runtime, the items in the array of the custom bean get marshaled into XML who’s tags do not match that which is defined in the WSDL. For example, the object below gets translated into the following xml…


As you can see, its impossible to determine where the actual items begin in the array. What what we really need is the following so that the XML string conforms to the WSDL where its schema is defined. The tag represents each Entity2 object in the array. It helps the parser on the receiving end to determine each child element of the Entity2 array.



The Axis class responsible for handling this logic is the ArraySerializer class in the org.apache.axis.encoding.ser package. In order to address the problem, the code needs to be changed in this class under the serialize() method. Change the following code by adding the statements that are in bold.

Adding this code tells Axis to create the array element tag name as “item” rather than its actual collection name. the QNAME_LITERAL_ITEM constant is an existing constant that we have leveraged to keep things consistent.

Apache Axis and Dates

Recently, I began working on an existing application where the web service implementation was built using Apache Axis. It didn’t take long to notice that Axis was ignoring the timezone that I had set in my calendar objects. After investigating further, I found that the default behavior of Axis was to convert all the dates to “GMT”. Take a look at the following code in the org.apache.axis.encoding.ser package…



And...


Because of this, all dates that were not set to “GMT” before they are serialized/deserialized resulted in having incorrect times. If your time zones uses “GMT, then Axis seems to handle this just fine. Otherwise, you could go about fixing this in several different ways. You could change the “GMT” string to whatever timezone you application uses, or perhaps a better solution would be to read the timezone from a property so that it can easily be changed in the future. In my case, I was able to read a property string of “EST” since I am using eastern time. After making the change, you can use Ant or whatever build tool you are familiar with to recompile and package Axis for your application.

WCC Business Proxies (Composite Transaction Services)

Business Proxies are just a fancy name for a custom service that you can create by extending the product. They are often also referred to as Composite Transactions which really indicate that you are taking several base WCC transactions (ie: addParty, addContract, etc…) and executing them together as one composite unit of work.

Lets walk through the steps it takes to create a business proxy. After you have your requirements and know what you need to build, study the product help manual to see what base services are available to meet your needs. As a side discussion, you’ll want to design your services so that multiple consumers can be satisfied, but your implementation is not clouded with each of your consumer’s business rules. Trust me, living by this rule makes upgrading and maintenance much easier.

As a specific example, assume you need to add a phone number on an existing customer. When you start evaluating the services that WCC has provided for customer contact points, you notice that there is an addPartyContactMethod services which accepts a TCRMPartyContactMethodBObj object. This is exactly what you want to do! But for this requirement you do not need a business proxy since you have found an out-of-the-box service that already fulfills the requirement. Now change the requirement up a bit and say that you want to add that same phone number to a contract that the customer owns (Contract data could be a checking account, saving account, insurance policy, etc…) The reason for fulfilling this requirement is that the business may want to store one-to-many phone numbers for a customer, but only add one of the customer’s phone numbers as a contact point for the checking account that the customer owns. So any time a customer opens a checking account for example, we want to store that phone number on the customer (if the phone number doesn’t already exist), as well as checking account. The custom may be known by many phone numbers, but the checking account only has one number associated to it for other business purposes such as auditing. For this requirement, you’ll need to code some business logic and create your own business proxy in order to ensure that the requirement is fulfilled as one unit of work.

We’ll call this service “maintainContractRoleLocation” since it should have the ability to add TCRMContractRoleLocationBObj objects as well as update them in the case of changing a phone a number on the account. In either case, we want our custom service to make this decision. In my previous WCC post, you can see that the TCRMContractRoleLocationBObj is used to associate party contact methods to a contract role. Specifically, I may have another consumer that comes along in the future who would need the ability to store an address instead of phone number. Since address is another type of contact point, this service could be reused appropriately to fit that need as well… even though we originally designed it to handle attaching phone numbers to accounts.

Once you are ready to begin building the service, you’ll need to build a java class and have it extend the WCC base objects so that you may override normal functionality with your own. Create a java class and name it “MaintainContractRoleLocationBp.java”. This class should extend the WCC base DWLTxnBP class as denoted in the diagram below. Next you must override the execute() method. This is where the actual service implementation will be placed.

Now you must tell WCC that you have a new service that you would like it to provide to consumers. Take the fully qualified class name of MaintainContractRoleLocationBp and create an entry in the DWLCommon_extension.properties.

BusinessProxy.tcrm.maintainContractRoleLocation=MaintainContractRoleLocationBp

The BusinessProxy.tcrm.maintainContractRoleLocationentry of this property tells WCC to create a new service named “maintainContractRoleLocation”. The second part of this line after the “=” tells WCC the implementation to use by way of reflection. In this case, it’s the MaintainContractRoleLocationBp class that we just created. You also need to add an entry to the CDBUSINESSTXTP table in order to declare that “maintainContractRoleLocation” is a new service that the request handler can understand.

INSERT INTO CDBUSINESSTXTP (BUSINESS_TX_TP_CD, NAME, TX_OBJECT_TP) VALUES (100000, 'maintainContractRoleLocation', 'P');

The BUSINESS_TX_TP_CD is any number that you wish to assign to the new service for keying purposes. The standard is to usually begin at 100000 which helps to identify custom entries as well as avoiding repeating an already used by another object. The TX_OBJECT_TP should be set to ‘P’ since this is a persistent transaction. In other words, we want to save or modify data as part of maintaining it. Other values for this field are ‘I’ or ‘S’ for ‘Inquiry” and “Search” respectively. You would use these transaction types if you would like to create a custom business proxy for retrieving data based on keys, or searching for data with a specific criteria

After you have provided your implementation, you can call the service by sending the RequestHandler the following XML message.