Download
slide1 n.
Skip this Video
Loading SlideShow in 5 Seconds..
Peter van Dam PowerPoint Presentation
Download Presentation
Peter van Dam

Peter van Dam

110 Views Download Presentation
Download Presentation

Peter van Dam

- - - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - - -
Presentation Transcript

  1. Dynamic WebClient Programming Peter van Dam

  2. Peter van Dam • Progress fanatic since 1985 • Version 3-4-5-6-7-8-9 • CHUI-GUI-Batch-WebSpeed-WebClient • Founder of www.v9stuff.com • Author in Progressions & user group magazines • Founder of www.netsetup.nl

  3. Dynamic WebClient Programming • Dynamic Windows, Frames & Widgets • Dynamic Browses • Dynamic Buffers & Queries • Dynamic Temp-Tables • Objects, Handles, Methods & Attributes • AppServers • WebClient

  4. What is WebClient? WebClient = runtime – db connect

  5. WebClient = runtime – db connect DB AppServer • Need AppServer to talk to a database • Separate User Interface from Business Logic

  6. Internet orIntranet Run Progress over inter/intranet • Full GUI capabilities on end user PC • WebClient does NOT run in browser DB AppServer

  7. Prepare your application • No database connects from the client • Port your application to AppServer • User Interface runs on client • Business Logic runs on server • Client issues AppServer calls • ADM II offers these capabilities

  8. Consider the following window

  9. Window architecture • Built in ADM II • SDO, SmartDataBrowser, SmartDataViewer, SmartPanel • Run with AppServer • RowsToBatch=100 • Nothing fancy (we’ll get to that later)

  10. Startup time 6 s (!) over 28k8

  11. Startup statistics • 198 KB of client-side r-code to start • 6 AppServer calls over internet • 117 KB of server-side r-code to start • 19 KB of data received • 100 rows cached on client

  12. After 100 rows • 4 AppServer calls • 18 KB of data received • 200 rows cached on client • Response time 4 seconds on 28k8

  13. Deployment • This screen compiles to 198 KB of client-side r-code • Remember, nothing fancy • Not a single bit of custom code • Imagine deploying an entire application…

  14. Deploying an application (I) • Consider an average application with 100 screens • Some screens are simpler • Many screens are more complex • Some screens are much more complex • Some objects are being reused

  15. Deploying an application (II) • A conservative guess: average screen size 250 KB of client side code • 100 x 250 KB = 25 MB • Not counting images, adm tree, support code etc. • Download times:28k8 modem: ~ 150 minsDual ISDN: ~ 34 mins

  16. Deploying an application (III) • Compressing .r code saves just 20 % • Initial deployment on CD possible (with WebClient image) • However, even small application updates turn into megabytes to deploy • Did we choose internet to limit deployment possibilities?

  17. Surely there is a better way?!?

  18. Three Golden Rules: • Reduce AppServer calls • Reduce network traffic • Reduce client .r code

  19. Consider this window again: What do we really really need?

  20. Apply the Golden Rules • A single AppServer call should do • Do not send all viewer properties for all records • Create windows dynamically

  21. A single AppServer call should do • All data for the entire window should be prepared on the server and returned in a single call • The server needs to know about the screen configuration • Describe screen definitions in a database (‘Repository’)

  22. Do not send unnecessary data • The browser shows just 3 fields • Fetch the viewer data only when needed • Activate a time delay when the user scrolls • The ideal call returns just a single packet (up to about 1,500 bytes)

  23. Do not send unnecessary data (2) Ask yourself: • Does the client REALLY need this information from the server? • Do I send information to the server that the server already knows?

  24. Do not send unnecessary data (3) • The browser shows just 3 fields • Fetch the viewer data only when needed • Activate a time delay when the user scrolls • A call should ideally return just a single packet (1500 bytes)

  25. 3: Create windows dynamically • Send repository data to the client • Client creates all screens dynamically • NO r-code deployment at all! • In V9.1 this is NOT fiction

  26. New startup statistics • Startup time 2 seconds on 28k8 • Client code always resides in memory • A single AppServer call • 41 KB of server-side r-code to start • 6 KB of data received • 100 rows cached on client

  27. Why do we show the first 100? • The example window shows the first 100 customers • What are the chances that this is useful? • The first thing the user probably will do is find the customer she needs • Why start with a useless data transfer?

  28. A new approach: start empty Let the user enter her selections first

  29. A new approach: start empty Transfer only what the user asks for

  30. Results for the new approach • 1 second response time on 28k8 for each user interaction • Just 2-3 KB received on each call • The application is now usable with a 28K8 modem and simply fast on anything better

  31. 9600 baudDemonstration

  32. How does it all work? • Write a generic ‘rendering’ program for the client (ui.p) • Introduce a repository • Write a generic program on the server that can merge repository information with data

  33. The Big Picture AppServer WebClient uihooks.p blhooks.p Repository ui.p bl.p Application data Application data Appserver boundary

  34. The implementation getscreen.p Repository ui.p save.p Application data Application data Delete.p Appserver boundary

  35. ui.p Creates: • Dynamic windows and dialogs • Dynamic field level widgets • Dynamic panels • Dynamic browsers And fills them with dynamic data from the server

  36. getscreen.p • Fetches screen description from repository • Creates dynamic database queries for each data set • Puts the results in dynamic temp-tables • Returns dynamic data and static screen description to client

  37. Dynamic Temp-Tables • New in Progress v9.1 • Created specifically for dynamically passing data from an AppServer to a WebClient • Create temp-table structures on the fly • Requires only run-time Progress

  38. Dynamic Temp-Tables (2) • Move data from getscreen.p to ui.p without knowing about db tables at compile time • Create in getscreen.p at runtime • Pass definitions & data to ui.p using new OUTPUT TABLE-HANDLE parameter

  39. Creating a Dynamic Temp-Table DEFINE VARIABLE hTemp as HANDLE NO-UNDO CREATE TEMP-TABLE hTemp ASSIGN hTemp:UNDO = FALSE. • Just like any dynamic widget • Now we have created an empty structure • Use methods to define the structure

  40. Dynamic Temp-Table Methods CREATE-LIKE ADD-FIELDS-FROM ADD-NEW-FIELD ADD-LIKE-FIELD ADD-LIKE-INDEX ADD-NEW-INDEX ADD-INDEX-FIELD

  41. Use ADD-NEW-FIELD • Most versatile • We may want to overrule some dictionary properties in the repository • We want to add some extra fields such as the database ROWID of a record • Check the return value for errors

  42. ADD-NEW-FIELD ADD-NEW-FIELD( field-name-exp, datatype-exp [ , extent-exp [ , format-exp [ , initial-exp [ , label-exp [ , column-label-exp ] ] ] ] ] )

  43. ADD-NEW-FIELD examples hTemp:ADD-NEW-FIELD ("rowid","rowid”). hTemp:ADD-NEW-FIELD (hField:NAME, /* from dd */ hField:DATA-TYPE, /* from dd */ hField:EXTENT, /* from dd */ repository.cFormat, repository.cInitial, repository.cSideLabel repository.cColumnLabel).

  44. Indexes • We do not need any indexes on these temp-tables • The client shows the records in the order in which they were created • Any server-side sorting included • Client may sort the records locally as well

  45. Prepare the Temp-Table • hTemp:TEMP-TABLE-PREPARE(<name>). • ‘Compiles’ the temp-table at run time • Check the return value for errors • Provide the name argument for debugging purposes • Now you can fill the new structure with data… dynamically

  46. Populate the Dynamic Temp-Table • We need a buffer handle for this: DEF VAR hDefault AS HANDLE NO-UNDO. hDefault = hTemp:DEFAULT-BUFFER-HANDLE. • But how do we get the data into the dynamic temp-table?

  47. Populate the dynamic temp-table • First we need to create a dynamic buffer for each database table involved in the query: DEF VAR cTable AS CHAR INITIAL “customer”. DEF VAR hData AS HANDLE NO-UNDO. CREATE BUFFER hData for table cTable.

  48. Populate the dynamic temp-table • Then we create a dynamic query: DEF VAR hQuery AS HANDLE NO-UNDO. CREATE QUERY hQuery. hQuery:ADD-BUFFER(hData). hQuery:QUERY-PREPARE(SUBSTITUTE( “FOR EACH &1 NO-LOCK”, cTable)).

  49. Populate the dynamic temp-table • Then we open the query and buffer-copy the data: hQuery:QUERY-OPEN(). hQuery:GET-FIRST(). DO WHILE hQuery:QUERY-OFF-END = FALSE: hDefault:BUFFER-CREATE(). hDefault:BUFFER-COPY(hData). hQuery:GET-NEXT(). END.

  50. Returning the dynamic temp-table • Don’t forget to fill the ROWID field as well • Maximize the number of records to be returned (e.g. 100 or even 50) • The new dynamic temp-table (meta schema + data) is returned to the client using OUTPUT PARAMETER TABLE-HANDLE • DELETE OBJECT hTemp. (never forget!) • Delete magically postponed by Progress