Welcome!

PowerBuilder Authors: Chris Pollach, Yeshim Deniz, Jayaram Krishnaswamy, Kevin Benedict, Avi Rosenthal

Related Topics: PowerBuilder

PowerBuilder: Article

PowerBuilder XML Generator For DataWindows

PowerBuilder XML Generator For DataWindows

The number of PowerBuilder and EAServer solutions in production continues to grow. It would be an understatement to say that there's a large XML movement underway in the industry. While PowerBuilder 9.0 will include some exciting XML capabilities, this article focuses on building a solution that provides XML capabilities for DataWindows today, in PowerBuilder 7 and 8.

We'll describe the design and implementation of an XML generation solution (affectionately referred to here as the PB XML Generator) built using PowerBuilder and Java. The complete solution will be available as a free download from the Sybase Developer's Network (SDN) at www.sybase.com/developer/applicationdeveloper. This download will include:

  • The full source code for the PowerBuilder and Java components
  • The full source code for the JSP custom tag library
  • A Jaguar .jar file with the binaries of each of these (tested on EAServer 3.6.1, 4.x)
  • A sample Web application (also in Jaguar .jar format) demonstrating several different XML generation examples from DataWindows that run against the standard demo database shipping with EAServer
  • Installation directions along with Apache Ant deployment scripts

Solution Architecture
The PowerBuilder XML Generator enables developers to export existing PB 7.x and 8.x DataWindows as XML through a simple JavaServer Page (JSP) tag library and EAServer components. Figure 1 depicts our solution architecture. Tag attribute values are specified through a JSP, customizing the DataWindow export to XML. When the JSP containing our tag library is processed, the doStartTag() method of the DataWindowTag class executes. The tag class populates an array of name-value pairs that map back to the tag library attributes. These properties are then passed to the PBXMLgen/MetaParser component (written in PowerBuilder) where the DataWindow's metadata is accessed.

It's here inside the PowerBuilder component that the data is retrieved from the database using dw.retrieve(). The DataWindow metadata, the result set, and the tag library attributes are then passed over to another component written in Java, the PBXMLgen/XMLgenerator. This component actually performs the XML generation. The resulting XML is then passed back through the call stack to the original JSP page on its way back to the requesting client.

The XML produced is compliant with the XML 1.0 specification, meeting all its well-formedness constraints, and may optionally contain DataWindow data and metadata with explicit markup information, such as column definition, a read-only indicator, and syntax. Note: The current release handles only the one-way processing of a dw.Retrieve() to XML.

Building the JSP Custom Tag Library
We simply don't have enough space to adequately describe all the idiosyncrasies of building custom tag libraries. There are a number of great JSP books out there, and most have a chapter or more describing how to build JSP custom tag libraries. A great reference is Core Servlets and JavaServer Pages by Marty Hall.

One of the first challenges we faced in developing the tag library was sharing data between the PowerBuilder and the Java world. In the solution architecture we describe, we have name-value pairs gathered in the tag handler class that need to be passed into the PowerBuilder component. This component reads some of the values it needs, and then must forward all the name-value pairs to another component written in Java. As you can see, we're crossing language lines a couple of times.

At first we thought we could just use java.util.Properties, but we quickly discovered this was not an option. This class is built atop a hashtable that, unfortunately, PowerBuilder doesn't understand. The result was a BLOB in the method signature of the PowerBuilder proxy where the java.util.Properties argument was located. To overcome this problem we looked to EAServer's CORBA roots for help.

In the CORBA world, interfaces are described using the Interface Definition Language (IDL). Each component deployed to EAServer has its public interface described in IDL. Jaguar passes around a lot of name-value pairs, as described by the IDL in Jaguar::Properties. In fact, this IDL representation of name-value pairs is easy to use in PowerBuilder and Java. Through the use of Jaguar::Properties, we were able to seamlessly pass name-value pairs between both languages. Problem solved!

Over 95% of the code in the DataWindowTag class merely collects and stores attribute values for use later when the doStartTag() method is invoked. To achieve this, we declare one private string instance variable for each attribute. Each attribute requires a setter method (and may actually have a getter method as well), which contains one line of code, for example:

public void setLibName(String value) { this.libname = value; }

Once the DataWindowTag class has collected all the name-value pairs specified in the JSP, we move them into an instance of Jaguar::Properties to pass them in an intercomponent call. We get a handle to an instance of the MetaParser object (described in detail in the next section) using a CORBA Factory. Listing 1 describes how to look up a PB component in EAServer from Java.

Once we have a Factory from our doCorbaLookup() method, we need to do one more thing before we have an invocable component reference:

...
PBXMLgen.MetaParser parser;
Factory factory = doCorbaLookup("PBXMLgen", "MetaParser");
If( factory != null) {
parser = PBXMLgen.MetaParserHelper.narrow(factory.create());
} else {
//log the error out using the JSPWriter
}
...

The colName attribute contains a list of DataWindow column names and what they should map to in the generated XML. For simplicity, this single attribute is expanded into two string arrays, dwnames and newnames. Through the of_parse_meta() method, we pass in the name arrays, the name-value pairs, and a StringHolder that will contain the generated XML. Intercomponent calls that need to leverage pass-by-reference arguments must use holder classes. When this method call returns, the StringHolder argument contains the generated XML, which is then written out using the JSPWriter's print() method.

...
String xml = "";
StringHolder xml_holder = new StringHolder( xml);
//tagprops is an instance of Jaguar::Properties
//dwnames and newnames are String arrays
int rtn = parser.of_parse_meta(dwnames, newnames, tagprops, xml_holder);
...

In our implementation, a number of customizable attributes can be used to control how the XML is generated from the DataWindow. In a JSP custom tag library, it's the responsibility of the taglib.tld file to define each of the attributes on the tag. Table 1 is a list and description of each attribute we defined for the DataWindowTag class.

Mining for Metadata: The PB Component
When building the PB XML Generator we wanted to leverage core PowerBuilder functionality. To that end, we extracted the metadata from the DataWindow using the dw.describe() method and retrieved the data using the standard dw.retrieve() method. This is significantly simpler to implement than working with Statements (or PreparedStatements) in Java. Most of the code inside the of_parse_meta()method is straightforward PowerScript, like initializing SQLCA to connect to the database and creating and initializing a DataStore with the values passed in from the custom tag attributes.

One area of interest is how the method accesses the DataWindow object. The custom tag library provides two different options, either an absolute path to a .PBL or .PBD or the name of a package/component. Both approaches leverage PowerBuilder's ability to dynamical modify the library list through the setLibraryList() method; however, determining what the libraries are when a package/component is specified deserves an explanation. When you deploy a PowerBuilder component to EAServer, typically all the objects are bundled in one or more .PBD files and copied over to the EAServer repository. We need to use three pertinent properties and one method call to assemble absolute paths from the given package/component:

  • com.sybase.jaguar.component.type
  • Jaguar/Management API's getEnv() method
  • com.sybase.jaguar.component.pb.cookie
  • com.sybase.jaguar.component.pb.librarylist

The first property (.type) is a check to make sure the named package/component is indeed a PB component. It doesn't make sense looking for a DataWindow if the component is an EJB! Next, PowerBuilder uses a strict naming convention to track deployments - "Cxx", where "C" is a constant and xx is a sequential number, for example, C23 and C134 are valid directory names. Each of these directories would contain all the .PBDs for a given component. The .pb.cookie property tracks the current "version" number. Inside any EAServer repository each PowerBuilder component would have a directory structure similar to this:

$JAGUAR/repository/component/<Package Name>/<Component Name>/Cxx

To determine what $JAGUAR equates to, we used the Jaguar/Management API's getEnv() method, useful for looking up environment variables. The .pb.librarylist property contains a delimited list of libraries, and it uses a $ prefix to indicate a relative path to each library based on the aforementioned cookie structure. With this knowledge, translating a package/component becomes an exercise in string manipulation, yielding an absolute path for each library. This information is passed into the setLibraryList method.

At this point, we can access any of the objects in these newly discovered .PBDs, including the DataWindow object that was specified as a tag library attribute. We retrieve the data from the database, extract the metadata from the DataWindow, and store it in a simple structure. PowerBuilder structures map seamlessly into CORBA IDL structures, allowing them to easily be passed into Java components. And the reverse is true as well. After running the proxy project, the Jaguar::Properties IDL structure is represented as a structure in PowerBuilder. All this information is passed into the Java component where final assembly of the XML document will take place.

Building the XML: The Java Component
The first approach we considered was to leverage the W3C Document Object Model (DOM) interfaces through the Java API for XML Parsing (JAXP) to build the XML tree. While technically feasible, it was determined that this was too much overhead and not worth the effort. Another approach was to leverage the MSXML parser through its COM interface inside a PowerBuilder component. Again, while technically feasible, we determined that it would entail too much overhead. The final option we considered was using a single string and concatenation to build the XML document. This is perhaps the simplest and most straightforward approach of the three options, and we decided to go with it.

The primary reason for using a Java component in place of a PB one is speed. Java will handle the string manipulation much better than PowerBuilder. After the class was written, an overwhelming majority of the code in this class called the append() method on a StringBuffer variable.

There was a secondary consideration for using a Java component, which we'll discuss later.

Putting It All Together
After the tag library is built (the full source code can be downloaded from www.sys-con.com/pbdj/sourcec.cfm) and the components are deployed, we need to create a simple JSP page that allows us to play with variations of the DataWindow XML generation. Figure 2 displays a sample JSP page named PBXMLDemo.jsp that accomplishes this.

This HTML form collects all the values and passes them into another JSP page where they'll be processed and the generated XML displayed. Listing 2 provides the two lines of JSP code (PBXMLDemoTagLib.jsp) that's required to process the request and turn a DataWindow into an XML document.

The first line of code in Listing 2 defines a tag library for use inside a JSP page. We assign a namespace prefix of "pbxml" to the tag library that's described in /Web-INF/tlds/taglib.tld, bundled with the JSP, and deployed as a J2EE Web application archive (.war) file. The second line of code (split across multiple lines for readability) is where we set the tag library attributes (nothing more than name-value pairs) that control the XML generation. Notice how the attributes are populated using the request.getParameter() method, which exposes the values that were typed into the HTML form.

The PB XML Generator could also be exposed more directly as a servlet. The sample source code includes the XMLGenServlet, which demonstrates how the custom tag library and the JSP can be bypassed when generating XML from a DataWindow. The only attributes currently implemented in the servlet are "libName" and "dwName" (see Table 1 for more details). However, the servlet includes the necessary code to implement all the attributes described in Table 1 through the same Property class used in the JSP tag library.

Figure 3 shows a picture of the end result - a browser displaying XML from one of the sample DataWindows.

Looking Ahead
The logical extension of this design would include the ability to turn an XML document back into a DataWindow. The architecture described here is suitable for achieving this and wasn't implemented as a result of time and space constraints. The use of the Java component in the architecture is particularly interesting. This component could leverage JAXP to parse an incoming XML document, pushing the data back into a structure. A mapping mechanism would be needed if the metadata wasn't included in the XML document. This information would then be passed back over to the PowerBuilder component, where the metadata would be pushed back into the DataWindow through the dw.modify(), dw.insertRow(), and the dw.SetItem() methods.

Another reason beyond space and time for not implementing round-trip XML capabilities is that PowerBuilder 9.0 will be released later in 2002. Users will be able to select data values from a DataWindow and save as XML according to a user-defined XML Export Template. A new "Save As Template" view allows users to either graphically define a new XML export template from scratch, generate a default template from the DataWindow definition, or import an existing XML Schema to help format the XML output.

An XML Export Template consists of element and attribute names that will be fully customizable. They'll be mapped to specific DataWindow columns, computed fields, and other data values. Expressions and formatting may be applied to the data values to produce XML data values that differ from the display format on the printed report.

Each XML Export Template will be saved by name, and users may create multiple XML Export Templates for each DataWindow. A new Save-As XML configuration property lets the user choose which XML template to apply at runtime, thereby allowing a single DataWindow to generate several different XML data files, each with a unique customized format.

Similarly, new ImportFile Templates can be defined to import data from XML documents into a DataWindow. Again, the XML element and attribute names will be mapped to specific DataWindow columns and computed fields.

References
For more information on using a custom tag library, see Tag Extensions in the JSP 1.1 Specification. You can find another custom tag library example at www.sybase.com/detail/1,6904,1012876,00.html.

For more information on Jaguar::Properties and other public EAServer interfaces, see $JAGUAR/html/ir/index.html, where $JAGUAR maps to your EAServer installation.

More Stories By Jason Weiss

Jason Weiss has over 12 years of real-world design and development experience. He's a published author and frequently lectures at industry trade shows.

Comments (0)

Share your thoughts on this story.

Add your comment
You must be signed in to add a comment. Sign-in | Register

In accordance with our Comment Policy, we encourage comments that are on topic, relevant and to-the-point. We will remove comments that include profanity, personal attacks, racial slurs, threats of violence, or other inappropriate material that violates our Terms and Conditions, and will block users who make repeated violations. We ask all readers to expect diversity of opinion and to treat one another with dignity and respect.