PBDJ 11-5Y - SYS
Transcription
PBDJ 11-5Y - SYS
CREATING WEB APPS FOR MOBILE DEVICES pg. 4 U.S. $15.00 (CANADA $16.00) FEBRUARY 2005 - Volume: 12 Issue: 2 www.sys-con.com/pbdj From the Editor Eating Your Own Dog Food The res u l ts o f t h e la t es t p o ll b y N o v a l y s o n P o w e r B u i l d e r u s e a re in. The res ults are g o o d . by Bruce Armstrong pg. 3 Industry Announcements by Bruce Armstrong pg. 34 D a t a Wi n d o w.NET is a nom ine e in pg.22 t h e 2 0 0 5 . N E T D e v e l o p e r ’s J o u r n a l R e a d e r s ’ C h o i c e Aw a r d s i n t h e l i b r a r i e s a n d c o n t r o l s c a t e g o r y. pg.14 ••• Relavis Corporation has selected the iAnywhere P y l o n A p p l i c a t i o n S e r v e r to power its soon-to-be re l e a s e d eSales Mobile application. ••• Mobile Apps: Unwired Accelerator in Action Not just mobility development Berndt Hamboeck 4 S yb a s e re p o r t e d t o t a l l i c en s e revenues i ncre a s e d 7 % f o r the four th quar te r e nd e d December 31, 2004. ••• Sybase announced the availability Techniques: About Surrogate and Natural Keys When are they approriate in a data model? Mike Nicewarner 10 of its re l a t i o n a l d a t a b a s e management system, Sybase Adaptive Ser ver Enterprise for L i n u x o n I B M ’s e S e r v e r OpenPower systems. RETAILERS PLEASE DISPLAY UNTIL APRIL 30, 2005 $15.00US $ 6 . 9 9 U S $ 7 .$16.00CAN 99CAN 02 3 0 09281 01314 3 Feature: Taking PowerBuilder’s PBDOM Out for a Spin Book Excerpt: EAServer Problem Analysis & Troubleshooting Part art, part science PART I Dropdown Filtering: Dynamic Web Page Content… Without refreshing the page Arthur Hefti 14 Jim O’Neil 18 Rahul Jain 28 FROM THE EDITOR EDITORIAL ADVISORY BOARD Eating Your Own Dog Food BRUCE ARMSTRONG, MICHAEL BARLOTTA, ANDY BLUM, KOUROS GORGANI, BAHADIR KARUV, PhD, BERNIE METZGER, JOHN OLSON, SEAN RHODY, IAN THAIN EDITOR-IN-CHIEF: EXECUTIVE EDITOR: ASSISTANT EDITOR: ONLINE EDITOR: CONTRIBUTING EDITOR: NEWS EDITOR: DATAWINDOWS EDITOR: RESEARCH EDITOR: BRUCE ARMSTRONG NANCY VALENTINE SETA PAPAZIAN MARTIN WEZDECKI JOHN OLSON BRUCE ARMSTRONG RICHARD BROOKS BAHADIR KARUV, PhD WRITERS IN THIS ISSUE BRUCE ARMSTRONG, BERNDT HAMBOECK, ARTHUR HEFTI, RAHUL JAIN, MIKE NICEWARNER, JIM O’NEIL SUBSCRIPTIONS FOR SUBSCRIPTIONS AND REQUESTS FOR BULK ORDERS, PLEASE SEND YOUR LETTERS TO SUBSCRIPTION DEPARTMENT SUBSCRIPTION HOTLINE:888 303-5282 COVER PRICE: $15/ISSUE DOMESTIC: $149/YR. (12 ISSUES) CANADA/MEXICO: $169/YR. OVERSEAS: BASIC SUBSCRIPTION PRICE PLUS AIRMAIL POSTAGE (U.S. BANKS OR MONEY ORDERS). BACK ISSUES: $12 U.S., $15 ALL OTHERS PRESIDENT AND CEO: FUAT KIRCAALI VICE PRESIDENT,BUSINESS DEVELOPMENT: GRISHA DAVIDA SENIOR VP,SALES & MARKETING: CARMEN GONZALEZ PRODUCTION CONSULTANT: JIM MORGAN GROUP PUBLISHER: JEREMY GEELAN VICE PRESIDENT,SALES & MARKETING: MILES SILVERMAN CREDITS & ACCOUNTS RECEIVABLE STEVE MICHELIN FINANCIAL ANALYST: JOAN LAROSE ACCOUNTS PAYABLE: BETTY WHITE ADVERTISING DIRECTOR: ROBYN FORMA NATIONAL SALES & MARKETING MANAGER: DENNIS LEAVEY ADVERTISING SALES MANAGER: MEGAN MUSSA ADVERTISING SALES MANAGER: KRISTIN KUHNLE ASSOCIATE SALES MANAGER: KIM HUGHES ASSOCIATE SALES MANAGER: DOROTHY GIL PRESIDENT, EVENTS: GRISHA DAVIDA EVENTS,NATIONAL. SALES MANAGER: JIM HANCHROW ART DIRECTOR: ALEX BOTERO ASSOCIATE ART DIRECTOR: ABRAHAM ADDO ASSOCIATE ART DIRECTOR: LOUIS F. CUFFARI ASSOCIATE ART DIRECTOR: RICHARD SILVERBERG ASSOCIATE ART DIRECTOR: TAMI BEATTY ASSISTANT ART DIRECTOR: ANDREA BODEN INFORMATION SYSTEMS CONSULTANT: ROBERT DIAMOND WEB DESIGNER: STEPHEN KILMURRAY WEB DESIGNER: MATTHEW POLLOTTA CIRCULATION SERVICE COORDINATOR: EDNA EARLE RUSSELL CIRCULATION SERVICE COORDINATOR: LINDA LIPTON CIRCULATION SERVICE COORDINATOR: MONIQUE FLOYD EDITORIAL OFFICES SYS-CON MEDIA 135 CHESTNUT RIDGE ROAD, MONTVALE, NJ 07645 FAX: 201 782-9600 TELEPHONE: 201 802-3000 [email protected] POWERBUILDER DEVELOPER’S JOURNAL (ISSN#1078-1889) is published monthly (12 times a year) for $149 by SYS-CON Publications, Inc.,135 Chestnut Ridge Rd., Montvale, NJ 07645 Periodicals Postage rates are paid at Montvale, NJ 07645 and additional mailing offices. POSTMASTER: Send address changes to: POWERBUILDER DEVELOPER’S JOURNAL, SYS-CON Publications, Inc., 135 Chestnut Ridge Rd., Montvale, NJ 07645 ©COPYRIGHT Copyright © 2005 by SYS-CON Publications, Inc. All rights reserved. No part of this publication may be reproduced or transmitted in any form or by any means, electronic or mechanical, including photocopy or any information storage and retrieval system, without written permission. For promotional reprints, contact reprint coordinator Kristin Kuhnle. SYS-CON Publications, Inc., reserves the right to revise, republish and authorize its readers to use the articles submitted for publication. WORLDWIDE NEWSSTAND DISTRIBUTION Curtis Circulation Company. New Milford, NJ NEWSSTAND DISTRIBUTION CONSULTANT Gregory Associates/W.R.D.S. 732-607-9941 [email protected] FOR LIST RENTAL INFORMATION: Kevin Collopy: 845 731-2684, [email protected] Frank Cipolla: 845 731-3832, [email protected] 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 companies or products covered in PowerBuilder Developer’s Journal. BRUCE ARMSTRONG ou might remember from my TechWave 2004 notes, “eating your own dog food” is my favorite means of describing a company using its own products in its public interface to their customers (e.g., their Web site). If a company expects their customers to put faith in the utility and stability of the product, they should be showing that same confidence in the product themselves. Y I also mentioned in last month’s editorial that the Audiovox SMT5600 I’m now using and the Motorola MPX220 both use the mini-SD card rather than a standardsized SD memory card. If you’re as unfamiliar as I was with the mini-SD card at that time, you may not realize that the mini-SD card comes with an adapter that will allow it to work in a standard SD slot. Pretty slick. PowerBuilder Use Survey Results Well, we have another excellent example of Sybase doing that. Are you familiar with the search engine on Sybase? No, not that search engine! That was the old one that ran slowly and gave you useless results. Sybase recently replaced that with a search engine built on EAServer accessing data stored in Adaptive Server Enterprise (which, incidentally, is the same technology combination I used for the newsgroup search engine on teamsybase.com, but I digress…). The end result is search results that come back quickly and are actually highly relevant. Perhaps Sybase could sell the solution to Microsoft’s MSDN site, which could certainly use it. SmartPhone Review The folks at eWeek just did a review of the Motorola MPX220 that I was so hot for a while back (they also reviewed one Palm and one BlackBerry device). One interesting note from their review was the following: “We’d love to see smartphone hardware and software vendors license SureType from RIM for inclusion in their products – the technology represents one of the best new ideas in mobile device input that we’ve seen in some time.” As I indicated in my last comments on the smartphone platform, the key hurdle is user input. It sounds like BlackBerry has come up with an advance in that area. Most phones use the same letter-to-number key assignments as a house phone, which requires anywhere from two to four key presses to obtain a single correct letter. The BlackBerry keyboard uses a standard QWERTY typewriter layout, with only one or two letters assigned to each key, making it much easier for the predictive software to guess which letter you are trying to type. The results of the latest poll by Novalys on PowerBuilder use are in. The results are good. A lot of people are still using PowerBuilder and intend to continue doing so for some time. An increasing number are using PowerBuilder to do new development work, rather than simply maintaining existing applications. The number of developers on a particular project has increased over previous years. What I found particularly interesting is that the majority of people are using PowerBuilder versions 8 and 9. Only slightly over 1% of the respondents indicated they were using version 10. Perhaps Unicode support was not as important as was first thought. Hopefully, version 11 will offer some more compelling reasons to migrate. Note that half the respondents indicated they will upgrade in the next year, so that may indicate people moving to version 10, just not that quickly. Web Services Changes The W3C and OASIS have a number of new standards for Web services. The one of particular interest to PowerBuilder developers will be XOP (XML-binary Optimized Packaging), a standard means of transmitting binary data via XML. The others – MTOM (Message Transformation Optimization Mechanism) and RRSHB (Resource Representation SOAP Header Block) – are more under-the-cover implementations to improve performance. Unfortunately, the other key headache for Web services developers is security, and those bodies are only starting to develop a common consensus on a new standard in that area. ~continued on page 8~ [email protected] AUTHOR BIO Bruce Armstrong is a senior programmer with Integrated Data Services (www.get-integrated.com). A member of TeamSybase, he has been using PowerBuilder since version 1.0.B. He was a contributing author to SYS-CON’s PowerBuilder 4.0 Secrets of the Masters and the editor of SAMs’ PowerBuilder 9: Advanced Client/Server Development. www.SYS-CON.COM/pbdj/ PBDJ volume12 issue 2 3 MOBILE APPS Unwired Accelerator in Action WRITTEN BY BERNDT HAMBOECK Not just mobility development ybase doesn’t just offer PocketBuilder for mobile development. Last month, we talked about Afaria and Unwired Accelerator, what they’re good for and how they might be used. This month we’ll take a closer look at Unwired Accelerator, install it and build a simple example with it. No coding will be required. S Introduction For those who missed the last issue, I will recap what Sybase Unwired Accelerator is: • First off, it’s a rapid mobilization solution. When Sybase says, “What used to take months, now takes hours,” it happens to be true. • It’s got RAD tools to accelerate mobilizing Web applications, intranets, portals, databases, XML and Web services. • It supports connected access from BlackBerrys, PocketPCs, WAPenabled phones, laptops and tablets. • It supports disconnected access from BlackBerrys and when used with M-Business Anywhere, another Sybase product, disconnected access from PocketPCs, Palm devices and tablets. • It’s a superset of Sybase Enterprise Portal (and contains EP-Information Edition and all the Mobile capabilities). • You’ll get the big picture and what’s possible with Unwired Accelerator in Figure 1. tem32\drivers\etc\hosts file called demo.sybase.com. Start the portal and sample databases by using the startdb.bat file. Pick up the Tomcat server by using starttomcat.bat. Now open your browser and go to the URL: http://demo.sybase.com: 4040/onepage/index.html You should see a login window. Log in with the user name masuper and the password m8super, and click the Login button. What you see are the default entries for the Mobile Web Studio account with administrative privileges. Once we’re logged into the Mobile Web Studio, we can start developing our application. There are several options on the left side (see Figure 2): 1. The Build menu includes: • Applications – create, edit, delete and manage applications and their content. They are dynamic and reusable components (also called portlets) that capture and deliver any information we want to define to our end users for using the portal or a wireless device. The data might be any source like Web content from another web site, XML feeds, database query results, JavaServer Pages or data from a corporate SAP system. • Templates – define the organization of applications with more than one element, where applications are located, background HTML code and so on. You can apply the templates you create to applications. Templates help applications display on specific device types. You can assign a different template for each device type for a given application. • Catalogs – here we create userdefined hierarchies of content to display in an application. When our portal users choose to add a portlet in the Portal Interface, they can browse through the catalog and add portlets of their choosing to their personal pages and page groups. • Pages – here we create, edit, delete and manage the Portal Interface pages on which the applications display. • Page Groups – this is the place to create, edit, delete and manage page groups to group and organize Portal Interface application pages. • Composite Apps – create virtual Web applications using several existing applications. 2. Automate menu objects on the Auto- Installing and Starting AUTHOR BIO Berndt Hamboeck is a senior consultant for BHITCON (www.bhit con.net). He’s a CSI, SCAPC8, EASAC, and SCJP2 and started his Sybase development using PB5. 4 To get an evaluation copy go to eshop.sybase.com and pick Unwired Accelerator 6.5 with Windows 2000 as the platform (feel free to use the Linux version, but my step-by-step description uses the Windows version). The download is about 80MB. The install is pretty simple, just unzip the file and add an entry to your WinNT\sys- PBDJ volume12 issue 2 FIGURE 1 | UA in action www.SYS-CON.COM/pbdj/ ©2003 Sybase, Inc. All rights reserved. All trademarks are the property of their respective owners. 4GL RAD Tools HE SAYS J2EE. SHE SAYS .NET. YOU SAY POWERBUILDER PowerBuilder ® 9.0 gives you the power and flexibility to create applications for the platform of your choice in today’s heterogeneous environments. You’ll find new RAD JavaServer TM Pages, tools for Web Services, third-party application server support and more. Get the power you need to develop and integrate new Web, n-tier and rich-client apps. Technical details are waiting for you now at sybase.com/powerbuilder. INFORMATION LIQUIDITY. SYBASE INTEGRATION TECHNOLOGIES. E V E R Y T H I N G W O R K S B E T T E R W H E N E V E R Y T H I N G W O R K S T O G E T H E R .TM FIGURE 2 | Mobile Web Studio menu mate menu include: • Agents – they allow us to schedule or externally trigger the automatic processing (for example by SMS or email) of a portlet’s content. • Adapters – they’re needed if we want to write a portlet’s content to a file, an e-mail message or a database table. When the agent is triggered, the adapter interface would write the associated portlet’s content to wherever we want (maybe into a database). • Servers – agents have to run on agent servers. During the installation, the default agent server is created by the portal. All agents run on the default agent server unless we assign them to a different agent server – look in tomcat\webapps\onepage\config\global.properties.xml for the property AgentServerID, another interesting file if you want to reconfigure the portal to use your own brands, styles or messages (styles.xml, css.css and messages.xml). 3. The Manage menu includes: • Users/Roles – edit users and manage the resource with which they’re associated. Create, edit and manage the roles, and assign roles to users. • Personalization – create and manage keys that let users personalize applications. • M-Business – deploy applications to M-Business Server groups, channels and users, and perform the M-Business Anywhere administration tasks specifically required by Mobile Web Studio. Building an Application Now it’s time to start to write a simple application that users can see from a mobile device. We’re going to build it from an existing Web application (try http://<your machineneame>:4040/ custview/Search.jsp and enter any username and password combination to log in to the sample app included in Unwired Accelerator). The steps for creating the mobile application using Web Studio include: • Create the application with a Web element using the Application Builder wizard, save it and give it a name, access privileges and additional configuration details. We will also approve it to make it available for the public. • Add the application to a page and add this page to an existing page group so our mobile users can call the page using, say, Pocket Internet Explorer. 6 PBDJ volume12 issue 2 CREATE A WEB ELEMENT USING THE APPLICATION BUILDER Action Result 1. Select Applications in the left pane, select New under Application Manager Status, and click the New button to launch Application Builder. Click Add to create a Web Element. Enter the URL of the included web application and login using any username and password. Now enter one of the three company names as search cryteria: Wells Fargo Oracle Morgan Stanley And click the Find button. Then click next in the upper right corner. Result You see the New Web Element window including the search result of the included Web application. When we move the mouse over the table with the data it changes so that we see that it is the right place to click it. 2. Place the cursor over any site entry in the table, and click the mouse. The screen refreshes showing various presentation styles. Just take the first one by clicking the select button on the left and the next button on the right upper corner and a second time the next button to skip the split config window. Click “Records contain labels.” The “Labels are displayed in Record” option displays. Accept the default 1 for the row. 3. Click Next. The Filter window displays. On the Filter window, define a filter rule that only fields 1–3 are displayed: Under Add Filter Rule, select “Include fields” from the dropdown list. Select “number” from the number/label drop-down list. Enter 1-3 in the value. Click Add. Fields 1, 2, and 3 are highlighted in the Preview section, and the new rule appears under the Current Filter Rules section. Feel free to add a second rule for example to change the label by using “edit record” from the drop-down list and label as field. 4. Click Next. The parameter definition window displays. Again click Next to bypass the window. The Window Preview window displays. In Element Name, enter customerSites as the Web element name and click Next and Finish. This brings us back to the Application builder. Click Save and enter customerSites for the name. www.SYS-CON.COM/pbdj/ Source: 08830081A GET MORE OUT OF ® POWERBUILDER WITH POWERDESIGNER 9.5.2! ® • Integrate PowerBuilder logic in a heterogeneous environment that includes Java,™ J2EE™ and .NET™ to ensure PowerBuilder skills stay relevant in the modern IT infrastructure. • Manage simple and complex designs easily using unique features like Object/Relational mapping, customizable pattern based code generation, VBScript customization, and more… • Easily re-factor code from ANY PowerBuilder object into an n-tier architecture with complete reverse engineering capabilities. • Apply the advantages of UML to PowerBuilder development with comprehensive code generation and round-trip engineering. Download a FREE evaluation copy of PowerDesigner 9.5.2 Today! www.sybase-iad-services.com/30081a 1-877-230-6771 | www.sybase-iad-services.com/30081a After clicking the Finish button we can close the Application builder and we’re back in the Web Studio. Now it’s time to set the status from “New” to Approved on our newly created customerSites Application. This is done with a right-click on the customerSites application in the detail pane. Select Approval Status and Approved. After closing the page builder we’re back in the Web Studio again, where we again set the status from “New” to Approved on the created customersites page. The last and final step is to add the page to the existing DefaultPageGroup. This pagegroup is pre-defined and available to all mobile users when they connect to the mobile portal. Testing the application Unwired Accelerator provides browser access to the mobile device interface. Just point another browser window to http://demo.sybase.com:4040/onepag e/mpindex.jsp. You won’t have an account when you’re running Unwired Accelerator for the first time, but the global.properties.xml property, MB.AutoRegistration, determines how user accounts are handled when Unwired Accelerator and MBusiness Anywhere are integrated. If MB.AutoRegistration is set to true, which is the default, the user automatically joins the M-Business Anywhere server with the user name and password entered. Feel free to pick whatever you want. I’m using mobile/mobile as my user/password combination. After creating the user on the desktop, use your mobile device (I used my PocketPC with ActiveSync) to browse to the mobile portal (using Pocket Internet Explorer with the URL http://<your machinname>:4040/onepage/mpindex.jsp). You should be prompted for your username and password, and after log- ADD THE APPLICATION TO A PAGE Action Result 1. Select Pages in the left pane, select New under Page Manager Status, and click the New button to launch Page Builder. Switch to Full Layout by clicking the layout button. Click the add button and you see the search window popping up. Simply click the search button and choose the customerSites application and click the add button and click the save button and give it the name customersites, add the role everybody so that all people are able to access the page. Result FIGURE 3 | The mobile pages in action ging in, you will see the default page for the mobile users. Now choose the customersite page from the dropdown and, voilà, you’ll see the created page on your device. Conclusion Sybase Unwired Accelerator is an interesting tool if you want to create Web applications for mobile devices. Most of the pages needed can be created by changing a few properties. In this simple example we used only a few of the available options. We didn’t touch the continuous capture feature, which lets you capture a set of Web pages from a remote site and define how to extract the content for display, an impressive feature. Another feature is the built-in transaction support, a must for mobile enterprise applications. Lastly, we didn’t get into M-Business Anywhere, which would let us work with a Web-based mobile application offline. Sybase is impressive when it comes to mobile development. Worth getting a demo. ▼ [email protected] ~continued from page 3~ Eating Your Own Dog Food Blue Marble If you’re into Geographical Information Systems, you might want to take a look at Blue Marble. They just announced a free evaluation version of their toolkit that “will allow developers to embed sophisticated image reprojection and tiling in their applications in a matter of minutes with just a few function calls.” Microsoft MVP Program… Rumors that Microsoft was going to do 8 PBDJ volume12 issue 2 away with their MVP program (essentially the equivalent of TeamSybase) have been put to rest. Actually, their program is just a bit bigger. There are 30 TeamSybase members, and there are something like 2,600 Microsoft MVPs. Part of what was haunting the MVP program is their recent rapid growth: three years ago there were only 600 MVPs. The MVP program was patterned after TeamSybase (actually TeamPowersoft at the time). Microsoft hosted a meeting with a number of TeamPowersoft members shortly before they launched their program. Can’t take too much credit though, TeamSybase was patterned after Borland’s TeamB, which has been around quite a bit longer. One big difference with the MVP program is that the memberships are only good for one year; you have to keep being reselected. TeamSybase (and TeamB) membership is continuous provided you continue to meet program requirements. For a glimpse of the early days of the MVP program, you might check out the following article on one of the first MVP summits: www.noveltheory.com/techpapers/mvp.htm. Resource • My PBDJ blog: http://bruce.pbdjmagazine.com www.SYS-CON.COM/pbdj/ TECHNIQUES About Surrogate and Natural Keys WRITTEN BY MIKE NICEWARNER When are they appropriate in a data model? he purpose of this article is to discuss and describe the terms “Surrogate Key” and “Natural Key,” and explain when they are appropriate to use in a data model. Furthermore, the concepts of “Intelligence” and “Generated” will be applied to both types of keys. T The goal is for the reader to understand the plusses and minuses of all forms of identifying records uniquely in a database system. The reader is also challenged to think critically about the business situation before adopting any given identification methodology. Terms Defined AUTHOR BIO Mike Nicewarner has been doing data modeling since the early 1990s for a number of insurance, manufacturing and finance companies. He has taught and written papers about data modeling tools and techniques. When it comes to modeling tools, he strives to improve the state-ofthe-art for everyone involved. 10 SURROGATE KEY A surrogate key is a column or columns that are not defined by business requirements, but are added to a table simply to identify records uniquely. For example, a business might define a set of related attributes that it wants to keep track of. In that list there may be a number of items that could be considered unique (candidate keys), but none appear to be stable enough to be the primary identifier for the set of attributes. The data analyst might suggest an additional attribute in the form of an Entity Name plus the text “Identifier.” For instance, for an entity called “Survey,” this would be “Survey Identifier.” There is no business purpose or meaning for this new attribute, and therefore the resulting table column would be more resistant to business changes. NATURAL KEY A natural key is a column or columns that a business chooses to uniquely identify records. The data analyst allows them because they are considered stable enough to be the primary identifier. For instance, an existing business process might define a Product Code that uniquely identi- PBDJ volume12 issue 2 fies equipment in a company. By selecting this as the equipment’s primary key, the business accepts the resulting database structures more readily. INTELLIGENT KEY An intelligent key derives its name from the intelligence behind the values assigned to the columns in the key. For instance, a Product Code may be a 10character field (defined as CHAR(10) in the DBMS). This can be mapped as follows: the first two characters are the business unit, the next two indicate the month of manufacture, the next three is a product-type code, the last three is a sequence number. This specific case could also be called a concatenated key since it’s actually a combination of four separate fields in one single field. GENERATED KEY A generated key has no intelligence to the contents, and is typically assigned a value by the computer through some internal mechanism like a sequential or random number generator or some other method. The point is that the business doesn’t care about the value assigned to any given key, just that a unique value is assigned that can be referred to by dependent tables. For example, an Invoice Number might be defined as a 10-digit number, and assigned values sequentially, beginning at some starting point and incrementing by one for each new record added to the Invoice table. The Keys in Use In most databases, relationships between tables are handled in two primary ways, and both can be found. First is the single-column key. In this method, each table is assigned a single primary key column, all foreign keys are also single-column, and all referential integrity is on pairs of columns. The second method has the child table inherit the primary key column(s) from the parent as part of its own primary key because it’s a dependent of the parent table. In this case, the key column www.SYS-CON.COM/pbdj/ BE YOUR OWN MOBILE SUPER HERO WITH THE POWER OF POCKET POWERBUILDER YOU HAVE THE SKILL SET LET SYBASE GIVE YOU THE POWER! Got PowerBuilder? Go Mobile! PowerBuilder® developers can easily leverage their expertise to create new or extend existing applications using the Pocket. Pocket PowerBuilder—a new rapid application development tool that speeds the creation of mobile and wireless enterprise Pocket PC applications. Go Mobile now with this limited time offer! Purchase Pocket PowerBuilder today at $495. That’s more than 50% savings. Checkout it out today at: http://eshop.sybase.com/eshop © 2003 Sybase, Inc. All rights reserved. All trademarks are the property of their respective owners. of the child table is not sufficient to identify the records uniquely, so it needs both the parent primary key and the child table primary key. Single-column primary keys are well suited to surrogate keys, since the surrogate key has no business meaning and is stable by itself. They are typically system-generated. Child tables also have a single unique primary key column. The reference from the child to the parent is on the single parent column and carried as a mandatory foreign key column in the child. A child of the child would also have its own unique primary key column, and would have a single-column foreign key to the child table. Dependent table configurations are suitable for natural keys. The parent table has whatever columns are chosen to identify the record uniquely as its primary key. The child table’s primary key is composed of the parent primary key plus a column from the child that makes each record unique. Since natural keys are defined by the business, there’s a good chance that at least one of them will be an intelligent key. It’s extremely rare to see just singlecolumn primary keys in a database, or for all tables to depend on their parents for parts of their primary keys. Rather, some deference is usually given to a judicious mix of single- and multi-column primary keys. For instance, associative tables typically have their primary key defined as the combination of the primary keys of the parent tables, which may themselves be single-column primary key tables. Strengths & Weaknesses A design that favors single-column surrogate primary keys will have very efficient joins between tables, since most of them will be single-column joins. Tables will also be narrower than their natural key cousins, meaning less deadweight. However, getting from a deeply nested great-great-greatgrandchild table to the ultimate parent table may take some serious navigation. Read that as complex queries. Relational database engines are optimized for these kinds of queries, and the overall reduction in table deadweight tends to offset the complexity of the queries. The natural key structure is, simply enough, more natural for the developer and the super-user accessing the tables through their favorite query tool to deal with. Child tables make sense 12 PBDJ volume12 issue 2 “My sympathy to anyone who has had to make • massive changes throughout a DB2 • subsystem because of an intelligent key that was anything but” • intuitively, since the primary key columns can be used to discover the lineage. Unfortunately, this comes at a fairly steep price. If any key is intelligent, it’s going to be almost everywhere, and any business change will be devastating. Take the case of a data-type change because the Product Code described above has maxed out the three-digit sequence code. The business started using letters after it passed 999, and now even that’s not enough. It wants to make the last part of the Product Code five digits, increasing the Product Code from CHAR(10) to CHAR(12). Every table that uses that Product Code as part of the primary key will have to be structurally changed. Many databases won’t let you make that change casually, and typically require that the data be unloaded, the table dropped and rebuilt, then the data reloaded. In large database systems, this could be a monumental undertaking. Best Practices So, what’s the best thing to do? Well, that depends, of course. There is no absolute mandate that says there’s only one way to manage keys. However, to minimize the impact of future business changes, there are a few rules of thumb with a good track record. • Make every attempt in the initial design to find an absolutely stable primary identifier. Press the business to be honest and say upfront whether there’s any possibility that the natural key they recognize will ever change in • value or data-type. Be ready with arguments to support using surrogate keys. They are inherently stable, perform well in joins, have referential integrity, and provide simple joins from table to table. Establish a maximum limit for nested dependent tables. One published guide claims that five levels of dependent tables is a red flag. Re-evaluate the tables and consider introducing surrogate keys somewhere along the line. If using single-column primary keys, remember that deeply nested tables may need a direct foreign key link to a great-grandparent table. It can provide a shortcut up the chain if the application and data access tendencies require it. NOTE: This introduces problems, and violates at least second normal form. However some denormalization can be tolerated because database engines aren’t perfect, and complex joins might perform poorly. Don’t automatically assume that multiple natural keys are bad. Many situations such as Invoice and Invoice Detail and Order and Order Detail tables are obvious places to use the business-understood Line Number as the Detail table primary key, combined with the parent table primary key. Trying to force a surrogate key on the Detail tables would be cumbersome and a relatively poor performer. As already stated, associative tables typically use the combined keys of the parent tables as the primary key. However, if the associative table is itself a parent of a lot of other tables, be ready to come up with a singlecolumn primary key for it. Disclaimer and Notes Your experience may vary. If you disagree, great. Please send your feedback on what I’ve said to the email address below. I’m always willing to learn and, heck, I might have left out some important details. My hat’s off to every DBA who has to maintain a database he inherited with the kind of Product Code-from-hell I described. I actually went through that ordeal in one of the companies I worked for. My sympathy to anyone who has had to make massive changes throughout a DB2 subsystem because of an intelligent key that was anything but. ▼ This article has been reprinted with permission from www.datamodel.org. [email protected] www.SYS-CON.COM/pbdj/ T H E S T R A I G H T G O O D S O N E A S e r v e r. BRING APPS TO THE WEB WITHOUT LEAVING YOUR POWERBUILDER INVESTMENT BEHIND. It’s easy. It’s proven. Sybase EAServer is the have all rapidly web-enabled their PowerBuilder apps complete solution with the highest ROI with a faster and easier time to market. To discover how for moving PowerBuilder applications to the you can leverage your existing investments, check out Web. But don’t just take our word for it. Sierra our ROI Case Study Guide at Club, The Greenbrier Companies and Hennepin County, MN, www.sybase.com/pbextension. I n f o r m a t i o n A n y w h e r e™ S Y B A S E e - B U S I N E S S S O F T W A R E. TM E V E R Y T H I N G W O R K S B E T T E R W H E N E V E R Y T H I N G W O R K S T O G E T H E R. ©2002 Sybase, Inc. All rights reserved. All trademarks are the property of their respective owners. Written by Arthur Hefti o you think, “Why bother using PBDOM?” Well, you can use PDOM to manipulate elements in an XML document. That means you can move elements in a document or from one document to another. You can add elements to a document or delete them from a document. And, with a little coding, you can import nested XML data into a DataWindow. S With the XML capabilities in the DataWindow introduced with Sybase’s PowerBuilder 9, it’s possible to import and export data very fast and easily. You might have glanced at the PBDOM definition in the PowerBuilder help and figured it looked hard to handle but, fear not, I’ll introduce you to PBDOM and give you some code samples. Importing & Exporting with DataWindows Starting with PowerBuilder 9, the DataWindow can import and export data in XML. This powerful feature lets you exchange large amounts of data very fast. Importing and exporting is templatebased. You can define several templates for one DataWindow. With the DataWindow painter, you assign a template for importing and one for exporting the data. At run-time, it’s possible to change the template using the code. Figure 1 shows the definition of a template in the DataWindow painter used for export. Loading data from the EAS Demo DB and saving it with the defined template generates the XML data in Listing 1. PDOM Use PBDOM stands for PowerBuilder Document Object Model. It’s similar to the World Wide Web Consortium’s DOM API and the Java-based document object model for XML files JDOM. You can find a comparison of these three models in the PowerBuilder Help (PowerBuilder Extension Reference/PowerBuilder Document Object Model/PBDOM objects). Technically, PBDOM is implemented as a PBNI (PowerBuilder Native Interface) extension that makes use of the Apache/Xerces DLL. 14 PBDJ volume12 issue 2 PBDOM Classes All PBDOM classes (except PBDOM_Builder and PBDOM_Exception) are inherited from PBDOM_Object. • PBDOM_Builder is used to create a PBDOM_Document from data sources like files, strings or DataStores. • PBDOM_Exception extends the PowerBuilder exception class and is used for exception handling. • PBDOM_Object represents any node in an XML node tree and serves as a base class for the different node types. • PBDOM_Document is the representation of the XML DOM document. It accesses document-level elements. • PBDOM_Element represents an XML element and accesses its attributes, children and text. • PBDOM_Attribute is the representation of an XML attribute and accesses its values and namespace information. • PBDOM_Text represents a DOM text node in a XML document. • PBDOM_Processinginstruction are the XML document’s processing instructions. When looking at Listing 1, the saved XML data from the DataWindow, you can see some of the described types. The class PBDOM_Document references all the data including the XML header. The PBDOM_Processinginstruction object references the data in the XML header (e.g., version). [Processing instructions are used to send instructions to the application that is reading the XML. They begin with "<?" and contain a target (e.g., "xml-stylesheet") that indicates which application should be reading the instruction, followed by data for that application and finally a closing "?>". Technically, the XML Declaration is not a Processing Instruction, although it is often referred to as such and does has a similar format. – Editor.] The items CUSTOMERS, CUSTOMER, FIRSTNAME etc. are PBDOM_Elements. The ID in the CUSTOMER tag is a www.SYS-CON.COM/pbdj/ PBDOM_Attribute and PBDOM_Text references the values in the tags like Michaels or Devlin. A namespace in a document is used to distinguish between elements and attributes with the same name but belonging to different items. The element CUSTOMER and the element COMPANY could both have a child element named NAME. References to the element NAME would be ambiguous without a namespace. The solution with the prefix, the document, could look like this: <cust:NAME>Doe<cust:NAME> <comp:NAME>Sample LLC<comp:NAME> You will find more details about namespaces on the W3C web site and many examples and answers on the XML Namespace FAQ at http://www.rpbourret.com/xml/NamespacesFAQ.htm. Before you can start working with PBDOM, you have to add PBDOM100.PBD to the library list. In PowerBuilder’s application search path the following files should be accessible: PBDOM100.DLL, PBXerces100.DLL and xerces-c_2_1_0.dll. You have to deploy these four files with your application. For PowerBuilder 9 choose the appropriate PBD and DLLs, whereas the Xerces DLL is the same as for PowerBuilder 10. Creating an XML Document An XML document can be created from scratch or from an existing file, string or DataStore. In Listing 2 the XML output from Listing 1 is used to generate an XML DOM document. Only minimal error handling is implemented in this listing. The BuildFromFile method from the PBDOM_Builder class reads and parses the XML Document. The method returns a reference to the PBDOM_Document. The next few lines of code lines show some details about the first level of the document. The method GetContent from the PDBOM_Document returns an array of objects in the document. In our sample, the method will return an array of two elements. The first element is of type PBDOM_Processinginstructions, the second of type PBDOM_Element and references the element CUSTOMERS. Calling the method GetRootElement returns the root element of the document, which is also CUSTOMERS. To visualize a XML document in PowerBuilder you can use a TreeView. Listing 3 shows a recursive function that takes an array of PBDOM_Objects and displays it in a TreeView. The function loops through all elements of the array. Depending on the type of element different information besides the object name is displayed. In the case of a PBDOM_Element, the function loops over all the attributes of this element and creates name/value pairs of each. The name of the PBDOM_Object plus the display information is added to the TreeView. Should the PBDOM_Object have children, the same function is called with an array of these children and the handle of the inserted TreeView item. array. The function then loops over the attributes and – as soon as the attribute with the name to search for is found – the value is checked. When the value matches, the element is returned. If there is no match and the element has children, the method calls itself passing that element. [There are W3C standard methods for searching XML documents known as XPath and XQuery. However, at least when this article was written, PBDOM does not support XPath or XQuery type operations. – Editor] After the appropriate element is found, I add a sales order header (see Listing 5). At first I create a sales order with CREATE PBDOM_Element. Then I set the name of this instance to SALESORDER with the method SetName. The SetName method validates the name (e.g., for spaces in the element name). I then add an attribute with the name ID and the value 111. For the sales order, I need an order date and region. I create them, set their name and put the value into it with SetText. After all these elements are prepared, I put them together with the method AddContent, which checks the data for structure (e.g., no loops in a tree) and consistency of namespace to ensure there is only one root element. To catch the run-time errors, I put a TRY…CATCH statement around the call. To demonstrate some additional data manipulation, I also remove the customer with ID equals 104. The search for that customer is done using the same method shown in Listing 4. To remove that element the method Detach is used: lpbdom_Found.Detach() After the manipulation is done, the XML document can be saved with the method SaveDocument of the PBDOM_Document. Unfortunately, as of this writing, there was no method to save it to a string or blob. Instead, you must save the XML to a temporary file and then read it back into a string or blob, as applicable. Conclusion The PDBOM interface is a powerful way to manipulate complex Manipulating the XML Document The big advantage with PBDOM is the possibility of manipulating a single node in a document. For the following example, I’ll add some information for customer ID 102. Using the default EAServer Demo DB, I’ll add an order to the customer. Listing 4 shows how we search for the customer with an ID of 102. The function is recursive and loops through all the elements and attributes until the element with the required attribute value is found. Note that the search is case-sensitive. Starting with the first element, its content is loaded into an array. The method loops over the items of this array. If the item is of type PBDOM_Element the name of it – returned with the method GetName – is compared with the name to search for (CUSTOMER in our example). When an element with the name to search for is found, the method GetAttributes loads all the attributes of this element into an www.SYS-CON.COM/pbdj/ FIGURE 1 | Defining an XML Template FIGURE 2 | The PBDOM Object Hierarchy PBDJ volume12 issue 2 15 XML documents. There are various usages possible. We can use it to customize style sheets for an application. Another possible use would be in an EAServer component to manipulate XML before returning it to the client. This article has provided you with a base to start from. For additional information, refer to chapter 14 of Application Techniques in the PowerBuilder. In addition, you can also download other examples at the CodeXchange site of the Sybase Developer Network. ▼ Listing 1: Saved XML Data <?xml version="1.0" encoding="UTF-16LE" & standalone="no"?> <CUSTOMERS> <CUSTOMER ID="101"> <FIRSTNAME>Michaels</FIRSTNAME> <LASTNAME>Devlin</LASTNAME> <ADDRESS>3114 Pioneer Avenue</ADDRESS> <CITY>Rutherford</CITY> <STATE>NJ</STATE> <ZIP>07070</ZIP> <PHONE>2015558966</PHONE> <COMPANY>The Power Group</COMPANY> </CUSTOMER> <CUSTOMER ID="102"> <FIRSTNAME>Beth</FIRSTNAME> .. </CUSTOMER> </CUSTOMERS> Listing 2: Loading a XML Document PBDOM_Builder lpbdom_Builder PBDOM_Document lpbdom_Doc PBDOM_Object lpbdom_Obj[] PBDOM_Element lpbdom_Root integer li_Counter, li_Max string ls_Text // Create PBDOM Builder lpbdom_Builder = CREATE PBDOM_BUILDER TRY // Import File and generate XML Document lpbdom_Doc = & lpbdom_Builder.BuildFromFile( “XMLOUT.XML” ) CATCH (PBDOM_Exception lpbdom_Except) // Error Handling goes here, MessageBox( "PBDOM_Exception", & lpbdom_Except.GetExceptionCode()) RETURN END TRY // Get 1st Level data lpbdom_Doc.GetContent( lpbdom_Obj ) li_Max = UpperBound( lpbdom_Obj ) FOR li_Counter = 1 TO li_Max ls_Text = ls_Text + "~r~n" + & lpbdom_Obj[li_Counter].GetObject ClassString()+& ": " + lpbdom_Obj[ li_Counter ].Get Name() NEXT lpbdom_Root = lpbdom_Doc.GetRootElement() ls_Text = ls_Text + "~r~n" + & lpbdom_Root.GetObjectClassString() + & ": " + lpbdom_Root.GetName() DESTROY lpbdom_Builder Listing 3: Display XML Document in a TreeView /* Parameters: pbdom_object apbdom_Obj[] long al_Parent */ PBDOM_Object lpbdom_Children[] PBDOM_Attribute lpbdom_Attr[] PBDOM_Element lpbdom_Element long ll_Handle integer li_Counter, li_Max, li_Attr Counter, & li_AttrMax string ls_Disp li_Max = UpperBound(apbdom_Obj) // Loop through all elements in the array 16 PBDJ volume12 issue 2 AUTHOR BIO Arthur Hefti is CEO of CATsoft Development GmbH in Zurich. He has been a PowerBuilder developer for 10 years and has taught dozens of PowerBuilder training classes. He and his team create custom-made client/server and web software with PowerBuilder and JBoss using XML, Web Services and encryption quite frequently. FOR li_Counter = 1 TO li_Max ls_Disp = "" // Get tag information depeding on type of entry CHOOSE CASE & apbdom_Obj[li_Counter].GetObject ClassString() CASE "pbdom_processinginstruction" ls_Disp = ": " + & apbdom_Obj[li_Counter].DYNAMIC GetData() CASE "pbdom_text" ls_Disp = ": " + & apbdom_Obj[li_Counter].DYNAMIC GetText() CASE "pbdom_element" // An element might have attributes lpbdom_Element = apbdom_Obj[ li_Counter] IF lpbdom_Element.HasAttributes() THEN lpbdom_Element. GetAttributes (lpbdom_Attr) li_AttrMax = UpperBound (lpbdom_Attr) // Loop through all attributes FOR li_AttrCounter = 1 TO li_AttrMax ls_Disp = ls_Disp + & lpbdom_Attr[li_AttrCounter].GetName()+& "=" + & lpbdom_Attr[li_AttrCounter].GetText()+ “ “ NEXT ls_Disp = ": " + ls_Disp END IF CASE ELSE ls_Disp = ": " + & apbdom_Obj[li_Counter].GetText() END CHOOSE // Display name + additional information ls_Disp = apbdom_Obj[li_Counter]. GetName()+& ls_Disp ll_Handle=tv_1.InsertItemLast(al_ Parent,ls_Disp,0) // if object has children call the same function IF apbdom_Obj[li_Counter].HasChildren() THEN apbdom_Obj[li_Counter].GetContent(lpbdom_ Children) of_BuildTree(lpbdom_Children,ll_ Handle) tv_1.ExpandItem(ll_Handle) END IF NEXT RETURN Listing 4: Searching an Element with Attribute of certain Value /* Parameters By reference pbdom_object apbdom_Found String as_Element, as_Attribute, as_Value pbdom_object apbdom_Start */ boolean lb_Found PBDOM_Object lpbdom_Obj[] PBDOM_Attribute lpbdom_Attrib[] PBDOM_Element lpbdom_Ele string ls_Attribute long ll_Counter, ll_Max integer li_Counter, li_Max apbdom_Start.GetContent(lpbdom_Obj) ll_Max = UpperBound(lpbdom_Obj) // Loop over all objects FOR ll_Counter = 1 TO ll_Max IF lpbdom_Obj[ll_Counter]. GetObjectClassString() & = "pbdom_element" THEN [email protected] lpbdom_Ele = lpbdom_Obj[ll_Counter] IF lpbdom_Ele.GetName()=as_Element THEN // Get Attributes lpbdom_Ele.GetAttributes(lpbdom_Attrib) li_Max = UpperBound(lpbdom_Attrib) // Loop over all Attributes FOR li_Counter = 1 TO li_Max ls_Attribute = & lpbdom_Attrib[li_Counter]. GetName() IF ls_Attribute = as_Attribute THEN IF lpbdom_Ele.GetAttributeValue (ls_Attribute)& = as_Value THEN apbdom_Found = lpbdom_Obj [ll_Counter] lb_Found = TRUE EXIT END IF END IF NEXT END IF IF NOT lb_Found AND & lpbdom_Ele.HasChildren() THEN lb_Found = & This.of_FindElementWithAttribute Value( & apbdom_Found,as_Element,as _Attribute,& as_Value,lpbdom_Ele) END IF END IF IF lb_Found THEN EXIT END IF NEXT RETURN lb_Found Listing 5: Adding an Element PBDOM_Element lpbdom_Customer, lpbdom_Order, & lpbdom_OrderDate, lpbdom_OrderRegion TRY // Create sales order lpbdom_Order = CREATE PBDOM_Element lpbdom_Order.SetName( "SALESORDER" ) lpbdom_Order.SetAttribute( "ID", "111" ) // Create order date lpbdom_OrderDate = CREATE PBDOM_Element lpbdom_OrderDate.SetName( "ORDERDATE" ) lpbdom_OrderDate.SetText( "2004-12-31" ) // Create order region lpbdom_OrderRegion = CREATE PBDOM_ Element lpbdom_OrderRegion.SetName( "ORDERREGION" ) lpbdom_OrderRegion.SetText( "Switzerland" ) // Add elements to sales order lpbdom_Order.AddContent( lpbdom_ OrderDate ) lpbdom_Order.AddContent( lpbdom_ OrderRegion ) // Add sales order to customer lpbdom_Customer.AddContent( lpbdom_Order ) CATCH (PBDOM_Exception lpbdom_Except2) // Error Handling goes here, MessageBox( "PBDOM_Exception", & lpbdom_Except2.GetExceptionCode()) RETURN END TRY DOWNLOAD THE CODE! www.sys-con.com/pbdj/ www.SYS-CON.COM/pbdj/ ©2003 Sybase, Inc. All rights reserved. All trademarks are the property of their respective owners. 4GL RAD Tools POWERBUILDER THE CLASSIC, TRIED-AND-PROVEN CLIENT/SERVER DEVELOPMENT TOOL. POWERBUILDER THE HANG-ONTOYOUR-SEAT CLIENT/SERVER DEVELOPMENT TOOL. For years, PowerBuilder® has reigned Take your client/server applications as the premier development tool to the next level with the Power- for client/server applications. Our Builder Native Interface. Integrate newest iteration extends both our your existing and new Power- leadership and your investment Builder applications with in skills and applications for C and C++ applications. And client/server development. There’s easily work with J2EE and .NET a host of exciting new features. components and applications Download all the technical details exposed as Web Services. Details at sybase.com/powerbuilder. at sybase.com/powerbuilder. INFORMATION LIQUIDITY. SYBASE INTEGRATION TECHNOLOGIES. E V E R Y T H I N G W O R K S B E T T E R W H E N E V E R Y T H I N G W O R K S T O PBDJ GPBDJ ETH E R TM . volume11 volume12 issue issue10 2 BOOK EXCERPT Part Art, Part Science Part 1 WRITTEN BY JIM esigning and implementing an n-tier or Internet application is a complex task, and issues resulting from errors in the runtime configuration or the application code itself are practically inevitable. Problem analysis and troubleshooting are part art, part science. Therefore, although the techniques discussed here can be helpful, the sheer diversity of client and server environments precludes a single recipe for resolving all issues. D We’ll focus on problems that involve PowerBuilder that occur from the point of connectivity all the way through an EAServer component’s lifecycle, and close with a troubleshooting checklist of potential resolutions to some of the more common error situations. Client and Server Environment One of the first techniques for validating both the client and EAServer environments involves checking the versions and locations of the PowerBuilder executable modules (DLLs on Microsoft Windows platforms) and Java classes that are loaded at runtime. In terms of PowerBuilder clients and components, Sybase recommends that the version of the PowerBuilder Virtual Machine (VM) on the client machine match that used by EAServer. This is required rather than recommended when using proprietary techniques such as the blob format used in DataWindow synchronization (for example, the getFullState and setFullState methods). Client Requirements Client requirements for PowerBuilder applications that access EAServer are no different than those for client/server applications. Specific requirements are detailed in the “Application Techniques” 18 PBDJ volume12 issue2 O’NEIL manual accompanying the PowerBuilder product, and include the PowerBuilder VM (PBVM90.DLL), the DataWindow engine (PBDWE90.DLL), database interface libraries and the EAServer client ORB implementation (LIBJCC.DLL). NOTE: Client applications built using the initial release of PowerBuilder 9.0 require that one additional DLL, LIBJSYBHEAP.DLL, be deployed. Beginning with the 9.0.1 maintenance release, this DLL is no longer required because its functionality has been subsumed by PBVM90.DLL. All of the PowerBuilder DLLs used for a given client application must be of the same build. Although LIBJCC.DLL ships with PowerBuilder, it’s actually an EAServer module and, as such, isn’t stamped with a specific version number. Because the implementation is backward-compatible, your client application should use the LIBJCC.DLL shipped with the most recent version of EAServer to which it may connect. Several tools are available to determine what DLLs have actually been loaded by your client application. The Sysinternals web site (www.sysinternals.com) has many useful diagnostic tools, including listdlls and ProcessExplorer, that can be used for this. You can even get a list of modules loaded through the About dialog box in Microsoft Word. Server Requirements All versions of EAServer have a serverstart.bat file (or serverstart.sh file on Unix plat¬forms) that contains the core of the environment setup and the actual command to launch the server executable image (jagsrv). In EAServer 4.0 and later, a setenv and optional user_setenv command file accompany the serverstart script. When the serverstart script is invoked, it invokes the other www.SYS-CON.COM/pbdj/ two scripts to set site-specific environment requirements complementing those required by the core EAServer product. The primary environment variables used by EAServer 4.0 and later are shown in Table 1. For most installations, neither the serverstart nor the setenv script requires modification. A user_setenv script may be required, though, to supply additional libraries or classes. For example, Informix JDBC connection caches require that the IBM Informix JDBC driver classes be located on the CLASSPATH, and Oracle OCI caches on a Windows 2000 server require that the Oracle client software be accessible via the PATH variable. CLASSPATH The CLASSPATH that is established for EAServer can be viewed directly from the server properties of Jaguar Manager. Keep in mind, however, that EAServer also uses custom class loaders during its execution, so the absence of a required class on the system CLASSPATH doesn’t necessarily mean that failure is imminent. However, the presence of a class on the system CLASSPATH can interfere with an identical class loaded by a custom class loader resulting in a Java ClassCastException or ClassNotFoundException. The remedy is to ensure that all classes required by a component are loaded via custom class loaders. You do this by including such classes in the java.classes property of the associated application, web application, servlet, package, component or even the server itself. EAServer offers two tracing options to help diagnose class loader errors. • Setting the com.sybase.jaguar.server.jvm.verbose property to true causes the location from which each class is loaded to be recorded in the EAServer log file. • Setting com.sybase.jaguar.server.classloader.debug to true also records the class loader used for each class. Listing 1 is an excerpt from the EAServer log where both these properties have been set. The trace lines prefaced with JCL: result from the classloader.debug option, while the others originate with the jvm.verbose setting. This particular example shows the sequence used to instantiate the Java Connection Manager ( JCM) service upon server startup. BOOTCLASSPATH Environment Variable Description JAGUAR Root directory of EAServer installation JAGUAR_HOST_NAME Machine name for default listeners JAGUAR_JDKnn Root JDK directory (nn = 12, 13, 14) Root directory of the JDK JDK_LATEST being used to launch the server; assumes the value of one of the JAGUAR_JDKnn variables CLASSPATH Search path for Java classes required for server operations Where Set setenv setenv setenv serverstart serverstart for core classes user_setenv for sitespecific requirements serverstart for core classes user_setenv for sitespecific requirements serverstart for core classes. user_setenv for sitespecific requirements BOOTCLASSPATH Search path for Java classes to be bootstrapped before the built-in JRE classes PATH (Intel) LD_LIBRARY_PATH (Solaris) LIBPATH (AIX) SHLIB_PATH (HP-UX) Search path for executable images (DLLs, shared objects. and so on), including the EAServer libraries, and the JDK libraries Search path for native functions user_setenv (in DLLs or shared objects) invoked by Java classes BOOTLIBRARYPATH TABLE 1 | EAServer environment variables Operating System Microsoft Windows (NT, 2000, and XP) Solaris HP-UX AIX Utility Command listdlls (from www. listdlls -r jagsrv.exe sysinternals.com) pldd /usr/proc/bin/pldd pid, where pid is the process ID of jagsrv determined by running ps -ef | grep jagsrv shl_get() Requires implementing an EAServer component that invokes shl_get() genld genld The BOOTCLASSPATH is used with JDK 1.2 and later so the system class loader can load classes before it loads the core Java classes provided in rt.jar. This is required whenever alternative implementations of classes located in rt.jar need to be used. For instance, in EAServer 4, the EAServer ORB class is org.omg.CORBA.ORB and is located in easclient.jar. Sun’s rt.jar distribution, however, also includes this class. To ensure that EAServer uses the Sybase implementation, the serverstart script puts easclient.jar on the BOOTCLASSPATH ahead of rt.jar. Other classes that need to access classes on the BOOTCLASSPATH may also need to be added to the BOOTCLASSPATH. A common example is third-party JDBC drivers used by EAServer connection caches such as the Oracle Thin JDBC driver. If you include the driver classes (such as %ORACLE_HOME%/jdbc/lib/classes12.zip) in the CLASSPATH but not in the BOOTCLASSPATH, you will encounter a ClassNotFoundException due to class loader conflicts. platform and functionality. The value of the Microsoft Windows PATH variable (and its Unix analogs) used by EAServer can be ascertained via the operating system commands and utilities shown in Table 2. These utilities are particularly useful in ensuring that the correct versions of the PowerBuilder libraries are loaded at runtime. The listdlls utility has an advantage over the Unix commands because each DLL version is reported as part of the output. On Unix platforms, you need to extract the version number from each specific object file using the strings command. For instance, the following command on HP-UX reports the version of the PowerBuilder VM implemented by the libpbvm80x.sl file: PATH strings libpbvm80x.sl | grep -i “^Version [0-9]” At a minimum, PowerBuilder 9.0 components running in EAServer require that the PBVM90 and PBJAG90 modules be available on the operating system path established for the EAServer process. Generally, most components make use of DataStores and one or more database connections; therefore, the PBDWE module and one or more database interfaces (PBJDB, PBODB, PBSYJ, PBO90 and so on) are also needed. The “Application Techniques” manual accompanying PowerBuilder provides specifics on the binary images required by www.SYS-CON.COM/pbdj/ TABLE 2 | Commands and utilities for viewing modules loaded by a process JVMType Switch When starting EAServer or installing it as a service on a Microsoft Windows system, the -jvmtype switch can specify that the client, server or classic Java VM be used (assuming that the JDK version and operating system support is use). Historically, the Java server VM has had a reputation for being less stable than the client VM, and although it’s tuned for application server performance, you may PBDJ volume12 issue 2 19 Error Code Representative ErrText 50 Unsupported driver name 57 This connection object is not connected to a server 92 Required property is missing Potential Remedy Set the driver property of the Connection object to jaguar. This error can have a number of causes, as explained further in this section. Set the location or userid prop erty of the Connection object. TABLE 3 | Error codes resulting from a failed connection attempt want to use the default client VM if you encounter specific stability issues. Generally, stability is more of a factor in older releases of the Java VM and is characterized by rather severe Java VM abort messages appearing in the EAServer log. Considerations When Running as a Service When running EAServer as a service on Microsoft Windows operating systems, the key environment settings are drawn from the registry hive at \\HKEY_LOCAL_MACHINE\ SYSTEM\CurrentControlSet\Services\service-name\Parameters, where service-name is the name of the EAServer instance provided on the serverstart install command line. The settings for PATH, CLASSPATH and BOOTCLASSPATH are stored in the registry when the service is installed. When the service is actually started, the current values of these environment variables are appended to the values that were stored in the registry when the service was created. Because the EAServer process itself sets these environment variables, a minimal environment that includes the %JAGUAR%/dll directory in the system PATH must exist for the service to start. Also note that when installing the service, the CLASSPATH is extended to include each JAR or ZIP file located in the %JAGUAR%/java/lib directory. If you start the server as a service, only the JARs and ZIPs present in that directory when the service was installed are added to the CLASSPATH. In contrast, when starting the server via the serverstart batch file, the JARs and ZIPs present in that directory at the moment the server is started are dynamically added to the CLASSPATH. Manager) or an EAServer custom authentication service to verify user credentials. When using one of these techniques, multiple failed requests will lock you out of the server because it has interpreted those requests as a possible attack. Note: The excerpt from the EAServer log (see Listing 2) where the IP address of the client attempting access is recorded can be useful in identifying the failed client or the source of an attempted break-in. Obviously, if the client fails to connect with the server, the EAServer log won’t contain any error information, so the absence of information itself can be a clue to the cause. As a first step in diagnosing such cases, ensure that the location property of the Connection object has the following format: protocol://server:port Here, the protocol is either iiop or iiops. Next, match this value to an entry at the beginning of the server log similar to this: Dec 23 21:22:08 2002: Listener # 6: Jaguar_iiop: Active: yes Protocol: ‘IIOP’: ‘phoenix’,9000 Security Profile: ‘*NONE*’ If the Active attribute is set to no, the listener is not operational, as the following EAServer log entry demonstrates: Dec 23 21:33:19 2002: SRVLIB Message: 16240/10/0: Net-Library routine ?net_listen(phoenix 9000) failed in srv__start_listeners Network error: status = 23 - Net-Lib protocol driver call to register a listener failed The most common causes for this behavior are that another server instance is already running or that some other application has already claimed use of that port. To verify, use the netstat command to determine what ports are in use. Listing 3 shows some output of the netstat command executed on a Solaris machine. Here the presence of ports 8080 and 9000 (both default EAServer ports) in a LISTEN state likely means that an EAServer instance is already running on that machine. Tracing Client Connectivity Requests Connecting to EAServer Some of the most common and easiest issues to overcome involve connectivity from a PowerBuilder application or another client to EAServer. Connectivity issues may occur because of configuration issues in the client environment, failures on the server side or even issues involving firewalls and network address translation. In some cases, the EAServer log file alone might provide little insight into why you failed to connect to the server. In these situations, you might have to resort to tracing the underlying network protocol traffic. Using EAServer or Sybase and even third-party tools there are ways to capture packets to and from EAServer in any of the three supported communication protocols: IIOP, HTTP, and TDS. Diagnosing Failed Connections IIOP Requests The Connection object is the usual mechanism for establishing a client connection to EAServer from PowerBuilder. When the connection to server fails, the ConnectToServer method returns one of the error codes shown in Table 3. That information, along with the contents of the ErrText property of the Connection object, often reveals the root cause of the failure. The error code 57 can pop up in a number of scenarios such as a reference to a nonexistent server, an incorrect communications protocol or an invalid user ID or password. By default, a client attempts to connect five times with a delay of two seconds between tries; therefore, an error 57 immediately returned to the client generally indicates that it found the server but that there was a problem validating the user’s credentials. If the failure results from a timeout, it’s usually because the location property doesn’t specify a valid operating EAServer. In both cases, an investigation of the EAServer log via Jaguar Manager or a text editor is in order. By default, EAServer doesn’t validate any user except for the special administrative user, jagadmin. You need to use operating system authentication (an EAServer server property configurable via Jaguar To turn on IIOP tracing from a PowerBuilder client, populate the options property of the Connection object with the ORBLogIIOP and ORBLogFile parameters, as demonstrated next. For the ORBLogFile attribute, make sure that a full path is given and enclosed in quotation marks: 20 PBDJ volume12 issue2 ln_connect.options = “ORBLogIIOP=’true’,ORBLogFile=’c:\orb.log’” Listings 4 and 5 contain excerpts of an IIOP client trace indicating a failed session initialization. The IIOP putMessage in Listing 4 shows the request to create a session for user jagadmin using the password badpwd. The response (see Listing 5) is in the form of an IIOP getMessage packet that contains a NO_PERMISSION exception because the wrong password was given. Detailed analysis of IIOP packets is really beyond our scope here; however, the chapter entitled “General Inter-ORB Protocol” in The Common Object Request Broker: Architecture and Specification (available from www.omg.org) can be used to help interpret these traces. www.SYS-CON.COM/pbdj/ You can also enable IIOP tracing on EAServer itself by setting the com.sybase.jaguar.server.log.iiop server property to true. Many internal workings of EAServer are handled via inter-component calls using IIOP — not to mention the fact that a server may be handling many clients — so IIOP logging causes the EAServer log to grow quickly. You can reduce the size of the log somewhat by setting the com.sybase.jaguar.server.log.iiop.ac property to true, which defers the tracing until the server actually begins accepting requests from clients. HTTP Requests When using PowerBuilder client applications, the primary mode of communicating with EAServer is via IIOP. PowerBuilder’s GetURL and PostURL functions, however, offer a mechanism to access EAServer servlets and JSPs via the HTTP protocol (HTTPS is not supported here). In such a scenario, PowerBuilder accesses EAServer as a web server, so you can diagnose connectivity issues as you would when trying to access any web site from a browser client such as Internet Explorer. The error and return codes are those defined by the World Wide Web Consortium (W3C) in the HTTP specification available from www.w3c.org. Three log files associated with EAServer running as a web server can aid in diagnosing problems with HTTP client requests. 1. The HTTPRequest log provides a one-line summary of every URL accessed, the IP address of the requesting client, the HTTP return code and the number of bytes of data returned. This log also contains entries for failed requests such as the ubiquitous 404 Page Not Found. The default format for this file is the Common Log Format as defined by the W3C. Extended log file format (as shown in Listing 6) can also be enabled by setting the hostaddr date time reqline status length cookie referer user-agent method uri-stem http_version host port TABLE 4 | Extended log file format options its capabilities when compared to IIOP connectivity options, PowerBuilder’s SYC database driver can access components in EAServer via a TDS port and the technique known as Methods as Stored Procedure (MASP). The Ribo utility shipped with the jConnect for JDBC driver and available by free download from the Sybase web site is a convenient tool for tracing TDS traffic. We will discuss Ribo in more detail in the upcoming section on diagnosing database access issues. It’s more likely that you will use the tool to investigate the interaction of EAServer connection caches with Sybase databases and gateways. Instantiating Components Most component instantiation failures happen because of coding errors or problems in the server environment. PowerBuilder clients (or other EAServer components making inter-component calls) usually initiate component instantiation via the Lookup or CreateInstance functions. Both methods are available on the Connection object for client access and the TransactionServer object for intercomponent calls. The lower-level JaguarORB object can also be used to access EAServer and instantiate components via the base CosNaming techniques. Establishing Server Connectivity “Connectivity issues can arise because of configuration issues in the client environment, failures on the server side or issues involving firewalls and network address translation” com.sybase.jaguar.server.http.elffenable server property to true in Jaguar Manager. The additional property com.sybase.jaguar.server.http.elffitems lets you specify exactly which items are included in the extended log file format and in what order they appear. The options include those in Table 4 where the default value for this property is hostaddr,date,time,reqline,status,length, cookie,referer. 2. The HTTPServlet log includes information about servlet and JSP execution. This log proves valuable in determining the cause of HTTP 500 Internal Server Errors because it records Java class loading errors and JSP compilation failures. You can also set the com.sybase.jaguar.server.servlet.trace property to true to provide additional information about servlet initialization and execution. 3. The HTTPError log records HTTP server failures such as socket errors when writing a response to the client’s HTTP port. TDS Requests Tabular Data Stream (TDS) is Sybase’s proprietary protocol for communicating between Open Client and Open Server applications, such as Adaptive Server Enterprise. Although it’s rather restrictive in 22 PBDJ volume12 issue 2 Error 57 can also occur as a return code from the CreateInstance or Lookup functions on the Connection object and usually indicates a coding error or failure to handle errors returned from the ConnectToServer method. Because error 57 means there’s no server connection, the EAServer log file won’t contain any information to help diagnose the failure. When using the JaguarORB object in PowerBuilder to connect to the server, you first create proxies for various EAServer packages such as SessionManager and Factory. As a rule, rather than returning error codes, these methods throw exceptions when there are failures, so they should be issued in the context of TRY-CATCH blocks in your PowerScript client code. Locating Components Locating a component on EAServer before instantiating it involves two distinct steps. First, verify that a component with the requested name exists on one or more EAServers cataloged by the targeted naming server. If the component is found, the second step is to confirm that the component instance found does indeed implement the desired interface. The failure of either step results in EAServer reporting one of the following two exceptions: • omg.org/CosNaming/NamingContext/NotFound • omg.org/CORBA/OBJECT_NOT_EXIST Now let’s look a little closer at the processing involved here to get a better understanding of common points of failure. Lookup The first step toward locating a component is verifying that the named component is accessible to one of the naming server(s) specified in the Connection object’s location property or in the ORBNameServiceURL property supplied when initializing the JaguarORB object. When using COSNaming via the JaguarORB object, the component name is explicitly provided via the NameComponent structure. When www.SYS-CON.COM/pbdj/ YOUR FASTEST ROUTE TO POWERBUILDER DEVELOPERS • Each issue is devoted exclusively to the newest aspects of PB development using version 9.0, Pocket PB 1.0, PowerDesigner 9.5.2, iAnywhere Solutions, etc. • Written by acknowledged PB and EAServer experts • Published monthly, circulated worldwide - the world's first and leading PowerBuilder print and online resource • Now in its 10th year ! www.sys-con.com/pbdj/ For more details contact Carrie Gebert 201 802.3026 [email protected] FIGURE 1 | Client error message occurring from a failed component lookup using the PowerBuilder Connection object, the component name is taken directly from the Lookup function or from the CreateInstance function, if the optional component name argument is provided. When you use the one-argument form of the CreateInstance function, PowerBuilder constructs the component name based on the default package name (specified in the application property of the Connection object), followed by a / character and then the variable type of the proxy argument. Although this sounds convenient, we recommend that you always use the two-argument form of CreateInstance for the following reasons: • You must always remember to change the application property of the Connection object when calling components in different packages. If the application property of the Connection object isn’t specified, the Connection object will report error code 92 as shown in Table 17.3. • If you elected to generate proxies that are prefaced by the package name, the instantiation will fail because the variable type seen by PowerBuilder (that is, the proxy name) won’t match the actual component’s name. Whatever the source of the component name, the naming server checks its list of bound objects (created at startup or refresh) to see if any of the object names match. Although the standard naming convention is package/component, if the com.sybase.jaguar.component.bind.naming property is explicitly set, its value is the name by which the server recognizes the component. The component’s bound name doesn’t have to resemble the actual package or component name as installed on the server. So let’s assume at this point that the requested component was located on at least one server and continue on to the next step. Narrow When using the CreateInstance method, the component is narrowed to a SessionManager::Factory interface only. It assumes that the corresponding proxy used in the client application includes valid interface methods implemented by the component. Any impending failures in this regard are not made manifest until a method is invoked on the component. When using the Lookup method, the interface specified must be the home interface of the requested EJB; otherwise, the actual lookup will succeed, but the attempt to narrow the component to that interface will fail. The client will still show an error 57 code, which may be puzzling because the component name itself could be correct. When using the JaguarORB and the Narrow function of the PowerBuilder CORBAObj object, the interface must also be specified. A failed Narrow method at runtime may produce no error; however, it will result in aberrant application behavior. A good programming practice is to always verify the implementation of an interface via the is_a function on CORBAObj before attempting to narrow the object reference to that interface. Common Causes of Lookup Issues EAServer doesn’t consider a lookup failure to be an error, so no information is recorded in the EAServer log for this step. Although you may see errors in the log when using the CreateInstance function, they are actually recorded when an attempt is made to instantiate the component on the target server (which we’ll discuss in the next session). Some of the common causes of failure to locate components are: 24 PBDJ volume12 issue2 • The package containing the desired component isn’t installed on the specific EAServer being targeted (or on any of the member servers in the case of a clustered environment). It’s not enough for the package to be included in the EAServer repository; it must be installed in each server instance where it may be needed. • The package or component name was misspelled as in Figure 17.1. The package and component names aren’t case-sensitive in this context. • The bound name of the component is something other than the default package/component format, which can be verified by examining the component’s bind.naming property. This property isn’t case-sensitive either. • When using Lookup or CosNaming (via the JaguarORB object) directly, the desired interface name isn’t found, perhaps because it’s misspelled. In this case, the name of the interface is case-sensitive. Instantiating Components A component isn’t instantiated when the CreateInstance or Lookup is issued. It happens when the first method call is requested for that instance. The lookup step previously described results in a list of EAServer profiles (a server and port combination) where the requested component can be instantiated. In a clustered environment, this list likely includes multiple EAServers. The client ORB always tries to instantiate a component on the first server in the profile list, assuming that the profile list is already in an order that appropriately reflects the load-balancing technique selected for that cluster. If the instantiation fails because of a communication error (for example, the server has gone down), the request is retried transparently on the next server in the profile list returned by the naming server. Because the list of profiles is returned to the client from the naming server, there’s a change in context in the interpretation of the server locations included in those profiles. This change in context can cause instantiation failures in two common scenarios: • When a standalone EAServer or a server in a cluster has an active localhost listener (such as the loopback address of 127.0.0.1), that listener is returned to the client application that requests a component along with the list of profiles. If the client ORB attempts to use that localhost profile to instantiate the component, the attempt will fail because localhost is now the client machine, not the EAServer machine hosting the component. In a production environment, there’s no need for localhost listeners. • When accessing EAServer through a firewall, the server addresses in the profile list returned to the client may be unreachable. In an internal network, the private IP addresses (namely 10.x.x.x, 172.16.x.x and 192.180.x.x as designated by the Internet Assigned Numbers Authority) are often used to identify machines running on the corporate intranet. So the EAServer naming servers in that environment use those internal addresses when creating the list of profiles that indicate where a requested component can be instantiated. If that list of profiles is forwarded to service a request from an EAServer client outside the firewall, the instantiation will fail because these private Internet addresses aren’t reachable from the client. When using firewalls that do network-address translation from publicly accessible IP addresses to private IP addresses, you must configure your clients’ host file to do reverse-address translation or use the ORBProxyHost and ORBProxyPort parameters when initializing the client ORB. Assuming that the server on which the component is to be instantiated is indeed reachable, let’s look at how EAServer loads the component implementation for a PowerBuilder component. Understanding the four main steps of this process, as outlined here, can help identify the source of the errors if the instantiation fails: 1. EAServer determines the implementation model via the compo- www.SYS-CON.COM/pbdj/ nent’s com.sybase.jaguar.server.type property. For PowerBuilder components, this value is always pb. 2. EAServer next determines the PowerBuilder version in which the component was implemented by examining the com.sybase.jaguar.component.pb.version property. If the property isn’t specified, the component is assumed to have been built using PowerBuilder 7. 3. If it hasn’t been loaded already, EAServer initializes the PowerBuilder VM. Each component instance is allocated a unique session in the one instance of the PowerBuilder VM hosted by the EAServer process. 4. Finally, the PowerBuilder VM determines what PBDs to load for the component by consulting the com.sybase.jaguar.component.pb.cookie and com.sybase.jaguar.component.pb.librarylist properties. The library list can contain two kinds of entries: • PBDs or PBLs prefaced by a $ are loaded from an EAServer repository subdirectory of that component named Cn, where n is the value of the pb.cookie property (and increases for each deployment from PowerBuilder). • PBDs or PBLs with explicit or relative paths not prefaced by the $ are located according to normal pathing rules for the host operating system. To use this approach, you must manually change the librarylist property in Jaguar Manager; furthermore, if you redeploy the component from PowerBuilder later, your changes will be overwritten. When these steps fail, it’s usually a problem in the EAServer configuration. The error in the EAServer log will provide insight into the actual cause of the failure. The client application, on the other hand, will experience the generic CORBA::OBJECT_NOT_EXIST or CORBA::TRANSACTION_ROLLEDBACK exceptions. Invoking Component Methods Assuming that everything has been error-free so far, the next step is the actual method invocation. Although the success of the method execution depends largely on whether the developer correctly implemented it, there are at least two circumstances in which a method invocation might fail before it even gets into the PowerBuilder component’s code. Failed invocations can occur in the development cycle when obsolete proxy objects are used. Whenever you modify the component interface on EAServer, you must be sure to regenerate the proxies for those interfaces on PowerBuilder. The PowerBuilder proxies are merely remote wrappers for the component’s functionality that the client application currently thinks is available. Any attempt to call a method that doesn’t exist (or no longer exists) results in a CORBA::TRANSACTION_ ROLLEDBACK or CORBA::BAD_OPERATION exception. In a production environment, an instantiation can fail when valid component references become invalid because, say, the EAServer on which the instance was hosted has failed. If you have configured the component for failover (by setting the com.sybase.jaguar.component.auto.failover property) and the component is marked as being automatically demarcated/ deactivated (the com.sybase.jaguar.component.tx_vote property is false), successive attempts to access the component automatically fail over to the other EAServer instances returned in the original list of profiles derived from the lookup request. If failover isn’t configured or there are no remaining servers in the cluster that can host the requested component, a CORBA::OBJECT_NOT_EXIST or CORBA::COMM_FAILURE exception will occur when the client invokes the method on that component. ▼ This article is based on PowerBuilder 9 Internet and Distributed Application Development by various authors (ISBN 0672324997), published by Sams Publishing. AUTHOR BIO Jim O’Neil is a principal technical support engineer at Sybase, Inc. He has been with Sybase for six years, concentrating on resolving customer issues with Sybase products such as PowerBuilder, EAServer and PowerJ. Prior to Sybase, Jim spent about 10 years working as a software engineer for two defense contracting firms. [email protected] www.SYS-CON.COM/pbdj/ PBDJ volume12 issue 2 25 LISTING 1 EAServer Log Showing Class Loader Diagnostics Dec 23 21:22:12 2002: JCL:JCL <4127408>: custom= Dec 23 21:22:12 2002: JCL:setName <4127408>: Name changing from 4127408 to Jaguar/JCM Dec 23 21:22:12 2002: JCL:setDirs <Jaguar/JCM>: _dirs=[Ljava.lang.String;@3c5982 Dec 23 21:22:12 2002: JCL:displayArray <Jaguar/JCM>: strs = [Ljava.lang.String;@3c5982 Dec 23 21:22:12 2002: JCL:displayArray <Jaguar/JCM>: strs.length = 3 Dec 23 21:22:12 2002: JCL:displayArray <Jaguar/JCM>: strs[0] = C:\Program Files\Sybase\EAServer/java/classes/ Dec 23 21:22:12 2002: JCL:displayArray <Jaguar/JCM>: strs[1] = C:\Program Files\Sybase\EAServer/html/classes/ Dec 23 21:22:12 2002: JCL:displayArray <Jaguar/JCM>: strs[2] = C:\Program Files\Sybase\EAServer/java/lib/ Dec 23 21:22:12 2002: JCL:setCustomList <Jaguar/JCM>: custom= Dec 23 21:22:12 2002: JCL:loadClass <Jaguar/JCM>: name=com.sybase.jaguar.jcm.JCM Dec 23 21:22:12 2002: JCL:loadClass <Jaguar/JCM>: name=com.sybase.jaguar.jcm.JCM, resolve=false Dec 23 21:22:12 2002: JCL:loadClass <Jaguar/JCM>: ?class DefName=com.sybase.jaguar.jcm.JCM, name=com.sybase.jaguar.jcm.JCM, resolve=false Dec 23 21:22:12 2002: JCL:loadClass <Jaguar/JCM>: ?class DefName=com.sybase.jaguar.jcm.JCM, name=com.sybase.jaguar.jcm.JCM, resolve=false, trySystem ClassLoader=true Dec 23 21:22:12 2002: JCL:loadClass <Jaguar/JCM>: Try from our local cache Dec 23 21:22:12 2002: JCL:inCustomList <Jaguar/JCM>: name=com.sybase.jaguar.jcm.JCM Dec 23 21:22:12 2002: JCL:inCustomList <Jaguar/JCM>: len=0, rets=false Dec 23 21:22:12 2002: JCL:loadClass <Jaguar/JCM>: incustom=false Dec 23 21:22:12 2002: JCL:loadClass <Jaguar/JCM>: try the system class loader Dec 23 21:22:12 2002: [Loaded com.sybase.jaguar.jcm.JCM Dec 23 21:22:12 2002: from C:\Program Files\Sybase\ EAServer\java\lib\easserver.jar Dec 23 21:22:12 2002: ] LISTING 2 EAServer Log Showing a Lockout Situation Dec 23 19: 03:10 2002: NO_PERMISSION: user jagadmin (possible attack from ?65.57.230.61) Dec 23 19: 03:10 2002: SystemException: NO_PERMISSION (Manager/createSession [email protected]) Dec 23 19: 03:13 2002: NO_PERMISSION: user jagadmin (account locked for 600 seconds) Dec 23 19: 03:13 2002: SystemException: NO_PERMISSION (Manager/createSession [email protected]) LISTING 3 Netstat Output Showing Active Ports phoenix% netstat -a -P tcp TCP Local Address Recv-Q State phoenix.58616 ESTABLISHED phoenix.8080 phoenix.8081 phoenix.9000 phoenix.9001 phoenix.telnet ESTABLISHED LISTING 5 IIOP Response Packet Sent to Client Application IIOP putMessage Hexadecimal [padding] (interpretation) ISO 8859-1 encoding getOctet < 47 (71) G getOctet < 49 (73) I getOctet < 4F (79) O getOctet < 50 (80) P getOctet < 01 (1) . getOctet < 01 (1) . getOctet < 01 (1) . getOctet < 01 (1) . getULong < 3C000000 (60) <... getMessage | GIOP version = 1.1 | flags = 1 (‘<’ little endian) | message type = 1 (Reply) | message size = 60 (after 12 byte header) getReply | service context: getRequest | service context length: getULong < 00000000 (0) .... getReply | request id: getULong < 00000000 (0) .... getReply | reply status: getULong < 02000000 (2) .... getULong < 24000000 (36) $... getString < 49444C3A6F6D672E6F72672F434F5242412F4E 4F5F5045524D495353494F4E3A312E3000IDL:omg.org/CORBA/ NO _PERMISSION:1.0. getULong < 00000000 (0) .... getULong < 01000000 (1) .... Remote Address Swind Send-Q Rwind LISTING 6 HTTPRequest Log in Extended Log File Format hpsupp.6000 32768 0 8760 0 0 0 LISTEN 0 0 *.* *.* 0 0 0 0 LISTEN *.* 0 0 0 0 LISTEN 0 LISTEN 0 0 0 *.* otter.44460 24820 0 8760 0 LISTING 4 IIOP Request Packet Issued from Client Application IIOP putMessage Hexadecimal [padding] (interpretation) ISO 8859-1 encoding putOctet < 47 (71) G putOctet < 49 (73) I putOctet < 4F (79) O putOctet < 50 (80) P . putOctet < 01 (1) . putOctet < 01 (1) putBoolean < 01 (TRUE) . . putOctet < 00 (0) 26 putULong < 00000000 (0) .... | GIOP version = 1.1 putMessage | flags = 1 (‘<’ little endian) | message type = 0 (Request) putRequest | service context length: putULong < 00000000 (0) .... | request id: putRequest putULong < 00000000 (0) .... | response expected: putRequest putBoolean < 01 (TRUE) . | reserved: putRequest . putOctet < 00 (0) putOctet < 00 (0) . . putOctet < 00 (0) putRequest | object key: putULong < 02000000 (2) .... putOctets < 4D00 M. putRequest | operation: putULong < 00000E000000 [2] (14) ...... putString < 63726561746553657373696F6E00 createSession. putRequest | requesting principal: putULong < 000000000000 [2] (0) ...... putRequest | request body: putULong < 09000000 (9) .... putString < 6A616761646D696E00 jagadmin. putULong < 00000007000000 [3] (7) ....... badpwd. putString < 62616470776400 endMessage | message size = 71 (after 12 byte header) PBDJ volume12 issue 2 #Version: 1.0 #Date: 2002-12-21 18:50:40 #Fields: s-ip date time cs-request cs-status cs-bytes cs(Cookie) cs(Referer) 199.95.51.242 2002-12-21 18:50:40 “GET /ir/CtsServlet.html HTTP/1.1” 200 318 - “ http://porkchop:8080/ir/index.html” 199.95.51.242 2002-12-21 18:50:43 “GET /ir/CtsServlet__ServletService.html HTTP/ 1.1” 200 436 - “http://porkchop:8080/ir/CtsServlet.html” 199.95.51.242 2002-12-21 18:50:49 “GET /ir/ CosTransactions.html HTTP/1.1” 200 43 6 - “http://porkchop:8080/ir/index.html” 199.95.51.242 2002-12-21 18:52:14 “GET /webapp/index.html HTTP/1.1” 404 369 - 199.95.51.242 2002-12-21 18:55:58 “GET /customer/index.jsp HTTP/1.1” 404 361 - DOWNLOAD THE CODE! www.sys-con.com/pbdj/ www.SYS-CON.COM/pbdj/ DROPDOWN FILTERING Dynamic Web Page Content WRITTEN BY RAHUL JAIN Without refreshing the page ropdown filtering is one of the most requested features in web applications and one of the seemingly more difficult tasks. There are many ways to provide dropdown filtering including retrieving all possible values and filtering on the client side with JavaScript as well as making round trips to the server to reload the page with a filtered dropdown. D AUTHOR BIO Rahul Jain is a distributed systems architect with Cynergy Systems (www.cynergysystems.com). He has more than eight years of experience building web, distributed and client-server applications using PowerBuilder, EAServer and EAF. 28 Here we will explore a more sophisticated approach that uses the XMLHttpRequest DOM object to retrieve the data from the server using XML and repopulate the dropdown without refreshing the page. Our main purpose is to show you how to use the XMLHttpRequest object. It’s more useful than just for dropdown filtering. It can, for instance, be used to validate the client-side data, get data dynamically and call Web Services. What is the XMLHttpRequest object? The XMLHttpRequest document is a client-side object that can process HTTP calls with any valid URL. Although it’s called the XMLHttpRequest object, it’s not limited to being used with XML, it can request or send any type of HTTP-compliant data using standard HTTP calls. What we basically do with this object is send data to the server side and get content back, all in the background. The data returned could be a simple string like “true” or a more complex XML document. The return could also be binary content, but that could be a little difficult to handle in JavaScript. Microsoft first implemented the XMLHttpRequest object in Internet Explorer 5 for Windows as an ActiveX object. Firefox and Safari also come with a native version of the object. 1. Create the object. 2. Make a request to the server page. 3. [optional] Check for errors. 4. [optional] Process the data returned. In Firefox and Safari you use this code instead: Take a look at the very simple script below: A call to the “open” function in line 2 opens the http request and specifies the information. The method signature is: 1 var xmlHttp = ActiveXObject ("Microsoft.XMLHTTP "); 2 xmlHttp.open (“GET”, “customerlist.jsp”, false); 3 xmlHttp.send (); 4 var returnValue = xmlHttp. responseText; The code on line 1 is creating the object. In Internet Explorer, you can create the object using a script depending on the version of MSXML installed. new ActiveXObject ("Msxml2.XMLHTTP") or new ActiveXObject ("Microsoft.XML HTTP") new XMLHttpRequest() Open (“method”, “URL”[, asyncFlag[, “username”[, “password”]]]) In this method we are telling the object the page name (URL), what method to use (GET/POST) and whether we want the call to be synchronous or asynchronous, true by default (more on this argument in a minute). We can optionally supply the username and password to be used for the call. The call to the “send” method in line 3 sends the http request to the server. Line 4 captures the data sent back from the server. Using the XMLHttpRequest object in JavaScript The script for using the object is simple. The following steps are involved: PBDJ volume12 issue 2 www.SYS-CON.COM/pbdj/ PBDJ ADVERTISER INDEX ADVERTISER URL PHONE PAGE Active Endpoints, Inc. www.active-endpoints.com 203-929-9400 2 Amyuni Technologies www.amyuni.com 866-926-9864 33 Assande www.assande.com ClearNova www.clearnova.com/thinkcap 770-442-8324 21 E.crane www.ecrane.com 603-226-4041 36 iAnywhere www.ianywhere.com 800-801-2069 35 IT Solutions Guide www.sys-con.com/IT 201-802-3020 23 PowerBuilder Developer's Journal www.sys-con.com/pbdj 201-802-3026 27 Sybase http://eshop.sybase.com/eshop 877-230-6771 11 Sybase www.sybase.com/pbextension 877-230-6771 13 Sybase www.sybase.com/powerbuilder 877-230-6771 5, 17 Sybase www.sybase-iad-services.com/30081a 877-230-6771 7 9 Advertiser is fully responsible for all financial liability and terms of the contract executed by their agents or agencies who are acting on behalf of the advertiser. This index is provided as an additional service to our readers. The publisher does not assume any liability for errors or omissions. www.SYS-CON.COM/pbdj/ PBDJ volume12 issue 2 29 Synchronous and Asynchronous Calls Method Description abort() Stops the current request getAllResponseHeaders() Returns complete set of headers (labels and values) as a string getResponseHeader("headerLabel") Returns the string value of a single header label open("method", "URL"[, asyncFlag[, "userName"[, "password"]]]) Assigns destination URL, method, and other optional attributes of a pending request send(content) Transmits the request, optionally with postable string or DOM object data setRequestHeader("label", "value") Assigns a label/value pair to the header to be sent with a request 1 var xmlHttp = ActiveXObject ("Microsoft.XMLHTTP "); 2 xmlHttp.onreadystatechange = processCustomerList; 3 xmlHttp.open (“GET”, “customerlist.jsp”); 4 xmlHttp.send (); Line 2 in script above tells the object what to do when the call is completed. Now the question becomes how to make sure the call was successfully completed. Take a look at the script below to get an idea. 1 function processCustomerList () { 2 if (xmlHttp.readyState == 4) { 3 if (xmlHttp.status == 200) { 4 // Process the list 5 }else{ 6 alert (“Problem occurred retrieving the Customer List.\n” + xmlHttp.statusText); 7 } 8 }10 } 9 PowerBuilder Makes It Easy With DataWindow’s XML feature, all we really need to do is send the XML content back. So the same DW that you’ve been using for dropdowns can now be used with various templates and sent back to the client. To be able to filter dropdowns dynamically, we will need a JSP to return the XML to the client side with the data and display values. So, to achieve this, create a JSP 30 Common XMLHttpRequest Object Methods An important though optional third parameter to the open method is a Boolean value that controls whether the upcoming transaction should be handled asynchronously. The default behavior (true) is to act asynchronously, which means that script processing carries on immediately after the send method is invoked, without waiting for a response. If you set this value to false, however, the script waits for the request to be sent and for a response to arrive from the server. While it might seem like a good idea to wait for a response before continuing processing, you run the risk of your script hanging if a network or server problem prevents the completion of the transaction. It’s safer to send asynchronously and design your code around the onreadystatechange event for the request object. The script below is an example of how to make an asynchronous call. PBDJ volume12 issue 2 Common XMLHttpRequest Object Properties Property Description onreadystatechange Event handler for an event that fires at every state change readyState Object status integer: 0 = uninitialized 1 = loading 2 = loaded 3 = interactive 4 = complete responseText String version of data returned from server process responseXML DOM-compatible document object of data returned from server process status Numeric code returned by server, such as 404 for "Not Found" or 200 for "OK" statusText String message accompanying the status code TABLE 1 | XMLHttpRequest Reference and call the PB component that would generate the XML from the DW. On the client side we will need to parse this XML and repopulate the dropdown. The responseXML property of the object can be used to get the XML that is returned by the server. To see a basic live example, please see this page: http://demos.cynerg y s y s t e m s. c o m / e a f e x a m p l e s / c u s tomerorder.jsp. This example is built using PB 10 abd EAF. As you can see, on this page we have a DW with two columns, Customer and Order. Order DDDW is filtered on change of Customer. In itemchanged event of the DW, we grab the customer ID and pass it to the order JSP via XMLHttpRequest and get the orders XML back, which is then parsed and populated in the order dropdown. ▼ References You might find following links useful for further reading: • Using the XML HTTP Request object: http://jibbering.com/2002/4/httpre- quest.html • Dynamic HTML and XML: The XMLHttpRequest Object: http://developer.apple.com/internet/webcontent/x mlhttpreq.html • How to Submit Form Data by Using XMLHTTP or ServerXMLHTTP Object: http://support.microsoft.com/default .aspx?scid=KB;ENUS;Q290591&ID=KB;EN-US;Q290591 • Get dynamic Web content with HTTPRequest: A refreshing approach to page refreshes: www106.ibm.com/developerworks/web/li brary/wa-httpget/ You also might want to read about how Google uses XMLHttpRequest object in its Gmail and Google Suggest applications. This link might help: • Chris Justus – Server Side Guy: “Google Suggest Dissected...”: http://serversideguy.blogspot.com/2004/12/googl e-suggest-dissected.html [email protected] www.SYS-CON.COM/pbdj/ Power Puzzle 1 2 3 4 5 6 7 8 9 10 11 12 13 15 14 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 Created with EclipseCrossword — www.eclipsecrossword.com Across––––––––––––––––––––––––-------------------------------------3. An _______ key is called this because there is intelligence behind the values assigned to the columns in the key. (Nicewarner) 4. Search path for Java classes to be bootstrapped before the built-in JRE classes (O’Neill) 7. A ________ in a document is used to distinguish between elements and attributes with the same name but belonging to different items. (Hefti) 8. Define the organization of applications with more than one element, where applications are located, background HTML code, and so on. (Hamboeck) 11. By default, a client attempts to connect five times with a delay of two seconds between attempts; therefore, a 57 error immediately returned to the client generally indicates that the server was located but that there was a problem _______the user’s credentials. (O’Neill) 12. PowerBuilder’s GetURL and PostURL functions, however, offer a mechanism to access EAServer servlets and JSPs via the ____ protocol. (O’Neill) 14. Technically, PBDOM is implemented as PBNI (PowerBuilder ______ Interface) extension that makes use of the Apache/Xerces DLL. (Hefti) 16. The one [new SOAP standard] of particular interest to PowerBuilder developers will be XOP (XML-binary _____ Packaging), a standard means of transmitting binary data via XML. (Armstrong) 18. The _______ property of the [XMLHTTPREQUEST] object can be used to get the XML that is returned by the server. (Jain) 20. Here we create user-defined hierarchies of content for display in an application. (Hamboeck) 25. The ____________ log provides a one-line summary of every URL accessed, the IP address of 32 PBDJ volume12 issue 2 Answers available online at www.sys-con.com/powerbuilderpuzzle the requesting client, the HTTP return code, and the number of bytes of data returned. (O’Neill) 26. ______ Data Stream (TDS) is Sybase’s proprietary protocol for communicating between Open Client and Open Server applications, such as Adaptive Server Enterprise. (O’Neill) 27. A ____ key is a column or columns that are chosen by the business to uniquely identify records, and are allowed by the data analyst because they are considered to be stable enough to become the primary identifier. (O’Neill) 29. As stated already, __________ tables typically use the combined keys of the parent tables as the primary key. (Nicewarner) 30. [When using the XMLHTTPREQUEST] It is safer to send asynchronously and design your code around the ________ event for the request object. (Jain) 31. The remedy for such errors [Java ClassCastException or ClassNotFoundException] is to ensure that all classes required by a component are loaded via _____ class loaders. (O’Neill) Down––––––––––––––––––––––––-------------------------------------1. A _______ key has no intelligence to the contents, and is typically assigned a value by the computer through some internal mechanism. (Nicewarner) 2. If you start the server as a service, only the JARs and ZIPs present in that directory when the service was installed are added to the __________. (O’Neill) 5. In EAServer 4.0 and later, a _______ and optional user_setenv command file accompany the serverstart script. (O’Neill) 6. The method ____ from the PBDOM_ Builder class reads and parses the XML Document. 9. Search path for native functions (in DLLs or shared objects) invoked by Java classes (O’Neill) 10. They are needed, for example, if we want to write a portlet’s content to a file, an e-mail message, or a database table. (Hamboeck) 13. Many internal workings of EAServer are handled via ________________ calls using IIOP-not to mention that a server may be handling many clients-so IIOP logging causes the EAServer log to grow very quickly. (O’Neill) 15. The default behavior [of the XMLHTTPREQUEST Open method] (true) is to act ___, which means that script processing carries on immediately after the send method is invoked. (Jain) 17. However some ______ may be tolerated because database engines aren’t perfect, and the complex joins might perform poorly. (Nicewarner) 19. The ______________ document is a client side object that can process HTTP calls with any valid URL (Jain) 21. A __________ key is a column or columns that are not defined by business requirements, but are added to a table simply to uniquely identify records. (Nicewarner) 22. PBDOM means PowerBuilder _________ Object Model (Hefti) 23. Establish a maximum limit for the number of _______ dependent tables. (Nicewarner) 24. ____________ table configurations are suited for natural keys. (Nicewarner) 28. The most common cause of this behavior [NetLib protocol driver error] is that another server instance is already running or that some other application has already claimed use of that ____. (O’Neill) www.SYS-CON.COM/pbdj/ PowerBuilder News All things of interest to the PB community BY BRUCE ARMSTRONG [email protected] Third-Party Tools PBmiqui announced the availability of several code samples, including a wrapper for the FreeImage DLL using PBNI, a multiselect DDLB, and Pbintelli, an expanded IntelliSense add-in for the PowerBuilder IDE, currently in beta. www.miqui.it/ DataWindow.Net DataWindow.Net is a nominee in the 2004 Best .NET Products of 2005 awards in the libraries and controls category. www.sys-con.com/dotnet/readerschoice2004 iAnywhere 2/14 – iAnywhere Solutions, a subsidiary of Sybase, announced that SQL Anywhere Studio powers innovative health care applications developed by MedicWare, MediNotes Corporation, Microlog, and Microsys Computing, Inc. SQL Anywhere Studio from iAnywhere helps vendors deliver cost-effective and quality health care solutions that enable organizations of any size to deliver timely access to critical patient information, streamline business processes, and reduce administrative costs. 01/25 – iAnywhere Solutions, a subsidiary of Sybase, announced that Relavis Corporation, a world leader in customer relationship management (CRM) solutions, has selected the iAnywhere Pylon 34 PBDJ volume12 issue 2 Application Server to power its soon-to-be released eSales Mobile application. Using Pylon Application Server, eSales Mobile will enable sales people to access key company information, track leads, update customer profiles and manage accounts through handheld devices. 01/17 – iAnywhere Solutions, a subsidiary of Sybase, announced that it was awarded two MobileTrax 2005 Mobility Awards. The company’s Answers Anywhere product was pocked as a winner in the “Software” category, while its April 2004 acquisition of XcelleNet also won in the “Mergers and Acquisitions” category. iAnywhere was the only software company to win in more than one category for the wellknown annual Mobility Awards. 01/11 – iAnywhere Solutions, a subsidiary of Sybase, launched the latest version of its AvantGo service, delivering superior features for managing and viewing mobile Internet content offline or online, anywhere at anytime. Enhanced capabilities allow for improved wireless synchronization, easier on-device web-channel management and expanded support for AvantGo users, resulting in a more robust online and offline user experience. Sybase Corporate 01/15 – Sybase reported total license revenues increased 7% for the fourth quarter ended December 31, 2004 compared with the same quarter the previous year. Total revenues for the quarter increased 4% to $218.6 million from $210.7 million for the fourth quarter of 2003. Adaptive Server Enterprise 2/15 – Sybase announced at LinuxWorld Conference & Expo the general availability of its relational database management system (RDBMS), Sybase Adaptive Server Enterprise (ASE) for Linux on IBM’s eServer OpenPower systems with complete support and consulting services from Sybase and IBM to support mission-critical applications. Sybase ASE for IBM’s eServer OpenPower systems offers the lowest total cost of ownership (TCO) of any enterprise database on Linux. Sybase and IBM will coordinate worldwide sales, marketing, and services responsibilities for the Linux platform, with a strong focus on offering solutions that meet the demanding requirements of the financial services sector. Recognized as a Linux database total cost of ownership (TCO) leader by The Standish Group, Sybase ASE was the first RDBMS ported to the Linux OS, and has garnered several prestigious awards, including LinuxWorld Magazine’s Readers’ Choice Award for “Best Linux Database.” 2/15 – Sybase announced that its enterprise class relational database Sybase ASE 12.5.2 has attained a security certification of level 4 (EAL4) from the International Common Criteria for Information Technology Security Evaluation, making it the most recent database offering in the industry to achieve this level of certification. This certification level, the highest achieved by general-purpose software, is evidence of Sybase ASE’s impressive security features such as SSL-protected com- munications and row-based access controls. The Common Criteria Certification is required by the United States Government before any IT products can be considered for purchase by government offices, departments, and other federally funded organizations. In addition, Common Criteria is an internationally recognized security evaluation required by numerous central governments worldwide for any of their departments interested in procuring commercially available products. Common Criteria certification also assures businesses of a standard measure of the security design of their computing products. 01/06 – Sybase announced that its enterprise-class relational database management system, Sybase Adaptive Server Enterprise (ASE) for Linux, won Open Source World’s Editor’s Choice Award for the “Best Linux Database.” Sybase ASE won the publication’s “Best SME Linux Package Award” with ASE for Linux and Turbolinux 7 Server at the same event in 2003. Through its outstanding product performance and after-sale services, Sybase ASE for Linux has gained widespread recognition. Events TechWave 2005 August 21-25 Caesar’s Palace Las Vegas, Nevada www.sybase.com/techwave www.SYS-CON.COM/pbdj/ Forget the wires. We know the ropes. Wondering how to get your Wi-Fi projects off the ground? We can show you how. We’re iAnywhere Solutions, the leading provider of solutions for the unwired enterprise. Emerging wireless technologies such as Wi-Fi now enable businesses to deliver a desktop computing experience to mobile workers. We have more than a decade of experience delivering "always available" access to corporate data and applications – keeping your mobile workers productive when they don’t have a wireless connection and providing information security and synchronization services when they enter a wireless LAN or hot spot. More than ten thousand companies and one thousand partners worldwide rely on mobile technology from iAnywhere Solutions. Let us show you the ropes to get your Wi-Fi solutions off the ground quickly. Call 1-800-801-2069 or visit www.ianywhere.com. Copyright 2003. iAnywhere Solutions, Inc. All rights reserved. iAnywhere is a trademark of Sybase, Inc. or its subsidiaries. All other trademarks are the property of their respective owners. www.ianywhere.com
Similar documents
Rules of Rules of - SYS
SUBSCRIPTIONS FOR SUBSCRIPTIONS AND REQUESTS FOR BULK ORDERS, PLEASE SEND YOUR LETTERS TO SUBSCRIPTION DEPARTMENT
More informationDeploying Applications and Components to .NET
Upgrades are provided only at regularly scheduled software release dates. No part of this publication may be reproduced, transmitted, or translated in any form or by any means, electronic, mechanic...
More informationPowerBuilder techniques
To order additional documents, U.S. and Canadian customers should call Customer Fulfillment at (800) 685-8225, fax (617) 229-9845. Customers in other countries with a U.S. license agreement may con...
More information