In tijden waar IT organisaties onder steeds grotere kostendruk komen te staan worden stijgende productiviteit en hergebruik een vereiste om aan de verwachtingen van de gebruikersorganisatie te kunnen voldoen. Hergebruik doelt in dit opzicht echter niet alleen op het al langer toegepaste hergebruik van individuele softwarecomponenten, maar ook op hele applicatiesystemen en uiteindelijk zelfs op degenen die deze ooit maakten: de legacy ontwikkelaars. In dit artikel wordt uiteengezet hoe IBM’s Rational Business Developer (RBD) met de Enterprise Generation Language (EGL) hierbij kan helpen.
Evolutie in de software-ontwikkeling
In de laatste decennia van de vorige eeuw zijn programmeertalen uitgegroeid tot volledige ontwikkelomgevingen, met codegeneratie, patterns, overerving en andere vormen van abstractie en hergebruik. Code werd steeds meer logisch van aard en geschreven door business developers in plaats van door technici op byte niveau. Vaak was de software gerelateerd aan een bepaald platform, of een bepaalde technische infrastructuur (Synon, client/server). Overgang van het ene platform naar het andere of toepassing van een andere infrastructuur was niet of slechts door conversie of herbouw mogelijk. Voordeel was dat er met de nieuwe tools steeds sneller ontwikkeld kon worden: het aantal uren per functiepunt ging steeds verder omlaag.
Halverwege de jaren ’90 begon de opmars van een nieuwe, object georiënteerde taal: Java. Door de platformonafhankelijkheid, een uitgebreide set libraries en de mogelijkheden om web applicaties te ontwikkelen werd de taal snel populair. Na verloop van tijd bleek echter dat Java grote problemen met zich mee bracht. Complexiteit van de taal en de libraries, het voor velen nieuwe object-oriëntatie concept, de steeds groter wordende hoeveelheid frameworks in allerlei versies en de samenwerking ertussen maakte de overstap voor zowel IT organisaties als de individuele – procedureel geschoolde – ontwikkelaar moeilijk. In veel gevallen zelfs onmogelijk.
Maar als ze nou Java zouden kunnen ontwikkelen zonder Java te kennen …
De gestegen productiviteit was door de overgang naar Java en de bijbehorende object-georiënteerde manier van programmeren ineens voor een deel verloren gegaan. Inmiddels is de productiviteit weer aan het groeien door strikter gebruik van frameworks en betere IDE’s, samen met aangepaste ontwikkelstraten en de uitstroom van een nieuwe generatie ontwikkelaars van de hogescholen en universiteiten die de nieuwe techniek met de paplepel ingegoten hebben gekregen.

Fig. 1: Productiviteitsverloop in de loop van de tijd
De vraag is echter of dit voldoende is. Bij veel bedrijven staan legacy systemen die al twee of meer decennia naar volle tevredenheid draaien en dermate groot en belangrijk zijn dat uitfasering nog lang op zich zal laten wachten. Herbouw of conversie is vaak geen optie door de enorme omvang. Daarnaast zijn er grote groepen ontwikkelaars van deze systemen die zich moeten richten op nieuwe uitdagingen. Voorbeelden hiervan zijn het toegankelijk maken van de legacy systemen voor andere toepassingen, zoals het web en uitwisseling van gegevens met derden via XML. Voor deze ontwikkelaars zal omscholing naar Java vanwege de complexiteit geen optie zijn, maar als ze nou Java zouden kunnen ontwikkelen zonder Java te kennen…
RBD met EGL: Java zonder Java
IBM heeft hiervoor sinds drie jaar een product, Rational Business Developer, kortweg RBD. Zoals de naam al doet vermoeden is dit product bedoeld om bedrijfskritische applicaties te laten ontwikkelen door mensen die business problemen oplossen en niet zozeer technische problemen. Zoals zoveel moderne IDE’s is RBD gebaseerd op het – oorspronkelijk door IBM ontwikkelde – Eclipse framework. Hierdoor wordt integratie met andere Eclipse gebaseerde tools ondersteund. Rational Business Developer biedt de mogelijkheid om vanuit een logische taal Java of COBOL code te genereren voor allerlei platforms. Denk hierbij aan webapplicaties die op een J2EE Application Server draaien (WebSphere, Tomcat, BEA), Windows en Linux (J2SE), de zSeries (mainframe) en de PowerSystems (voorheen i5, iSeries, AS/400).
Onderdeel van RBD is een generatietaal, de Enterprise Generation Language (EGL). Dit is een abstracte, declaratieve en procedurele taal die eenvoudig te leren is. Het leertraject is 1 tot 2 weken; na een maand is een ontwikkelaar volledig zelfstandig. Naast het feit dat EGL eenvoudig is en zoveel mogelijk de technologie verbergt, biedt het wel de ondersteuning die je van een moderne ontwikkeltaal mag verwachten. Zo kun je er allerlei soorten applicaties mee ontwikkelen (Web 1.0, Web 2.0, batch en SOA ondersteunende applicaties). Ook is er een geïntegreerde debugger. Als laatste redmiddel: als je er met EGL niet uitkomt, kun je altijd nog zelf Java of COBOL source code schrijven in zogenaamde external types en die zeer eenvoudig gebruiken vanuit EGL.
EGL in een notendop
Maar genoeg inleidende marketingpraat, laten we naar de opzet van EGL kijken. De beschrijving van de IDE laten we hier achterwege omwille van de ruimte. Iedereen (zeker hier?) die wel eens met een op Eclipse gebaseerde omgeving heeft gewerkt kent de werkwijze, met workspaces, projecten, packages, source objecten, perspectives en views.
Om de omvang van het artikel te beperken zullen we ons verder hier vooral richten op het maken van webapplicaties, dus het genereren van J2EE code in combinatie met Java Server Pages (JSP’s) op een Application Server. Genereren van COBOL of het aanroepen van bestaande legacy applicaties is in de praktijk wel belangrijk, maar zal wellicht op een later moment worden besproken.
EGL bestaat in de basis uit verschillende soorten source files. Deze hebben de extensie .egl en kunnen worden onderverdeeld in:
- Programs – losstaande programma’s met een enkel entry point;
- Libraries – groepen van programma’s in één file, dus meerdere entry points;
- Services – groepen van operations in één (web) service, meerdere entry points;
- JSFHandlers – event handling programma behorend bij een Java Server Page;
- BIRTHandlers – event handling programma behorend bij een BIRT report;
- BuildFiles – configuratiefile om instellingen vast te leggen voor het genereren van code (doelplatform, database, etc.).
De source files worden in een logische structuur onderverdeeld in packages en hebben binnen een package een unieke naam. Vanuit deze EGL source files worden Java source files gegenereerd, die op hun beurt door Eclipse worden gecompileerd tot Java class files.
EGL sources zijn op een bepaalde manier opgebouwd, afhankelijk van het soort source. Als voorbeeld is in listing 1 de code van een programma om een record uit de Customer tabel op te halen afgebeeld.
package programs;
import egldemo.StatusRec;
import egldemo.access.CustomerLib;
import egldemo.data.Customer;
// basic called program
//
program myProgram type BasicProgram(customerID string,
customerRecord Customer) {}
// Variable Declarations
status StatusRec;
function main()
customerRecord.CUSTOMER_ID = customerID;
CustomerLib.GetCustomer(customerRecord, status);
if(!status.succeeded)
SysLib.writeStderr("Error fetching record!");
end
end
end
Listing 1: Een eenvoudig EGL programma om een record op te halen
Voor de Java kenners onder ons zal de structuur bekend voorkomen. Er zitten dan ook aardig wat overeenkomsten tussen Java en EGL voor wat betreft opbouw van sources. Maar ook voor een procedurele programmeur is de source goed leesbaar. Voor de verduidelijking lopen we de statements door vanaf het begin:
- Package – geeft aan waar in de hiërarchische structuur van folders deze source staat;
- Import statements – zorgen ervoor dat in het programma gebruikte objecten die niet in dezelfde package staan kunnen worden gevonden;
- Program – dit is de definitie van het programma, met het interface (een veld customerID en een record van het type Customer, beide zowel in- als output);
- Status – een variabele-definitie, waarbij status wordt gedefinieerd als zijnde van het type StatusRec (een record);
- Function main() – het entry point van het programma.
Binnen het main() entry point wordt de eigenlijke code geprogrammeerd. In dit geval wordt in het customerRecord het veld CUSTOMER_ID gevuld met het customerID dat via de call binnenkomt. Daarna wordt een functie GetCustomer aangeroepen in een library CustomerLib (hierover later meer). Het customerRecord is een dual parameter, waar dus het CUSTOMER_ID gevuld is. Als er een record voor dit CUSTOMER_ID bestaat, zal een volledig gevuld customerRecord worden geretourneerd. Het status record zal na de aanroep van de GetCustomer functie informatie bevatten of het aangeroepen programma succesvol is verlopen. Binnen het status record bevindt zich een boolean veld, succeeded. Als dit niet true is wordt een melding naar de console gestuurd via de ingebouwde EGL functie SysLib.writeStderr. Daarna eindigt het programma.
Aan dit voorbeeld is te zien hoe eenvoudig EGL source in elkaar zit. De in EGL ingebouwde content assist, waarbij slechts delen van een statement hoeven te worden ingevuld waarna EGL zelf de statements aanvult, helpt enorm bij het snel programmeren. Om b.v. het statement CustomerLib.GetCustomer(…) in te voeren geeft de programmeur eerst een aantal beginletters in, bijvoorbeeld Cust, en drukt dan CTRL-spatie. Uit de lijst die dan wordt getoond kan CustomerLib worden gekozen.

Fig. 2: Content assist
Na het kiezen van de CustomerLib library geeft de programmeur een
punt (.) in en drukt weer CTRL-spatie. Nu toont EGL alle functies die in de betreffende library beschikbaar zijn en kan hieruit een keuze worden gemaakt. Door beginletters in te geven kan de subset worden verkleind.
Door het veelvuldig gebruik van content assist kan met grotere snelheid worden geprogrammeerd en worden fouten voorkomen.
Erg krachtig is de manier waarop database-definities kunnen worden geïmporteerd
Data access
Erg belangrijk in een bedrijfsapplicatie is bijna altijd het benaderen van databases. EGL doet dit met SQL via JDBC. In principe is iedere database te gebruiken die een JDBC driver heeft. Erg krachtig is de manier waarop database-definities kunnen worden geïmporteerd, waarna automatisch libraries worden gegenereerd om de data in de betreffende database te kunnen benaderen. Nieuwe databases en tabellen kunnen worden gemaakt in de zogenaamde Data Perspective. Er kunnen dus zowel bestaande als nieuwe databases worden gebruikt.
De database-import gebeurt met behulp van de Data Access Application Wizard. Deze wizard geeft de ontwikkelaar in achtereenvolgende stappen de mogelijkheid om:
- De database te selecteren;
- Al dan niet een filter te leggen op een bepaald schema in die database;
- Tabellen te selecteren;
- Eventueel wijzigingen aan te brengen in de sleuteldefinities die door EGL zullen worden gebruikt;
- Eventueel ervoor te kiezen dat er na de import ook standaard JSP’s worden aangemaakt om de data in de database te bewerken.
Na de import heeft EGL de volgende packages met daarin EGL source objecten aangemaakt (zie figuur 3):
- Package egldemo.primitivetypes.data: bevat veldtypen die worden gebruikt;
- Package egldemo.data: bevat record definities van de tabellen;
- Package egldemo.access: bevat libraries die voor de database-toegang zorgen.
De sources in deze packages maken gebruik van elkaar. Zo zijn record-definities van tabellen samengesteld uit veldtypen in de primitivetypes package. De libraries met database-toegang uit de access package maken weer gebruik van de record-definities uit de data package.

Fig. 3: Objecten aangemaakt door de database-import
Zoals eerder gezegd verbergt EGL technische details waar mogelijk voor de ontwikkelaar. Een mooi voorbeeld daarvan is het commando om een record op te halen. Eerder in dit artikel gebruikten we de CustomerLib.GetCustomer functie om een record op te halen. Deze functie bekijken wij nu door de CustomerLib library te openen en naar de functie te scrollen. Een makkelijker alternatief hiervoor is om op het CustomerLib.GetCustomer statement te gaan staan en F3 te drukken. EGL toont dan de functie in een nieuwe editor. Met behulp van deze functionaliteit is het dus erg eenvoudig om objecten binnen de applicatie te vinden.
Listing 2 toont de GetCustomer functie.
Function GetCustomer(searchRecord Customer inout,
status StatusRec)
try
get searchRecord with
#sql{…
};
if (SysVar.sqlData.sqlCode == 100)
HandleDBRecordNotFound(status, "CUSTOMER");
else
HandleSuccess(status);
end
SysLib.commit();
onException (exception SQLException)
HandleException(status, exception);
end
end
Listing 2: de GetCustomer functie
We zien de functiedefinitie met parameter-interface en allerlei logica om af te handelen wat er moet gebeuren als iets fout gaat bij het ophalen van het record. Wat we ook zien is dat er één enkel statement is dat voor het lezen van het record zorgt: get searchRecord. Dit is een zogenaamd impliciet EGL statement, waaronder de eigenlijke SQL code is verborgen. Doordat searchRecord van het type Customer is, weet EGL dat een Customer record moet worden opgehaald. Naast ‘get’ zijn er de keywords ‘add’, ‘delete’ en ‘replace’, voor respectievelijk het toevoegen, verwijderen en wijzigen van records.
We kunnen het SQL-statement zichtbaar maken door met rechts op het impliciete statement te klikken en Add te kiezen. EGL voegt dan de volledige syntax in, zoals te zien is in listing 3.
Function GetCustomer(searchRecord Customer inout,
status StatusRec)
try
get searchRecord with
#sql{
select
CUSTOMER.CUSTOMER_ID, CUSTOMER.FIRST_NAME,
CUSTOMER.LAST_NAME, CUSTOMER.PASSWORD,
CUSTOMER.PHONE, CUSTOMER.EMAIL_ADDRESS,
CUSTOMER.STREET, CUSTOMER.APARTMENT,
CUSTOMER.CITY, CUSTOMER."STATE",
CUSTOMER.POSTALCODE, CUSTOMER.DIRECTIONS
from CUSTOMER
where
CUSTOMER.CUSTOMER_ID = :SEARCHRECORD.CUSTOMER_ID
};
if (SysVar.sqlData.sqlCode == 100)
HandleDBRecordNotFound(status, "CUSTOMER");
else
HandleSuccess(status);
end
SysLib.commit();
onException (exception SQLException)
HandleException(status, exception);
end
end
Listing 3: Impliciet SQL statement volledig getoond
We zien het SQL-statement dat wordt gebruikt om het record op te halen. Het expliciet maken van een SQL-statement heeft natuurlijk alleen nut als we er iets aan willen veranderen. Op die manier kan een record op een andere manier worden opgehaald door een kopie van de GetCustomer functie te maken, een andere naam te geven en in die kopie het SQL statement aan te passen.
Overigens kunnen aangepaste definities eenvoudig worden veiliggesteld, zodat ze bij een nieuwe import van de database niet worden overschreven. Hiervoor is een speciale plek gereserveerd in iedere library.
Het importeren van database-definities maakt het mogelijk om vanuit EGL bestaande databases te benaderen. De manier van werken met database libraries die de toegang verzorgen en de techniek verbergen houdt daarbij de programmatuur erg overzichtelijk.
Webservices
EGL ondersteunt zowel het publiceren als het consumeren van (web)services. Ook dit gebeurt op een abstracte manier, waarbij de techniek zoveel mogelijk wordt verborgen. Als eerste zullen we kijken naar het produceren van een webservice.
EGL ondersteunt zowel het publiceren als het consumeren van (web)services
Zoals we eerder zagen is er een source type Service. Met behulp van een wizard maken we een nieuwe service, MyService.egl. We geven daarbij aan dat dit een webservice moet worden, waardoor EGL op de achtergrond allerlei zaken voor ons regelt. In de service voegen we een operatie toe die twee getallen bij elkaar optelt en het resultaat teruggeeft (zie listing 4). Merk op dat door middel van de keywords ‘in’ en ‘out’ kan worden aangegeven wat in- en output-parameters zijn. Daarnaast is er een keyword ‘inout’, dat aangeeft dat een parameter zowel in- als output is. Het gebruik ervan is echter triviaal, omdat parameters in EGL standaard al zo worden gegenereerd.
package services;
service MyService
function myOperation(number1 int in, number2 int in,
result int out)
result = number1 + number2;
end
end
Listing 4: Een eenvoudige webservice
Om de webservice te kunnen publiceren moeten we nu nog een zogenaamd WSDL-file maken. Deze bevat de locatie en het interface, waardoor derden de webservice kunnen aanroepen. Dit doen we eenvoudigweg door met rechts op de service te klikken en te kiezen voor Generate WSDL File. Via een wizard, waarin bijvoorbeeld de poort en server locatie voor de webservice kunnen worden ingevuld, maken we het WSDL-file aan. Zie als resultaat de (grafische weergave van) het WSDL-file in figuur 4. In dit geval hebben we als server localhost ingevuld met poort 9080.

Fig. 4: WSDL-file
We kunnen deze webservice nu gebruiken vanuit andere software die webservices kan consumeren. Om te laten zien hoe we dit in EGL doen zullen we een webpagina maken die onze service gebruikt. Tevens wordt dan duidelijk hoe we een webpagina met bijbehorende eventhandler (JSFHandler) maken.
Als eerste klikken we met rechts op het WSDL-file en kiezen Create EGL Client Interface. Dit zorgt ervoor dat er een EGL-library wordt aangemaakt die de toegang tot de webservice verzorgt.
Met behulp van een wizard (New -> Web page) maken we een nieuwe JSP aan, callWS.jsp. Deze opent leeg in een nieuwe editor. Vanuit de palette, een view met componenten die we op de pagina kunnen toevoegen, kiezen we EGL->Service en slepen dit op de pagina (zie figuur 5).

Fig. 5: Aanmaken van de servicedefinities op een JSP
We kiezen uit een lijstje van beschikbare services onze MyService service. Dit zorgt ervoor dat definities voor zowel het parameter-interface van de webservice als de functie om de webservice aan te roepen worden aangemaakt.
Door met rechts op de pagina te klikken kiezen we Edit Page Code. Hierdoor opent de JSFHandler, dus de EGL eventhandler die bij de pagina hoort. We zien dat de code om de webservice aan te roepen al voor ons is ingevoegd doordat wij het service-component op de JSP hebben geplaatst. De code staat in listing 5.
package jsfhandlers;
import com.ibm.egl.jsf.*;
import services.MyService;
handler callWS type JSFHandler
{onConstructionFunction = onConstruction,
onPrerenderFunction = onPrerender,
view = "callWS.jsp",
viewRootVar = viewRoot}
viewRoot UIViewRoot;
number1 int;
number2 int;
result int;
// Function Declarations
function onConstruction()
end
function onPrerender()
end
function callWebService()
myService MyService {@bindService};
myService.myOperation(number1, number2, result);
end
end
Listing 5: Aanroep van een webservice vanuit een JSFHandler
Naast de standaard code zoals die in een nieuwe JSFHandler automatisch staat is het volgende toegevoegd:
- Drie variabele-definities type int voor de velden number1, number2 en result;
- Een functie callWebService.
In die laatste functie wordt eerst een locaal object myService aangemaakt. Dit is van het type MyService, dus het client-interface die de webservice kan aanroepen. Daarna wordt de operatie myOperation van de webservice aangeroepen, met de parameters die eerder als variabelen zijn gedefinieerd.
Nu willen we in de JSP zorgen dat we de variabelen kunnen vullen en de callWebService functie kunnen aanroepen. Hiervoor gaan we terug naar de JSP en slepen uit de Page Data view (zie figuur 6 links onderin) de betreffende velden op de JSP. Wederom wordt een wizard gestart die ons vraagt wat voor velden (input of output, in ons geval input) dit moeten worden, waarna automatisch JSF componenten voor de velden op de pagina worden geplaatst. Daarnaast wordt meteen (naar keuze) een button op het scherm gezet.

Fig. 6: Opmaken van een JSP
Op deze manier hebben we onze variabelen als invoervelden op het scherm geplaatst, waarbij ook meteen de binding (de koppeling tussen de JSF-componenten en de EGL-variabelen) is geregeld.
Nu willen we er nog voor zorgen dat de functie callWebService wordt aangeroepen als we op de Calculate button klikken. Dit doen we door de callWebService() functie, die in de Page Data view links onderin onder Actions staat, op de button te slepen. Hierdoor ontstaat een binding tussen de button en de functie.
Als we nu de JSP opstarten op onze Application Server (die onderdeel is van de ontwikkelomgeving), dan kunnen we getallen invullen en de berekening uitvoeren.

Fig. 7: Aanroep van de service vanuit een webpagina
AJAX, RichUI en Web 2.0
Naast de hier genoemde functionaliteit biedt EGL nog ondersteuning voor andere moderne technieken, zoals AJAX en Rich User Interfaces (RichUI) door middel van JavaScript-generatie en DOJO/Silverlight-widgets. Hiermee zijn o.a. mashups mogelijk om informatie uit verschillende bronnen te combineren. Hieraan wordt vaak gerefereerd met de term Web 2.0.
EGL biedt ook ondersteuning voor andere moderne technieken als AJAX en Rich User Interfaces
Conclusie
Met de Rational Business Developer en EGL heeft IBM een product dat het voor de klassieke ontwikkelaar mogelijk maakt om de nieuwe wereld van Java- en web-applicaties te betreden. Kennis van Java is in beperkte mate wenselijk, namelijk voor foutopsporing of het maken van zogenaamde external types, dus stukjes Java source code om eventuele extra ondersteuning te bieden waar EGL dit (nog) niet kan. In een team zal het vaak voldoende zijn om één iemand op te nemen die deze kennis heeft.
Op een zeer eenvoudige manier kan een bestaande database-definitie worden ingelezen en kan de database daarna worden benaderd. Ook webservices kunnen makkelijk worden geproduceerd en geconsumeerd. Daarnaast worden steeds nieuwe technieken toegevoegd aan het product, zoals recentelijk Rich User Interfaces. Hierbij wordt in plaats van Java Server Pages JavaScript gegenereerd om webapplicaties te bouwen met processing in de browser.
Voor ontwikkelaars die al bekend zijn met de Java-wereld kan EGL ook perspectieven bieden. Het bouwen van bedrijfskritische applicaties is veel eenvoudiger en er kan sneller resultaat worden geboekt, al zitten er aan een generatie-tool altijd beperkingen waar een Java-ontwikkelaar zich snel aan zal storen.