In diesem Thema wird ein Beispiel für die End-to-End-Verarbeitung erläutert. Als Back-End fungiert ein UI-Programm. Als Front-End fungiert eine Rich-UI-Anwendung, die ein Datengrid anzeigt. Hintergrundinformationen zu den beiden Technologien finden Sie in 'UI-Programm und Gateway-Service' und 'Rich-UI-Datengrid und Datengrid-QuickInfo'.
Anfängliche Darstellung der Rich-UI-Anwendung:

Kurzbeschreibung: Das Datenladeprogramm fordert eine erste Seite an. Das UI-Programm ruft die für alle Seiten erforderlichen Datensätze ab und gibt die Gesamtzahl zusammen mit den Datensätzen für die erste Seite zurück. Das Datenladeprogramm antwortet auf Benutzerklicks mit dem Aufruf des UI-Programms, um je nach Bedarf zusätzliche Seiten bereitzustellen. Wenn der Benutzer die letzte Seite anfordert, die zuvor noch nicht angezeigt wurde, fordert das Datenladeprogramm die Seitennummer -1 an, wodurch das UI-Programm beendet wird.
.EglRuiDataGridHeaderCell {
text-align: center;
}
Die Rich-UI-Anwendung muss erst dann im Zielprojekt implementiert werden, wenn alle Entwicklungsarbeiten abgeschlossen sind.
Für eine erfolgreiche Generierung müssen Sie angeben, dass die Builddeskriptoroption genProject das Zielprojekt referenziert. Stellen Sie ferner sicher, dass der Implementierungsdeskriptor über einen Eintrag zur Implementierung des Gateway-REST-Service verfügt und das Kontrollkästchen Mit Zustandsüberwachung (STATEFUL) auf der Registerkarte Web-Service-Implementierung aktiviert ist.
http://localhost:8080/MyTargetProject/MyRichUIHandler-en_US.html
Dies ist die richtige Adresse, wenn Sie das Projekt auf Ihrer Workstation implementieren, der Anwendungsserver für Port 8080 empfangsbereit ist, der Name des Zielprojekts MyTargetProject und der Name des Rich-UI-Handlers MyRichUIHandler lauten, und die HTML-Datei für die Ländereinstellung 'US English' konfiguriert ist.
Das Datenbankschema ist nur für ein Beispiel geeignet. Es liegen beispielsweise keine Integritätsbedingungen vor.
CREATE TABLE APP.CAR_MASTER
(
VIN CHAR(17) NOT NULL,
Make VARCHAR(15) NOT NULL,
Model VARCHAR(15) NOT NULL,
TheYear CHAR(4) NOT NULL
);
CREATE TABLE APP.CAR_PURCHASES
(
VIN CHAR(17) NOT NULL,
PURCHASE_DATE DATE NOT NULL,
COST DECIMAL(8,2) NOT NULL
);
CREATE TABLE APP.CAR_SALES
(
VIN CHAR(17) NOT NULL,
SALE_DATE DATE NOT NULL,
PRICE DECIMAL(8,2) NOT NULL
);
INSERT INTO APP.CAR_MASTER VALUES
( '11111111111111111', 'Honda', 'Accord', '1998'),
( '22222222222222222', 'Ford', 'Mustang', '2006'),
( '33333333333333333', 'Chevrolet', 'Camaro', '2010'),
( '44444444444444444', 'Toyota', 'RAV4', '2008'),
( '55555555555555555', 'Triumph', 'Spitfire', '1980'),
( '66666666666666666', 'BMW', '328XI', '2007'),
( '77777777777777777', 'Cadillac', 'Escalade', '2004'),
( '88888888888888888', 'Chrysler', 'Sebring', '2006'),
( '99999999999999999', 'Lexus', 'ES 300', '2009'),
( 'AAAAAAAAAAAAAAAAA', 'Honda', 'Civic', '2008'),
( 'BBBBBBBBBBBBBBBBB', 'Toyota', 'Celica', '2005');
INSERT INTO APP.CAR_PURCHASES VALUES
( '11111111111111111', '2004-06-15', 4000.00),
( '22222222222222222', '2008-07-26', 7200.00),
( '33333333333333333', '2010-11-11', 21000.00),
( '44444444444444444', '2009-02-02', 18000.00),
( '55555555555555555', '2007-01-04', 20500.00),
( '66666666666666666', '2010-08-08', 26900.00),
( '77777777777777777', '2010-04-04', 17200.00),
( '88888888888888888', '2009-11-06', 11400.00),
( '99999999999999999', '2009-12-07', 37000.00),
( 'AAAAAAAAAAAAAAAAA', '2010-11-12', 13000.00),
( 'BBBBBBBBBBBBBBBBB', '2008-03-03', 8300.00);
INSERT INTO APP.CAR_SALES VALUES
( '11111111111111111', '2004-11-18', 4800.00),
( '22222222222222222', '2009-01-12', 7000.00),
( '33333333333333333', '2010-11-14', 22000.00),
( '44444444444444444', '2009-02-03', 19200.00),
( '55555555555555555', '2007-02-18', 23500.00),
( '66666666666666666', '2010-09-20', 28000.00),
( '77777777777777777', '2010-05-06', 18500.00),
( '88888888888888888', '2009-11-06', 11400.00),
( '99999999999999999', '2010-02-07', 37200.00),
( 'AAAAAAAAAAAAAAAAA', '2010-11-16', 13800.00),
( 'BBBBBBBBBBBBBBBBB', '2008-04-05', 7400.00);
Im Folgenden ist ein Beispiel für ein UI-Programm aufgeführt:
package myPkg;
record CarStatus type SQLRecord {
tableNames =[["APP.CAR_MASTER", "A"],
["APP.CAR_PURCHASES", "B"],["APP.CAR_SALES", "C"]],
defaultSelectCondition =
#sqlCondition{ A.VIN = B.VIN AND A.VIN = C.VIN ORDER BY VIN},
keyItems =[VIN]}
VIN string{column = "A.VIN"};
MAKE string;
MODEL string;
YEAR string{column = "A.THEYEAR"};
PURCHASE_DATE date;
COST decimal(8, 2);
SALE_DATE date;
PRICE decimal(8, 2);
end
// initial page size from requester
Record PageSizeContainer
pageSize INT;
end
Record MyException type Exception end
Record SendListContainer
// number of available records
numberOfRecords INT;
pageNumber INT = 1;
sendList CarStatus[]{};
end
program MyUIProgram type UIProgram
{ inputUIRecord = myPageSizeContainer, segmented = true }
const MAXIMUM_DATABASE_ROWS INT = 100;
myPageSizeContainer PageSizeContainer;
function main()
tentativeCarListSize INT;
numberToSend INT;
numberOnLastPage INT;
sendCounter, startRowOnPage, endRowOnPage INT;
numberOfAvailablePages INT;
mySendListContainer SendListContainer;
myCarList CarStatus[]{};
i int;
if (myPageSizeContainer.pageSize <= 0)
throw new MyException{ message =
"Your page size is not valid. You requested " + numberToSend + "."};
end
tentativeCarListSize = getNumberofCars();
if (tentativeCarListSize > MAXIMUM_DATABASE_ROWS || tentativeCarListSize == 0)
throw new MyException{message =
"The number of available rows is not valid. Cannot return " +
tentativeCarListSize + " rows."};
end
// set up array with retrieved database rows.
try
get myCarList;
SQLLib.disconnect();
onException(except AnyException)
throw new MyException{message = "Problem in data access. "
+ except.message};
end
// no exception thrown if too many rows now
mySendListContainer.numberOfRecords = myCarList.getSize();
numberOfAvailablePages =
MathLib.Ceiling(mySendListContainer.numberOfRecords /
myPageSizeContainer.pageSize);
numberOnLastPage = mySendListContainer.numberOfRecords %
myPageSizeContainer.pageSize;
if (numberOnLastPage == 0)
numberOnLastPage = myPageSizeContainer.pageSize;
end
while (mySendListContainer.pageNumber != -1)
// set up array for the number of elements to send
if (mySendListContainer.pageNumber < numberOfAvailablePages)
numberToSend = myPageSizeContainer.pageSize;
else
numberToSend = numberOnLastPage; // last page
end
for (sendCounter from 1 to numberToSend)
mySendListContainer.sendList.appendElement(new CarStatus{});
end
// specify which database records to send
if (mySendListContainer.pageNumber == 1)
startRowOnPage = 1;
else
startRowOnPage = (mySendListContainer.pageNumber - 1) *
myPageSizeContainer.pageSize + 1;
end
if (mySendListContainer.pageNumber == numberOfAvailablePages )
endRowOnPage = startRowOnPage + numberOnLastPage - 1;
else
endRowOnPage = startRowOnPage + myPageSizeContainer.pageSize - 1;
end
// copy the database records to send
i = startRowOnPage;
for (n int from 1 to numberToSend)
mySendListContainer.sendList[n] = myCarList[i];
i = i + 1;
end
converse mySendListContainer;
mySendListContainer.sendList.removeAll();
end
end // end main()
function getNumberOfCars() returns(int)
numberOfRows INT;
countQuery STRING = "Select count(*) from APP.CAR_MASTER";
try
prepare myTest from countQuery;
get with myTest into numberOfRows;
onException(except AnyException)
throw new MyException{message =
"Problem in accessing the row count. " + except.message}; end
return(numberOfRows);
end
end
Im Folgenden ist ein Beispiel für eine Rich-UI-Anwendung aufgeführt:
package myRichUIPkg;
import com.ibm.egl.rui.widgets.DataGrid;
import com.ibm.egl.rui.widgets.DataGridColumn;
import com.ibm.egl.rui.widgets.DataGridLib;
import egl.ui.gateway.UIGatewayRecord;
record CarStatusBasic type SQLRecord
VIN string;
MAKE string;
MODEL string;
YEAR string;
PURCHASE_DATE date;
COST decimal(8, 2);
SALE_DATE date;
PRICE decimal(8, 2);
end
record PageSizeContainer
pageSize int;
end
// field names must match entries in the JSON string
record CarStatusBasicContainer
numberOfRecords int;
pageRequested int{JSONName = "pageNumber"} = 1;
sendList CarStatusBasic[]{};
end
handler MyRichUIHandler type RUIhandler
{initialUI =[grid], onConstructionFunction = start,
cssFile = "css/RichUIProject.css", title = "View Car Sales"}
grid DataGrid{pageSize = PAGE_SIZE, showButtonBar = true, style = "overflow:auto",
columns =[
new DataGridColumn{name = "VIN", displayName = "VIN", width = 135,
alignment = DataGridLib.ALIGN_CENTER},
new DataGridColumn{name = "MAKE", displayName = "Make",
alignment = DataGridLib.ALIGN_CENTER},
new DataGridColumn{name = "Model", displayName = "Model",
alignment = DataGridLib.ALIGN_CENTER},
new DataGridColumn{name = "Year", displayName = "Year",
alignment = DataGridLib.ALIGN_CENTER},
new DataGridColumn{name = "Purchase_Date", displayName = "Purchase Date",
alignment = DataGridLib.ALIGN_CENTER},
new DataGridColumn{name = "Cost", displayName = "Purchase Price",
alignment = DataGridLib.ALIGN_RIGHT, width=90},
new DataGridColumn{name = "Sale_Date", displayName = "Sale Date",
alignment = DataGridLib.ALIGN_CENTER},
new DataGridColumn{name = "Price", displayName = "Sale Price",
alignment = DataGridLib.ALIGN_RIGHT, width =80},
new DataGridColumn{name = "Profit", displayName = "Profit (Loss)",
formatters =[formatProfit], alignment = DataGridLib.ALIGN_RIGHT, width = 80}]};
const PAGE_SIZE int = 5;
myPageSizeContainer PageSizeContainer;
listContainer CarStatusBasicContainer{};
firstInvocation boolean;
gridDataList CarStatusBasic[1]{};
requestedPage int = 1;
pagesRequested boolean[]{};
handledEarlier boolean;
numberOfAvailablePages int;
gateRec UIGatewayRecord{};
allLoaded boolean;
gatewayServiceVar UIGatewayService{@BindService{bindingKey = "UIGatewayService"}};
function start()
gateRec.uiProgramName = "myPkg.MyUIProgram";
myPageSizeContainer.pageSize = PAGE_SIZE;
StrLib.defaultDateFormat = "yyyy-MM-dd";
pagesRequested.appendElement(false);
firstInvocation = true;
allLoaded = false;
// at this writing, sorting is available only when all the data is loaded
grid.enableSorting = false;
grid.dataLoader = myDataLoader;
grid.data = gridDataList as any[];
end
function formatProfit(class string inOut, value string inOut, rowData any in)
calculation decimal(8, 2) =
rowData.Price as decimal(8, 2) - rowData.Cost as decimal(8, 2);
if(calculation < 0)
calculation = -calculation;
value = "(" + calculation + ")";
else
value = calculation as string;
end
end
function myDataLoader(startRow int in, endRow int in, sortFieldName string in,
sortDirection int in) returns(boolean)
if(allLoaded)
return(true);
end
if(firstInvocation)
if(pagesRequested[1] == true)
handledEarlier = true;
else
handledEarlier = false;
pagesRequested[1] = true;
gateRec.data = ServiceLib.convertToJSON(myPageSizeContainer);
call gatewayServiceVar.invokeProgram(gateRec)
returning to callbackFunc onException handleException;
end
else
requestedPage = mathLib.ceiling(startRow /
myPageSizeContainer.pageSize);
if(pagesRequested[requestedPage] == true)
handledEarlier = true;
else
handledEarlier = false;
listContainer.pageRequested = requestedPage;
pagesRequested[requestedPage] = true;
gateRec.data = ServiceLib.convertToJSON(listContainer);
call gatewayServiceVar.invokeProgram(gateRec)
returning to callbackFunc onException handleException;
end
end
return(handledEarlier);
end
function callbackFunc(gatewayRecord uigatewayrecord in)
i, n, startUpdate, endUpdate int;
ServiceLib.convertFromJSON(gatewayRecord.data, listContainer);
numberOfReturns int = listContainer.sendList.getSize();
allLoaded = true;
// can set up the pagesRequested array only after learning
// the number of records available from the UI program
if(firstInvocation)
numberOfAvailablePages =
MathLib.Ceiling(listContainer.numberOfRecords /
myPageSizeContainer.pageSize);
if(numberOfAvailablePages > 1)
for(i from 2 to numberOfAvailablePages)
pagesRequested.appendElement(false);
end
end
// set up the data array for the grid
for(i from 2 to listContainer.numberOfRecords)
GridDataList.appendElement(new CarStatusBasic);
end
firstInvocation = false;
end
// end use of the UI program?
for(i from 1 to numberOfAvailablePages)
if(pagesRequested[i] == false)
allLoaded = false;
end
end
if(allLoaded)
grid.enableSorting = true;
listContainer.pageRequested = -1;
gatewayRecord.data = ServiceLib.convertToJSON(listContainer);
call gatewayServiceVar.invokeProgram(gatewayRecord)
returning to handleServiceEnd onException handleException;
end
// load data
if(requestedPage == 1)
for(i from 1 to numberOfReturns)
gridDataList[i] = listContainer.sendList[i];
end
else
startUpdate = (requestedPage - 1) * myPageSizeContainer.pageSize + 1;
endUpdate = startUpdate + numberOfReturns - 1;
n = 1;
for(i from startUpdate to endUpdate)
gridDataList[i] = listContainer.sendList[n];
n = n + 1;
end
end
grid.data = gridDataList as any[];
grid.render();
end
function handleException(exp AnyException in)
SysLib.writeStdOut(exp.message);
grid.cancelDataLoader();
end
function handleServiceEnd(gateRec uiGatewayRecord in)
if(!gateRec.terminated)
SysLib.writeStdOut("Error: The program is still running.");
grid.render();
end
end
end