Richard (Rik) Brooks

Subscribe to Richard (Rik) Brooks: eMailAlertsEmail Alerts
Get Richard (Rik) Brooks via: homepageHomepage mobileMobile rssRSS facebookFacebook twitterTwitter linkedinLinkedIn

Related Topics: Java EE Journal, Java Developer Magazine

J2EE Journal: Article

Converting PowerBuilder To Java

Converting PowerBuilder To Java

Dear Cliff,

You would salivate at the stuff I'm doing. If you thought PowerBuilder was nice, Jaguar blows it clean away. The stuff I'm doing with Jaguar is beyond belief.

Just to catch you up, Jaguar is an application server. Actually it's only one small part of a piece of software that comes bundled from Sybase called Enterprise Application Server. Along with it comes a Web server with its own scripting language (PowerDynamo) and a bunch of tools for translating between one protocol and another.

Essentially you create components. These are just nonvisual objects. You can write them in PowerBuilder, Java, C/C++, or any language that generates CORBA objects. In fact, since EAServer is J2EE compliant, you can even host EJBs on it. Then, using something called the Jaguar Manager, you deploy the objects to Jaguar. Of course, if you're using a Sybase development tool, you can do it from that.

Once it's on Jaguar, you can access it in several different ways. You have to know the TCP/IP address of Jaguar, though. It's easy to do it from a Sybase development tool. Click on New, then select a wizard to generate local proxies. This gives you an object you can use in your application like any other NVO.

Before you can use the proxy, you have to connect to Jaguar, where another wizard steps you through generating a connection object. It, too, winds up looking like a proxy. Here's the code to use that connection object:

n_myConnection_object go_jaguar // assuming you are defining it as global

Then in your script put the following lines:

go_jaguar = create n_myConnection_object
if go_jaguar.of_connectToServer() = -1 then
messagebox("ERROR", "Could not connect")
halt close
end if

To use a proxy, you define it as a variable (just like any other NVO) and create it, but since it's CORBA you can't just use the CREATE. Here's what you do:

n_myJaguarObject localObject go_jaguar.createInstance(localObject)

Now you can use your proxy as if it was a PowerBuilder NVO.

But it goes much deeper than that. There are three different kinds of Jaguar objects: normal, shared, and services.

Normal objects are stateless. They go out of scope after one function call (PowerBuilder has finally taken to calling functions methods). In other words, a thread is created and the variable is put in it. You can optimize this by using instance pooling to provide a minimum number of prebuilt but empty objects that are sitting there waiting for use. It's sort of like the paging we used to do years ago when writing word processors in C. Remember that? You'd read a part of the file that was edited and try to keep your current index somewhere in the middle of that to minimize the "hiccups" the user would see when doing page down and up. It's pretty much the same concept.

The shared objects don't go out of scope, and there's never more than one of these at a time in Jaguar memory x, since that one is shared. It fires off a separate thread for every process that calls it.

The services objects allow you to create something akin to Windows services or UNIX CRONs, except that it runs entirely within the context of Jaguar. It fires off and just keeps running forever, sleeping for a programmer-defined period after each run. There's a function call to make it sleep (JagSleep).

So these are the types of components. The story doesn't end here though. Inheritance is fully supported so you have all the power of inheritance in your components. In mine, for example, I created a base class and then added code that would write to the server log file. Of course, that wasn't quite enough (when is anything enough?).

I read an article in PowerBuilder Developer's Journal in which Mike Barlotta described how to use Jaguar component properties. In this way, whoever is charged with maintaining Jaguar can fire up an application called the Jaguar Manager, find a package and a component within that, then right-click on it and add a new property. The property, like any other, has a name and a value except that it's a string. From within my component I can get that property with a function called getContextKeywords. It returns me to an array of strings that are the values for all the properties the Administrator set up by a particular property name in the Jaguar Manager. I try to get the Administrator never to set up more than one, but he or she may set up a property named "foo" on more than one component, in which case I get one array element for each of them.

I have a ServicesManager object that's really just a shared object, not a service at all. Basically, the idea is that the programmer can register (taking a page from PFC) objects that he or she inherits from a component I created with this manager. It'll store the objects in an array and check them periodically. If, judging from the internal properties of the component, it finds one that's ready to fire, it fires the component run method and resets the next time it's due to run.

I've got this set up so that each runnable component can be set up to run on specific days of the week, days of the month, or every day. The programmer can also specify a start and end time along with an interval at which to run the component run method.

Author's comment: This is a message that I sent to Cliff High, an old friend and fellow programmer. We've worked together from time to time for the last two decades - mostly with C++ contracts - but recently with a PowerBuilder contract. I helped him learn PowerBuilder through e-mail and he was strongly impressed with the language, especially the ability to create truly object-oriented applications. This contract wasn't EAServer so he wasn't exposed to it. The message above is in response to his asking me how I like my current EAServer contract.

In other words, a programmer can inherit from my component, write some code in the run method, then specify that this code will run every hour on the third of each month; every Monday, Wednesday, and Friday; or anything he or she chooses. I even have it set up so the programmer can tell the component to run only on the third day of specific months.

I've also set up this manager so that it either perpetually loops (with a yield in there, of course, so it doesn't monopolize the server) or it will, at the end of each run, find the next time that any of its components need to run and will "sleep" until that time. The problem with this is that you can't register objects with it while it's sleeping. So during development I just loop. Once it goes into production we can set another component property to make the thing sleep and be better behaved.

Pretty cool, huh? Now the programmer doesn't have to call the JagSleep, and I get to handle the sleeptime entirely outside the component. I can optimize the sleeptime at runtime by just going into the Jaguar Manager and changing the value of the property. Of course, it's not perfect. Let's say that your sleeptime is 10 minutes and your system is experiencing heavy traffic, so you want to make it 20 minutes. Let's also say that your component just finished its run. If you change the 600 to 1,200, then your component is still going to wake up after 10 minutes, not 20. But after that run it will go to 20-minute intervals. I guess that's not quite as bad as the other way around. If it's running every 10 minutes and you want to change that to every minute, then you have to wait the 10 minutes after the change before it goes to every minute. I guess you just can't have everything.

I mentioned server logs before. When I read Mike Barlotta's article I got curious and started exploring all the other component properties that were already there. I found one that told me if I was running Jaguar in debug mode (oh yes, there's a remote debugger for Jaguar components, but that's worth a whole message in itself). So I went to my logging function in my ancestor component and put in the code to find out if Jaguar was in debug (again using the getContextKeywords method). I set it up so that the component would log only if we were in debug.

One more thing before I sign off and write some more Jaguar components. Mike Barlotta wrote two books on Jaguar (one, Taming Jaguar, which he coauthored, came out in August) in which he describes something called a State Manager. This is a component that lets browser-based applications store state information on Jaguar. I expanded this a little by adding a timeout on each variable and then writing the state information in a table. I then created a Garbage Collector (a fancy name for a typical services component) that wakes up every 600 seconds (or whatever the Administrator defined for StateGarbageCollectorInterval). It runs through the table removing expired data.

I've skipped the whole topic of the HTML DataWindow. Basically there's new functionality in the DataWindow that allows you to return HTML to a browser that will paint the DataWindow in the browser - complete with presentation styles and JavaScript code to handle events and validation, and basically run the DataWindow.

Sorry I've given such a simplistic explanation of the new Jaguar, but hey, Mike Barlotta wrote a whole book on the subject and still found that he had to write another.

More Stories By Richard (Rik) Brooks

Rik Brooks has been programming in PowerBuilder since the final beta release before version 1. He has authored or co-authored five books on PowerBuilder including “The Definitive DataWindow”. Currently he lives in Mississippi and works in Memphis, Tennessee.

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.