iRUI - The Rich Client and i iRUI - The Rich Client and i Pluta - - PowerPoint PPT Presentation
iRUI - The Rich Client and i iRUI - The Rich Client and i Pluta - - PowerPoint PPT Presentation
iRUI - The Rich Client and i iRUI - The Rich Client and i Pluta Brothers Design, Inc. Joe Pluta Agenda Who is PBD? Multi-Tiered Application Design The Tiers of a Rich Client The Messages Creating a Business Logic Library Function Creating
Pluta Brothers Design, Inc. http://www.plutabrothers.com Page 2 joepluta@plutabrothers.com
Agenda
Who is PBD? Multi-Tiered Application Design The Tiers of a Rich Client The Messages Creating a Business Logic Library Function Creating a Client Connecting to ILE Code Advanced Concepts
Pluta Brothers Design, Inc. http://www.plutabrothers.com Page 3 joepluta@plutabrothers.com
Who is PBD?
In business since 1998
Devoted to application modernization through industry standards
using IBM tooling Products
CPYSPLFPDF - The first commercial Java-based product for the i
family
PSC/400 - The first tool to completely replace the display file with
servlets and JSPs Services
Training, mentoring, consulting Specializing in proofs of concept
Pluta Brothers Design, Inc. http://www.plutabrothers.com Page 4 joepluta@plutabrothers.com
Who is PBD?
Started building open source and commercial solutions
for Java-based modernization in 1999
Early adopter of Visual Age for Java, Eclipse, and
WDSC ("wrote the book" on the latter two)
Started writing about EGL in 2005 Began pushing the multi-tiered EGL/RPG concept in
2006
Advocate EGL as the primary interface to the i Gave the first hands-on lab for EGL at an i-related
conference
Pluta Brothers Design, Inc. http://www.plutabrothers.com Page 5 joepluta@plutabrothers.com
Who is PBD?
Articles, sessions, labs Wrote the business logic for the first public EGL
application, the scheduling application for the Rational Software Developer Conference
This was a unique accomplishment, since it used the
Rich UI in conjunction with an i back end
Working with a large i ISV to web enable their product
line using thin client EGL to access their existing back end logic
Blog - "EGL and i" on EGL Cafe Rich UI book coming out Real Soon Now
Pluta Brothers Design, Inc. http://www.plutabrothers.com Page 6 joepluta@plutabrothers.com
Multi-Tiered Application Design
Multi-Tiered Applications Thick Client 5250 - The original multi-tier Thin Client (Browser Based) Multi-Tiered Rich Internet Applications
Pluta Brothers Design, Inc. http://www.plutabrothers.com Page 7 joepluta@plutabrothers.com
Multi-Tiered Applications
User Interface Business Logic
Pluta Brothers Design, Inc. http://www.plutabrothers.com Page 8 joepluta@plutabrothers.com
Thick Client Applications
PC Host
Pluta Brothers Design, Inc. http://www.plutabrothers.com Page 9 joepluta@plutabrothers.com
5250-Based Applications
PC
5250 Emulation
i
Business Logic / Database
Pluta Brothers Design, Inc. http://www.plutabrothers.com Page 10 joepluta@plutabrothers.com
Thin Client Applications (Browser-Based)
PC
Browser
i
Web Application Server Business Logic / Database
Pluta Brothers Design, Inc. http://www.plutabrothers.com Page 11 joepluta@plutabrothers.com
Thin Client (JSF) in EGL
EGL Page Handler JSF Page EGL Library Function ILE Business Logic
Pluta Brothers Design, Inc. http://www.plutabrothers.com Page 12 joepluta@plutabrothers.com
Multi-Tiered Rich Internet Applications
Browser
JavaScript Interpreter
i
Web Application Server DOM (Web Page) Business Logic / Database
Pluta Brothers Design, Inc. http://www.plutabrothers.com Page 13 joepluta@plutabrothers.com
Rich Client with EGL
REST Service EGL Library Function ILE Business Logic The point here is that regardless of the interface, the business logic stays the
- same. And with the concept of a dynamic array of records, even the EGL library
function can remain the same, leaving only the interface to change, which is the ultimate goal of a UI independent application development environment. Web Service EGL Rich UI Application
Pluta Brothers Design, Inc. http://www.plutabrothers.com Page 14 joepluta@plutabrothers.com
Tiers of a Rich Client
Business Logic Service Layer Rich UI Tier Between these, you have messages
Pluta Brothers Design, Inc. http://www.plutabrothers.com Page 15 joepluta@plutabrothers.com
Business Logic
Two components First is the library function within EGL
Note: not necessarily a call to ILE!
It could be a call to SQL It could be a call to another service
In the iRUI architecture, it is a call to an ILE program
The other component of the business logic for iRUI is the code in the ILE program
Pluta Brothers Design, Inc. http://www.plutabrothers.com Page 16 joepluta@plutabrothers.com
Service Layer
Written entirely in EGL Runs in a web application server
WebSphere or Tomcat The web application server provides the infrastructure to support REST or SOAP services
The web application server can run on the i or not NOTE: The EGL portion of the business logic interface also runs in the web application server
Pluta Brothers Design, Inc. http://www.plutabrothers.com Page 17 joepluta@plutabrothers.com
Rich UI Tier
JavaScript Runs in the browser on the end user PC Responds to events from the user (keystrokes, button clicks, mouse movement) Calls logic on the host via services (REST or SOAP)
Pluta Brothers Design, Inc. http://www.plutabrothers.com Page 18 joepluta@plutabrothers.com
Business Logic Messaging
REST Service EGL Library Function ILE Business Logic Web Service EGL Rich UI Application SOAP/REST Flexible Records Fixed Records
Pluta Brothers Design, Inc. http://www.plutabrothers.com Page 19 joepluta@plutabrothers.com
Fixed vs. Flexible
Not a whole lot of differences Fixed records have fixed length fields
Used when calling ILE Map directly to data structures
Flexible records do not (especially character fields)
Better between EGL layers
Used to hide the complexities of service call formatting Can be translated easily to either XML or JSON
Pluta Brothers Design, Inc. http://www.plutabrothers.com Page 20 joepluta@plutabrothers.com
Simple vs. Composite
When talking to the host, use simple fixed records These are interchangeable with data structures When passing data between layers, however, you can use more complex data structures Let's take a look how this would map out
Pluta Brothers Design, Inc. http://www.plutabrothers.com Page 21 joepluta@plutabrothers.com
record DSOrderHeader{} 10 OrderNumber string(10); 10 CustomerNumber decimal(6,0); 10 CustomerName string(50); 10 ShippingAddr string(50); 10 Tax money(9,2); 10 Freight money(9,2); 10 Total money(9,2); end record DSOrderLine{} 10 ItemNumber string(15); 10 Description string(30); 10 Quantity decimal(9,2); 10 Price money(9,2); 10 Extended money(11,2); end
I use the prefix DS on these records to indicate clearly that they are data structures (fixed), not flexible records.
Pluta Brothers Design, Inc. http://www.plutabrothers.com Page 22 joepluta@plutabrothers.com
record OrderHeader{} OrderNumber string; CustomerNumber decimal(6,0); CustomerName string; ShippingAddr string; Tax money(9,2); Freight money(9,2); Total money(9,2); end record OrderLine{} ItemNumber string; Description string; Quantity decimal(9,2); Price money(9,2); Extended money(11,2); end record Order{} Header OrderHeader; Lines OrderLine[]; end
Note that in the flexible records strings have no lengths. Also, we see the concept of the Order, which is a composite.
Pluta Brothers Design, Inc. http://www.plutabrothers.com Page 23 joepluta@plutabrothers.com
Messaging Design Points
The primary message format is flexible
Composite flexible records are used between EGL functions Fixed is used only in the lowest level of the library functions to interface with the ILE programs
The functions that call ILE are responsible for reformatting and packaging the simple records into composites
Support may be added for "simplified" flexible records
Flexible records are directly supported by the service generation pieces (SOAP and REST)
Pluta Brothers Design, Inc. http://www.plutabrothers.com Page 24 joepluta@plutabrothers.com
Creating the Business Logic Function
Now that we've got the architecture in place, it's time to start cooking with gas First, create a dummy library function
Pluta Brothers Design, Inc. http://www.plutabrothers.com Page 25 joepluta@plutabrothers.com
Creating the Business Logic Function
Add some logic to create a dummy record
function getOrderLocal(orderNumber string in, order Order out) returns (Error)
- rder = new Order { Header = new OrderHeader {
OrderNumber = orderNumber, CustomerNumber = 789, CustomerName = "Pluta Brothers Design, Inc.", ShippingAddr = "542 E. Cunningham, Palatine, IL, 60074", Tax = 17.19, Freight = 14.95, Total = (17.19 + 14.95 + 4.32 + 23.95 + 9.45) }, Lines = [ new OrderLine { ItemNumber = "AS-1445", Description = "Squirt Guns", Quantity = 36, Price = .12, Extended = 4.32 }, new OrderLine { ItemNumber = "IIR-7728", Description = "Wading Pool", Quantity = 1, Price = 23.95, Extended = 23.95 }, new OrderLine { ItemNumber = "IIR-7243", Description = "Metal Ladder", Quantity = 1, Price = 9.45, Extended = 9.45 } ]}; return (null); end
Pluta Brothers Design, Inc. http://www.plutabrothers.com Page 26 joepluta@plutabrothers.com
Thin Client is Now Enabled
From this point forward, you can start developing thin client (JSF) applications The flexible record definitions can be used to build the screen By creating a library function (and not a service), the business logic is now available to the thin client
At this point, it takes just a few minutes to throw together a JSF interface A few minutes more, you add AJAX support
Pluta Brothers Design, Inc. http://www.plutabrothers.com Page 27 joepluta@plutabrothers.com
Create a Service
But we're here for the SOA piece, so let's get there First, create a service part
service OrderService function getOrder(orderNumber string in, order Order out) returns (Error) return ((OrderLib.getOrder(orderNumber, order))); end end
This is a proxy. Its purpose is to surface the library function as a service.
Pluta Brothers Design, Inc. http://www.plutabrothers.com Page 28 joepluta@plutabrothers.com
And Now We Generate a Service
That's all it takes. Done.
Pluta Brothers Design, Inc. http://www.plutabrothers.com Page 29 joepluta@plutabrothers.com
Creating the Rich UI
Rich UI is different than JSF For green screen veterans like me, it's different than just about anything we've ever done But it's not that bad; you build boxes
Pluta Brothers Design, Inc. http://www.plutabrothers.com Page 30 joepluta@plutabrothers.com
Creating the Rich UI
Boxes are like grids - you specify the number of columns, and then put components in the box and they get laid out in the columns
Components can be simple things like labels and text fields Complex things like grids Even other boxes
You can also create custom widgets that have their
- wn layout, and embed them
Pluta Brothers Design, Inc. http://www.plutabrothers.com Page 31 joepluta@plutabrothers.com
The Order Widget
Pluta Brothers Design, Inc. http://www.plutabrothers.com Page 32 joepluta@plutabrothers.com
The Order Widget
Three Boxes: Header Box Lines Box Totals Box
Pluta Brothers Design, Inc. http://www.plutabrothers.com Page 33 joepluta@plutabrothers.com
Crafting the UI
- rderBox Box {
columns = 1, paddingtop = 20, children = [ header, lines, totals] }; header Box = new Box { columns = 2, class = "header", children = [ new TextLabel { text = "Order Number", class = "prompt" }, new TextLabel { class = "value" }, new TextLabel { text = "Customer Number", class = "prompt" }, new TextLabel { class = "value" }, new TextLabel { text = "Customer Name", class = "prompt" }, new TextLabel { class = "value" } ] };
Pluta Brothers Design, Inc. http://www.plutabrothers.com Page 34 joepluta@plutabrothers.com
Crafting the UI (cont'd)
lines Grid { behaviors = [ GridBehaviors.alternatingColor, formatCells ], headerBehaviors = [ GridBehaviors.grayCells ], columns = [ new GridColumn{name = "ItemNumber", width = 90, displayName = "Item Number"}, new GridColumn{name = "Description", width = 170 }, new GridColumn{name = "Quantity", width = 70 }, new GridColumn{name = "Price", width = 80 }, new GridColumn{name = "Extended", width = 80 } ], data = (new any[]) }; totals Box = new Box { columns = 2, class = "totals", children = [ new TextLabel { text = "Tax", class = "prompt", width = 430 }, new TextLabel { class = "rvalue", width=80 }, new TextLabel { text = "Shipping and Handling", class = "prompt" }, new TextLabel { class = "rvalue" }, new TextLabel { text = "Order Total", class = "prompt" }, new TextLabel { class = "rvalue" } ] };
Pluta Brothers Design, Inc. http://www.plutabrothers.com Page 35 joepluta@plutabrothers.com
A Little Stylin'
<style type="text/css"> /* Standard overrides */ body { font-family: "Verdana"; } .prompt, .value, .rvalue { padding: 3px 10px 2px 10px } .header .prompt { text-align: left; background-color: blue; color: white; } .totals .prompt { text-align: right; } .rvalue, .right { text-align: right; } </style>
Pluta Brothers Design, Inc. http://www.plutabrothers.com Page 36 joepluta@plutabrothers.com
And a Little Gridwork
// Handle column formatting function formatCells( grid Grid in, cell Widget in, row any in, rowNumber int in, column GridColumn in) // Set attributes based on column name case when (column.name == "Quantity") html HTML = cell.children[1]; cell.class = "EglRuiGridCell right"; tf TextField = new TextField { text = html.text, width = 50, class = "right",
- nChange ::= updateQuantity };
tf.setAttribute("row", rowNumber); cell.children = [ tf ]; when (column.name == "Price" or column.name == "Extended") cell.class = "EglRuiGridCell right"; end end
Pluta Brothers Design, Inc. http://www.plutabrothers.com Page 37 joepluta@plutabrothers.com
The Magic (Info)Bus
function setId(ibmSrc string in) id = ibmSrc; InfoBus.subscribe(id, listener); end function listener(eventName String in, eventData any in) ibm = eventData; case when (ibm.action == "SHOW") showOrder(ibm.data); end end function sendResponse(action string in, data any in) InfoBus.publish(ibm.src, new InfobusMessage { src = id, action = action, data = data }); end
Pluta Brothers Design, Inc. http://www.plutabrothers.com Page 38 joepluta@plutabrothers.com
More on the Bus
MC Press Online just published an article today (Great timing, eh?) http://tinyurl.com/8jddd6 That's short for this: http://www.mcpressonline.com/programming/web- languages/rich-ui-unleashed.html
Pluta Brothers Design, Inc. http://www.plutabrothers.com Page 39 joepluta@plutabrothers.com
Install the Service
Generate a WSDL in the EGL project Copy the WSDL into the RUI project Right-click on the WSDL and generate the client interface
Pluta Brothers Design, Inc. http://www.plutabrothers.com Page 40 joepluta@plutabrothers.com
Invoking the Service
function showOrder(order string) InfoBus.publish(ibm.src, new InfobusMessage { action = "*STATUS", data = "Reading Order " :: order } ); OrderLib.getOrder(order, orderNotify); end // Remote functions function getOrderRemote(orderNumber string, orderNotify OrderNotify in)
- ncb = orderNotify;
- rderService OrderService { @WebBinding {
wsdlLocation="wsdl/OrderService.wsdl", wsdlPort = "OrderService", wsdlService = "OrderServiceService"}}; wOrder order; wError error; call orderService.getOrder(orderNumber, wOrder, wError returning to gORCallback; end function gORCallback(order Order in, error Error in)
- ncb(order, error);
end
Pluta Brothers Design, Inc. http://www.plutabrothers.com Page 41 joepluta@plutabrothers.com
Getting the Results
function orderNotify(orderIn Order in, error Error in) if (error != null and error.severity != 0) sendResponse("*STATUS", "Order Read Error[" :: error.severity :: "]:" :: error.message); else; (header.children[2] as TextLabel).text = order.Header.OrderNumber; (header.children[4] as TextLabel).text = order.Header.CustomerNumber; (header.children[6] as TextLabel).text = order.Header.CustomerName;
- rderLines.data = order.Lines as any[];
(totals.children[2] as TextLabel).text = order.Header.Tax; (totals.children[4] as TextLabel).text = order.Header.Freight; (totals.children[6] as TextLabel).text = order.Header.Total; (shipping.children[2] as TextLabel).text = order.Header.ShippingAddr; (shipping.children[2] as TextLabel).text = MyAddress; sendResponse("SHOW", orderBox); end end
Pluta Brothers Design, Inc. http://www.plutabrothers.com Page 42 joepluta@plutabrothers.com
Connecting Back to the i
function getOrderPgmCall(orderNumber string in, order Order out) returns (Error) control Control; line OrderLine; control.opcode = "H";
- rder.Header.OrderNumber = orderNumber;
call "ORDSVR" (control, order.Header, line); // Fill header control.opcode = "D"; call "ORDSVR" (control, order.Header, line); // First line while (control.retcode == "0")
- rder.Lines.appendElement(line);
call "ORDSVR" (control, order.Header, line); // Next line end end
Pluta Brothers Design, Inc. http://www.plutabrothers.com Page 43 joepluta@plutabrothers.com
The RPG Code
FORDHDR IF E K DISK FORDDTL IF E K DISK DdsCONTROL E DS QUALIFIED DdsORDHDR E DS QUALIFIED DdsORDDTL E DS QUALIFIED DORDSVR PR D P1 likeds(dsCONTROL) D P2 likeds(dsORDHDR) D P3 likeds(dsORDDTL) DORDSVR PI D P1 likeds(dsCONTROL) D P2 likeds(sdORDHDR) D P3 likeds(dsORDDTL) /free select; when P1.opcode = 'H'; chain P2.OHNUM ORDHDR dsORDHDR; P1.retcode = %found(ORDHDR); setll P2.OHNUM ORDDTL; when P1.opcode = 'D'; reade P2.OHNUM ORDDTL dsORDDTL; P1.retcode = %eof(ORDDTL); endsl; /end-free
Pluta Brothers Design, Inc. http://www.plutabrothers.com Page 44 joepluta@plutabrothers.com
Advanced Concepts
Encapsulation REST vs SOAP Extensions Debugging
Pluta Brothers Design, Inc. http://www.plutabrothers.com Page 45 joepluta@plutabrothers.com
Encapsulation
function getOrder(orderNumber string in, order Order out) returns (Error) case (access) when (Utility.ACCESS_LOCAL) return (getOrderLocal(orderNumber, order)); when (Utility.ACCESS_SQL) return (getOrderSql(orderNumber, order)); when (Utility.ACCESS_PGMCALL) return (getOrderPgmCall(orderNumber, order));
- therwise
return (Utility.Fatal("Invalid access " :: access)); end end
Pluta Brothers Design, Inc. http://www.plutabrothers.com Page 46 joepluta@plutabrothers.com
REST vs. SOAP
ios com.pbd.svc.IOrderService { @RESTBinding {baseURI = "http://localhost:9081/iEGL/restservices/OrderService"}};
- rder com.pbd.data.Order;
call ios.getOrder(orderNumber, order) returning to gORCallBack
- nException ServiceLib.serviceExceptionHandler;
Pluta Brothers Design, Inc. http://www.plutabrothers.com Page 47 joepluta@plutabrothers.com
Extensions
ExternalType Fmt type JavaScriptObject { relativePath = "com/pbd/util", javaScriptName = "Fmt" } function getNow() returns (string); end egl.defineClass('com.pbd.util', 'Fmt', // this class { "constructor" : function() { this.ms = new Date().getTime(); }, "getNow" : function( ) { function two(x) {return ((x>9)?"":"0")+x} function three(x) {return ((x>99)?"":"0")+((x>9)?"":"0")+x} var sec = Math.floor(this.ms/1000); var msec = this.ms % 1000; var min = Math.floor(sec/60); sec = sec % 60; var hr = Math.floor(min/60); min = min % 60; hr = (hr + 18) % 24; return (two(hr) + ":" + two(min) + ":" + two(sec) + "." + three(msec)); }});
Pluta Brothers Design, Inc. http://www.plutabrothers.com Page 48 joepluta@plutabrothers.com
Debugging
EGL-level debugging Java debugging Console logging Web service explorer Chris Laffra's service monitor Service Entry Points (SEPs)
Pluta Brothers Design, Inc. http://www.plutabrothers.com Page 49 joepluta@plutabrothers.com