Welcome!

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

Related Topics: PowerBuilder

PowerBuilder: Article

Creating A Distributed Power-Builder PDF Generator

Creating A Distributed Power-Builder PDF Generator

The purpose of this project was to create a Web-based custom-forms generation system that would allow administrators to add reports to their requested package, and users to select reports. Several modularized pieces were included within its spectrum and each one needed to be connected for the application to work effectively. These pieces were three disparate database systems.

The user interface should be through a browser, and the pages can't be bookmarked. Data validation and data autofilling must be real time. A messaging system was needed so the workflow process wouldn't halt. This system had to allow users to specify the reports they wanted packaged together. The report package had to be presented to the user through a Web interface, stored for future reference and protected by a password. This article focuses on how we used PowerBuilder to create the report server and COM object.

The project requirements were based on the following issues:

  1. Reports on the Web never print out the way the user wants them to.
  2. The user wants to capture information at a particular moment.
  3. The user wants to save the report for viewing.
  4. The user wants to configure different report combinations.
  5. The user wants to be selective in the reports he or she prepares and places in the package.
The PowerBuilder DataWindow allowed us to show exactly what users would get in a printout. We created the DataWindows so they'd fit on a page. We can change the retrieval arguments on the fly and remove certain DataWindow objects. To get information from several sources and present the data on one page, the application must be connected to Oracle, Access and DB2 data sources.

Architecture
The pieces of this project range from the user interface, Web server processes and distributed PowerBuilder service to database connections. I'll provide an overview of these different pieces.

We used ColdFusion to generate the Web-based user interface. We needed to dynamically populate HTML objects with data stored in the database, connect to different databases and communicate with COM objects. We used JavaScript to perform the following tasks: data validation, popup windows, interwindow communications and prefilling data. We used PowerBuilder to create the reports (DataStores), COM objects and the report server. Because we used the Windows 2000 server, the Web server was IIS. Two major logical databases were used for this application: master and control. The master database contained the user data, which was stored on an Oracle database. The control database contained different report and argument-retrieval information for each report accessed by the report server. We used Access for the control database. We also used a DB2 database for messaging the workflow portion of the application.

Note: The master and control databases can be configured on the same machine and be on the same database. Figure 1 shows the application architecture.

Distributed PB
Distributed PowerBuilder lets you serve PowerBuilder functionality for other programs to use. To provide some level of fault tolerance we ensured, through a utility called "srvany," that this could be configured as a service. This program can be created as a service using another utility, "instsrv". Once it's a service, you can modify its registry settings to run another program. One limitation is that you can't spawn another window from the "service" application. It's important that the application properties are configured so the system is the owner of the application, since no one will be logged onto the machine in the normal state. The only other thing to consider is that the application must be put into a listening mode when launched. Our application starts in a minimized state. The distributed PowerBuilder application was really serving only one object, which had several functions callable from another application (see Figure 2).

The COM module, created using PowerBuilder 7, was the glue that allowed ColdFusion to talk with distributed PowerBuilder. As a distributed PowerBuilder client, the COM module needed a proxy version of the served object in the distributed application. Our object name was n_expose. Our proxy version was a copy of our real version in the distributed application but with the code removed and a return call for each function so you could compile your COM object, called n_pb7com. The COM object was created using the COM object wizard in PB7. When creating COM objects it's important that each of the function's return values, arguments and any exposed (not protected) instance variables be simple types supported by the COM specification. Simple is certainly better in this environment. Any functions that contain arguments of complex types must also have an access declaration of "protected". With some effort this information can be gleaned from the error message you receive when you attempt to build the COM object. It's a bit of a switch from normal PowerBuilder programming and you might forget to protect a few things.

The COM object can be instantiated from any application environment that supports COM. In our case it was the common link between PowerBuilder and ColdFusion. Once instantiated, you can call the functions in the PB COM object. These, in turn, call functions from the distributed application. The functions we exposed to the COM interface were of_beginjob, of_addreport, of_runjob and of_deletejob.

In distributed PowerBuilder applications it's useful to create an administration tool to get the status of people accessing the application. Distributed PowerBuilder provides several functions that allow you to do this. Our management application was triggered from a button on the actual distributed PowerBuilder server container application. It consisted of a single DataWindow that showed one row for each user accessing the server. It also gave the ability to "kill" a user on the server for whatever administrative reason made sense at the time. This is often used to get rid of hung processes on databases and OSs. Hung processes weren't a big problem, but it was nice to monitor the service activity. The most helpful distributed PowerBuilder function is:

connection.getserverInfo(connectioninfo[]

It provides an array of connection information records you can loop through to stuff in a DataWindow. One of the elements of the connection information record is the clientid, which disconnects using the i_connection.RemoteStopConnection(clientid) method.

Web Interface
The client requirements for this application required us to use ColdFusion. The application server needed to create a dynamic site. This functionality allowed us to change the JavaScript variables depending on the user's security permissions. This created a more personalized application. We used JavaScript due to certain requirements; for example, the user wanted to click on a selected object such as a check box. The system would then autofill objects related to that action. Scripts were also written to check security and workflow, and to open and close selected windows. One of the system requirements of this application was that users shouldn't know their password. The system was designed to pull the user's name from the calling application and then poll a network application for the user's password. Because of the high security on the system, passwords were changed once a week. Since a major part of the application was creating reports, we needed the COM functionality to communicate with the report server. The report server is the major working mechanism; the COM object is the liaison for the application. Listing 1 provides the ColdFusion code to call the COM object.

Report Generation
The DataWindow definitions – the point of this distributed application – are nothing special. The application's objective is to leverage PowerBuilder's ability to generate clear, effective and printable reports. Most of our reports were highly formatted single-page reports. It isn't necessary to create any DataWindow arguments in the DataWindow since any SQL arguments are added dynamically at runtime. It's important to keep the SQL relatively simple so you can give yourself more flexibility with the arguments. In our application we had each report take the same arguments; however, the report engine was written to support a varying number of arguments for each report. In our version the report engine used a structured array to pass arguments to an added report. This is obviously not COM compliant; therefore we had to make the COM object specific to this application with respect to the report arguments.

In most situations the final PDF file would be a multiple page document made up of a number of DataWindow reports. We handled this by using Adobe Acrobat to print each DataWindow to a file named with a millisecond-level time stamp. Once each file had been printed, we'd merge the PDF files into a single output file using the ActivePDF toolkit from ActivePDF.com. This has an API that can be called from PowerBuilder (see Listing 2). This worked magnificently and incurred very little overhead. We had to adopt this method once we realized we couldn't open a print job and use several DataWindow print functions to build the multipage report. A print job can't be called from a distributed user object since it needs a window to be its parent. We adopted this window mechanism initially, but found it wouldn't work once we made the distributed application an NT service. The ActivePDF toolkit gave us the ability to deal with these restrictions.

The linkage between the COM object and distributed PowerBuilder isn't any different than calling a distributed PowerBuilder application from any non-COM PowerBuilder application. You must first connect to the distributed application using the connect function, which results in a connection handle. This handle can then be used to call the functions of the object that's being served in the server application. The code in Listing 3 illustrates this connection.

Storage of Reports
Storage space for these reports is an ongoing issue. One of the problems is calculating the space required for this type of project. Luckily for this one there was plenty of space. In most cases, though, we have to set up a scheduling mechanism to run periodically and remove any files older than a predefined time. The space for the debugging files also needs to be considered. For this task we decided to delete the debug file upon successful completion of the report being generated, which allowed for quicker debugging. We effectively solved the problems for the targeted report and didn't worry about the other reports in the system.

The requirements for this project included having the reports saved for the calling application and also for quick reference from a browser, which was different than the main section of the application that allowed for no book marking. We created a separate virtual directory for the reports. This allows for browser book marking, where the actual application does not allow for any book marking. Figure 3 shows an example report.

Debugging Reports Errors
The space for the debugging files also needs to be considered. For this task we decided to delete the debug file upon successful completion of the report being generated. This would allow us to find the problem reports quickly. This allowed us to effectively solve for the targeted report and not worry about the other reports in the system.

Summary
Because of the architecture, adding new reports is a simple task – simply follow the rules that have already been stated. I'm sure your clients won't have a problem designing new reports to make your life interesting. This also allows you to use reports from your old application and make them Web-ready in hours, instead of weeks. We also demonstrated the ability to reuse code with the COM object functionality. This enables developers to take existing business logic and make it into distributed PowerBuilder objects. Your Web application can call the COM object and use code from existing applications. This project showed us that we can use the distributed PowerBuilder mechanics to create a more effective system and maintain the code in one place.

More Stories By Gerald Giggs

Gerald Giggs is vice president of technology at Infovision, Inc. He manages all application development delivery including Web and
client/server integration.

More Stories By Scott Heffron

Scott Heffron is a senior application engineer located in the Salt Lake City area. He has been involved in client/server, GIS and Web projects for the past 10 years. He is currently working on WAP technologies.

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.