A Simple XML Messaging Application

For example, consider the case in which a mainframe is used to manage employee personnel records. To simplify and expand the reach of this personnel system, the IT department is tasked to provide a Web-based interface into the mainframe system. Rather than build a tightly coupled solution using procedural technologies, using a basic messaging facility in conjunction with XML enables a much more powerful and yet simpler system to be rapidly built.

The following list includes the basic information that would be maintained for a single employee:

EMPLOYEE_ID

FIRST_NAME

LAST_NAME

SSN

START_DATE

FLEX_DAYS_REMAINING

HOME_PHONE

HOME_STREET_ADDRESS

HOME_CITY

HOME_STATE

HOME_ZIP

The Procedural Solution

Before XML, the most obvious solution to this problem would likely be to define a server-based API for manipulating employee records on a field-by-field basis. The problem with this approach is that as the number of fields increases, the complexity of the underlying implementation increases as well. Here's a minimal API in pseudo-code that would be required to support the employee record listed earlier:

EMPLOYEE_ID AddEmployeeRecord()
void DeleteEmployeeRecord(EMPLOYEE_ID)
String GetFirstName(EMPLOYEE_ID)
void SetFirstName(EMPLOYEE_ID, NEW_FIRST_NAME)
String GetLastName(EMPLOYEE_ID)
void SetLastName(EMPLOYEE_ID, NEW_LAST_NAME)
String GetSSN(EMPLOYEE_ID)
void SetSSN(EMPLOYEE_ID, SSN)
String GetStartDate(EMPLOYEE_ID)
void SetStartDate(EMPLOYEE_ID, NEW_START_DATE)
String GetFlexDaysRemaining(EMPLOYEE_ID)
void SetFlexDaysRemaining(EMPLOYEE_ID, FLEX_DAYS_REMAINING)
String GetHomePhone(EMPLOYEE_ID)
void SetHomePhone(EMPLOYEE_ID, NEW_HOME_PHONE)
String GetHomeStreetAddress(EMPLOYEE_ID)
void SetHomeStreetAddress(EMPLOYEE_ID, NEW_STREET_ADDRESS)
String GetHomeCity(EMPLOYEE_ID)
void SetHomeCity(EMPLOYEE_ID, NEW_HOME_CITY)
String GetHomeState(EMPLOYEE_ID)
void SetHomeState(EMPLOYEE_ID, NEW_HOME_STATE)
String GetHomeZip(EMPLOYEE_ID)
void SetHomeZip(EMPLOYEE_ID, NEW_HOME_ZIP)

Supplying even this basic level of functionality would require the mainframe team to implement 22 distinct API functions! Additionally, each API call would require a full round-trip to the mainframe. Depending on physical connectivity issues, this could create serious application latency problems. If each API call was routed through a satellite link, the speed-of-light limitation would impose a penalty of 200–600 milliseconds on each call. Creating a new employee record would require 10 separate API calls.

To further complicate matters, an error could occur during any given call. The client application would need to determine what steps to take to correct the problem. And because the API doesn't include any transaction semantics, it is unclear what to do about the partially completed employee record in the meantime.

The XML Messaging Approach

See the Migrating Legacy Data project (Chapter 17) for an example of a system that implements some of the features described here.

Contrast this approach with an XML message-based approach. The entire API shown previously could be reduced to a single call:

String SendMessage(XML_MESSAGE)

The actual type of operation and data to be used would be encoded in the XML message body. For example, a message for adding a new employee record could be encoded like this:

<message>
  <employee command="add">
    <FIRST_NAME>John</FIRST_NAME>
    <LAST_NAME>Doe</LAST_NAME>
    <SSN>123-45-6578</SSN>
    <START_DATE>01/01/2001</START_DATE>
    <FLEX_DAYS_REMAINING>4</FLEX_DAYS_REMAINING>
    <HOME_PHONE>803.555.1212</HOME_PHONE>
    <HOME_STREET_ADDRESS>123 Any Lane</HOME_STREET_ADDRESS>
    <HOME_CITY>Any Town</HOME_CITY>
    <HOME_STATE>SC</HOME_STATE>
    <HOME_ZIP>29123</HOME_ZIP>
  </employee>
</message>

By encoding the data in the message body, new fields could be added to or removed from the basic personnel record at will. The API itself need never change. Also, because the entire operation can be performed using one API call, network latency ceases to be an issue.

When the message has been received by the mainframe application, it is free to implement the underlying functionality as efficiently as possible. The large number of freely available XML parsers makes the job of extracting information from the message packet relatively simple. The result of the requested operation would be reported to the client in another XML message:

<result>
  <employee id="1357911" command="add" result="success"/>
</result>

This basic framework can be extended to support other operations, such as deleting employee records:

<message>
  <employee id="123456" command="delete"/>
</message>

Unlike procedural API calls, incorporating detailed error and diagnostic information into the message reply is extremely simple using XML:

<result>
  <employee id="123456" command="delete" result="failure">
    <message xml:lang="en-us">No employee record for ID '123456'
        was found.</message>
    <corrective-action xml:lang="en-us">Verify the employee ID and
        try again.</corrective-action>
  </employee>
</result>

Notice the presence of the xml:lang attributes to indicate the human language in which the error message is written. This attribute is part of the XML 1.0 standard and can be used to support rich internationalized applications that return language-appropriate responses to users. When this response is received by the client application, the application can parse it and return the appropriate error message to the end user.

Although the add and delete operations are fairly straightforward, performing record updates requires more complicated logic. In most cases, the current record data will be presented to the user, probably via a Web page. This creates a window where the original data can be modified by another user before the first user submits his updates. One possible solution to this problem is to include a time stamp or serial number in the data record on the mainframe. For example, consider the following query request:

<message>
  <employee id="1357911" command="query"/>
</message>

The mainframe would read this request, access the corresponding record, and return the record to the caller:

<result>
  <employee id="1357911" serial="10">
    <FIRST_NAME>John</FIRST_NAME>
    <LAST_NAME>Doe</LAST_NAME>
    <SSN>123-45-6578</SSN>
    <START_DATE>01/01/2001</START_DATE>
    <FLEX_DAYS_REMAINING>4</FLEX_DAYS_REMAINING>
    <HOME_PHONE>803.555.1212</HOME_PHONE>
    <HOME_STREET_ADDRESS>123 Any Lane</HOME_STREET_ADDRESS>
    <HOME_CITY>Any Town</HOME_CITY>
    <HOME_STATE>SC</HOME_STATE>
    <HOME_ZIP>29123</HOME_ZIP>
  </employee>
</result>

The serial attribute is a simple numeric counter that is incremented each time this particular employee record is modified. This serial number can be used by the host to detect when changes have been made to an out-of-date copy of the employee's record. Consider the case in which a Web user has viewed the record and made a modification to a field (for instance, the FLEX_DAYS_REMAINING field). The Web server could submit a change request message to the mainframe using the same basic message format as before:

<message>
  <employee id="1357911" serial="10" command="update">
    <FLEX_DAYS_REMAINING>3</FLEX_DAYS_REMAINING>
  </employee>
</message>

By sending the serial number that was previously retrieved from the mainframe, it is possible to detect whether the employee record has been changed in the meantime by another process. If the serial number in the request doesn't match the serial number in the actual record, an error could be generated.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
13.59.88.212