11.07.2015 Views

WEB-ENABLE POWERBUILDER APPS WITH SYBASE EASERVER ...

WEB-ENABLE POWERBUILDER APPS WITH SYBASE EASERVER ...

WEB-ENABLE POWERBUILDER APPS WITH SYBASE EASERVER ...

SHOW MORE
SHOW LESS
  • No tags were found...

Create successful ePaper yourself

Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.

Sybase, Incwww.sybase.com/pbworkshop2 PBDJ volume9 issue4www.SYS-CON.COM/pbdj/


JOHN OLSON, EDITOR-IN-CHIEFFROM THECOEDITORE D I T O R I A L A D V I S O R Y B O A R DBRUCE ARMSTRONG, MICHAEL BARLOTTA, ANDY BLUM,RICHARD BROOKS, KOUROS GORGANI, BAHADIR KARUV, PH.D.,BERNIE METZGER, JOHN OLSON, SEAN RHODYCOEDITOR-IN-CHIEF: JOHN OLSONCOEDITOR-IN-CHIEF: BOB HENDRYEXECUTIVE EDITOR: M’LOU PINKHAMMANAGING EDITOR: CHERYL VAN SISEEDITOR: NANCY VALENTINEASSOCIATE EDITOR: JAMIE MATUSOWASSOCIATE EDITOR: GAIL SCHULTZASSOCIATE EDITOR: JEAN CASSIDYONLINE EDITOR: LIN GOETZTECHNICAL EDITOR: BERNIE METZGERNEWS EDITOR: BRUCE ARMSTRONGDATAWINDOWS EDITOR: RICHARD BROOKSW R I T E R S I N T H I S I S S U EBRUCE ARMSTRONG, TIMOTHY BECK, JACEK FURMANKIEWICZ,BERNDT HAMBOECK, BOB HENDRY, SCOTT MCREYNOLDS, JOHN OLSON,DIANE VEZINA, JASON WEISSS U B S C R I P T I O N SFOR SUBSCRIPTIONS AND REQUESTS FOR BULK ORDERS,PLEASE SEND YOUR LETTERS TO SUBSCRIPTION DEPARTMENTSUBSCRIPTION HOTLINE: 800 513-7111COVER PRICE: $15/ISSUEDOMESTIC: $149/YR. (12 ISSUES) CANADA/MEXICO: $169/YR.OVERSEAS: BASIC SUBSCRIPTION PRICE PLUS AIRMAIL POSTAGE(U.S. BANKS OR MONEY ORDERS). BACK ISSUES: $12 EACHPUBLISHER, PRESIDENT, AND CEO: FUAT A. KIRCAALIVICE PRESIDENT, PRODUCTION & DESIGN: JIM MORGANVICE PRESIDENT, BUSINESS DEVELOPMENT: GRISHA DAVIDASENIOR VP, SALES & MARKETING: CARMEN GONZALEZVP, SALES & MARKETING: MILES SILVERMANCHIEF FINANCIAL OFFICER: BRUCE KANNERASSISTANT CONTROLLER: JUDITH CALNANACCOUNTS PAYABLE: JOAN LAROSEACCOUNTS RECEIVABLE: JAN BRAIDECHACCOUNTING CLERK: BETTY WHITEADVERTISING DIRECTOR: ROBYN FORMAADVERTISING ACCOUNT MANAGER: MEGAN RINGASSOCIATE SALES MANAGER: CARRIE GEBERTASSOCIATE SALES MANAGER: ALISA CATALANOASSOCIATE SALES MANAGER: KRISTIN KUHNLEASSOCIATE SALES MANAGER: LEAH HITTMANVICE PRESIDENT, EVENTS: CATHY WALTERSCONFERENCE MANAGER: MICHAEL LYNCHSALES EXECUTIVE, EXHIBITS: MICHAEL PESICKSALES EXECUTIVE, EXHIBITS: RICHARD ANDERSONART DIRECTOR: ALEX BOTEROASSOCIATE ART DIRECTOR: CATHRYN BURAKASSOCIATE ART DIRECTOR: LOUIS F. CUFFARIASSOCIATE ART DIRECTOR: AARATHI VENKATARAMANASSOCIATE ART DIRECTOR: RICHARD SILVERBERGASSISTANT ART DIRECTOR: TAMI BEATTY<strong>WEB</strong>MASTER: ROBERT DIAMOND<strong>WEB</strong> DESIGNER: STEPHEN KILMURRAY<strong>WEB</strong> DESIGNER: CHRISTOPHER CROCECUSTOMER RELATIONS/JDJ STORE: ANTHONY D. SPITZERE D I T O R I A L O F F I C E SSYS-CON MEDIA135 CHESTNUT RIDGE ROAD, MONTVALE, NJ 07645TELEPHONE: 201 802-3000 FAX: 201 782-9600SUBSCRIBE@SYS-CON.COM<strong>POWERBUILDER</strong> DEVELOPER’S JOURNAL (ISSN#1078-1889)is published monthly (12 times a year) for $149 bySYS-CON Publications, Inc.,135 Chestnut Ridge Rd., Montvale, NJ 07645Periodicals Postage rates are paid atMontvale, NJ 07645 and additional mailing offices.POSTMASTER: Send address changes to:<strong>POWERBUILDER</strong> DEVELOPER’S JOURNAL, SYS-CON Publications, Inc.,135 Chestnut Ridge Rd., Montvale, NJ 07645© C O P Y R I G H TCopyright © 2002 by SYS-CON Publications, Inc. All rights reserved.No part of this publication may be reproduced or transmitted in any form or by anymeans, electronic or mechanical, including photocopy or any information storage andretrieval system, without written permission. For promotional reprints, contact reprintcoordinator Carrie Gebert. SYS-CON Publications, Inc., reserves the right to revise,republish and authorize its readers to use the articles submitted for publication.All brand and product names used on these pages are trade names,service marks or trademarks of their respective companies.SYS-CON Publications, Inc., is not affiliated with the companiesor products covered in PowerBuilder Developer’s Journal.Two Heads Are BetterThan OneAfter careful consideration I’ve come to the conclusion that having two heads is better thanhaving just one. While it may sound like I’m simply stating the obvious, in fact, most peoplehave only one head. 1 However, those who are blessed with two heads enjoy a measurableadvantage over their single-headed rivals. This conclusion was affirmed in a headlinegrabbingpaper by two Princeton economists for the National Bureau of Economic Researchentitled “Are Two Heads Better Than One?” 2Having multiple heads is most beneficial when performing work that requires multitasking,such as speaking on two phones at the same time. Though that may seem like an inconsequentialskill, how would your life change if you never had to put anyone on hold? Or youcould speak to both your children at the same time? Or you could see behind you? Or neverlose at a game of Trivial Pursuit? Telecommuters who watch TV and work at the same timecould actually be productive! 3 I’m sure you can see where I’m going here.That being said, I must concede that having multiple heads is not for everyone. Consider aman who is clumsy, klutzy, or suffers from recurrent dizziness. That man would likely be bonkinghis heads together constantly. Severe and permanent injuries could result. Even worse,having three or more heads could cause severe neck cramping. Obviously, the person wouldbe more susceptible to head games. Sacrifices would also have to be made. Solitaire, forexample, would need to be given up. In many cases, it may be better to just stick with one.Now to my point. You’ve seen Bob Hendry’s head on pages in this magazine for severalyears. No, it’s not pretty, but it is functional. While many of you have considered him a headcase, others see him as head and shoulders above the other writers who are much shorter thanhim. Anyway, I have asked him to join me as editor-inchiefof PBDJ…and surprisingly, he has accepted. Ofcourse, this situation raises the awkward question: “Howcan two people be editors at the same time?!” Well, thePrinceton economists hit the nail on the head when theydetermined that groups of one are more likely to come tounanimous decisions than groups of two or more. We’refacing that problem head-on and have decided to alwaysagree unanimously, whether we agree or not.As coeditors, we will each continue to perform manyvery important tasks; then when we’re done with those, we’ll spend what free time we have leftworking on this magazine. Please join me in welcoming Bob to his new post by flooding himwith dozens of article proposals marked “process immediately!” ;-)References1. The 2000 U.S. census* indicated that the vast majority of Americans have exactly one head.Statistics show that it is an anomaly for persons to have more than one head.*Persons with 0 heads were not counted in the census.2. Chiu Hays, Y. (2001). “Study Affirms: Two Heads Are Better Than One.” Princeton WeeklyBulletin. Vol. 90, No. 16. www.princeton.edu/pr/pwb/01/0212/1b.shtml3. Though telecommuters may become more productive with the addition of each head, it’smore likely that they would obtain additional televisions so they could watch more thanone show at a time. ▼john@sys-con.comAUTHOR BIOJohn Olson is principal of Developower, Inc., a consulting company specializing in software solutions usingSybase development tools. A CPD professional and charter member of TeamSybase, he is a coauthor ofSYS-CON’s Secrets of the PowerBuilder Masters books.www.SYS-CON.COM/pbdj/PBDJ volume9 issue43


FROM THE COEDITORI’m Happy to Still Be HereWRITTEN BYBOB HENDRYIstarting reading PBDJ in 1995, justwhen PowerBuilder was becomingbig. At that time, only seven years ago,PowerBuilder was the most popularclient/server development tool. Thebuzz was incredible. Just mentioningthe word PowerBuilder would drawthousands of developers, speakers, andvendors to conferences worldwide.PowerBuilder had arrived.At users’ groups and conferences,attendees would soak up all thePowerBuilder knowledge they could. Tosatisfy this seemingly insatiable need,books were written, speakers lectured,and vendors marketed a blinding arrayof PowerBuilder-related products. Thismaelstrom of blinding enthusiasm hada center – PowerBuilder Developer’sJournal.Not only was this magazine part ofthe PowerBuilder boom, it defined it.Every serious PB developer would waitwith bated breath for the next edition – Iknow I did. The articles were filled withuseful advice from the world’sPowerBuilder experts. At one point, thismagazine was so popular it was stockedwith the other computer publications atmy local 7-Eleven. 7-Eleven!In the PowerBuilder world, the writerswere all household names, icons in theirfield, beyond gurus. Back in its heyday,PowerBuilder gurus learned from thewriters in this magazine. The writers literallydefined correct coding practicesin each article they wrote. On projects,we would code a certain way becausethat’s how so and so did it.The writing quality was incredible.This was the first computer-related publicationI really enjoyed reading. Whilemost other technical magazines readlike cookbooks, PBDJ was actually fun.In this writer’s opinion, it was the firstpublication to employ writers that lacedboring technical content with color, texture,and, heaven forbid, humor. My hatwent off to SYS-CON. They could havestuck with the dry technical tone of theday and the magazine would have beengood. But they didn’t, and it was better.After a year of reading PBDJ and admiringits writers, I decided I wanted to beone.I sent an e-mail to SYS-CON suggestinga Beginning PowerBuilder column.This column should run every monthand focus on beginner issues, which Ithought was a great idea. At the time, Iwas teaching about 20 PowerBuilderclasses a year and had the pulse of thePowerBuilder newbies. If there was oneflaw in PBDJ, it was that thePowerBuilder newbie did not understandmost of the content.SYS-CON liked my suggestion andasked if I could recommend someone towrite it. To no one’s surprise, I nominatedmyself. Two weeks later, I submitted awriting sample. Since that date, I’vebeen a regular contributor to this magazine.My original column doesn’t runanymore. Writers, like everything else inlife, must evolve to survive.Last month, John Olson asked if Iwould like to be coeditor-in-chief of thismagazine. I just about fell out of mychair. Me, a humble writer, was justasked to be coeditor of PowerBuildergeekdom? Say it’s not so! This magazinehas had a long line of great editors. Whatcould I possibly have to offer? I acceptedJohn’s offer and told him I felt like thelast Roman emperor. I almost asked himhow many others had turned him down.John has been a great editor-in-chiefover the years. Notably, Johnled the transition fromclient/server articles only toarticles that focused on othertechnologies – mainly Power-Builder and the Web. The transitionwas smooth; hardly anyonenoticed. This change inwriting content would havekilled most magazines. Butunder John’s leadership PBDJkept chugging along. After all thework John has put into this magazine,he needs a little help. The jobof editor-in-chief is a difficultone. I’m amazed he has gonethis long on his own.So here I am. I have manyideas that will hopefully restorethis publication to the success itenjoyed in its heyday. I realize thatPowerBuilder is a mature product, andmature products don’t generate thebuzz of newer, hotter technologies.To the strong, loyal core ofPowerBuilder users: this will always beyour magazine, I promise. ▼bob@sys-con.com4PBDJ volume9 issue4AUTHOR BIOBob Hendry is a PowerBuilder instructor for Envision Software Systems and a frequent speaker at national and international PowerBuilder conferences. He specializes inPFC development and has written two books on the subject, including Programming with the PFC 6.0.www.SYS-CON.COM/pbdj/


F O C U SWRITTEN BYJASON WEISS AND DIANE VEZINAThe number of PowerBuilder and EAServersolutions in production continues to grow. Itwould be an understatement to say thatthere’s a large XML movement underway inthe industry. While PowerBuilder 9.0 willinclude some exciting XML capabilities, thisarticle focuses on building a solution that providesXML capabilities for DataWindowstoday, in PowerBuilder 7 and 8.6 PBDJ volume9 issue4 www.SYS-CON.COM/pbdj/


We’ll describe the design and implementation of an XML generationsolution (affectionately referred to here as the PB XML Generator)built using PowerBuilder and Java. The complete solution will beavailable as a free download from the Sybase Developer’s Network(SDN) at www.sybase.com/developer/applicationdeveloper. This downloadwill 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 EAServer3.6.1, 4.x)• A sample Web application (also in Jaguar .jar format) demonstratingseveral different XML generation examples from DataWindows thatrun against the standard demo database shipping with EAServer• Installation directions along with Apache Ant deployment scriptsSolution ArchitectureThe PowerBuilder XML Generator enables developers to export existingPB 7.x and 8.x DataWindows as XML through a simple JavaServerPage (JSP) tag library and EAServer components. Figure 1 depicts oursolution architecture. Tag attribute values are specified through a JSP,customizing the DataWindow export to XML. When the JSP containingour tag library is processed, the doStartTag() method of theDataWindowTag class executes. The tag class populates an array ofname-value pairs that map back to the tag library attributes. Theseproperties are then passed to the PBXMLgen/MetaParser component(written in PowerBuilder) where the DataWindow’s metadata isaccessed.It’s here inside the PowerBuilder component thatthe data is retrieved from the database usingdw.retrieve(). The DataWindow metadata, theresult set, and the tag library attributes are thenpassed over to another component written inJava, the PBXMLgen/XMLgenerator. Thiscomponent actually performs the XML generation.The resulting XML is then passedback through the call stack to theoriginal JSP page on its wayback to the requestingclient.The XML producedis compliant with theXML 1.0 specification,meeting all itswell-formedness constraints,and mayoptionally containDataWindow dataand metadata withexplicit markup information,such as columndefinition, aread-only indicator,and syntax. Note: Thecurrent release handlesonly the onewayprocessing of adw.Retrieve() to XML.Building the JSP Custom Tag LibraryWe simply don’t have enough space to adequately describe all theidiosyncrasies of building custom tag libraries. There are a number ofgreat JSP books out there, and most have a chapter or more describinghow to build JSP custom tag libraries. A great reference is Core Servletsand JavaServer Pages by Marty Hall.One of the first challenges we faced in developing the tag library wassharing data between the PowerBuilder and the Java world. In the solutionarchitecture we describe, we have name-value pairs gathered in thetag handler class that need to be passed into the PowerBuilder component.This component reads some of the values it needs, and then mustforward 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 wequickly discovered this was not an option. This class is built atop ahashtable that, unfortunately, PowerBuilder doesn’t understand. Theresult was a BLOB in the method signature of the PowerBuilder proxywhere the java.util.Properties argument was located. To overcome thisproblem we looked to EAServer’s CORBA roots for help.In the CORBA world, interfaces are described using the InterfaceDefinition Language (IDL). Each component deployed to EAServer hasits public interface described in IDL. Jaguar passes around a lot of namevaluepairs, as described by the IDL in Jaguar::Properties. In fact, this IDLrepresentation of name-value pairs is easy to use in PowerBuilder andJava. Through the use of Jaguar::Properties, we were able to seamlesslypass name-value pairs between both languages. Problem solved!Over 95% of the code in the DataWindowTag class merely collects andstores attribute values for use later when the doStartTag() method isinvoked. To achieve this, we declare one private string instance variable foreach attribute. Each attribute requires a setter method (and may actuallyhave 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 pairsspecified in the JSP, we move them into an instance of Jaguar::Propertiesto pass them in an intercomponent call. We get a handle to an instanceof the MetaParser object (described in detail in the next section) using aCORBA Factory. Listing 1 describes how to look up a PB component inEAServer from Java.FIGURE 1PB XML Generator Architecturewww.SYS-CON.COM/pbdj/PBDJ volume9 issue47


Attribute nameDescriptionlibNameFull path of the .pbl/.pbd library or the EAServer package/component name where the DataWindow can be found, requireddwNameDataWindow name, requireddbmsDataSource, ex: "ODBC", requireddbparmDatabase parameters, ex:"UseContextObject='No',ConnectString='DSN=EAS Demo DBV3;UID=dba;PWD=sql'", requiredserverinfoEAServer location, defaults to "iiop://localhost:9000"logidEAServer Login ID, defaults to "jagadmin"logpass EAServer Login password, defaults to ""rootElementXML root element tag, defaults to "Root"rowElementXML row element tag, defaults to "Row"colNameA comma-separated list of existing and new column names,ex: "f_name -> first_name, l_name -> last_name" (a spacemust be included on either side of the "->"), if left empty, theDataWindow column names are usedretrievalArgDataWindow retrieval arguments to be specified as a commaseparatedlist (no spaces), ex: "100,Whitney". Maximum 20entries, defaults to no argumentsxmltoFileThe XML generated will also be saved to the path/file specifiedomitXMLdecl Whether or not to omit the XML declaration (set to true toomit the declaration if you wish to append multiple XMLdocuments), defaults to "false"dwcDataDynamically inserts "CDATA" if special characters preventingthe proper display of XML are detected, defaults to "true"dwmetaData When set to true, the metadata is included in the XML,defaults to "false"processGroup Group processing (not yet implemented)nestedRetrieve Nested DataWindow processing (not yet implemented)appDebugOutput debugging information in the JSP and set thecomponent trace, debug, pb.debug and pb.trace repository,option to true in EAServer for the PBXMLgen package onlyTABLE 1Custom tag attributes for the DataWindowTag classOnce we have a Factory from our doCorbaLookup() method, we needto 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 namesand what they should map to in the generated XML. For simplicity, thissingle attribute is expanded into two string arrays, dwnames and newnames.Through the of_parse_meta() method, we pass in the namearrays, the name-value pairs, and a StringHolder that will contain thegenerated XML. Intercomponent calls that need to leverage pass-by-referencearguments must use holder classes. When this method callreturns, the StringHolder argument contains the generated XML, whichis 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 arraysint rtn = parser.of_parse_meta(dwnames, newnames, tagprops,xml_holder);…In our implementation, a number of customizable attributes can beused to control how the XML is generated from the DataWindow. In a JSPcustom tag library, it’s the responsibility of the taglib.tld file to defineeach of the attributes on the tag. Table 1 is a list and description of eachattribute we defined for the DataWindowTag class.Mining for Metadata: The PB ComponentWhen building the PB XML Generator we wanted to leverage corePowerBuilder functionality. To that end, we extracted the metadata from theDataWindow using the dw.describe() method and retrieved the data usingthe standard dw.retrieve() method. This is significantly simpler to implementthan working with Statements (or PreparedStatements) in Java. Most of thecode inside the of_parse_meta()method is straightforward PowerScript, likeinitializing SQLCA to connect to the database and creating and initializing aDataStore 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 pathto a .PBL or .PBD or the name of a package/component. Both approachesleverage PowerBuilder’s ability to dynamical modify the library list throughthe setLibraryList() method; however, determining what the libraries arewhen a package/component is specified deserves an explanation. When youdeploy a PowerBuilder component to EAServer, typically all the objects arebundled 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 assembleabsolute 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.librarylistThe first property (.type) is a check to make sure the named package/componentis indeed a PB component. It doesn’t make sense lookingfor a DataWindow if the component is an EJB! Next, PowerBuilderuses a strict naming convention to track deployments – “Cxx”, where “C”is a constant and xx is a sequential number, for example, C23 and C134are 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 PowerBuildercomponent would have a directory structure similar to this:$JAGUAR/repository/component///CxxTo determine what $JAGUAR equates to, we used the Jaguar/Management API’s getEnv() method, useful for looking up environmentvariables. The .pb.librarylist property contains a delimited list oflibraries, and it uses a $ prefix to indicate a relative path to each librarybased 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 ispassed 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 taglibrary attribute. We retrieve the data from the database, extract themetadata 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 reverseis true as well. After running the proxy project, the Jaguar::Properties IDLstructure is represented as a structure in PowerBuilder. All this informationis passed into the Java component where final assembly of the XMLdocument will take place.8 PBDJ volume9 issue4 www.SYS-CON.COM/pbdj/


FIGURE 2FIGURE 3Generate test formSample output from the PB XMLGeneratorBuilding the XML: The Java ComponentThe first approach we considered was to leverage the W3C DocumentObject Model (DOM) interfaces through the Java API for XML Parsing(JAXP) to build the XML tree. While technically feasible, it was determinedthat this was too much overhead and not worth the effort. Anotherapproach was to leverage the MSXML parser through its COM interfaceinside a PowerBuilder component. Again, while technically feasible, wedetermined that it would entail too much overhead. The final option weconsidered was using a single string and concatenation to build the XMLdocument. This is perhaps the simplest and most straightforwardapproach 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 isspeed. Java will handle the string manipulation much better thanPowerBuilder. After the class was written, an overwhelming majority of thecode 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 TogetherAfter the tag library is built (the full source code can be downloadedfrom www.sys-con.com/pbdj/sourcec.cfm) and the components aredeployed, we need to create a simple JSP page that allows us to play withvariations of the DataWindow XML generation. Figure 2 displays a sampleJSP page named PBXMLDemo.jsp that accomplishes this.This HTML form collects all the values and passes them into another JSPpage where they’ll be processed and the generated XML displayed. Listing 2provides the two lines of JSP code (PBXMLDemoTagLib.jsp) that’s requiredto 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 aJSP page. We assign a namespace prefix of “pbxml” to the tag librarythat’s described in /Web-INF/tlds/taglib.tld, bundled with the JSP, anddeployed as a J2EE Web application archive (.war) file. The second line ofcode (split across multiple lines for readability) is where we set the taglibrary attributes (nothing more than name-value pairs) that control theXML generation. Notice how the attributes are populated using therequest.getParameter() method, which exposes the values that weretyped into the HTML form.The PB XML Generator could also be exposed more directly as aservlet. The sample source code includes the XMLGenServlet, whichdemonstrates how the custom tag library and the JSP can be bypassedwhen generating XML from a DataWindow. The only attributes currentlyimplemented in the servlet are “libName” and “dwName” (see Table 1for more details). However, the servlet includes the necessary code toimplement all the attributes described in Table 1 through the sameProperty class used in the JSP tag library.Figure 3 shows a picture of the end result – a browser displaying XMLfrom one of the sample DataWindows.Looking AheadThe logical extension of this design would include the ability to turn anXML document back into a DataWindow. The architecture described here issuitable for achieving this and wasn’t implemented as a result of time andspace constraints. The use of the Java component in the architecture is particularlyinteresting. This component could leverage JAXP to parse an incomingXML document, pushing the data back into a structure. A mapping mechanismwould 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 DataWindowthrough the dw.modify(), dw.insertRow(), and the dw.SetItem() methods.Another reason beyond space and time for not implementing round-tripXML capabilities is that PowerBuilder 9.0 will be released later in 2002. Userswill be able to select data values from a DataWindow and save as XMLaccording to a user-defined XML Export Template. A new “Save As Template”view allows users to either graphically define a new XML export templatefrom 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 thatwill be fully customizable. They’ll be mapped to specific DataWindowcolumns, computed fields, and other data values. Expressions and formattingmay be applied to the data values to produce XML data valuesthat differ from the display format on the printed report.Each XML Export Template will be saved by name, and users may createmultiple XML Export Templates for each DataWindow. A new Save-AsXML configuration property lets the user choose which XML template toapply at runtime, thereby allowing a single DataWindow to generate severaldifferent XML data files, each with a unique customized format.Similarly, new ImportFile Templates can be defined to import datafrom XML documents into a DataWindow. Again, the XML element andattribute names will be mapped to specific DataWindow columns andcomputed fields.10 PBDJ volume9 issue4 www.SYS-CON.COM/pbdj/


Dynamic Buyer Inc.www.ibm.com/smallbusiness/dynamicbuyerwww.SYS-CON.COM/pbdj/PBDJ volume9 issue411


ReferencesFor more information on using a custom tag library, see TagExtensions in the JSP 1.1 Specification. You can find anothercustom tag library example at www.sybase.com/detail/1,6904,1012876,00.html.For more information on Jaguar::Properties and other public EAServerinterfaces, see $JAGUAR/html/ir/index.html, where $JAGUAR maps toyour EAServer installation.AUTHOR BIOSJason Weiss is a software engineering manager for Sybase with over 12 years of real-world design anddevelopment experience. He’s a published author, and frequently lectures at industry trade shows.Diane Vezina is a software engineer for Sybase with over 18 years’ experience in software development.She’s a Certified Sybase Instructor and Certified Sybase Professional focusing on Sybase EAServer andEnterprise Portal products. ▼weissj@sybase.comvezina@sybase.comListing 1public Factory doCorbaLookup(String pack, String comp) {Factory factory = null;Try {Java.util.Properties props = new java.util.Properties();Props.put("org.omg.CORBA.ORBClass","com.sybase.CORBA.ORB");ORB orb = ORB.init((java.lang.String[])null, props);//serverinfo is actually an attribute passed in fromthe tagManager manager =ManagerHelper.narrow(orb.string_to_object(serverinfo));//logid and logpass are actually attributes passed infrom the tagSession session =manager.createSession(logid, logpass);Factory =FactoryHelper.narrow( session.lookup(pack + "/" +comp));} catch (Exception e) {e.printStackTrace();}return factory;}Listing 2Download the Code!The code listing for this article can also be located atwww.sys-con.com/ pbdj/12 PBDJ volume9 issue4www.SYS-CON.COM/pbdj/


SimplexKnowledgeCompanywww.skc.comwww.SYS-CON.COM/pbdj/PBDJ volume9 issue413


F E A T U R EWRITTEN BY JACEK FURMANKIEWICZAdda powerful tool to your applicationdevelopment toolkitExpanding into other language markets presents an ample challengefor any PowerBuilder shop. In my case, we were faced withinternationalizing our existing sales audit application intoFrench (we’re based in Quebec, where French versions of applicationsare required by law), as well as UK English (there areenough differences in retail terminology between North America andEngland to make this necessary). Our European salespeople were alsotargeting clients in Germany and Spain and, realistically, we had to anticipatesupporting more languages in the future.Our application is fairly mature and quite large by now. Developmentstarted in early 1996 and the application now consists of over 55 PBLs withthousands of objects. Due to time pressures, we didn’t design with internationalizationin mind, and we faced the daunting task of designing aninternationalization solution for our application that could be implementedin a realistic time frame by our fairly small PowerBuilder developmentteam (six programmers). Also, it had to be easy to maintain and integratewell with the tools used by our translation team, who were also responsiblefor non-PowerBuilder applications (we have large Visual Basic and VisualC++ development teams for some of our other products).The internationalization solution recommended by Sybase is to use thePowerBuilder Translation Toolkit (included since version 6.5, if I remembercorrectly), but after initial investigation we decided we needed to build ourown custom solution. In a future article I’ll focus on our internationalizationsolution; in this article I focus solely on the use of resource DLLs in PB.14 PBDJ volume9 issue4www.SYS-CON.COM/pbdj/


Using Resource DLLs in PowerBuilderNot knowing much about Visual Basic orVisual C++, I investigated their internationalizationtools and it became apparent that theywere all based on the usage of regular Windowsresource DLLs (which, incidentally, is whatDelphi uses). A Windows resource DLL cancontain many different types of resourcesincluding graphics, video files, and text. Letyour imagination run wild as to how you canuse resource DLLs in your applications. In ourcase we were interested only in simple DLLsthat stored string phrases identified by numericresource IDs. In Windows it can be anunsigned integer, so you have up to 65,535possible unique resource IDs within one DLL,which was more than enough for our needs.As an added benefit, fetching stringresources from a resource DLL is extremelyfast. In my initial tests I was able to fetch over100 resources from a DLL in less than 200ms.These tests made it clear that this method waspreferred over any other we had considered(e.g., storing the phrases in the database or in atext file).To efficiently use a resource DLL the followingsteps must be completed:• The DLL has to be loaded into memory atstartup time.• String resources are fetched from it multipletimes during the user’s session.• The DLL is unloaded from memory whenthe user shuts down the application.Unfortunately, since PowerBuilder doesn’tprovide any built-in functions for loading DLLsinto memory or reading string resources fromthem, we’ll have to use Windows APIs toaccomplish this task. I would like to thank allthe fine folks in the PowerBuilder newsgroups(Roy Kiesler and the rest of Team Sybase in particular)for helping me with this.In essence, to load a DLL into memory youneed the following Windows API declaration(defined in PowerBuilder as an external localfunction):Function Ulong LoadLibraryA (stringlpLibFileName) Library "kernel32.dll"This returns a variable of type unsignedlong,which is your handle to the loaded DLL.To read a string from the loaded DLL you’llneed the following API:Function IntLoadStringA(Ulong hInstance, Uint UiD, refstring lpBuffer, int nBufferMax) Library"user32.dll"The first variable is your unsignedlong handleto the DLL as returned by the initialLoadLibraryA. The next variable is yourresource ID, the numeric identifier of the stringphrase you’re trying to retrieve, then a stringvariable (passed by reference) that will hold theretrieved text.The last variable is the maximum size of thestring you’re expecting. We initially set thisvalue to 255, but have run into some longerFrench phrases along the way and have nowchanged that to 512 characters.To unload the DLL from memory you mustuse:Function Boolean FreeLibrary (UlonghLibModule) Library "Kernel32.dll"once again passing it the unsignedlong handleto your initially loaded DLL.Listing 1 provides this entire process in PBcode. It illustrates all the steps needed to load,fetch a resource, and unload a DLL from memory.Obviously, this is not how we would beusing it in production, where the DLL is loadedonce at startup, used repeatedly to fetchresources from during the user’s session, andthen unloaded from memory at the end whenthe application is shut down.However, this listing clearly shows there’s nomagic in integrating resource DLLs intoPowerBuilder; it’s actually quite simple onceyou know which Windows APIs to use.More important, there’s no French-specific(or any language-specific) logic anywhere inthis code. All you need to do to support a differentlanguage is load a different languageDLL at runtime, depending on the user’s preferences.In our application, we currentlydeploy three DLLs: one with phrases in U.S.English, one with UK English, and one withFrench. To support other languages we onlyneed to create new DLLs with the translateddescriptions and give the user the option to usethat language at startup; that’s it. As you cansee, it’s much simpler than the PowerBuilderTranslation Toolkit approach of requiring differentcompilations of the EXE for each of thesupported languages.As an added benefit, the compiled resourceDLLs are extremely small. We have over 6,000phrases in our application (window titles, buttons,combo boxes, group boxes, messages,help, etc.); the English DLL is around 350KBand the French one is around 400KB. Thereforethe impact on memory usage is negligible.Creating Resource DLLsNow that we know how to use resource DLLsin PowerBuilder, we’re faced with the muchtougher issue of how to create them. Most ofthe other Windows development tools (VisualBasic, Visual C++, Delphi) come with their ownresource editors and compilers that allow themto create resource DLLs natively within theirIDEs. PowerBuilder comes with neither ofthese, so we had to look at third-party tools.The simplest solution would be to get aVisual Basic or Visual C++ license for each ofthe PowerBuilder developers, so they couldcreate the resource files and compile themfrom within those tools. However, that seemedlike a waste of money and no self-respectingPowerBuilder developer would be caught witha copy of Visual Basic on his or her PC (well, atleast not before VB.Net arrived recently).The first thing we needed to find was a(preferably free) C or C++ compiler that couldturn resource files (which are simple ASCII textfiles) into DLLs. In our production environmentwe settled on using LCC-WIN32, a free,open-source C compiler maintained by JacobNavia from France and available fromwww.cs.virginia.edu/~lcc-win32/.Make sure you not only download the com-www.SYS-CON.COM/pbdj/PBDJ volume9 issue415


FIGURE 1Same window internationalized in two languagespiler installer (lccwin32.exe) with the manual,but also the documentation installer(lccdoc.exe). It’s a command-line compiler thatcomes with a simple yet very capable IDE (andeven includes a GUI builder).At the very beginning we ran into someissues with the LCC-WIN32 resource compilerfailing to compile strings larger than 255 characters(quite common for some of our Frenchmessages). What happened next made me abeliever in open source. I contacted JacobNavia about the problem around 5 p.m. EST viae-mail. Despite the time difference (Franceversus Canada), he had a fixed version for methe next morning. My congratulations go out toJacob for providing such superb support for histool.Please refer to the sidebar, Installing andSetting Up LCC-WIN32, for a detailed list of thesteps required to install LCC-WIN32 and set upa project in it that you can use to maintainresource strings and compile them into a DLL.Seeing It All in ActionPlease download the LANGUAGE.PBL fromwww.sys-con.com/pbdj/sourcec.cfm. It containsthe class N_CST_LANGUAGE in which allthe required APIs are already set up for you. Italso includes a small test application thatprompts you to enter any of the two DLLs supplied(English.dll and Polish.dll, for example)and displays an internationalized window inwhatever language the selected DLL was compiledin (see Figure 1).Note that the test window doesn’t containFIGURE 2LCC-WIN32 resource editor outputoptionsany hard-coded internationalization logic;instead it’s encapsulated in the ancestor visualobjects (command button, label, multilineedit, etc.). They automatically translate themselvesupon creation using a resource IDembedded in their text label. This simpleapproach allows you to visually enter resourceIDs in the PowerBuilder GUI builder instead ofcoding them by hand, making the wholeprocess faster and more productive.INSTALLING AND SETTING UP LCC-WIN321. Install LCC-WIN32 using the installer EXE. I recommend installing intothe default directory (usually “C:\lcc”) to avoid installing into a directorywith spaces embedded in its name.2 After installing, start up the lcc-win IDE (Wedit) using the shortcut inStart—>Programs—>lcc-win32.3. After Wedit starts up, create a new project using File—>New—> Project….4. Choose a project name.5. Define the project properties (namely, the source directory in whichyou want your files to be compiled). Be sure to select the “Type ofProject” as “Dynamic Link Library (dll)”.6. When prompted whether to create an application skeleton, select“Yes.”7. Wedit displays a summary of the options for your project. Please notethe “Resource file” field at the bottom. It’s the actual resource file we’llbe maintaining and then compiling into a DLL.8. You’re then prompted for the default compiler settings; select “OK” toaccept them.9. Select “OK” to accept the default linker settings.10. Select “Finish” to accept the default debugger settings and completethe wizard. This will create the stub C code necessary to compile aDLL. No other C coding on our part is required; Wedit makes theentire process very simple.11. Create a resource file within the project using the Design—>Open/New… menu option and then type in the required name of theresource file (it can be anything you want, but I keep it the same as theproject name). This opens the Wedit resource editor, which can be usedto create all types of resources, not just strings. This editor is gearedmore toward creating dialogs, menus, etc., but you’ll only be using it tomaintain the string table of all phrases you want to internationalize. Toaccomplish that, change a few of the default resource settings.12. Invoke the Design—>Output menu option, which pops up the outputoptions dialog. Make sure the “RC ASCII resource file (.rc)” option isset up and flagged as “Generate,” as in Figure 2. Select “Validate” tosave the settings.13.Our next step is the actual creation of a string resource. To accomplishthis we need to go to Design—>New—>strings. This opens the StringTable editor where we can finally start entering string phrases with theresource IDs that identify them.14. To start adding strings, select the “Add” action on the right-hand sideof the window, which prompts you for the resource string to enter aswell as its ID (see Figure 3).The “Value” field is the resource ID; the “Content” field is the actualstring phrase. Selecting “OK” saves the value to the resource file.Using this resource editor we can add all the string phrases requiredby our application.15. After you’re finished, select “Save” to save your changes to the file.Obviously, you can reopen the same resource file later from withinWedit and add any new phrases that you might need later.16. To let LCC-WIN32 know that this resource file needs to be compiledwith the DLL, you need to add it to the project. This is a one-timeaction that you need to perform only after creating the file for the firsttime. It can be accomplished via the Project—>Add/Delete Files…menu option, which in turns brings up the dialog box shown in Figure4, where you can add the newly created *.RC file to the project.Simply select the “Add” button and select your *.RC file. Select the“Validate” button when you’re finished.17. At this point we already have a base C project and a base resource filein which we can keep adding new strings. To compile both of theminto a DLL we simply need to invoke the Compiler—>Compile “project_name.c”option. This compiles the DLL and makes it ready for youto use in your PowerBuilder application. The compiled DLL is locatedin the “\lcc” subdirectory of your project’s base directory.16PBDJ volume9 issue4www.SYS-CON.COM/pbdj/


Building an Internationalization Framework Basedon Resource DLLsIn my next article I’ll discuss creating an internationalization frameworkbased on resource DLLs that takes care of translating all window controlsand DataWindow objects, as well as resizing them dynamically at runtime toproperly display internationalized text regardless of its length (which variesfrom language to language). It will also cover the differences between resizingregular window controlsand DataWindow elements,which require a totally differentapproach due to theFIGURE 3FIGURE 4Resource string editorProject setupWindows APIs that areinvolved. I’ll also cover thecoding and layout issuesinvolved in developing internationalizedapplications aswell as a few obscurePowerBuilder issues you needto be aware of in order todeliver a professional, polishedproduct. Currently, weare successfully using such aframework in production,supporting three differentlanguages with more to come.SummaryTo recap, you’ve now seen how to use resource DLLs in PowerBuilder codeand how to create them using the LCC-WIN32 Wedit IDE. In other words, youhave everything you need to start fully integrating resource DLLs into yourapplication and using them as a primary means of internationalization. Again,that’s just one use for resource DLLs. Now that you know how to create and usethem, you have another powerful tool to add to your application developmenttoolkit.Stay tuned and happy internationalization! ▼AUTHOR BIOJacek Furmankiewicz is a PowerBuilder R&D supervisor at the Montreal office of STS Systems, an NSB company.His team is responsible for developing applications for some of the largest retailers in North Americaand Europe. Jacek has been using PowerBuilder since version 4.0 in Sybase, Oracle, and Microsoft SQL Serverenvironments.jfurmankiewicz@stssystems.comListing 1stringls_textunsignedlonglul_dll_handle//fill the string variable with spaces – ALWAYS neededwhen working with Windows APIsls_text = Space(512)//load the DLL into memorylul_dll_handle = This.LoadLibraryA("C:\program files\myapp\french.dll")//make sure the DLL loaded properlyIF lul_dll_handle > 0 THEN//fetch a resource string from it, e.g. string # 1045This.LoadStringA(lul_dll_handle,1045,ls_text,512)//unload the DLL from memoryThis.FreeLibrary(lul_dll_handle)END IF//display the text for resource IDsMessagebox("TEST",ls_text)Download the Code!The code listing for this article can also be located atwww.sys-con.com/ pbdj/www.SYS-CON.COM/pbdj/PBDJ volume9 issue417


D I S T R I B U T E D A P P L I C A T I O N SEAServer Component Development ProcessPART 3A tutorialWRITTEN BYTIMOTHY BECKIn Part I of this series (PBDJ,Vol. 9, issue 2), I provided the necessary backgroundinformation for building EAServer components. I also introducedthe development workflow – a set of steps for building an applicationusing EAServer components. Using the workflow, you can create a Webbasedor a client/server application.Part 2 (PBDJ, Vol. 9, issue 3) focusedon developing EAServer components.Using the workflow from Part I as aguide, I showed you how to build objectsthat would become components, fromcreating a directory structure that supportsyour development to writing thecode. Finally, there was a developmentchecklist to ensure the objects werecomplete.Part 3 completes the componentdevelopment process. Here you’ll takethe final step in developing an EAServercomponent: deploying the component.Once again, pull out the developmentworkflow and keep it handy.Deploying Components to EAServerWhen a completed object is deployedit becomes a component. When developinga window or a Web page, severalcomponents may be involved, either bybeing called directly or through intercomponentcalls. Once the object isready to be deployed, start by deployingthe component to EAServer on the localmachine.In PowerBuilder, deployment occursusing a project. This project containsseveral important pieces of informationthat EAServer uses to manage the componentand handle its interaction withother components. It’s important tounderstand each property and itspotential impact on a component.PACKAGE NAMEA package is a collection of similarcomponents. Since EAServer is casesensitiveand you access components bypackage name, it’s important that thisname is spelled correctly and in theproper case.COMPONENT NAMEThis is the visible name of your component.In PowerBuilder, your objectname may be “n_cst_vendor”, but to therest of the world this component shouldbe called “Vendor”. Again, you’ll accesscomponents by name so it’s importantthat they’re spelled correctly and in theproper case.COMPONENT TYPE (STANDARD, SHARED, SERVICE)The overwhelming majority of yourcomponents will be standard, that is,they have no special attributes. The restwill be shared or service components.• Standard components are the workerbees of EAServer. They can be writtenin any language, they may supporttransaction management, and multipleinstances may be in memory at anygiven time. They can be pooled, i.e., aninstance, once created, is kept in memoryso other clients can reuse it.• Shared components are those sharedby all clients. There’s never more thana single instance of a shared component.It’s not thread-safe, so multipleinstances can’t run concurrently.Shared components are used forcaching relatively static data or makinginformation available that allclients can use.• Service components perform backgroundprocessing. EAServer runsthem when the server first starts up.They may run “forever,” or performsome task and stop. Service componentsare standard components with aspecial purpose. They’re referenced inthe EAServer server property“com.sybase.jaguar.server.services”, soEAServer knows to run them at startup.They contain three extra methods(subroutines – functions with noreturn value) that EAServer calls:–Start: Initializes the service component.Typically, you’ll set a Booleaninstance variable to “true” here.–Run: Does the actual work. Typically,this function is in a perpetual loopwhile the instance variable set inStart is true. You can use the“JagSleep” external function to putyour service component to sleep fora short time before processingagain.–Stop: Stops the component fromrunning. This method typically setsthe Boolean instance variable tofalse, causing the Run method tocomplete execution.TRANSACTION SUPPORT (NOT SUPPORTED, SUPPORTS,REQUIRES, REQUIRES NEW)Transaction support, along with stateprimitives, controls how EAServer handlesdatabase transactions. For transactionsupport to work, there are tworequirements:1. You must use a connection cache.2. You must set the “UseContextObject”dbparm value to true (UseContextObject=’Yes’).For several components to participatein a transaction, you must use a “transactioncoordinator” – a component that,through intercomponent calls (Create-Instance), calls the other componentsinvolved in a transaction. In addition,you must set the Transaction Supportproperty to one of the following:• Not Supported: The component won’tparticipate in a transaction. It’ll commitor roll back its changes independentof any other component.• Supports: Participates in the callers’transaction only if a transaction isrunning. If not, this component willact as if transaction support is set to“not supported.”• Requires: Creates a new transaction ifone isn’t already running. If there isone, it will participate in the callers’transaction.• Requires New: Always creates a newtransaction regardless of any currenttransactions. In effect, it allows you tonest transactions.20 PBDJ volume9 issue4www.SYS-CON.COM/pbdj/


CONCURRENCYThis property indicates that the componentis thread-safe, meaning multipleinstances can run in memory simultaneously.Shared components are notthread-safe, neither are PowerBuildercomponents with instance DataStores (aDataStore has embedded operating systemfunctionality that prevents it frombeing thread-safe and surviving whenmultiple instances are running at onetime). Setting this attribute to trueimproves performance for those componentsthat are thread-safe.AUTOMATIC DEMARCATION/DEACTIVATION (CHECKEDFOR STATELESS COMPONENTS)Stateless components automaticallydeactivate after every method call. If possible,all components should be statelesssince it increases reusability and decreasesthe load on server resources. Anotherconsideration here is that stateful componentsare bound to the client until they’redeactivated, creating a potential memoryleak.SUPPORT INSTANCE POOLINGInstance pooling allows componentsto be reused without being reinstantiated,thus improving performance. From adeveloper’s perspective, instance-pooledcomponents must be initialized in theactivate event and code cleaned up inthe deactivate event.COMPONENT TIMEOUTSet this property for stateful componentsto the number of secondsbetween method calls. Setting this propertyprevents a component from beingleft orphaned in memory.During the deploy process, severalerrors can occur. Generally, these are theresult of some setting in the deploy projectitself. For example, errors about therepository not being available can occurbecause you don’t have access to themachine or, more likely, because theserver name or port number are typedincorrectly. In addition, to redeploy servicecomponents, you may need toremove the component name fromthe list of services on EAServer(com.sybase.jaguar.server.services) andshut down and restart EAServer. If thereis a permissions error, check theusername and password provided forEAServer. Also, make sure it’s actuallyrunning on the server.Testing components locally is animportant part of the overall process. Itensures that a component performs asexpected when there are no other possibleavenues of interference. Test thecomponent in the environment youexpect to deploy to production. To isolatespecific functionality, you mightcreate a window or Web page to testwith, but once the testing is complete,remember to test the component in thedesired natural environment. It’s sometimeshelpful to test components beforedeploying them to EAServer by callingthe desired method from the open eventof the application object:n_cst_objectlnv_objectlnv_object = create n_cst_objectlnv_object.event activate()lnv_object.mymethod()Once the desired outcome has beenattained, create test scripts so theexpected results are clearly documented.In this process, make sure each stepis clearly laid out and nothing is left tochance.Once you’re satisfied that the componentswork as designed, deploy them tothe test box. Here the components mustnow commingle with other, perhapsunrelated, components.Any Web pages that call the componentsshould also be deployed at thistime. (Windows clients don’t need to bedeployed since they’ll ultimately resideon the client machine.) Any relatedpieces must be documented anddeployed at this time.Using the test scripts developed earlier,test the module again. Each pageshould be thoroughly covered and everyresult clearly documented. If the modulefails any test, the failure should beisolated, resolved, and the entire moduleretested first locally, then on the testbox.At this point, the module should beready for the unexpected: user acceptancetesting. Users can find ways ofbreaking an application that a developernever considered. Given this, it’s importantthat the users have as much time ashumanly possible.In addition, it’s important to continuetesting the application once it’sactually deployed to staging. Onceeveryone is satisfied that everythingworks as intended and desired, it’spassed all the tests, it looks good, andeverything is consistent and well documented,the module can be deployed toproduction. The whole cycle can thenstart over with changes, upgrades, ornew modules.ConclusionWhen building n-tier applications,carefully consider the application flow.Decide what business logic anddata-access logic will be deployed tothe application server and which languagesthese components will be writtenin. Examine each of these applicationpieces for reusability. Eachreusable piece of the application, aswell as business rules and data accesslogic, will become an object to bedeployed to EAServer. Make sure theseobjects are broken out into the smallestpossible pieces to ensure maximumreusability.Follow the development workflowprocess to ensure that the applicationdevelopment is complete and the entireapplication is completely documented.Make sure the users are involved in theprocess from the beginning. Storyboardthe application so the flow is clear andthe developers and the users understandthe process. Create functionalspecs and the user interface, then createthe objects that will be EAServer components.Follow this six-step process to createEAServer components:1. Define the EAServer component in aserver library.2. Deploy the component to EAServer.3. Generate a proxy in the client application.4. Connect the client to EAServer.5. Initialize the proxy.6. Invoke the desired methods.When creating a component, start byinheriting from n_cst_jaguar in the server.pbllibrary. Use the component developmentchecklist to ensure nothing isleft out when developing a component.Before deploying the component toEAServer, verify the project properties toensure they are correct. Finally, test, test,and test again. ▼tpbeck@intelliserve.comAUTHOR BIOTimothy P. Beck ismanaging partner andfounder of IntelliServe LLC,a Sybase ConsultingPartner, an iAnywhereSystems Integrator, and aSybase Education Agent.He has been working withPowerBuilder since 1991,and has been a certifiedinstructor of PowerSoft(later, Sybase) technologyfor more than eight years.www.SYS-CON.COM/pbdj/PBDJ volume9 issue421


application from bringing down theentire system.A typical program will have a singleexecution path along the primarythread. It’s in the primary thread that themain portion of the program is executed.However, a process can have severalthreads executing within it and, therefore,have several executionpaths. Anapplication thathas more than onethread is calleda multithreadedapplication.EAServer is such an application. Eachtime a component is instantiated, a newthread is “spawned” or created to runthat component. This not only allowsmultiple components to be running inmemory simultaneously, but it alsoensures that EAServer won’t crashbecause of a bad component. When you“bind” the thread of a component to itsclient, you ensure that one instance ofthe component has a single executionpath that’s tied to the client. Multipleinstances can be invoked, each with itsown thread.With components that use threadlocalstorage, Bind Thread must be set.What Is Thread-Local Storage?Remember that athread has its ownexecution path,address space, andprogramming stack.In other words, a threadcan house its own data.When processes depend onthe data contained in thethread, they’re said to usethread-local storage. A componentwill also use threadlocalstorage if it utilizesresources that employ it.DataStores use internalWindows resources that usethread-local storage, requiringthe component that utilizesthem to use it too. This istrue only if the DataStore isan instance variable that’s notdestroyed between method calls.Microsoft COM (Component ObjectModel) components (such as ActiveXcomponents) also require thread-localstorage. Note that thread-local storageis specific to Microsoft Windowsmachines. Any component that uses itmust have the Bind Thread propertyset.How do you know if your componentuses thread-local storage? Does it useWindows resources and maintain thoseresources between method calls (as aninstance DataStore does)? Is it a COMcomponent that’s tied to Windows? Areyou accessing and maintainingWindows data (such as a Windows handle)?If you answered “yes” to any ofthese questions, then your componentuses thread-local storage and requiresBind Thread to be set to true.WHAT OTHER PROPERTIES ARE RELATED AND HOW?As mentioned earlier, when Poolingand Bind Thread are both set, the threadis pooled with the component. The factthat Bind Thread is set doesn’t affectperformance any more than BindThread alone does.Bind Thread combined with concurrencyallows multiple instances of abound component to be created.Because the threads are bound to theirclients, combining concurrency withBind Thread reduces resources on theserver. It’s possible for very large applicationsto instantiate so many threadsthat all resources are consumed, causingEAServer to crash. Future enhancementsof EAServer will prevent crashesunder these circumstances by freeingmemory and/or forcing waits.


Concurrency determines if clients can simultaneouslyinvoke methods on the same instance. EAServerallows the methods of a single instance to be run inseparate threads and thus be accessed by more thanone client at a time. To configure this option, you alsoneed to set the sharing option. Table 1 shows the relationshipbetween the sharing and concurrencyoptions.CONCURRENCY SHARING DESCRIPTIONOff Off EAServer will create multiple instances ofa component class for multiple clients.However, only one instance of a componentclass may be active at any point. EAServerwill block the creation of additionalcomponents if one of the instances ispresently active.On Off EAServer will create multiple instancesof a component class and execute theirmethods in parallel if the clients areattempting to invoke methods at thesame time.On On EAServer will create a single instance of acomponent class and execute the methodsagainst it. Because concurrency is on,EAServer will attempt to create multiplethreads for each method to executeagainst. 1Off On EAServer will create a single instanceagainst which all clients will execute. Onlyone client at a time may be activelyexecuting a method. All other requests arequeued and executed serially.1PowerBuilder components do not support this option because they’re notthread-safe, meaning they do not support multiple, simultaneous methodinvocations against a single client.TABLE 1Sharing and concurrency optionsAlthough there are several other component properties,none of them deal with threads, even thoughyou could attempt to make a case for stateless componentsand threads. The issues surrounding statelesscomponents and threads are the same ones I’vealready discussed in relation to Bind Thread.AUTHOR BIOTimothy P. Beck ismanaging partner andfounder of IntelliServe LLC,a Sybase ConsultingPartner, an iAnywhereSystems Integrator, and aSybase Education Agent.He has been working withPowerBuilder since 1991,and has been a certifiedinstructor of PowerSoft(later, Sybase) technologyfor more than eight years.ConclusionFor PowerBuilder components, use localDataStores instead of instance DataStores andavoid holding Windows resources betweenmethod calls. These two items alone mean youdon’t need to set the Bind Thread property, givingyour application a performance boost. For anotherperformance boost, set concurrency on butleave sharing off. In fact, for PowerBuilder components,never set both concurrency and sharing toon. If you do, EAServer will turn sharing or concurrencyoff automatically. It will also turn concurrencyoff if your component uses thread-localstorage. To determine if EAServer has done this,check the server log.Understanding threads will help you build bettercomponents. Knowing the properties that relate tothreads can help you create components that behaveand perform well. ▼24PBDJ volume9 issue4www.SYS-CON.COM/pbdj/


F R O M S Y B A S EWRITTEN BYSCOTT MCREYNOLDSSybase EAServer 4.1 –Web Services Enabled, J2EE 1.3 CertifiedAUTHOR BIOScott McReynolds worksin Sybase engineering onEAServer and is amember of the “SWAT”team. He has worked atSybase for six years andis a CPD, CPI. He’s usedPowerBuilder sinceversion 3.0.When Sybase released EAServer 4.0,it provided most of the J2EE functionalityfor the 1.3 specification, as well asperformance and usability enhancements.EAServer 4.1 is not only J2EE1.3–certified, but it also includes therequired technology for the next wave ofe-business – Web services.J2EE 1.3 CompatibilityThere’s a lot of talk about J2EE compatibility,but most folks have no ideawhat that means or what it takes. TheJava arm of Sun created a series of testscalled the Technology Core PlatformCompatibility Kit (TCK). The TCK consistsof a large number of tests (15,000+).These tests are developed to ensure thateach area of the specification is implementedin a compliant way.Why should you as a developer care?The biggest reason is that you can besure that if you write a J2EE application,you can easily move it from one vendor’sserver to another, provided the vendorhas passed the TCK. Remember thedatabase wars? It was very difficult tomove from one vendor to anotherbecause each one created their own setof functions and processes, even thoughthey said they supported the currentSQL standard. Since there was no test,Oracle and Sybase may each support thestandard, yet still have proprietary functions.Since the TCK has been in existence,Sybase has been among the firstvendors to pass and ship a compliantversion of its application server.Web Services EnabledWeb services has beendescribed as the glue thatbinds many different platformstogether with acommon interface. Thatis, a .NET object can talkto an EJB object withoutany problems. This is becauseWeb services provides a commoninterface and can be implementedusing any language. The data issent between the requestorand the receiver usingXML.Not to get into toomuch detail about Webservices, but here are somebasics. Simple Object AccessProtocol (SOAP) is used for exchangingdata between the client and the service.Web Services Description Language(WSDL) describes what services are availableand the method definitions withinthose services. WSDL supports ebXMLregistry features, which are similar toUDDIs. Universal Description, Discovery,and Integration has been organized as atype of directory lookup or yellow pagesfor Web services and is accessed via WSDL.Now you’re wondering, where doesEAServer 4.1 fit into this architecture?With 4.1 we support Web servicesnatively within the application server.The Web Services Toolkit generates aWSDL document and a client proxy. TheWSDL document describes the EAServercomponent you want to make availableas a Web service, as well as its location.Using the GUI, you can also publish thelocation of a WSDL document to a UDDIregistry on the Web.The Web Services Toolkit allows youto select a UDDI registry site and log in.After you log in, you can add businessand service data to it. Once you’ve publishedinformation to the registry, eachtime you log in the information isretrieved and available for you to review,modify, or delete.A business partner can use the clientproxy generated by the Web ServicesToolkit’s SOAP Management feature toinvoke a Web service without knowinghow to write SOAP messages. The clientproxy uses the WSDL document thatdescribes your Web service/EAServercomponent. The client application canthen use the Web service.Sybase makes it easy for their customersto create and distribute Web servicesfrom within EAServer.You’re Ready for the FutureWRITTEN BY TIM NESHAMWith the J2EE compatibility and theWeb services integration withinEAServer 4.1, you’re positioned for thefuture. EAServer 4.1 can provide theintegration between PowerBuilder, J2EE,and .NET. No other vendor can makethat statement.In the coming months look for morearticles on secure enterprise Web servicesand other Web services–enabledproducts from Sybase. ▼scott.mcreynolds@sybase.com26 PBDJ volume9 issue4www.SYS-CON.COM/pbdj/


www.SYS-CON.COM/pbdj/PBDJ volume9 issue427


F E A T U R EWRITTEN BY BERNDT HAMBOECK28 PBDJ volume9 issue4www.SYS-CON.COM/pbdj/


WAP stands for WirelessApplication Protocol and isbased on Wireless MarkupLanguage (WML), which isclosely related to Hypertext MarkupLanguage (HTML). WAP enablesyou to quickly and easily deliverinformation and services to mobileusers. It’s independent from anyother mobile or network standardand is compatible with all popularmobile communication networks.WAP is a communications protocol andapplication environment that can be built onany operating system, including PalmOS,EPOC, Windows CE, FLEXOS, OS/9, andJavaOS. It even provides service interoperabilitybetween different device families. The WAPForum defines this protocol and believeseveryone should have access to these specificationsto develop WAP applications.The WAP ForumAn industry association with over 500 members,the WAP Forum has developed this defacto world standard for wireless informationand telephony services on digital mobilephones and other wireless terminals. Their primarygoal is to bring together companies fromall segments of the wireless industry valuechain to ensure product interoperability andgrowth of the wireless market.WAP Forum members represent over 90% ofthe global handset market: carriers, subscribers,leading infrastructure providers, softwaredevelopers, and other organizations thatprovide solutions to the wireless industry (youcan find a list on the WAP Forum Web site).What Can You Do with It?You can build a lot of applications with WAP,but keep in mind that you’re transferring datato mobile phones and that WML is designed forthe constraints of small narrowband devices.These constraints include:• A small display and limited user input facilities.A small mobile device such as a phonehas only a few lines of textual display, witheach line containing 8–12 characters.• Narrowband network connection GSM canonly transfer data at 9,600 bits per second,while GPRS will have a speed of up to115,000 bit per second.• Limited memory and computationalresources (limited power constraints).• The user has to pay for the regular connectiontime between the device and the networkterminal. General Packet Radio Service(GPRS) makes it possible to bill for the transferreddata, so the user can be online withoutany added costs on the phone bill. GPRSis also much faster than the GSM transfer.Possible WAP applications are:• Paying your bills• Checking your bank account and wiringmoney• Reading and sending e-mail• Staying informed about the stock market• Checking weather, traffic, and events calendars• Navigating the Net• Automating your house• Developing customer service• Creating a mobile organizerHow Does It Work?Usually a Web page is a file (document)stored on a Web server that’s sent to a Webbrowser when requested. In WAP, the documentsare called decks and are stored on Webservers. Each deck contains one or more cards,the contents of which are displayed in the WAPbrowser window, although the display windowis scrollable. On the Web the markup languagefor documents is usually HTML; in WAP, it’sWML. WML inherits most of its syntactic constructsfrom XML. The two might look verysimilar, and for this article we’ll pretend theyare, but there are some important differences.Your Web browser will usually talk to a Webserver directly to ask for a certain page. In WAPthere’s another device involved, a WAP gateway.This device sits somewhere on the networkbetween your WAP device and the Webserver and helps the Web server send data tothe WAP device and vice versa.Although the WAP gateway has very little intelligence,it converts the WML code to a smallerformat, to save time, before the code is sent to theWAP browser. This also means that WML documentsmust have correct syntax (see Listing 1).XML is case-sensitive and WML inherits thischaracteristic. No case folding is performedwhen parsing a WML deck. This implies that allWML tags and attributes are case sensitive aswell as any enumerated attribute values.In a WML file the header is important. Thefirst character received by the WAP gatewaymust be the < character that starts the line. Any other character willbreak the card.The tag you see is the “deck.” InWML, a deck is the container for one or morecards. The deck provides necessary informationabout the document type, markup language,and navigational templates for the cardsincorporated in it.In WML, a card is the page that’s displayed tothe user and it must be contained in a WMLdeck.Notice the and tags. The tagsare typically used to begin a new paragraphand most WML tags must be closed, in this casewith a . Between the paragraph we wanttwo input fields displayed to the user, one forthe user’s name and one for the password.The do element provides a general mechanismfor the user to act upon the current card.In our case we want to verify the entered datathrough the Struts framework.FIGURE 1FIGURE 2WML browserLogging inwww.SYS-CON.COM/pbdj/PBDJ volume9 issue429


FIGURE 3J2EE TaglibsWe now know how to write a WAP applicationby hand, but there are several other waysto do this. I’ll present two other options: usingStruts in Sybase EAServer and using iAnywhereWireless Server.Using Struts for WAPStruts offers some simple tags to do verycomplex cards and decks. See Listing 2 for theStruts code in our example. It tells EAServer thatthe context for this page is text/vnd.wap.wmland that EAServer shouldn’t send text/HTMLback to the client. It’s important that the WAPclient gets what it expects – WML.and laptop clients.iAnywhere Wireless Server includes threeserver components:1. Synchronization Server: Smart client applicationclients can synchronize with enterpriseDataStores in a transaction-based model.2. Application Server: A J2EE-based applicationserver provides content delivery services,application management services suchas user authentication and session management,and enterprise data access. It’s the centralhub for the execution of business logic.3. Message Server: J2EE-based messaging providesinterapplication message delivery aswell as server-initiated synchronization formobile clients.The Success Page (success.jsp)Logon succeededThe Failure Page (failure.jsp)To keep it simple, in our example, EAServeruses additional components. You can easilyintegrate iAWS into the Sybase EnterprisePortal for a single sign-on. Our logon examplewould be coded using iAWS (see Listing 3).The example would be compiled anddeployed into EAServer as a servlet. In fact, italready comes with iAWS. The interesting thingis that iAWS notes the sorts of clients you have.This means you’ll get a valid output if your clientis a browser and also if it’s a mobile device. ThisLogon failedFIGURE 4JSP pages and WAR targetNow copy Listing 1 and paste it into yourfavorite text editor. Save the file and call itlogin.wml. Notice the .wml file extension; this isthe common file extension for WML files. Nowwe’ll look at this file in a WAP browser. Pick a software-basedbrowser (the UP.SDK is highly recommended).M3Gate can also open and displayWML decks that are stored on your local computer,which means you can test them without placingthem on a Web server (see Figures 1 and 2).The WAP components in the chain betweenyou and the Web server and the WAP gatewayand the WML browser are, as previously mentioned,very strict when it comes to syntaxerrors. If there are any problems, strip the codedown to the bare minimum. This is especiallytrue for the first two lines of code that are the“XML” and “DTD” definitions; if you type thecode in manually there’s lots of room for error.If you’re testing the code with a WML softwarebrowser such as an M3Gate or UP.Simulatorthat doesn’t involve the WAP gateway(you can configure a UP.Simulator to do so), itmight work even with some errors, but it won’twork on a real WAP device. The WAP gateway isa lot stricter than the emulators.Using PowerJWe have to set up PowerJ the same way we didin my last article (PBDJ, Vol. 9 issue 3) so we canuse the same (simple) business logic and not haveto change anything in the Action class or the bean.The Jaguar package that you deploy toshould be called struts-wap. We need two taglibraries: struts-wml and struts-logic (seeFigure 3). Your workspace should look like this(see Figure 4).We have our JSP pages and WAR target. Besure to add the files for the tag libraries (strutslogic.tldand struts-wml.tld) and the WMLclasses (strutswap.jar). After deploying, try itusing a WAP emulator (see Figure 5).iAnywhere Wireless ServeriAnywhere Wireless Server provides a comprehensiveinfrastructure for developing anddeploying always-available enterprise applications.It’s a midtier server that provides accessto enterprise DataStores, and enables thedevelopment of applications for mobile andwireless clients as well as traditional desktopFIGURE 5WAP emulator30 PBDJ volume9 issue4www.SYS-CON.COM/pbdj/


WLDJ ADVERTISER INDEXADVERTISER URL PHONE PAGEAmyuni Technologies, Inc. www.amyuni.com 514-868-9226 35Dynamic Buyer Inc. 800-426-7235 ext.5014 11EnginData Research www.engindata.com 27JDJEdge Conference & Expo 2002 www.sys-con.com 201-802-3069 9JDJStore www.jdjstore.com 888-303-JAVA 25,33Simplex Knowledge Company skc.com 845-620-3700 13Sybase, Inc www.sybase.com/pbworkshop 800-8-<strong>SYBASE</strong> 2Sybase, Inc www.sybase.com 800-8-<strong>SYBASE</strong> 36WebLogic Developer's Journal www.sys-con.com 800-513-7111 27Web ServicesEdge World Tour www.sys-con.com 201-802-3069 22-23Web Services Journal www.wsj2.com 800-513-7111 5Web Services Resource CD www.jdjstore.com 201-802-3012 18-19Wireless Business & Technology www.sys-con.com 800-513-7111 31XML Journal Subscribe www.sys-con.com 800-513-7111 17Advertiser is fully responsible for all financial liability and terms of the contract executedby their agents or agencies who are acting on behalf of the advertiser.www.SYS-CON.COM/pbdj/PBDJ volume9 issue431


FIGURE 6Adapting content to screen sizeListing 1Username:Password:Listing 2The Logn Page (logon.jsp)Username:Password:FIGURE 7is done through device identification. iAWS canidentify the client browser and the device makingthe request and customize the output forthat particular device. This can be implementedat a coarse level by providing WML, HDML, orHTML, or at a finer level by adapting the contentto the browser screen size (see Figures 6 and 7).ResourcesCustomized output• The WAP Forum: www.wapforum.org• The Specification: www1.wapforum.org/tech/terms.asp?doc=SPEC-WML-19991104.pdf• Installing Apache SOAP: http://my.sybase.com/detail?id=1013352• iAWS Documentation: http://sybooks.sybase.com/iaw.html ▼AUTHOR BIOBerndt Hamboeck is a senior consultant for Sybase Austria. He’s aCSI, SCAPC8, EASAC, and SCJP2 and started his Sybase developmentusing PB5.bhamboec@gmx.atLook at the first line:Listing 3package ianwyhere.samples.login;import ianywhere.framework.*;public class Login extends Application{}protected boolean create()throws Exception{return true;}private void unhandledEvent(String s, String s1, Object obj){}public Login(){addFilter(new FormLoginFilter(new iAWSUserDatabase()));}public ResponseGenerator index(){return _generator;}private static ResponseGenerator _generator =new StaticTextGenerator("Login successful");Download the Code!The code listing for this article can also be located atwww.sys-con.com/ pbdj/32PBDJ volume9 issue4www.SYS-CON.COM/pbdj/


PowerBuilder NewsAll things of interest to the PB communityBY BRUCE ARMSTRONGPRODUCT NEWSEricsson P800Smartphone3/6 – iAnywhere Solutions, asubsidiary of Sybase, announcedthat it will be first to enabledelivery of “always available”applications for the newSymbian-based Sony EricssonP800 Smartphone.Web Services Strategy2/20 – Sybase announced itsstrategy for delivering real integrationbusiness solutions forenterprises. The company planssupport for Web services inexisting infrastructure software,and to introduce new productsthat allow companies to bridgethe gap between different levelsof adoption of Web services. Anexample of the new initiativewas the introduction of a WebServices Toolkit with version 4.1of EAServer (www.sybase.com/products/applicationservers/easerver/webservices). A developer’sversion is available for a freedownload at www.sybase.com/easerver4dev.CORPORATE NEWSWebStar Service Award3/12 – The Service & SupportProfessionals Association (SSPA)announced that Sybase wasawarded the prestigious WebStarService Award for the secondyear ina row attheannual SSPA San Diego Summit.The annual WebStar ServiceAwards recognizes SSPA MemberSupport Centers that providesuperior customer service totheir online customers.www.supportgate.com/certifications/webstar.htmlTHIRD-PARTYPRODUCT NEWSPBR Manager3/7 – PowerBuilder Developer’sStation announced the release ofPBR Manager version 8, whichadds support for PowerBuilder8’s target files. It’s a tool to createPBR (PowerBuilder Resource)files. www.schtoo.com/pbstation/tool.php?ID=pbrmanVisual Expert3/5 – Novalys announced theavailability of Visual Expert forPB8. Visual Expert is very usefulto generate source code documentation,to do impact analysis,to work on an unfamiliarapplication, and to clean up thecode, making it lighter and morereadable. www.novalys.netPBDelta3/3 – PowerBuilder Developer’sResource announced the releaseof PBDelta version 3.3. Itincludes a number of improvementssuch as support for thePowerBuilder 8.x platform.PBBrowse2/17 – PowerBuilder Developer'sResource announced the releaseof PBBrowse version 3.0. Thenew version is a rewrite of theold application using the new V3class library and includes all thefeatures and enhancements thatcouldn’t be implemented in theprevious version due to restrictionsin the V2 code base.PBBrowse V3 supports Power-Builder 8.x. www.pbdr.comPB Code Analyzer2/16 – Ascension Labsannounced the release of PBCode Analyzer version 3.6. Thetool analyzes code and producesmetric reports and cross-referenceinformation, and includesan object browser, an objectexporter, an object searcher, anda PBDebug file viewer.www.ascensionlabs.com/pbcodeanalyzer.htmuNokSoftGroup1/25 – uNokSoftGroupannounced the release of version1.1.8.0 of the unoksoft.dll.The DLL is a base library to supportListViewMenus, FlatCommandButton, StatusBar,3Dbox, Transparent Static Text,Font and ColorDialogs, andmore. uNokSoftGroup also hasXML parsers writing in nativePowerBuilder. www.mycgiserver.com/~unoksoftgroup/PARTNERSHIPSSpectrum EBP3/13 – Spectrum EBP, LLC, abank-centric payment systemscompany for electronic bill presentmentand payment (EBPP),and Financial Fusion, a subsidiaryof Sybase, announced astrategic alliance in whichFinancial Fusion will be certifiedto the Spectrum network. Withthis alliance, Financial Fusioncan distribute bills and collectpayments for its five milliononline customers through theSpectrumnetwork ofconsumer service providers(CSPs) and participant financialinstitutions.www.spectrumebp.comeGuanxi3/6 – Sybase announced a jointsales initiative with eGuanxi,Inc., to provide a comprehensivetechnology package for electronicrecords management. E-businessinfrastructure softwarefrom Sybase and an organizationmodeling platform and e-businessproducts from eGuanxienables customers to define andexecute crossdomainor crossenterpriseserviceand record-intensive businesscases. www.eguanxi.comSharp Electronics2/20 – iAnywhere Solutions, asubsidiary of Sybase, and SharpElectronics Corp. announcedinitiatives to fuel development ofJava-based mobile enterpriseapplications. The companies areunveiling special promotions,pricing, and technical informationto help their developercommunities leverageiAnywhereSolutions’ m-Business platformwith the new Zaurus SL-5500 Personal Mobile Tool tocreate robust, portable, mobilebusiness applications.www.sharp-usa.com/products/TypeLanding/0,1056,116,00.htmlEVENTSEAServer andSybase Tools SeminarApril 22, Bloomington, MNwww.powerobjects.com/seminar/TDWI World Conferences(Data Warehousing)May 12–17, San DiegoAugust 18–23, Las VegasNovember 3–8, Orlando, FLwww.dw-institute.com/confmain.htmTechWave 2002Sybase’s Annual InternationalUser Training and SolutionsConferenceAugust 5–9, San Diegowww.sybase.com/techwave2002 ▼bruce.armstrong@teamsybase.com34 PBDJ volume9 issue4www.SYS-CON.COM/pbdj/


AmyuniTechnologies, Inc.www.amyuni.comwww.SYS-CON.COM/pbdj/ PBDJ volume9 issue4 35


Sybase, Incwww.sybase.com36 PBDJ volume9 issue4www.SYS-CON.COM/pbdj/

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!