22.11.2013 Views

Dankwoord - martes

Dankwoord - martes

Dankwoord - martes

SHOW MORE
SHOW LESS

Create successful ePaper yourself

Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.

<strong>Dankwoord</strong><br />

Ik wil alle mensen bedanken die rechtstreeks of onrechtstreeks hebben meegewerkt aan het tot<br />

stand brengen van deze thesis.<br />

In de eerste plaats gaat mijn dank naar mijn ouders die deze studies mogelijk gemaakt hebben.<br />

Daarnaast wil ik in het bijzonder mijn promotoren prof. dr. ir. Wouter Joosen en prof. dr.<br />

ir. Yolande Berbers en begeleiders Aram Hovsepyan en dr. Stefan Van Baelen bedanken. Ik<br />

mocht wekelijks langskomen om de evolutie van mijn thesis te bespreken. Aram en Stefan<br />

moedigden me aan waar nodig en stonden steeds klaar met goede raad. Ze zorgden ook voor<br />

het grondig nalezen van deze thesistekst.<br />

Ook wil ik Guy Pauwels en Michel Huybrechts van E2S bedanken.<br />

Nog vele anderen uit mijn omgeving verdienen mijn dank - mijn vrienden en vooral mijn<br />

vriendin voor de steun, interesse, hulp en suggesties die ze geboden heeft bij het maken van<br />

dit eindwerk.<br />

i


Inhoudsopgave<br />

1 Inleiding 1<br />

1.1 Situering . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1<br />

1.2 Probleem beschrijving . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3<br />

1.2.1 Wat is OCL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3<br />

1.3 Motivatie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4<br />

1.4 Doelstellingen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5<br />

1.5 Overzicht . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5<br />

2 State-of-the-art 7<br />

2.1 Evaluatiecriteria . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7<br />

2.1.1 Invarianten . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7<br />

2.1.2 Pre- en Postcondities . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8<br />

2.1.3 Attributen en Associaties . . . . . . . . . . . . . . . . . . . . . . . . . . 8<br />

2.1.4 Operaties op collecties . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8<br />

2.1.5 @pre en result . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8<br />

2.1.6 Assertion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9<br />

2.1.7 Slimme controle van klasse-invarianten . . . . . . . . . . . . . . . . . . . 9<br />

2.2 Tools . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10<br />

2.2.1 Octopus . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10<br />

2.2.2 OCLE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11<br />

2.2.3 Together 2006 for Eclipse . . . . . . . . . . . . . . . . . . . . . . . . . . 13<br />

2.2.4 Conclusie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16<br />

ii


INHOUDSOPGAVE<br />

iii<br />

3 Methodologie 17<br />

3.1 Design By Contract . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17<br />

3.1.1 Klasse-invarianten . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18<br />

3.1.2 Precondities en postcondities . . . . . . . . . . . . . . . . . . . . . . . . 18<br />

3.1.3 Assertions in Java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19<br />

3.1.3.1 Waarom assertie gebruiken? . . . . . . . . . . . . . . . . . . . . 19<br />

3.2 Beschrijving van de methodologie . . . . . . . . . . . . . . . . . . . . . . . . . . 20<br />

3.2.1 Vertaling van attributen en associaties . . . . . . . . . . . . . . . . . . . 20<br />

3.2.2 Vertaling van OCL operaties over basistypen . . . . . . . . . . . . . . . 21<br />

3.2.2.1 Boolean type . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21<br />

3.2.2.2 Real en Integer types . . . . . . . . . . . . . . . . . . . . . . . 22<br />

3.2.2.3 String type . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23<br />

3.2.3 Vertaling van OCL collectieoperaties . . . . . . . . . . . . . . . . . . . . 23<br />

3.2.3.1 Eenvoudige collectieoperaties . . . . . . . . . . . . . . . . . . . 24<br />

3.2.3.2 Collectieiteratoren . . . . . . . . . . . . . . . . . . . . . . . . . 24<br />

3.2.3.3 Inkapseling van sjablonen voor collectieoperaties in JAVA methoden<br />

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31<br />

3.2.4 Vertaling van OCL if-then-else expressies . . . . . . . . . . . . . . . . 32<br />

3.2.5 Vertaling van OCL let expressies . . . . . . . . . . . . . . . . . . . . . . 33<br />

3.2.6 Vertaling van klasse-invarianten . . . . . . . . . . . . . . . . . . . . . . . 33<br />

3.2.7 Vertaling van pre- en postcondities . . . . . . . . . . . . . . . . . . . . . 34<br />

3.2.8 Vertaling van meer geavanceerde constructies . . . . . . . . . . . . . . . 35<br />

3.2.8.1 Vertaling van het sleutelwoord @pre . . . . . . . . . . . . . . . 35<br />

3.2.8.2 Het sleutelwoord result . . . . . . . . . . . . . . . . . . . . . 36<br />

3.3 Naïeve aanpak . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37<br />

3.3.1 Vertaling van invarianten . . . . . . . . . . . . . . . . . . . . . . . . . . 37<br />

3.3.1.1 Inkapseling van een invariant in een booleaanse methode . . . 37<br />

3.3.1.2 Inkapseling van alle klasse-invarianten in een gemeenschappelijke<br />

methode . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38<br />

3.3.2 Vertaling van pre- en postcondities . . . . . . . . . . . . . . . . . . . . . 38<br />

3.4 Intelligente aanpak . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40<br />

3.4.1 Het Idee . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40<br />

3.4.2 Graafconstructie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40<br />

3.4.3 String matching . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42


iv<br />

INHOUDSOPGAVE<br />

3.4.4 Vertaling van klasse-invarianten . . . . . . . . . . . . . . . . . . . . . . . 42<br />

3.4.4.1 Inkapseling van een invariant in een booleaanse methode . . . 43<br />

3.4.4.2 Inkapseling van alle relevante klasse-invarianten in een gemeenschappelijke<br />

booleaanse methode . . . . . . . . . . . . . . . . . 43<br />

3.4.5 Vertaling van pre- en postcondities . . . . . . . . . . . . . . . . . . . . . 43<br />

3.5 Evaluatie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43<br />

4 Realisatie in HAT 46<br />

4.1 HAT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46<br />

4.2 Run-time OCL naar JAVA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48<br />

4.2.1 OCL attribuut-, associatie- en operatiemodelelementen . . . . . . . . . . 49<br />

4.2.2 OCL collectieiterator modelelementen . . . . . . . . . . . . . . . . . . . 49<br />

4.2.3 OCL If-then-else en let modelelementen . . . . . . . . . . . . . . . . . . 50<br />

4.2.4 Inkapseling van collectieoperaties . . . . . . . . . . . . . . . . . . . . . . 50<br />

4.3 Naïeve aanpak in HAT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51<br />

4.4 Intelligente aanpak in HAT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51<br />

4.5 Evaluatie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52<br />

5 Case study - Royal and Loyal 54<br />

5.1 Beschrijving van de case study . . . . . . . . . . . . . . . . . . . . . . . . . . . 54<br />

5.2 Vertaling met behulp van HAT . . . . . . . . . . . . . . . . . . . . . . . . . . . 55<br />

6 Besluit 59<br />

6.1 Doelstellingen en problemen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59<br />

6.2 Oplossing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59<br />

6.3 Kritische noot . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60<br />

6.4 Toekomstig werk: uitbreidingen en aanpassingen . . . . . . . . . . . . . . . . . 60<br />

A Lijst Van Afkortingen 62


L¼st van guren<br />

1.1 Relatie tussen PIM, PSM en code . . . . . . . . . . . . . . . . . . . . . . . . . . 2<br />

1.2 Gesimpliceerd UML model van een Luchthaven systeem . . . . . . . . . . . . . 3<br />

3.1 Afhankelijkheid tussen klasse invarianten en postcondities horend bij operaties . 41<br />

3.2 Klassediagram van het lopende voorbeeld. . . . . . . . . . . . . . . . . . . . . . 45<br />

4.1 Architectuur van de Agile MDA Tool . . . . . . . . . . . . . . . . . . . . . . . . 47<br />

4.2 Gesimpliceerde OCL meta-model . . . . . . . . . . . . . . . . . . . . . . . . . 48<br />

4.3 Abstract syntax metamodel voor ModelPropertyCallExpr . . . . . . . . . . . . 49<br />

5.1 Het aangepaste model van Royal and Loyal . . . . . . . . . . . . . . . . . . . . 55<br />

5.2 Het model van Royal and Loyal . . . . . . . . . . . . . . . . . . . . . . . . . . . 56<br />

v


L¼st van tabellen<br />

2.1 Evaluatiecriteria voor transformatie van OCL expressies door een tool . . . . . 9<br />

2.2 Evaluatie van Octopus . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10<br />

2.3 Evaluatie van OCLE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13<br />

2.4 Evaluatie van Together 2006 for Eclipse . . . . . . . . . . . . . . . . . . . . . . 13<br />

3.1 Standaard operaties voor de Boolean type . . . . . . . . . . . . . . . . . . . . . 21<br />

3.2 Standaard operaties voor Integer en Real types . . . . . . . . . . . . . . . . . . 22<br />

3.3 Standaardoperaties voor String type . . . . . . . . . . . . . . . . . . . . . . . . 23<br />

3.4 Afbeelding van OCL collectie typen naar JAVA collectie typen . . . . . . . . . 23<br />

3.5 Standaardoperaties over alle soorten van collectie typen . . . . . . . . . . . . . 24<br />

3.6 Collectieiteratoren operaties over alle collectietypen . . . . . . . . . . . . . . . . 25<br />

3.7 De resultaten van de evaluatie van naïeve en de intelligente aanpak . . . . . . . 44<br />

4.1 Evaluatie van HAT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53<br />

vi


Hoofdstuk 1<br />

Inleiding<br />

1.1 Situering<br />

De computer industrie is continu op zoek naar manieren om de productiviteit en kwaliteit van<br />

software ontwikkeling te verbeteren. In de vrij korte geschiedenis van software engineering<br />

hebben we al verschillende aanpakken gezien. Voorbeelden daarvan zijn Object-georiënteerdeontwikkelingen,<br />

Component-gebaseerde- ontwikkelingen, design patterns.<br />

Modelgedreven ontwikkeling (MDD) zou ook een belangrijke bijdrage in het proces van software<br />

ontwikkeling kunnen leveren. Een van de belangrijkste doelstellingen van het MDD is<br />

om het niveau van programmeerabstractie te verhogen zodat ontwikkelaars applicaties met<br />

minder moeite kunnen ontwikkelen. In plaats van applicaties in talen zoals JAVA en C++ te<br />

schrijven, creëren ontwikkelaars applicaties met behulp van specieke, hoogniveau programmeerconstructies.<br />

Dit soort constructies noemt men modellen. Deze software modellen hebben<br />

een centrale rol in het MDD ontwikkelingsproces.<br />

In MDD kan men speciceren hoe modellen gedenieerd in een taal naar modellen van een<br />

andere taal mogen getransformeerd worden. Modelleertalen worden in MDD als ontwikkelingsartefacten<br />

gebruikt veeleer dan enkel als ontwerpmiddelen. Uit een abstract model van<br />

een systeem wordt een meer concreet model gegenereerd. Uit dit model wordt dan nog een<br />

meer concreet model gegenereerd. Dit proces wordt meerdere keren uitgevoerd tot uiteindelijk<br />

het laagste niveau van abstractie bereikt is. Van deze laagniveau modellen wordt de broncode<br />

geproduceerd. Hierbij is codegeneratie niets meer dan een andere vorm van transformatie.<br />

Modelgedreven architectuur (MDA) [20] is eigenlijk een concreet voorbeeld van MDD. Het is<br />

een initiatief van Object Management Group (OMG) [16] dat een consortium van bedrijven en<br />

gebruikers is. De OMG heeft bovendien verschillende standaarden (UML, OCL, ...) ontwikkeld<br />

om MDD te kunnen implementeren.<br />

MDA is een verdere stap in de evolutie van het software ontwikkelingsproces. MDA is een<br />

raamwerk voor software ontwikkeling. Modellen krijgen een hoge prioriteit binnen het proces<br />

van software ontwikkeling. Anders gezegd wordt het ontwikkelingsproces gedreven door de<br />

modelleeractiviteit. Hierbij maakt men onderscheid tussen platformonafhankelijke modellen<br />

(PIM) en platformafhankelijke modellen (PSM). PIMs zijn op een hoogniveau van abstractie<br />

gebouwd en bovendien onafhankelijk van een set van implementatie technologieën. Voorbeelden<br />

daarvan zijn J2EE en .NET. PSMs zijn het resultaat van de transformatie van de<br />

1


2 HOOFDSTUK 1. INLEIDING<br />

PIM naar de nood voor een specieke implementatie technologie, bijvoorbeeld J2EE. Daarna<br />

wordt er vanuit de PSM code gegenereerd wat kan gezien worden als een transformatie van<br />

een PSM-model naar een code-model.<br />

Figuur 1.1: Relatie tussen PIM, PSM en code<br />

Sinds het MDA [3] proces gedreven wordt door een PIM dat automatisch getransformeerd<br />

wordt naar een PSM en nog verder naar code, kan modelleren beschouwd worden als programmeren<br />

op een hoger niveau. PIMs speciceren de code die geproduceerd (gegenereerd) moet<br />

worden. Bijgevolg zal het volume van de handgeschreven code kleiner zijn. Programmeren<br />

wordt uiteindelijk modelleren. Het software ontwikkelingsproces zal rond goede, hoog-niveau,<br />

onafhankelijke modellen draaien.<br />

Modelleren en vooral software modelleren wordt soms gebuikt als synoniem voor het maken<br />

van diagrammen. De meeste van de modellen bestaan uit een aantal vierkantjes, cirkels met<br />

pijlen en bijbehorende tekst. De informatie, die men van de gegeven modellen kan extraheren,<br />

is meestal incompleet, informeel en zelfs niet precies. De Object Constraint Language (OCL)<br />

[21] legt beperkingen op het model en op de semantiek ervan. Met OCL kan men al de supplementaire<br />

en benodigde informatie over de modellen in het model zelf uitdrukken. Speciceren<br />

van modellen gebruik makende van Unied Modeling Language (UML) [15] en de OCL-taal<br />

kan de kwaliteit van de modellen verbeteren.


1.2. PROBLEEM BESCHRIJVING 3<br />

1.2 Probleem beschrijving<br />

Net zoals broncode, moeten MDD modellen juist en precies zijn om tot een correcte broncode te<br />

kunnen komen. Er bestaan verschillende modelleertalen die in een MDD ontwikkelingsproces<br />

gebruikt kunnen worden. Voorbeelden daarvan zijn UML, GME, MetaEdit [15,17,18]. Hoe<br />

juist en precies men in elk van die talen kan modelleren hangt af van taal tot taal. In deze<br />

thesis gaan we enkel naar UML kijken. UML heeft veel zwakke punten maar blijft toch een<br />

van de meest populaire modelleertalen. Een van de zwakheden van UML modellen (vanaf<br />

hier gaan we de term modellen gebruiken in de context van UML) wordt veroorzaakt door de<br />

semantische onvolledigheid van de modellen.<br />

Modellen kunnen niet alle vaststellingen van een specicatie beschrijven. Bijvoorbeeld het<br />

model in figuur 1.2, duidt de associatie tussen de klasse Person en de klasse Flight aan<br />

dat er met een vlucht nul of meer passagiers geassocieerd kunnen zijn : multipliciteit (0..*).<br />

Dit impliceert dat het aantal passagiers oneindig kan zijn. In werkelijkheid zal dit aantal<br />

eerder beperkt zijn tot het aantal zetels in het vliegtuig dat aan de vlucht geassocieerd is.<br />

Dit voorbeeld toont aan dat deze beperking onbeschrijfbaar is in het UML klasse-diagram.<br />

Bijgevolg zullen modellen die in UML uitgedrukt zijn meestal incompleet, informeel en zelfs<br />

niet precies zijn.<br />

Figuur 1.2: Gesimpliceerd UML model van een Luchthaven systeem<br />

1.2.1 Wat is OCL<br />

De Object Constraint Language (OCL) is een notatie taal voor analyse en design van software<br />

systemen. Deze taal laat ons toe om expressies en beperkingen op een object-georiënteerde<br />

model te schrijven. OCL is ook een deelverzameling van de Unied Modeling Language (UML).<br />

Deze constraints zijn nuttig in het software ontwikkelingsproces. Deze laten de ontwikkelaar<br />

toe om een specieke verzameling van regels die de aspecten van de individuele objecten<br />

bestuurt te creëren.<br />

OCL is ook een constructie waarbij UML het concept van Design By Contract (DBC) [25]<br />

kan ondersteunen. Er zijn twee basis soorten van constraints: klasse-invarianten en pre- en


4 HOOFDSTUK 1. INLEIDING<br />

postcondities. Het uitgangspunt is dat UML modellen met constraint declaraties concreter en<br />

preciezer zijn dan modellen die dat niet hebben. Bovendien zijn deze OCL expressies eigenlijk<br />

de invoer voor de codegeneratoren in het MDA raamwerk.<br />

Expressies geschreven in een precieze, wiskundige gebaseerde taal zoals OCL bieden een aantal<br />

voordelen ten opzichte van het puur gebruik van modellen om het software systeem te speci-<br />

ceren. Deze expressies kunnen niet op verschillende manieren geïnterpreteerd worden door<br />

analisten of door programmeurs. Deze zijn ondubbelzinnig en maken onze modellen preciezer<br />

en correcter.<br />

Ten tweede kunnen deze expressies door geautomatiseerde tools gecontroleerd worden. Codegeneratie<br />

wordt op deze manier krachtiger. Met krachtiger bedoelen we hier dat de geproduceerde<br />

artefacten formeel en precies genoeg zijn en dat er geen ingreep door de programmeurs<br />

nodig is om de gegenereerde code aan te passen of om extra broncode toe te voegen.<br />

Laat ons naar het voorbeeld over het Luchthavensysteem teruggaan. De restrictie in de multipliciteit<br />

aan de kant van Person is op te lossen door de volgende OCL constraint aan het<br />

diagram toe te voegen.<br />

context Flight<br />

inv:<br />

passengers->size()


1.4. DOELSTELLINGEN 5<br />

• Ten vierde is het mogelijk om het principe van Design By Contract in een programmeertaal<br />

te simuleren.<br />

Indien we deze aanpak in software ontwikkeling volgen, zal de productiviteit zeker verhogen.<br />

Een implementatie van een systeem door MDD/MDA tools is sneller en eciënter dan een<br />

handgeschreven implementatie. Verder is de kwaliteit van ons systeem verhoogd. Er is garantie<br />

voor een consistentie tussen ons UML/OCL- model en de gegenereerde artefacten.<br />

1.4 Doelstellingen<br />

In het kader van dit eindwerk zullen we een bepaald aspect van de modeltransformaties proberen<br />

te bestuderen - namelijk de transformaties van OCL expressies naar werkende code. Tot<br />

nu toe zijn OCL expressies vooral gebruikt als validatie van modellen en documentatie. Dus<br />

spreken we hier over statische OCL. In deze thesis willen we verder gaan door beperkingen te<br />

leggen op instantiaties van UML modellen. Dit soort van OCL expressies noemt men run-time<br />

OCL. Er zijn twee basissoorten van OCL expressies of constraints: klasse-invarianten en preen<br />

postcondities. Wat we in deze thesis willen realiseren is precies deze twee basissoorten van<br />

OCL expressies te transformeren door een specieke codegeneratie. We gebruiken JAVA als<br />

doeltaal voor deze codegeneratie.<br />

Deze specieke transformatie (codegeneratie) zal gebeuren op basis van twee aanpakken. Een<br />

eerste aanpak is de naïeve aanpak waarbij beide basissoorten van constraints gecontroleerd<br />

worden op iedere stabiel moment van een systeem. Maar hier stoppen we niet. Een tweede<br />

meer geavanceerde aanpak zal bestudeerd worden. Hierbij worden alleen de relevante OCLexpressies<br />

gecontroleerd waarbij de overhead drastisch kan dalen en de eciëntie van ons<br />

systeem verhoogt.<br />

Deze transformaties zullen we uitwerken met het HAT-tool van het software engineeringsbedrijf<br />

E2S uit Gent [10].<br />

Hiernaast zullen we ook een aantal bestaande tools evalueren die run-time OCL ondersteunen.<br />

1.5 Overzicht<br />

In dit hoofdstuk werd het ontwerp van dit eindwerk in een ruimer kader geplaatst. De doelstellingen<br />

werden kort aangehaald.<br />

In het tweede hoofdstuk gaan we de state-of-the-art van OCL toolondersteuning bespreken.<br />

Hier stellen we eerst een aantal evaluatiecriteria voor. Op basis van de opgestelde criteria<br />

evalueren we een aantal tools. Ten slotte trekken we een conclusie over de huidige toolondersteuning<br />

van run-time OCL expressies.<br />

In het derde hoofdstuk stellen we verschillende aanpakken van transformaties van constraints<br />

naar code voor. Deze constraints zijn OCL expressies op UML modellen. Eerst zullen we een<br />

beschrijving van een mogelijke OCL naar JAVA vertaling voorstellen. Daarna zullen we deze<br />

transformaties zowel op een naïeve als op een meer intelligente manier beschrijven.


6 HOOFDSTUK 1. INLEIDING<br />

In het vierde hoofdstuk beschrijven we de realisatie van OCL transformaties in het HAT tool.<br />

Ten eerste zullen we een pure vertaling van OCL expressies naar JAVA bespreken. Ten tweede<br />

zullen we de naïeve en de intelligente aanpakken bespreken.<br />

In het vijfde hoofdstuk werken we een case studie uit. De voorgestelde aanpakken in het derde<br />

hoofdstuk worden naast elkaar gelegd. Alle voordelen en nadelen zullen we grondig bespreken.<br />

Het laatste hoofdstuk is een afsluitend hoofdstuk waarin we de huidige situering en de toekomst<br />

van MDD/MDA kritisch bespreken.


Hoofdstuk 2<br />

State-of-the-art<br />

De Object Constraint Language (OCL) [1] is een notatietaal voor analyse en ontwerp van<br />

software systemen. Het is een aanvulling op de industrie standaard UML waarbij ontwikkelaars<br />

beperkingen over modellen kunnen schrijven. Vandaag de dag vereisen veel software projecten<br />

complexe formele regels die in het businessmodel moeten worden uitgedrukt. OCL lost dit<br />

probleem op. OCL is eenvoudig genoeg om door business analisten gebruikt te worden maar<br />

ook formeel genoeg om door tools geïnterpreteerd en gemanipuleerd te worden.<br />

In dit hoofdstuk geven we een overzicht van de huidige stand van tools die OCL expressies<br />

naar JAVA vertalen. Hier gaan we eerst een aantal evaluatiecriteria voorstellen. Dan zullen<br />

we een aantal tools evalueren aan de hand van de voorgestelde criteria. Vervolgens zullen we<br />

deze tools naast mekaar zetten.<br />

2.1 Evaluatiecriteria<br />

In deze sectie gaan we een structuur voorstellen om tools te kunnen evalueren. Deze structuur<br />

is niet alleen gebaseerd op constructies die in de OCL taal aanwezig zijn maar ook op andere<br />

factoren: bijvoorbeeld de code die gegenereerd wordt na de vertaling van de OCL expressies<br />

naar een doel taal. In deze thesis wordt JAVA gebruikt als doeltaal voor de vertaling.<br />

In deze thesis onderzoeken we alleen maar een deel van de eigenschappen van OCL. We<br />

gaan voornamelijk in op klasse-invarianten, pre- en postcondities. Ook onderzoeken we de<br />

ondersteuning van meer ingewikkelde sleutelwoorden zoals @pre en result. Ten laatste breiden<br />

we onze criteria uit met manieren om de voldoening van constraints na te gaan. Daarom zijn<br />

onze criteria ook beperkt tot deze deelverzameling.<br />

In de context van OCL kunnen we meer informatie aan een model toevoegen aan de hand van<br />

invarianten. Deze invarianten kunnen op verschillende model elementen inwerken.<br />

2.1.1 Invarianten<br />

In specicaties is zo dat we vaak met invarianten te maken hebben. Klasse-invarianten garanderen<br />

ons dat objecten altijd een geldige toestand hebben. We zullen klasse-invarianten<br />

in meer detail in subsectie 3.1.1 bespreken. Daarom is de ondersteuning van invarianten door<br />

tools een basisvereiste.<br />

7


8 HOOFDSTUK 2. STATE-OF-THE-ART<br />

2.1.2 Pre- en Postcondities<br />

Indien men een meer complete specicatie van een systeem wenst is belangrijk om gebruik te<br />

maken van pre- en postcondities. Pre- en postcondities zijn beperkingen die de eecten en<br />

toepasbaarheid van operaties speciceren. In subsectie 3.1.2 zullen we dieper ingaan op preen<br />

postcondities.<br />

Sommige tools [13] beperken zich alleen maar tot precondities. De argumenten achter deze<br />

beslissing zijn dat de gebruiker de regels van een contract moet volgen. Indien dat niet zo is,<br />

is er geen garantie dat het resultaat van het uitvoeren van een stuk code correct zal verlopen.<br />

Verder wordt ook verondersteld dat het uitvoeren van een stuk code altijd correct beëindigt<br />

indien de precondities niet geschonden zijn.<br />

In deze thesis vertegenwoordigen we het gebruik van pre- en postcondities. De vereisten zijn<br />

dat een tool beide soorten van constraints ondersteunt.<br />

We hebben al twee soorten van constraints gezien: klasse-invarianten, pre- en postcondities.<br />

Bij elk van deze soorten van constraints zijn er verschillende modelelementen betrokken, namelijk<br />

attributen, associatie, operaties, enz.<br />

2.1.3 Attributen en Associaties<br />

Indien de visibiliteit van attributen en associaties als private gemodelleerd is dan zijn deze<br />

beperkt tot de klasse waarin ze gedenieerde zijn. Om naar deze modelelementen te kunnen<br />

refereren is het essentieel om inspectoren voor deze modelelementen te denieren.<br />

Indien een tool ondersteuning biedt voor invarianten en pre- en postcondities moet het tool<br />

minimaal een vertaling van eenvoudige constraints ondersteunen. Met eenvoudige constraints<br />

bedoelen we constraints die bijvoorbeeld alleen maar attributen en operaties op deze attributen<br />

bevatten. Ook vallen enkelvoudige associaties in deze categorie. Indien de associaties een<br />

collectie voorstellen is dat niet meer het geval. Dit wordt uitgelegd in de volgende paragraaf.<br />

2.1.4 Operaties op collecties<br />

Er bestaan twee soorten van operaties op collecties: zij die over de collecties itereren en zij<br />

die dat niet doen. Hier focussen we op de eerste soort, namelijk collectieiteratoren. In JAVA<br />

hebben OCL collectieiteratoren geen tegenhangers. Bijgevolg verkrijgen we meestal complexe<br />

constructies na de vertaling van deze collectieiteratoren naar een doeltaal. Wat we hier willen<br />

onderzoeken is in welke mate de complexiteit van deze constructies kan worden gereduceerd.<br />

2.1.5 @pre en result<br />

In OCL zijn er ook meer geavanceerde constructies voor postcondities. Hier bedoelen we<br />

constructies die naar waarden van modelelementen op twee verschillende tijdstippen refereren,<br />

bijvoorbeeld de OCL constructie @pre. Een andere constructie is een constructie die het result<br />

sleutelwoord bevat. Dit sleutelwoord duidt de terugwaarde van een operatie aan. Het type<br />

van result hangt af van het terugtype van de operatie.<br />

Beide sleutelwoorden kunnen de specicatie van een model verbeteren en hun vertaling naar<br />

een doeltaal is hier gewaardeerd


2.1. EVALUATIECRITERIA 9<br />

2.1.6 Assertion<br />

Hoewel deze criteria cruciaal zijn ontbreekt nog een deel van de puzzel. Is de transformatie<br />

uiteindelijk betrouwbaar? Wat gebeurt als een constraint geschonden is? Is er een exceptie<br />

gegooid? Dat zijn allemaal vragen die men kan stellen.<br />

Hiervoor gebruiken we de techniek van assertion [14]. In sommige programmeertalen is dat<br />

volledig ondersteunt of helemaal niet. Try-catch blokken zijn geen slechte manier van werken.<br />

Maar bij het uitvoeren van een systeem zal elke constraint nagegaan worden. Bij het installeren<br />

(deployment) leidt dat tot een vertraagd systeem. Daarom verkiezen we voor de assertion<br />

techniek die ons toelaat om de beslissing te nemen over het aan- en uitschakelen van de<br />

constraints op run-time. Een code die geen van deze twee technieken gebruikt beschouwen we<br />

als slechte code.<br />

2.1.7 Slimme controle van klasse-invarianten<br />

De criteria die we hanteren wat betreft de technieken voor het nagaan van voldoening van<br />

constraints hebben we hierboven beschreven. Eveneens van belang is de vraag of we telkens<br />

alle klasse-invarianten moeten nagaan na het uitvoeren van een publieke methode. Misschien<br />

is het wel beter om enkel de relevante klasse-invariaten te inspecteren. In hoofdstuk 3 gaan we<br />

een mogelijke intelligente methode voorstellen om na het uitvoeren van een publieke methode<br />

alleen maar relevante klasse-invarianten na te gaan.<br />

Alles wat we tot nu toe besproken hebben is samengevat in tabel 2.1. Deze tabel somt een<br />

aantal criteria op en geeft voor elke vereiste een beschrijving.<br />

Id Criteria Beschrijving<br />

1 invarianten Garanderen een geldige toestand van objecten<br />

2 pre-, postcondities Vervolledigen de specicatie door constraints<br />

op operaties toe te voegen<br />

3 attributen, Basismodelelementen in een OCL<br />

associaties<br />

expressie<br />

4 collectieiteratoren OCL collectieiteratoren hebben geen substituten in<br />

JAVA - hoe worden hulp operaties gegenereerd<br />

5 @pre Verbeteren de specicatie van postcondities<br />

door naar waarden op verschillende tijdstippen<br />

te refereren<br />

6 result Verbeteren de specicatie van postcondities(geeft<br />

de terugwaarde van operaties terug)<br />

7 assertion De manier van controle: zijn de constraints<br />

al dan niet geschonden<br />

8 Slimme controle van Zijn alle constraints nagegaan of maar deze<br />

klasse-invarianten die relevant zijn<br />

Tabel 2.1: Evaluatiecriteria voor transformatie van OCL expressies door een tool


10 HOOFDSTUK 2. STATE-OF-THE-ART<br />

2.2 Tools<br />

Er zijn al een aantal tools op de markt die ondersteuning en afhandeling van OCL expressies<br />

bieden. Hieronder geven we een overzicht van de tools waarmee we geëxperimenteerd hebben.<br />

We voegen ook extracten (skeletten) van code toe die door de tools gegenereerd waren. Sommige<br />

methodes kunnen leeg zijn maar dat is hier niet van belang want we willen de structuur<br />

van de gegenereerde code tonen.<br />

2.2.1 Octopus<br />

Octopus [13] is een tool dat het gebruik van OCL ondersteunt. Octopus staat voor OCL tool<br />

for Precise UML Specication. Het Octopus tool biedt twee belangrijke functionaliteiten. Ten<br />

eerste is in Octopus mogelijk om zowel de syntaxis van OCL expressies als de typen en het<br />

juiste gebruik van modelelementen na te gaan. Met modelelementen wordt hier attributen en<br />

associaties bedoeld. Ten tweede biedt Octopus de mogelijkheid om transformaties van UML<br />

modellen met de bijhorende OCL expressies (beperkingen die in OCL uitgedrukt zijn) naar<br />

JAVA uit te voeren.<br />

Dit tool biedt geen mogelijkheden om modellen te creëren. De modellen moeten eerst in andere<br />

modelleertools zoals bijvoorbeeld MagicDraw [22] gedenieerd worden en pas dan geïmporteerd<br />

worden. Dan kan men de specicatie uitgedrukt in OCL toevoegen. Vervolgens volstaat<br />

het om de codegenerator op te roepen. Het resultaat van de transformatie is een model in<br />

een platformafhankelijke taal. In dit tool is er geen mogelijkheid om de gegenereerde code te<br />

ne-tunen, namelijk om de structuur van de geproduceerde code (de elementen die het tool<br />

genereert) te veranderen.<br />

Id Criteria Opmerking Ondersteuning<br />

1 invarianten Ja<br />

2 pre-, postcondities allen precondities Ja<br />

3 attributen, inspectoren en mutatoren Ja<br />

associaties zijn gegenereerd<br />

4 collecties Voor ieder collectieiterator Ja<br />

een nieuwe methode<br />

5 @pre Neen<br />

6 result Neen<br />

7 assertion Alleen precondities zijn Ja<br />

door assert nagegaan<br />

8 slimme controle Neen<br />

klasse-invarianten<br />

Tabel 2.2: Evaluatie van Octopus<br />

De code die hier gegenereerd wordt, is volledig in de zin dat niet alleen de OCL expressie zijn<br />

vertaald naar JAVA maar er zijn ook constructoren, inspectoren en mutatoren gegenereerd.<br />

Met andere woorden verkrijgen we een volledig uitvoerbaar systeem. Het tool ondersteunt


2.2. TOOLS 11<br />

alleen maar invarianten en precondities. In de laatste versie 2.2.0 die we getest hebben, zijn<br />

postcondities nog niet ondersteund. Bijgevolg zijn sleutelwoorden als @pre en result ook niet<br />

vertaald.<br />

Iedere keer een OCL expressie gebruik maakt van collectieoperaties die over collecties itereren<br />

zijn er hulp methoden voor gecreëerd. Op deze manier wordt de code met dupliceerde<br />

hulp methoden aangevuld. Bij operaties zijn er wel de precondities gecheckt maar niet de<br />

invarianten.<br />

Hieronder geven we een skelet van hoe de gegenereerde JAVA code eruit ziet:<br />

Listing 1 Octopus<br />

class X{<br />

private int attribute;<br />

public X(){<br />

}<br />

public void operation(){<br />

assert (precondition);<br />

//... <br />

}<br />

private boolean helpMethod(){<br />

}<br />

public void inv0(){<br />

boolean result = helpMethod();<br />

if(!result) throw new InvariantException();<br />

public void inv1(){<br />

}<br />

public List checkAllInvariants(){<br />

List result = new ArrayList();<br />

try{<br />

inv0();<br />

}catch(InvariantException e){result.add(e);}<br />

try{<br />

inv1();<br />

}catch(InvariantException e){result.add(e);}<br />

return result;<br />

}<br />

}<br />

2.2.2 OCLE<br />

OCLE [12] is een UML CASE tool dat OCL volledig ondersteunt, zowel op metamodel als<br />

op modelniveau. De codegenerator produceert code voor de modelstructuur en voor de OCL<br />

specicatie. Het resultaat is een volledig werkende code. Versie 2.0 van het tool biedt ondersteuning<br />

voor OCL 2.0 en is compatibel met UML 1.5.<br />

Indien men dit tool voor codegeneratie wil gebruiken moet men eerst een model in het tool<br />

creëren en dan de bijbehorende OCL constraints toevoegen. Deze constraints kunnen geva-


12 HOOFDSTUK 2. STATE-OF-THE-ART<br />

lideerd worden voordat men code gaat genereren. Men kan niets aan de structuur van de<br />

gegenereerde code veranderen. Bovendien om de code te kunnen compileren moet men een<br />

bibliotheek importeren die bij het tool te vinden is.<br />

Alhoewel pre- en postcondities ondersteund zijn, worden de sleutelwoorden @pre en result niet<br />

correct geimplementeerd. Dat is te wijten aan het feit dat deze sleutelwoorden genegeerd zijn<br />

door de codegenerator.<br />

De controle over de constraints gebeurt door if-blokken. Indien de beperkingen in de specicatie<br />

geschonden zijn, wordt een boodschap getoond. Er is geen mogelijkheid om deze controles<br />

aan en uit te schakelen wanneer dat gewenst is. Dat is een min punt voor dit tool vermits<br />

volgens B.Meyer pre- en postcondities tijdens testen of debuggen moeten aangezet worden<br />

maar tijdens de echte uitvoering van het programma moeten afstaan [25].<br />

Bij collectieiteratoren worden geen hulpmethodes gegeneerd. Alle bewerkingen rond collectieiteratoren<br />

zijn te vinden in de methode van de invariant of pre- en postconditie zelf. Bijgevolg<br />

zijn de gegenereerde JAVA methoden langer en soms niet overzichtelijk.<br />

Hieronder tonen we in Listing 2 hoe een klasse met de bijbehorende specicatie eruit ziet.<br />

Listing 2 OCLE<br />

class X{<br />

private int attribute;<br />

public void operation(){<br />

class ConstraintChecker{<br />

public void checkPreconditions(){<br />

}<br />

public void checkPostconditions(){<br />

}<br />

ConstraintChecker ch = new ConstraintChecker();<br />

ch.checkPreconditions();<br />

ch.checkPostconditions();<br />

}<br />

}<br />

public class ConstaintChecker{<br />

public void checkConstaints(){<br />

check_X_inv0();<br />

check_X_inv1();<br />

}<br />

public void inv0(){<br />

//... <br />

if(!test)<br />

System.out.println(postcondition failed for object+X.this);<br />

}<br />

public void inv1(){<br />

}<br />

}<br />

}<br />

De gegenereerde code verkrijgen uit het OCLE tool is min of meer volledig in de zin dat we een


2.2. TOOLS 13<br />

compleet systeem als resultaat hebben. Natuurlijk zijn meer geavanceerde constructie (zoals<br />

@pre en result) nog niet ondersteund. In de tabel 2.3 is alles nog eens samengevat.<br />

Id Criteria Opmerking Ondersteuning<br />

1 invarianten Ja<br />

2 pre-, postconditie Ja<br />

3 attributen, Geen inspectoren of Neen<br />

associaties mutatoren gegenereerd,<br />

attributen met publieke visibiliteit<br />

4 collectie Ja<br />

5 @pre dit sleutelwoord is Neen<br />

genegeerd<br />

6 result Neen<br />

7 assertion Neen<br />

8 slimme controle Neen<br />

klasse-invarianten<br />

Tabel 2.3: Evaluatie van OCLE<br />

2.2.3 Together 2006 for Eclipse<br />

De Together 2006 Release 2 for Eclipse [11] versie 8.1.1 is een visueel platform dat ondersteuning<br />

biedt voor een grote groep van gebruikers, van software architecten en ontwikkelaars tot<br />

business process analisten. De mogelijkheden van dit tool zijn enorm groot. Hier gaan we ons<br />

tot een bepaald deel van de eigenschappen van het tool beperken, namelijk transformatie van<br />

OCL expressies naar code.<br />

Id Criteria Opmerking Ondersteuning<br />

1 invarianten Ja<br />

2 pre-, postconditie Ja<br />

3 attributen, Geen mutatoren of inspectoren, Neen<br />

associaties publieke visibiliteit attributen<br />

4 collectie Geen hulp methoden Ja<br />

5 @pre Ja<br />

6 result De semantiek van de vertaalde Ja<br />

code is niet precies<br />

7 assertion Goed gebruik van assertions Ja<br />

slimme controle<br />

8 klasse-inavianten Neen<br />

Tabel 2.4: Evaluatie van Together 2006 for Eclipse<br />

In dit tool kan men opnieuw zelf modellen creëren en dan constraints erop toevoegen. Het tool<br />

beschikt over een 'syntax completion' functie die men toelaat om snel en eciënt constraints


14 HOOFDSTUK 2. STATE-OF-THE-ART<br />

te schrijven. Controle voor geldigheid en consistentie van constraints is door het tool gedaan.<br />

Er is geen mogelijkheid om de structuur van de gegenereerde code te veranderen.<br />

Een van de positieve punten van dit tool is dat het tool ondersteuning biedt voor zowel<br />

invarianten als voor pre- en postcondities. Binnen elke gegenereerde klasse uit het model is<br />

een statische klasse gedenieerd met de bijbehorende constraints. Het skelet van een klasse<br />

ziet als volgt uit:<br />

Listing 3 Together<br />

class X{<br />

private int attribute;<br />

public void operation(){<br />

assert ( OCL.preOperation());<br />

// ... <br />

assert(OCL.AllInvariants() && OCL.postOperation());<br />

}<br />

protected static class OCL{<br />

private OCL(){<br />

}<br />

static boolean inv0(){<br />

}<br />

static boolean inv1(){<br />

}<br />

static boolean allInvariants(){<br />

return inv0()&& inv1();<br />

}<br />

static boolean preOperation(){<br />

}<br />

static boolean postOperation(){<br />

}<br />

}<br />

}<br />

Het tool genereert code voor alle attributen, associaties en operaties en natuurlijk ook voor<br />

de constraints uitgedrukt in OCL. Constructoren, mutatoren en inspectoren worden niet gegenereerd.<br />

De vertaalde OCL code refereert naar de attributen of associaties zelf en niet naar<br />

hun inspectoren. Vermits visibiliteit van attributen meestal beperkt is tot de klasse waarin ze<br />

gedenieerd zijn, is de gegenereerde code soms niet compileerbaar omwille van het probleem<br />

van visibiliteit. Een oplossing is om alle attributen publiek te maken wat niet altijd gewenst is.<br />

Operaties op collecties zijn ook ondersteund. Indien in een OCL expressie collectieiteratoren<br />

aanwezig zijn, zijn deze niet ingekapseld in aparte methoden maar tussen try-catch blokken<br />

binnen de invariant of pre- en postconditie methode zelf. Dat leidt bij complexe OCL expressie<br />

tot lange en soms niet overzichtelijke methoden met een aantal grote try-catch blokken.<br />

Indien we de code structuur van de gegenereerde code bekijken, zien we dat de controle op de<br />

constraints gebeurt door het gebruik van asserties. Dat beschouwen we als een goede techniek.<br />

Postcondities mogen meer geavanceerde constructies hebben. De sleutel worden @pre en result<br />

zijn geimplementeerd.


2.2. TOOLS 15<br />

Indien het sleutelwoord @pre in een van de postcondities aanwezig is dan is de structuur van<br />

de klasse waarbij deze postconditie behoort uitgebreid. Deze uitbreiding is gevat in een nieuwe<br />

abstracte statische klasse PrePost. Deze nieuwe klasse is een hulpklasse om de toestand van<br />

een variabele of object op te slaan voor de uitvoering van de operatie. Op deze manier worden<br />

pre- en postcondities correct geëvalueerd.<br />

We kunnen nu alles recapituleren in tabel 2.4.<br />

Listing 4 Together 2<br />

class X{<br />

private int attribute;<br />

public void operation(){<br />

OCL.PrePost oclPreState = OCL.preOperation();<br />

// ... <br />

assert(OCL.PrePost.checkPost(oclPreState,null) && OCL.AllInvariants() );<br />

}<br />

protected static class OCL{<br />

private static final boolean isEnabled = X.class.desiredAssertStatus();<br />

private OCL(){<br />

}<br />

protected static abstract class PrePost{<br />

private static boolean checkPost(PrePost preState, Object result){<br />

return preState != null ? preState.post(result) : !isEnabled;<br />

}<br />

protected abstract boolean post(Object result);<br />

}<br />

static protected PrePost preOperation(){<br />

if(!OCL.isEnabled) return null;<br />

PrePost preState = new PrePost(){<br />

// save the preState of the postcondition<br />

protected boolean post(Object _result){<br />

// ... <br />

}<br />

};<br />

return preState;<br />

}<br />

static boolean inv0(){<br />

}<br />

static boolean inv1(){<br />

}<br />

static boolean allInvariants(){<br />

return inv0()&& inv1();<br />

}<br />

static boolean preOperation(){<br />

}<br />

}<br />

}


16 HOOFDSTUK 2. STATE-OF-THE-ART<br />

2.2.4 Conclusie<br />

Er bestaan veel tools die statische OCL ondersteunen, namelijk voor validatie en documentatie<br />

van modellen. Bovendien zijn ze tegenwoordig betrouwbaar om mee te kunnen werken.<br />

Indien we run-time OCL willen gebruiken, is dat niet meer het geval. Het aantal tools dat<br />

deze soort van OCL ondersteuning aanbieden, is beperkt. Daarenboven is de code die ze<br />

genereren meestal niet volledig, of nog erger niet correct. In dit hoofdstuk hebben we de<br />

huidige ondersteuning van run-time OCL generatie onderzocht. De conclusie is dat de huidige<br />

state-of-the-art tools onvolledig zijn wat betreft de criteria opgesteld in het begin.<br />

In het volgende hoofdstuk gaan we zelf een transformatie uitwerken gebruik makende van het<br />

HAT tool en zien in welke mate die de criteria kan ondersteunen. Maar eerst zullen we een<br />

methodologie uitwerken voor het omzetten van OCL expressies naar JAVA code.


Hoofdstuk 3<br />

Methodologie<br />

In dit hoofdstuk bespreken we eerst wat Design By Contract (DBC) is. Hier worden klasseinvarianten,<br />

pre- en postcondities grondig uitgelegd. Verder leggen we uit hoe DBC in programmeertalen<br />

zoals JAVA kan gesimuleerd worden die per denitie geen expliciete ondersteuning<br />

van DBC heeft. Na deze inleiding over DBC gaan we uitleggen welke aanpakken we<br />

in deze thesis hebben gebruikt om de doelstellingen te kunnen bereiken. De eerste aanpak<br />

is redelijk naïef. Deze aanpak is eenvoudig maar veroorzaakt in sommige gevallen veel overhead.<br />

Een tweede aanpak die we ontwikkeld en bestudeerd hebben, noemen we de intelligente<br />

aanpak. Deze is meer eciënt dan de naïeve aanpak ten opzichte van de uitvoeringstijd maar<br />

tegelijkertijd is de complexiteit van de structuur die uiteindelijk de broncode gaat genereren<br />

ook verhoogd.<br />

3.1 Design By Contract<br />

Desing By Contract [25] is een methode voor het ontwikkelen van kwaliteitssoftware bedacht<br />

door Bertrand Meyer. DBC focusseert zich op het maken van software contracten op een<br />

expliciete en formele manier. Deze software contracten speciceren wat elke operatie in een<br />

systeem van de oproeper vereist en wat aan de oproeper gegarandeerd wordt.<br />

De denitie van een contract is in het DBC principe afgeleid van de notie van een contract.<br />

Een contract is een wettelijke overeenkomst tussen twee partijen waarin beide partijen alle<br />

verbintenissen aanvaarden. In termen van object-georiënteerde ontwikkeling is een contract<br />

een middel om de verantwoordelijkheden van objecten op een precieze en niet ambigu manier<br />

vast te leggen. Een object is aansprakelijk voor het uitvoeren van diensten (verplichten) enkel<br />

en alleen als sommige voorwaarden voldaan zijn. Een contract is een nauwkeurige specicatie<br />

van de interface van een object. Alle objecten die gebruik willen maken van de aangeboden<br />

diensten heten klanten of consumenten. Het object dat deze diensten aanbiedt noemt men de<br />

leverancier of producent.<br />

Alhoewel de notie van contract afkomstig van de rechten praxis is, wijkt het contract beetje af<br />

wanneer het men in de context van object-georiënteerde ontwikkeling neerzet. Namelijk een<br />

contract is aangeboden door een leverancier al dan niet een klant aanwezig is. Echter als een<br />

klant gebruik van de aangeboden diensten in een contract maakt, verplicht de klant zich aan<br />

de voorwaarden in het contract.<br />

17


18 HOOFDSTUK 3. METHODOLOGIE<br />

Een contract beschrijft de diensten die door een object aangeboden worden. Voor elke dienst<br />

speciceert het contract:<br />

• Onder welke voorwaarden de dienst zal aangeboden worden.<br />

• De specicatie van het resultaat van de aangeboden dienst gegeven dat alle voorwaarden<br />

voldaan zijn.<br />

Elk object kan een aantal operaties uitvoeren. Deze operaties zijn te vinden in de interface<br />

van het object zelf. Voor elke van deze operaties kan een contract geëxpliciteerd worden.<br />

De rechten van het object komen met precondities overeen en de verplichten van het object<br />

corresponderen met de postcondities.<br />

Indien minstens een van beide partijen de voorwaarden van het contract niet respecteren, is<br />

het contract geschonden. Als dat gebeurt dan is het duidelijk wie aan de voorwaarden van<br />

het contract niet voldeed. Ofwel heeft de klant de aangeboden diensten niet correct gebruikt,<br />

ofwel heeft de leverancier de aangeboden dienst niet correct uitgevoerd. De programmeertaal<br />

EIFFEL [19] is de enige taal die een implementatie van DBC voorziet. DBC kan gebruikt<br />

worden binnen de context van object-georiënteerde ontwikkeling.<br />

In volgende sectie zullen we bespreken wat klasse-invarianten, pre- en postcondities zijn.<br />

3.1.1 Klasse-invarianten<br />

Klasse-invariant - is een booleaanse expressie die een conditie vaststelt. Deze conditie moet<br />

altijd voldaan zijn voor alle instanties waarvoor deze conditie gedenieerd is. Een invariant<br />

moet juist na de afhandeling van een constructor of na de afhandeling van elke publieke<br />

operatie waar zijn maar niet noodzakelijk tijdens het uitvoeren van de operatie. Anders<br />

gezegd, een klasse-invariant moet waar zijn op eender welke consistente toestand van een<br />

systeem. Indien het systeem bijvoorbeeld een operatie uitvoert dan is ons systeem niet in een<br />

consistente toestand en bijgevolg moet de invariant niet meer waar zijn. Uiteraard moet na<br />

de uitvoering van de operatie de invariant opnieuw waar zijn.<br />

3.1.2 Precondities en postcondities<br />

Pre- en postcondities zijn gebruikt om operaties te speciceren. Deze vervolledigen de interface<br />

van een operatie. Pre- en postcondities speciceren niet hoe het lichaam van een operatie<br />

geimplementeerd moet worden. Hieronder zijn deze concepten gedenieerd:<br />

Preconditie - is een booleaanse expressie die op het moment dat het uitvoeren van de operatie<br />

begint waar moet zijn.<br />

Postconditie - is een booleaanse expressie dat op het moment dat het uitvoeren van de operatie<br />

eindigt waar moet zijn.<br />

Met andere woorden pre- en postcondities moeten alleen op bepaalde tijdstippen (respectievelijk<br />

voor en na het uitvoeren van operaties) waar zijn in tegenstelling tot invarianten die<br />

altijd waar moeten zijn.


3.1. DESIGN BY CONTRACT 19<br />

Het principe achter pre- en postcondities is meestal gerefereerd naar het principe van Design<br />

By Contract (DBC) dat wij in de vorige sectie uitgelegd hebben.<br />

Vermits niet alle programmeertalen het principe van DBC ondersteunen, kan DBC op een of<br />

ander manier gesimuleerd worden in andere programmeertalen. Volgende sectie introduceert<br />

het begrip assertion en meer bepaald hoe dat kan geimplementeerd worden in de programmeertaal<br />

JAVA.<br />

3.1.3 Assertions in Java<br />

Een assertie (assertion) [14] is een booleaanse expressie die ons toelaat om een veronderstelling<br />

over een programma te toetsen. Als deze veronderstelling niet waar is, zal het programma een<br />

exceptie gooien. Indien de vericatie van deze booleaanse expressie waar levert dan bevestigt<br />

de corresponderende assertion de gemaakte veronderstelling. Als gevolg krijgt men foutsvrije<br />

programmas en de kwaliteit van de programmas is verhoogd.<br />

Ervaring toont dat het gebruik van assertions tijdens programmeren een van het snelste en<br />

meest eectieve manieren is om fouten te detecteren en corrigeren. Bovendien dienen assertions<br />

voor documentatie van programmas en op deze manier is de onderhoud verbeterd.<br />

In JAVA heeft assertion de volgende vorm:<br />

assert Expressie1 : Expressie2 ;<br />

waarbij Expressie1 een booleaanse expressie is en Expressie2 een expressie is die een waarde<br />

heeft (deze expressie kan geen invocatie van een methode zijn die als void gedenieerd is). Het<br />

systeem evalueert Expressie1 en als dat false is dan gooit het systeem een AssertionError.<br />

Dan wordt de waarde van Expressie2 doorgegeven aan de constructor van AssertionError die<br />

de stringrepresentatie van de waarde van Expressie2 gebruikt om een gedetailleerde bericht<br />

van de fout te geven.<br />

De assert constructie is een informele soort van Design By Contract. Toch kan men een<br />

ondersteuning voor klasse-invarianten, pre- en postcondities bieden. De assert constructie<br />

dwingt ons niet om een bepaalde soort van constraint-checking te gebruiken. Meestal is gelegen<br />

om de expressies die constraints op de objecten van ons systeem opleggen te combineren in een<br />

enkele booleaanse methode. Dan wordt deze booleaanse methode opgeroepen door de assertie<br />

clausule.<br />

3.1.3.1 Waarom assertie gebruiken?<br />

Veel mensen zouden zich afvragen waarom men een assertie faciliteit moet aanbieden. Deze<br />

speciale ondersteuning van assertie in de JAVA programmeertaal kan expliciet geprogrammeerd<br />

worden.<br />

Alhoewel een ad hoc implementatie mogelijk is is het meestal minder gestructureerd (ifstatements<br />

nodig voor elke assert) en ineciënt (evaluatie van de condities zelfs als asserties<br />

uitgeschakeld zijn). Ten tweede heeft elke ad hoc implementatie zijn eigen manier van aanen<br />

uitschakelen van asserties. Dit reduceert het nut van deze implementaties vooral bij debuggen.<br />

Bijgevolg is de assertie cultuur nooit gevolgd door software ingenieurs in de JAVA<br />

programmeertaal.


20 HOOFDSTUK 3. METHODOLOGIE<br />

Het grootste voordeel van het assert statement in de JAVA programmeertaal is de mogelijkheid<br />

om deze asserties aan en uit te schakelen. Bij de implementatie- en testfasen van het<br />

ontwikkelingsproces is essentieel om deze opties aan te schakelen. Als we in plaats van asserties<br />

gewoon if-statements gebruiken om de constraints over ons model te veriëren maakt<br />

dat geen groot verschil. Het nadeel van de if-statements tegenover de asserties komt bij de<br />

fase van het installeren (deployment) van applicaties. Deze overhead van zulke vericatie kan<br />

enorm groot zijn waardoor de eciëntie van ons systeem kan dalen. If-statements zullen in<br />

alle gevallen uitgevoerd worden. Gebruik makende van asserties kunnen wij op elk moment<br />

beslissen of we al dan niet de constraints willen nagaan.<br />

3.2 Beschrijving van de methodologie<br />

In deze sectie zullen we een formele beschrijving van OCL expressies naar broncode geven, in<br />

ons geval is dat JAVA. We zullen ons op een deelverzameling van de OCL taal focussen. Deze<br />

deelverzameling zal attribuutmodelelementen, associatiemodelelementen, operaties en meer<br />

geavanceerde constructies zoals tijdgerefereerde variabelen bevatten.<br />

3.2.1 Vertaling van attributen en associaties<br />

De aanwezigheid van attributen en associatie is niet zo maar toevallig in OCL expressies.<br />

Attribuutwaarden stellen eigenschappen van klassen voor. Anderzijds representeren associatiewaarden<br />

de relaties tussen de verschillende klassen in een model. Bij gevolg hebben allebei<br />

een belangrijke rol en hun vertaling is wel nodig.<br />

Een attribuut of associatie kan in een OCL expressie zowel expliciet als impliciet gerefereerd<br />

worden. Indien men expliciet naar een contextuele instantiatie moet refereren, kan men gebruik<br />

maken van het sleutelwoord self. Als de referentie naar een contextuele instantiatie<br />

(in ons geval een attribuut of associatie) duidelijk is, is dit sleutelwoord optioneel.<br />

Bij vertaling van het OCL sleutelwoord self naar JAVA beeld dit zich af op het sleutelwoord<br />

this in JAVA. De waarde van het attribuut attribute is in JAVA te verkrijgen door de operatie<br />

getAttribute() op te roepen. Eender welke attribuutreferentie in OCL wordt op bijbehorende<br />

get operatie afgebeeld. Als we de volgende OCL expressie hebben:<br />

self.attribute<br />

wordt deze vertaald in JAVA op de volgende manier.<br />

this.getAttribute()<br />

De JAVA vertaling van associaties is als volgt: associaties worden afgebeeld op private JA-<br />

VA attributen met de bijbehorende get operatie. Dat wil zeggen dat OCL navigatie binnen<br />

associaties als een operatie oproep in JAVA gemodelleerd wordt. De OCL expressie


3.2. BESCHRIJVING VAN DE METHODOLOGIE 21<br />

self.associationEnd<br />

wordt getransformeerd naar de volgende JAVA code:<br />

this.getAssociationEnd();<br />

3.2.2 Vertaling van OCL operaties over basistypen<br />

Deze sectie denieert de vertaling van operaties over basistypen. Met basistypen bedoelen<br />

we hier de Boolean, Integer, Real en String typen. De vertaling van deze basistypen en<br />

hun bijbehorende operaties is op zichzelf niet zo moeilijk. We kunnen voor elke van deze<br />

operaties een implementatie in JAVA voorzien door middel van een van standaard bibliotheek<br />

waarin voor elk type een klasse zal geimplementeerd worden en binnen zo'n klasse zullen de<br />

bijbehorende operaties als statische methoden geimplementeerd worden. Vermits in JAVA<br />

deze typen en hun bijbehorende operaties tegenhangers hebben verkiezen we hier om een<br />

hergebruik van de JAVA API te maken. Bijgevolg is de vertaling van deze OCL operaties<br />

eigenlijk een afbeelding op hun tegenhangers in JAVA. We zullen kort de vertaling van de meest<br />

voorkomende operaties bespreken. We zullen deze vertaling ook in een tabelvorm voorstellen.<br />

We hebben al gezegd dat er Boolean, Integer, Real en String basistypen in OCL zijn. We<br />

beginnen met het Boolean basistype.<br />

3.2.2.1 Boolean type<br />

Een boolean type kan twee waarden hebben: false of true. JAVA biedt equivalente sleutelwoorden<br />

en bijgevolg is de vertaling naar JAVA direct. Natuurlijk moeten de bijbehorende operaties<br />

wel afgebeeld worden. In tabel 3.1 introduceren we het meest voorkomende booleaanse operaties.<br />

Booleaanse operaties hebben twee delen, namelijk een rechter- en een linkerdeel. In<br />

de tabel hieronder stelt 'a' het linker deel van deze operaties voor die een OCL expressies<br />

is. Hetzelfde geldt voor het rechterdeel. Het resultaat van het toepassen van een booleaanse<br />

operaties geeft een booleaanse waarde terug.<br />

Operatie OCL notatie Java vertaling Type van het resultaat<br />

or a or b a || b Boolean<br />

and a and b a && b Boolean<br />

exclusieve or a xor b (a || b) &&(a != b) Boolean<br />

negation not a ! a Boolean<br />

equals a = b a == b Boolean<br />

not equals a b a != b Boolean<br />

implies a implies b a ? b : true Boolean<br />

Tabel 3.1: Standaard operaties voor de Boolean type<br />

We gaan dat verduidelijken aan de hand van een voorbeeld voor de conjunctie en disjunctie<br />

van twee booleaanse attributen. Stel dat we de volgende OCL expressie hebben:


22 HOOFDSTUK 3. METHODOLOGIE<br />

self.attr1 and self.attr2 or self.attr3<br />

Dit wordt getransformeerd naar de volgende JAVA code:<br />

this.getAttr1() && this.getAttr2() || this.getAttr3();<br />

De volgorde van deze booleaanse operaties is voor de JAVA vertaling ook behouden bij de<br />

OCL expressie van daarboven.<br />

3.2.2.2 Real en Integer types<br />

Een Integer type stelt de natuurlijke getallen voor. Een Real type representeert het wiskundige<br />

concept van de reële getallen. Bijgevolg zijn integers een subtype van de reële getallen.<br />

Integers hebben tegenhangers in JAVA. Voor het Real type biedt JAVA float en double type<br />

aan. Men moet bij de vertaling een van deze twee types kiezen. De standaard operaties over<br />

Integer en Real types mogen op de java.lang.Math API afgebeeld woorden. In tabel 3.2<br />

hieronder geven we een JAVA vertaling van deze operaties.<br />

Operatie Notaties Java vertaling Resultaat<br />

equals a = b a == b Boolean<br />

not equals a b a != b Boolean<br />

less a < b a < b Boolean<br />

more a > b a > b Boolean<br />

less or equal a


3.2. BESCHRIJVING VAN DE METHODOLOGIE 23<br />

3.2.2.3 String type<br />

Voor de vertaling van operaties over strings kan een groot deel van de java.lang.String API<br />

opnieuw gebruikt worden. De operatie size() moet naar de methode length() in JAVA<br />

vertaald worden. Indien we de gelijkheid van twee strings willen nagaan kunnen we in JAVA<br />

gebruik maken van de equals() methode. Dit is samengevat in tabel 3.3.<br />

Operaties Notaties Java vertaling Resultaat<br />

concatenation str.concat(str) str.concat(str) String<br />

size str.size() str.length() Integer<br />

to lower case str.toLower() str.toLowerCase() String<br />

to upper case str.toUpper() str.toUpperCase() String<br />

substring str.substring(int,int) str.substring(int,int) String<br />

equals str1 = str2 str1.equals(str2) Boolean<br />

not equals str1 str2 ! str1.equals(str2) Boolean<br />

Tabel 3.3: Standaardoperaties voor String type<br />

3.2.3 Vertaling van OCL collectieoperaties<br />

Voor we aan de vertaling van collectieoperaties beginnen moeten we eerst iets over OCL collectietypes<br />

zeggen. Deze OCL collectietypes moeten op de collectietypen van een doeltaal<br />

afgebeeld worden. Gelukkig biedt JAVA een brede waaier van collectietypes aan. Een mogelijke<br />

afbeelding is voorgesteld in tabel 3.4.<br />

OCL collectietype Java type Concreet Java type<br />

Set Set HashSet<br />

Sequence List ArrayList<br />

Bag List ArrayList<br />

OrderedSet List ArrayList<br />

Tabel 3.4: Afbeelding van OCL collectie typen naar JAVA collectie typen<br />

Een Set in OCL stelt een wiskundige verzameling voor. Deze Set bevat elementen zonder<br />

duplicaten. Een OrderedSet is een Set waarbij zijn elementen geordend zijn. Bovendien een<br />

OrderedSet bevat geen duplicaten.<br />

Een Bag is een collectie waarbij duplicaten wel toegelaten zijn. Met andere woorden kan een<br />

object meerdere keren een element van een Bag worden. In een Bag is er geen volgorde.<br />

Een Sequence is een collectie waarbij de elementen geordend zijn. Een element kan meer dan<br />

een keer deel van een Sequence maken.<br />

In OCL hebben we twee typen van operaties over collecties. Operaties die over collecties<br />

itereren en operaties die dat niet doen. De eerste soort noemt men collectieiteratoren en<br />

de tweede eenvoudige collectieoperaties. We zullen eerst de vertaling van de tweede soort<br />

beschrijven.


24 HOOFDSTUK 3. METHODOLOGIE<br />

3.2.3.1 Eenvoudige collectieoperaties<br />

De implementatie van eenvoudige collectieoperaties is meestal niet zo moeilijk. De meeste van<br />

deze operaties hebben een tegenhanger in de JAVA API over collectietypen. Indien dat niet<br />

het geval is zullen we voor deze operaties een aparte implementatie voorzien. Daarvoor zullen<br />

we een soort van sjablonen gebruiken. In tabel 3.5 tonen we de meest gebruikte standaard<br />

OCL operaties over alle collectietypen en hun JAVA tegenhangers.<br />

OCL operatie Java Tegenhanger Omschrijving<br />

excludes(object) ! contains(object) Geeft waar terug indien het object<br />

geen element van de collectie is<br />

excludesAll(collection) ! containsAll(collection) Geeft waar terug indien alle<br />

elementen van de gegeven<br />

collectie niet aanwezig<br />

in de huidige collectie zijn<br />

includes(object) contains(object) Geeft waar terug indien het object<br />

een element van de collectie is<br />

includesAll(collection) containsAll(collection) Geeft waar terug indien alle<br />

elementen van de gegeven<br />

collectie aanwezig in<br />

de huidige collectie zijn<br />

isEmpty() isEmpty() Geeft waar terug indien de collectie<br />

geen enkel element bevat<br />

notEmpty() ! isEmpty() Geeft waar terug indien de collectie<br />

een of meerdere elementen bevat<br />

size() size() Geeft het aantal elementen<br />

in de collectie terug<br />

Tabel 3.5: Standaardoperaties over alle soorten van collectie typen<br />

3.2.3.2 Collectieiteratoren<br />

Collectieiteratoren laten ons om over collecties te itereren. De collecties waarop deze operaties<br />

toegepast zijn noemen we hier source. Ieder element van de source wordt tegen een expressie<br />

geëvalueerd. Deze expressie noemen we body. In tabel 3.6 tonen we de collectieiteratoroperaties<br />

over alle collectietypen.<br />

Omdat de collectieiteratoren altijd over collecties itereren moet men deze iteraties in termen<br />

van de doeltaal genereren. Bijvoorbeeld, zijn iteraties meestal in JAVA geimplementeerd met<br />

behulp van de interface Iterator. We zullen hier namelijk deze constructie gebruiken om over<br />

collectie te kunnen itereren.<br />

De OCL collectieiteratoren (zie tabel 3.6) hebben geen tegenhangers in de JAVA Collection<br />

API. Bijgevolg moeten we voor elke collectieiterator een methode creëren. Hiervoor zullen we<br />

een soort van sjablonen gebruiken. In deze sjablonen zullen we een vaste en een variërende<br />

stukcode hebben. De variërende code zullen we met een bold-italic lettertype noteren.


3.2. BESCHRIJVING VAN DE METHODOLOGIE 25<br />

Operaties<br />

any(expr)<br />

collect(expr)<br />

collectNested(expr)<br />

exists(expr)<br />

forAll(expr)<br />

isUnique(expr)<br />

iterate(...)<br />

one(expr)<br />

reject(expr)<br />

select(expr)<br />

sortedBy(expr)<br />

Omschrijving<br />

Geeft een willekeurig element uit de source collectie<br />

terug waarvoor de expressie expr waar is<br />

Geeft een collectie van objecten terug als resultaat<br />

van de evaluatie van expr voor ieder element<br />

uit de source collectie<br />

Geeft een collectie van collecties terug als resultaat<br />

van de evaluatie van expr voor ieder element<br />

uit de source collectie<br />

Geeft waar terug als er minstens een element in<br />

de source collectie bestaat waarvoor expr waar is<br />

Geeft waar terug als expr voor alle elementen in<br />

de source collectie waar is<br />

Geeft waar terug als expr een unieke waarde voor alle<br />

elementen in de source collectie heeft<br />

Itereert over alle elementen in de source collectie<br />

Geeft waar terug als er juist een element in de source<br />

collectie is waarvoor expr waar is<br />

Geeft een deelcollectie van de source collectie terug<br />

waarvoor voor ieder element uit de source collectie<br />

expr niet waar is<br />

Geeft een deelcollectie van de source collectie terug<br />

waarvoor voor ieder element uit de source collectie<br />

expr waar is<br />

Geeft een collectie terug die alle elementen van de<br />

source collectie bevat en geordend volgens expr zijn.<br />

Tabel 3.6: Collectieiteratoren operaties over alle collectietypen<br />

any operatie<br />

Om eender welk element van een source collectie te verkrijgen die aan een bepaalde voorwaarde<br />

voldoet kunnen we de any operatie gebruiken. De body parameter van deze operatie is een<br />

booleaanse expressie. Deze operatie zal over alle elementen van de collectie itereren om een of<br />

meer elementen te vinden die aan de body expressie voldoen. Indien er meer dan een element<br />

is die aan de body conditie voldoet dan is willekeurig een van deze elementen teruggeven.<br />

In onze implementatie wordt het eerste element teruggegeven. Anders is het resultaat niet<br />

gedenieerd. De volgende OCL expressie representeert de any operatie met de bijbehorende<br />

body conditie die op een source collectie toegepast is.<br />

source->any(body)<br />

De JAVA code ziet er zo uit:


26 HOOFDSTUK 3. METHODOLOGIE<br />

Listing 5 Sjabloon voor OCL any operatie<br />

ElementType result = null;<br />

Iterator it = source.iterator();<br />

while(it.hasNext()){<br />

ElementType elem = (ElementType) it.next();<br />

if(elem.body){<br />

return elem;<br />

}<br />

}<br />

return result;<br />

Wat te merken is dat er weinig van de OCL code in de JAVA code terug te vinden is. Bovendien<br />

is er een expliciete vermelding van het type van de elementen in de collectie source nodig. In<br />

termen van JAVA noemt men dat casten. In dat fragment casten we naar elementen van type<br />

ElementType.<br />

one operatie<br />

De one operatie geeft een booleaans resultaat terug. Indien er juist een element in de source<br />

collectie is die aan de voorwaarde in de body voldoet geeft deze operatie als resultaat waar<br />

terug.<br />

source->one(body)<br />

De JAVA code ziet er zo uit voor de one operatie:<br />

Listing 6 Sjabloon voor OCL one operatie<br />

Iterator it = source.iterator();<br />

int nr = 0;<br />

while(it.hasNext()){<br />

ElementType elem = (ElementType) it.next();<br />

if(elem.body){<br />

nr++;<br />

}<br />

}<br />

if(nr != 1){<br />

return false;<br />

}<br />

return true;<br />

collect operatie<br />

De collect operatie itereert over een gegeven source collectie dan berekent een waarde voor<br />

elk element in de collectie en verzamelt vervolgens de geëvalueerde waarden in een nieuwe<br />

collectie. De elementen in de nieuwe collectie zijn niet noodzakelijk van hetzelfde type als de<br />

source collectie. Het resultaat van een collect operatie is altijd een vlakke collectie.


3.2. BESCHRIJVING VAN DE METHODOLOGIE 27<br />

source->collect(body)<br />

De JAVA code ziet er zo uit:<br />

Listing 7 Sjabloon voor OCL collect operatie<br />

List result = new ArrayList();<br />

Iterator it = source.iterator();<br />

while(it.hasNext()){<br />

ElementType elem = (ElementType) it.next();<br />

Object bodyObj = elem.body;<br />

if(bodyObj != null){<br />

result.add(bodyObj);<br />

}<br />

}<br />

return result;<br />

iterate operatie<br />

De iterate operatie is de meest fundamentele en ingewikkelde operatie die over collecties<br />

itereert maar bijzonder generisch. De operaties reject, select, forAll, exists, collect<br />

kunnen allemaal in termen van iterate beschrijven worden. De collect operatie beschreven<br />

in termen van iterate is als volgt:<br />

Listing 8 collect operatie in termen van iterate<br />

collection->collect(x:T|x.property)<br />

is identiek aan :<br />

collection->iterate(x:T; acc: T2= Bag{}|<br />

acc->including(x.property))<br />

In deze thesis hebben we geen sjabloon voor iterate voorgesteld. We vinden dat wat men met<br />

iterate wil uitdrukken kan in de meeste gevallen ook uitgedrukt worden met een specieke<br />

collectieiterator. Bovendien is veel makkelijker en overzichtelijker indien we een collectieiterator<br />

gebruiken dan gewoon de OCL iterate operatie bij run-time OCL. Indien we de OCL<br />

expressies van Listing 8 met elkaar vergelijken dan is duidelijk dat de eerste indrukking overzichtelijker<br />

is die de collectieiterator collect gebruikt. In werkelijkheid zal een implementatie<br />

van de iterate operatie op zichzelf niet zo veel werk vragen.<br />

exists operatie<br />

Meestal wil men speciceren dat er minstens een element in een collectie is die aan een bepaalde<br />

conditie voldoet. De exists operatie kan hiervoor gebuikt worden. Deze operatie geeft een<br />

booleaans resultaat terug. Met andere woorden is het resultaat van deze operatie waar indien<br />

er minstens een element in de collectie bestaat dat aan de voorwaarden gespeciceerd in de<br />

body van de operatie voldoet. Indien we de volgende OCL expressie hebben


28 HOOFDSTUK 3. METHODOLOGIE<br />

source->exists(body)<br />

dan is de corresponderende JAVA code in Listing 9 te zien. Hier source is een collectie en<br />

daarvoor gebruiken we de JAVA interface Iterator om over deze collectie te kunnen itereren.<br />

De JAVA code ziet er zo uit:<br />

Listing 9 Sjabloon voor OCL exists operatie<br />

Iterator it = source.iterator();<br />

while(it.hasNext()){<br />

ElementType elem = (ElementType) it.next();<br />

if(elem.body){<br />

return true;<br />

}<br />

}<br />

return false;<br />

forAll operatie<br />

Soms wil men dat er een beperking voor alle elementen uit een collectie geldt. In dat geval kan<br />

hij de forall operatie gebruiken. Indien de OCL expressie in de body van de operatie voor<br />

een of meer elementen uit de collectie faalt geeft de forall operatie niet waar als resultaat<br />

terug. Gegeven de volgende OCL expressie<br />

source->forall(body)<br />

De vertaling van de OCL expressie naar JAVA die de forall operatie bevat is te zien in de<br />

volgende sjabloon:<br />

Listing 10 Sjabloon voor OCL forAll operatie<br />

Iterator it = source.iterator();<br />

while(it.hasNext()){<br />

ElementType elem = (ElementType) it.next();<br />

if(! elem.body){<br />

return false;<br />

}<br />

}<br />

return true;<br />

isUnique operatie<br />

Indien men in een collectie van elementen een unieke waarde voor ieder element in deze<br />

collectie wenst moet hij de isUnique operatie gebruiken. De body van deze operatie is meestal<br />

een expressie over een bepaalde eigenschap van het type van de betrokkene elementen in de<br />

collectie. Het resultaat van deze operatie geeft een booleaanse waarde terug. Deze operatie zal<br />

over alle elementen itereren en zal voor elk element de gevraagd waarde met de meegegeven


3.2. BESCHRIJVING VAN DE METHODOLOGIE 29<br />

body waarde vergelijken. Indien geen enkel van deze waarden aan elkaar gelijk zijn geeft deze<br />

operatie als resultaat waar terug. Voor de volgende OCL expressie hebben we<br />

source->isUnique(body)<br />

De JAVA code ziet er zo uit:<br />

Listing 11 Sjabloon voor isUnique operatie<br />

Iterator it = source.iterator();<br />

List values = new ArrayList();<br />

while(it.hasNext()){<br />

ElementType elem = (ElementType) it.next();<br />

if(values.contains(body)){<br />

return false;<br />

}<br />

values.add(body);<br />

}<br />

return true;<br />

select operatie<br />

Zowel associaties als resultaten uit operaties kunnen een collectie teruggeven. Indien men in<br />

een deelverzameling van deze collectie geïnteresseerd is kan hij de select operatie gebruiken.<br />

Met andere woorden kan men in de body van deze operatie een lijst van criteria speciceren<br />

om een selectie te maken. Bijgevolg is de body van de select operatie een booleaanse expressie.<br />

Het resultaat van deze operatie resulteert in een deelverzameling van de oorspronkelijke<br />

collectie. In deze deelverzameling zijn alleen maar elementen uit de oorspronkelijke collectie<br />

geselecteerd die aan de voorwaarden van de body voldoen.<br />

Gegeven de volgende OCL expressie, is source een collectie en body een booleaanse expressie.<br />

De corresponderende JAVA sjabloon is hieronder getoond.<br />

source->select(body)<br />

De vertaling van de select operatie naar JAVA is als volgt:<br />

Listing 12 Sjabloon voor OCL select operatie<br />

Set result = new HashSet();<br />

Iterator it = source.iterator();<br />

while(it.hasNext()){<br />

ElementType elem = (ElementType) it.next();<br />

if(elem.body){<br />

result.add(elem);<br />

}<br />

}<br />

return result;


30 HOOFDSTUK 3. METHODOLOGIE<br />

reject operatie<br />

De reject operatie is analoog aan de select operatie met het enige verschil dat allen elementen<br />

uit de source collectie geselecteerd moet worden waarvoor de expressie in de body van de<br />

operatie tot niet waar moet evalueren.<br />

source->reject(body)<br />

Hieronder geven we de JAVA vertaling van de OCL reject expressie.<br />

Listing 13 Sjabloon voor OCL reject operatie<br />

Set result = new HashSet();<br />

Iterator it = source.iterator();<br />

while(it.hasNext()){<br />

ElementType elem = (ElementType) it.next();<br />

if(!elem.body){<br />

result.add(elem);<br />

}<br />

}<br />

return result;<br />

sortedBy operatie<br />

De operatie sortedBy resulteert in een gesorteerde verzameling. Het element in de body van<br />

de operatie die de laagste waarde heeft komt als eerste element enz. Het type van de body<br />

expressie moet de < operatie denieren die een booleaanse waarde moet teruggeven. Indien<br />

we de volgende OCL expressie hebben<br />

source->sortedBy(body)<br />

De JAVA code ziet er zo uit:<br />

Listing 14 Sjabloon voor OCL sortedBy operatie<br />

List result = new ArrayList();<br />

result.addAll(source);<br />

Comparator comp = new ComparatorElementTypebody();<br />

Collections.sort(result,comp);<br />

return result;<br />

Combinatie van collectieiteratoren<br />

Het lichaam van een collectieoperatie kan veel complexer in vergelijking met de vorige voorbeelden<br />

uitzien wanneer we een combinatie van collectieiteratoren nemen. In zulke gevallen<br />

wordt onze JAVA code heel wat ingewikkeld en moeilijk om de OCL code te herkennen. We<br />

gaan dat aantonen aan de hand van een voorbeeld.


3.2. BESCHRIJVING VAN DE METHODOLOGIE 31<br />

source1->select(source2->forall(body))<br />

In deze OCL expressie hebben we met twee collecties te maken. De ene die over source1<br />

itereert en de andere die over source2 itereert. In OCL is wel mogelijk dat we meerdere<br />

geneste operaties over collecties kunnen hebben alhoewel dat uitzonderlijk is. De vertaalde<br />

JAVA code is als volgt:<br />

Listing 15 Sjabloon voor combinatie van collectieiteratoren<br />

Iterator it1 = source1.iterator();<br />

Set result = new HashSet();<br />

while(it1.hasNext()){<br />

Source1 s1 = (Source1) it.next();<br />

Iterator it2 = s1.source2.iterator();<br />

boolean forAllRes = true;<br />

while(it2.hasNext()){<br />

Source2 s2 = (Source2) it2.next();<br />

forAllRes = forAllRes && (s2.body);<br />

}<br />

if(forAllRes ){<br />

result.add(s1);<br />

}<br />

}<br />

return result;<br />

We kunnen samenvatten dat iedere collectieoperatie over een sjabloon moet beschikken. Deze<br />

sjabloon moet vervolgens ingevuld worden met de elementen van de OCL expressies. Er<br />

mogen nog wat optimalisaties over de sjablonen gemaakt worden. Natuurlijk resulteert dat in<br />

ingewikkelde JAVA code. Bijvoorbeeld, de sjabloon van hierboven kan herschrijven worden.<br />

Met andere woorden moet de iteratie stopen zodra het resultaat fout is.<br />

Een andere oplossing voor geneste collectieiteratoren is om gewoon de voorgestelde sjablonen<br />

voor elke collectieiterator te gebruiken. In ons voorbeeld van daarboven passen we eerst de<br />

sjabloon voor de select operatie toe. Vervolgens roepen we de sjabloon voor de forAll operatie<br />

op in de plaats waarin we de body van de select operatie nagaan. Op deze manier<br />

moeten we geen nieuwe sjablonen voor geneste collectieiteratoren denieren die wat gecompliceerd<br />

kunnen zijn. Als resultaat verkrijgen we in dit voorbeeld twee in plaats van een hulp<br />

methoden. Daarenboven zijn de verkregen hulp methoden overzichtelijk en eenvoudig.<br />

Met deze oplossing reduceren we niet alleen de complexiteit van onze sjablonen maar ook<br />

het aantal sjablonen die in elk geval gedenieerd moeten worden door een hergebruik van al<br />

bestaande sjablonen te maken.<br />

3.2.3.3 Inkapseling van sjablonen voor collectieoperaties in JAVA methoden<br />

De daarnet beschreven sjablonen voor OCL collectieoperaties moeten op een of andere manier<br />

in JAVA methoden ingekapseld worden. Hieronder geven we een aantal mogelijke oplossingen<br />

voor dit probleem.


32 HOOFDSTUK 3. METHODOLOGIE<br />

Een eerste oplossing die wie hier voorstellen is als volgt: telkens we een collectieoperatie<br />

tegenkomen dan gaan we een hulpmethode voor deze genereren in de klasse (context) waarbij<br />

deze hoort. In deze context zijn hulpmethode OCL collectieoperaties die geen tegenhangers<br />

in JAVA Collection API hebben. Bijgevolg is er de mogelijkheid van gedupliceerde methoden<br />

met dezelfde inhoud niet uitgesloten.<br />

Een tweede oplossing zou kunnen zijn om een keer een standaard bibliotheek te genereren die<br />

alle hulpoperaties zal bevatten die geen tegenhangers in de JAVA API hebben. Vermits onze<br />

sjablonen zowel een vast als een variabel deel hebben, moeten we in de signatuur van deze<br />

operaties als argumenten de source collectie en de body expressie meegeven om het variabele<br />

gedeelte in te vullen. Dit lijkt een goede oplossing maar aan de andere hand moeilijk te<br />

implementeren.<br />

Een derde oplossing zou kunnen zijn om in plaats van een standaard bibliotheek met statische<br />

methoden te genereren nemen we de eerste oplossing en passen we paar verbeteringen erop toe.<br />

Voor we een hulpoperatie gaan genereren, gaan we eerst nagaan of al deze niet gegenereerd<br />

was. Indien dat het geval was, moeten we deze niet meer gaan genereren. Om deze aanpak<br />

te kunnen implementeren, moeten we ergens alle onze gegenereerde hulpoperaties met hun<br />

bijbehorende source collectie en de body expressies bijhouden.<br />

In deze thesis gebruiken we de eerste aanpak. De uiteindelijke geproduceerde code zorgt voor<br />

heel wat duplicatie van methoden bij gebruik van collectieiteratoren. Indien dat door een<br />

programmeur handgeschreven is kan dat heel wat lastig zijn en tot fouten leiden. Vermits de<br />

code door een tool gegenereerd is, is deze code replicatie niet een probleem. Het enige nadeel<br />

is de grootte van de geproduceerde code. In alle systemen behalve embedded systemen is dat<br />

geen probleem. In embedded systemen waarin de geheugengrootte beperkt is is deze aanpak<br />

minder geschikt. Maar dit ligt buiten het bereik van onze thesis.<br />

3.2.4 Vertaling van OCL if-then-else expressies<br />

Er zijn twee mogelijkheden voor de vertaling van de OCL if-then-else constructie naar<br />

JAVA. Ofwel gebruiken we de corresponderende if-then-else constructie in JAVA ofwel de<br />

korte notatie voor deze constructie. Als voorbeeld geven we de volgende OCL if-then-else<br />

expressie.<br />

Listing 16 Een voorbeeld van een OCL if-then-else expressie<br />

if <br />

then <br />

else <br />

endif<br />

In dit eenvoudige voorbeeld hebben we geen collectieoperaties (collectieiteratoren) opgenomen<br />

maar indien dat het geval was dan zouden we extra hulpmethoden genereren. De JAVA code<br />

maakt gebruik van de verkorte notatie van de if-then-else constructie ook bekend als de<br />

ternaire operator ( ? : ). We gebruiken toch de verkorte notatie van de if-then-else<br />

constructie want deze past eleganter in onze sjablonen.


3.2. BESCHRIJVING VAN DE METHODOLOGIE 33<br />

Listing 17 Sjabloon OCL if-then-else expressie<br />

return (< translation of boolean OCL expression >) ?<br />

: ;<br />

3.2.5 Vertaling van OCL let expressies<br />

In OCL let expressies zijn er lokale variabelen gedenieerd. De implementatie van de let<br />

expressie in JAVA gebeurt op dezelfde wijze. In de sjabloon voor de let expressie worden<br />

deze lokale variabelen ook gedenieerd. Er moet wel aandacht aan de scope van de lokale<br />

variabelen besteed worden. De typen van deze variabelen in de OCL let expressie moeten op<br />

de juiste JAVA typen afgebeeld worden. Dat is het variabel gedeelte voor de let sjabloon. In<br />

de JAVA code is dat te zien met bold-italic lettertypen.<br />

Listing 18 Een voorbeeld van een OCL let expressie<br />

let<br />

tmp1 : Integer = self.attribute1,<br />

tmp2: String = self.attribute2<br />

in<br />

if self.attr3 then<br />

tmp1 >= 18<br />

else tmp1 < 18<br />

endif<br />

De bovenstaande OCL let-expressie illustreert hoe de vertaling naar JAVA gebeurt. Er<br />

kunnen ook nog collectieiteratoren in het 'let' of 'in' deel van de let expressie voorkomen.<br />

In dit geval worden hulpmethoden voor deze collecties gegenereerd.<br />

Listing 19 Sjabloon voor OCL let expressie<br />

boolean result = false;<br />

int tmp1 = this.getAttribute1() ;<br />

String tmp2 = this.get Attribute2() ;<br />

result = (this.getA ttr3() ? tmp1 >= 18 : tmp1 < 18;<br />

return result;<br />

3.2.6 Vertaling van klasse-invarianten<br />

Elke invariant wordt vertaald in een publieke booleaanse methode. Bij de naam van deze<br />

booleaanse methoden wordt de naam van de invariant geconcateneerd. Op deze manier is er<br />

een garantie voor consistentie tussen de verschillende gegenereerde invarianten. De publieke<br />

visibiliteit van de methode zorgt voor dat instantiaties van de klasse waarin deze methode<br />

gedenieerd is een toegang tot deze methode krijgen. Hieronder tonen we een sjabloon van<br />

een methode voor een klasse-invariant die een vast en een variabel gedeelte heeft.


34 HOOFDSTUK 3. METHODOLOGIE<br />

Listing 20 Sjabloon voor inkapseling van OCL invariant expressie in JAVA methode<br />

public boolean checkInvNameOfInvariant(){<br />

return < translation of inv OCL expressie >;<br />

}<br />

OCL expressies mogen constructies bevatten die hulpmethoden vereisten. Voorbeeld van zulke<br />

constructies hebben we al in de vorige sectie gezien, namelijk operaties die over collecties<br />

itereren. In dit geval worden een of meerdere hulpmethoden gegenereerd. Hier moeten we ook<br />

voor unieke namen van deze hulpmethoden zorgen. Dezelfde benadering als bij de namen van<br />

klasse-invarianten is genomen om het probleem van name clashes op te lossen.<br />

Dan zal onze sjabloon er als volgt uitzien.<br />

Listing 21 Sjabloon voor inkapseling van OCL invariant expressie in een JAVA methode<br />

public boolean checkInvNameOfInvariant(){<br />

return typeOfOCLExpressionNameOfInvariant();<br />

}<br />

private type typeOfOCLExpressionNameOfInvariant(){<br />

< template for the corresponding OCL expression >;<br />

}<br />

Met typeOfOCLExpression bedoelen we het type van een OCL expressie. Bijvoorbeeld dat<br />

kan een collectieiterator zijn (forall, exists, ...) of een let expressie of een andere OCL<br />

expressie zijn.<br />

3.2.7 Vertaling van pre- en postcondities<br />

De vertaling van pre- en postcondities heeft een aantal gelijkenissen met de vertaling van<br />

klasse-invarianten: elke pre- en postconditie zal in een aparte booleaanse methode ingekapseld<br />

worden. Er zullen nog hulpmethoden gegenereerd worden indien dit nodig zijn.<br />

Natuurlijk moeten we niet vergeten dat pre- en postcondities altijd bij operaties horen. Bijgevolg<br />

moeten ze bij het lichaam van de operatie zelf ingevoegd worden. Voor precondities is<br />

dat in het begin van de operaties, juist voor het uitvoeren van deze en voor postcondities is<br />

dat juist na het uitvoeren van de operatie.<br />

De sjabloon is hieronder te zien:


3.2. BESCHRIJVING VAN DE METHODOLOGIE 35<br />

Listing 22 Sjabloon voor pre- en postcondities<br />

public boolean checkPreNameOfPreconditionNameOfOperation(){<br />

return ;<br />

}<br />

public boolean checkPostNameOfPostconditionNameOfOperation(){<br />

return ;<br />

}<br />

operation(){<br />

assert checkPreNameOfPreconditionNameOfOperation();<br />

//<br />

// body of the operation<br />

//<br />

assert checkPostNameOfPostconditionNameOfOperation();<br />

//return statement if not void type<br />

}<br />

Klasse-invarianten zijn niet expliciet in operaties opgenomen maar ze moeten toch nagegaan<br />

worden na het uitvoeren van publieke methoden en constructoren. We hebben nog niet getoond<br />

hoe we dat zullen doen. In sectie 3.3 en 3.4 zullen we dat grondig bespreken.<br />

3.2.8 Vertaling van meer geavanceerde constructies<br />

3.2.8.1 Vertaling van het sleutelwoord @pre<br />

Het sleutelwoord @pre representeert de waarde van een attribuut of associatie op het begin<br />

van de uitvoering van een operatie. Dit sleutelwoord moet na de naam van het betrokken<br />

attribuut of associatie vermeld worden. Vermits hier duidelijk te zien is dat we met variabelen<br />

over tijd te maken hebben, moeten tijdelijke variabelen in de vertaalde code voorzien worden.<br />

Een voorbeeld is de volgende OCL postconditie in de context van een operatie operation die<br />

tot de klasse Class behoort.<br />

context Class :: operation(attribute2 : Integer)<br />

post p1:<br />

attribute = attribute@pre + attribute2<br />

Bij de vertaling naar JAVA moeten we een tijdelijke variabele denieren die de waarde van het<br />

attribuut attribute bijhoudt. We zullen deze variabele old_attribute noemen. Old_attribute<br />

moet een kloon of kopie zijn maar geen kopie van de referentie want de gerefereerde waarde<br />

zal tijdens het uitvoeren van de operatie veranderen.


36 HOOFDSTUK 3. METHODOLOGIE<br />

Listing 23 Sjabloon voor OCL @pre expressie<br />

void operation(int attribute2){<br />

int old_attr = this.getAttribute();<br />

// ...<br />

// <br />

// ...<br />

assert checkPostP1Operation(old_attr,attribute2);<br />

}<br />

public boolean checkPostP1Operation(int old_attr, int i){<br />

return this.getAttribute() == old_attr + i;<br />

}<br />

Indien we tijdelijke objecten willen bijhouden gebruiken we dan een kopie-constructor. Kopieconstructors<br />

moeten dan in de klasse waarin de betrokken operatie behoort gedenieerd worden.<br />

Vervolgens mogen we de sjabloon van daarvoor toepassen. De JAVA code tonen we<br />

hieronder:<br />

Listing 24 @pre object<br />

void operation(Object object2){<br />

Object old_obj = new Object(obj);<br />

// ...<br />

// <br />

// ...<br />

assert checkPostP1Operation(old_obj,object2);<br />

}<br />

public boolean checkPostP1Operation(Object old_obj, Object object2){<br />

return this.getObject().getProperty() ==<br />

old_obj.getProperty() + object2.getProperty();<br />

}<br />

3.2.8.2 Het sleutelwoord result<br />

Het sleutelwoord result geeft de terugwaarde van een operatie terug indien er een is. Bijgevolg<br />

is het type van result bepaald door het terugtype van de operatie. Dit sleutelwoord wordt<br />

gebruikt bij postcondities van operaties.<br />

Listing 25 Een voorbeeld van het OCL result sleutelwoord<br />

context Class :: operation(attribute2 : Integer):Integer<br />

post p2: result = attribute2*1000<br />

De resulterende JAVA code is:


3.3. NAÏEVE AANPAK 37<br />

Listing 26 Sjabloon voor OCL result sleutelwoord<br />

int operation(int attribute2){<br />

int result = 0;<br />

// ...<br />

// <br />

// ...<br />

assert checkPostP2Operation(result,attribute2);<br />

return result;<br />

}<br />

public boolean checkPostP2Operation(int result,int i){<br />

return result == this.getAttribute2()*1000;<br />

}<br />

3.3 Naïeve aanpak<br />

In deze sectie illustreren we de meest evidente aanpak. In deze aanpak worden klasseinvarianten,<br />

pre- en postcondities ingekapseld in booleaanse methoden. Klasse-invarianten<br />

moeten waar zijn op ieder consistent moment. Met andere woorden zijn klasse-invarianten<br />

gecontroleerd voor en na elke uitvoering van publieke methodes en constructoren. Alle klasseinvarianten<br />

zijn verder in een gemeenschappelijke booleaanse methode ingekapseld door een<br />

conjunctie van deze invarianten te nemen. Pre- en postcondities worden respectievelijk voor<br />

en na de executie van de publieke methoden en constructoren nagegaan.<br />

3.3.1 Vertaling van invarianten<br />

In de vorige sectie hebben we een beschrijving van een mogelijke vertaling van OCL expressies<br />

naar JAVA gezien. Nu kunnen we deze methodologie op klasse-invarianten in een model<br />

toepassen.<br />

3.3.1.1 Inkapseling van een invariant in een booleaanse methode<br />

De inkapseling van klasse-invarianten en de bijbehorende sjablonen waren al in de vorige<br />

sectie besproken. Hier zullen we meer uitgebreid deze vertaling bespreken. Stel voor dat we<br />

een klasse met een aantal klasse-invarianten hebben:<br />

Listing 27 voorbeeld<br />

context ClassA<br />

inv invariant_1: <br />

inv invariant_2: <br />

inv invariant_3: -> forall()<br />

De vertaling van deze klasse-invarianten naar JAVA is hieronder gegeven. Elke invariant is<br />

vertaald in een booleaanse methode. Bij de naam van elke van deze booleaanse methoden is<br />

de naam van de invariant geconcateneerd. Op deze manier is er een garantie voor consistentie<br />

tussen de verschillende gegenereerde invarianten. In invariant_3 zien we dat we met een


38 HOOFDSTUK 3. METHODOLOGIE<br />

collectieiterator (forall operatie) te maken hebben. In dit geval is een aparte methode<br />

gegenereerd waarin alle bewerkingen omtrent deze invariant ingekapseld zijn.<br />

Listing 28 Sjabloon vertaling van klasse invarianten<br />

public boolean checkInvInvariant1(){<br />

return ;<br />

}<br />

public boolean checkInvInvariant2(){<br />

return ;<br />

}<br />

public boolean checkInvInvariant3(){<br />

return forallInvariant3();<br />

}<br />

private boolean forallInvariant3(){<br />

<br />

}<br />

3.3.1.2 Inkapseling van alle klasse-invarianten in een gemeenschappelijke methode<br />

Eens we een implementatie voor alle invarianten hebben kunnen we deze in een gemeenschappelijke<br />

booleaanse methode inkapselen. Hierin geven we een conjunctie van alle invarianten<br />

terug. Deze methode zal vervolgens na iedere afhandeling van een publieke constructor of<br />

methode opgeroepen worden. Dat zal gebeuren door de assert statement die we in het begin<br />

van dit hoofdstuk besproken hebben. Op deze manier controleren we altijd alle invarianten.<br />

Dat levert een overhead van testen die overbodig kunnen zijn. We zullen een meer geavanceerde<br />

aanpak in volgende sectie bespreken. Hieronder tonen we de JAVA code die alle OCL<br />

invariant-expressies in een gemeenschappelijke methode inkapselt.<br />

Listing 29 Sjabloon checkAllInvariants<br />

public boolean checkAllInvariants(){<br />

return checkInvInvariant1()&&<br />

checkInvInvariant2()&&<br />

checkInvInvariant3();<br />

}<br />

3.3.2 Vertaling van pre- en postcondities<br />

Tot nu hebben we gezien hoe klasse-invarianten vertaald kunnen worden. Hier gaan we bespreken<br />

hoe de vertaling van de pre- en postcondities naar JAVA gebeurt. Pre- en postcondities<br />

horen altijd bij operaties. Bijgevolg zullen we deze in de operaties implementeren waarin ze<br />

gedenieerd zijn. Het mechanisme dat we hier gaan gebruiken is de JAVA assert. Laat ons<br />

veronderstellen dat we een operatie operation1 in de context van een klasse ClassA hebben.<br />

Deze operatie heeft twee precondities en een postconditie. De OCL code is hieronder gegeven:


3.3. NAÏEVE AANPAK 39<br />

Listing 30 voorbeeld operatie met pre- en postcondities<br />

context ClassA :: operation1() : <br />

pre pre1: <br />

pre pre2: <br />

post post1: <br />

Voor elke pre- en postconditie zullen we een aparte booleaanse methode genereren. Daarna<br />

voegen we de pas gegenereerde pre- en postconditiemethoden in in de juiste plaatsen van onze<br />

operatie. Voor precondities is dat in het begin van de operatie. Voor postcondities is dat op<br />

het einde van deze operatie. Het invoegen van deze code gebeurt door de assert constructie<br />

die we in het begin van dit hoofdstuk besproken hebben.<br />

De naam van elke pre- en postconditiemethode is geconcateneerd met de naam van de preof<br />

postconditie die ze voorstellen en met de naam van de operatie waartoe ze behoren. Dat<br />

zorgt voor unieke namen van methoden en lost het probleem van name clashes op.<br />

De JAVA code ziet er als volgt uit:<br />

Listing 31 Sjabloon voor pre- en post-condities bij de naïeve aanpak<br />

operation1(){<br />

assert(checkAllInvariants());<br />

assert(checkPrePre1Operation1());<br />

assert(checkPrePre2Operation1()) ;<br />

//<br />

// body of operation<br />

//<br />

assert(checkPostPost1Operation1());<br />

assert(checkAllInvariants());<br />

}<br />

private boolean checkPrePre1Operation1(){<br />

return ;<br />

}<br />

private boolean checkPrePre2Operation1(){<br />

return ;<br />

}<br />

private boolean checkPostPost1Operation1(){<br />

return ;<br />

}<br />

We moeten ook niet vergeten dat bij operaties klasse-invarianten ook gecontroleerd moeten<br />

worden alhoewel ze niet opgenomen zijn in de operatie. De controle op invarianten moet<br />

voor en na de uitvoering van elke publieke methode en na de uitvoering van elke constructor<br />

gebeuren. Bijgevolg moeten we een assertie van alle invarianten toevoegen. Dat is te zien in<br />

de eerste en laatste regel van de JAVA vertaling voor de operation1() methode.


40 HOOFDSTUK 3. METHODOLOGIE<br />

3.4 Intelligente aanpak<br />

De aanpak die we in de vorige sectie voorgesteld hebben is de meest intuïtieve aanpak. Voor<br />

elke uitvoering van een publieke operatie en na elke uitvoering van een publieke operatie of<br />

constructor toetsen we alle klasse-invarianten. We doen dat door een conjunctie van deze<br />

invarianten te nemen.<br />

In deze sectie stellen we een intelligentere aanpak voor. In plaats van alle klasse-invarianten<br />

te controleren na het uitvoeren van een publieke operatie gaan we alleen maar de relevante<br />

klasse-invariante testen.<br />

3.4.1 Het Idee<br />

De condities die in de klasse-invarianten vastgesteld zijn moeten altijd voldaan voor alle instantiaties<br />

zijn waarvoor deze voorwaarden gedenieerd zijn. Wanneer een instantiatie van<br />

toestand verandert door bijvoorbeeld een publieke operatie erop toe te passen dan moeten<br />

alle condities in de klasse-invarianten ook voldaan zijn. Echter betrekken operaties vaak niet<br />

alle condities van klasse-invarianten op de toegepaste instantiaties. Bijgevolg is de controle<br />

van alle klasse-invarianten overbodig. Bovendien is op deze manier de uitvoeringstijd van<br />

applicaties verhoogd. Een reductie van controles op de geldigheid van klasse-invarianten en<br />

uitvoeringstijd van applicaties is wat we met de intelligente aanpak willen bereiken.<br />

We gaan nu een constructie voorstellen voor de implementatie van een intelligente aanpak.<br />

Binnen deze intelligente aanpak hebben we twee mogelijke implementaties bedacht. De ene is<br />

door een graaf te construeren en de andere is op string matching gebaseerd. We sluiten hierbij<br />

niet uit dat er nog andere manieren zijn om de intelligente aanpak te kunnen implementeren.<br />

3.4.2 Graafconstructie<br />

Het idee van deze aanpak is om een twee-stap graaf te construeren. We willen een afhankelijkheid<br />

tussen invarianten en postcondities van operaties bouwen. In deze constructie hebben<br />

we twee stappen. De eerste stap noemen we post-code generatie en de tweede stap noemen<br />

we pre-compilatie. Bij de eerste stap kijken we naar de postcondities van onze methoden. Bij<br />

de tweede stap kijken we naar de implementaties van onze methoden.<br />

Bij de post-code generatie stap controleren we of de toestand van een variabele of object<br />

veranderd is. Om dat te kunnen doen, doen we beroep op de postcondities van onze operaties<br />

en de klasse-invarianten. Op deze manier kunnen we beslissen welke invarianten na<br />

het uitvoeren van de operatie nagegaan moeten worden. Hierbij zullen niet alle betrokken<br />

objecten of variabelen van toestand veranderen. Bijgevolg verwachten we dat de gegenereerde<br />

verzameling van relevante klasse-invarianten kleiner is.<br />

Indien onze operaties geen postcondities bevatten dan stappen we naar de tweede stap over,<br />

namelijk de pre-compilatie stap.<br />

Bij de pre-compilatie stap kijken we naar alle referenties van de objecten of variabelen betrokken<br />

bij de implementatie van de methode. Vervolgens zoeken we in welke klasse-invarianten<br />

deze variabelen te vinden zijn. Op deze manier selecteren we een deelverzameling van alle


3.4. INTELLIGENTE AANPAK 41<br />

Figuur 3.1: Afhankelijkheid tussen klasse invarianten en postcondities horend bij operaties<br />

klasse-invarianten. Deze deelverzameling is in ieder geval kleiner of gelijk dan de oorspronkelijke<br />

verzameling van alle klasse-invarianten.<br />

Kijken in de broncode van de operatie (pre-compilatie stap) voor variabelen die van toestand<br />

veranderen kan soms lastig zijn. Indien een operatie een andere operatie oproept en deze op<br />

zijn beurt een derde operatie oproept dan ontstaat er een geneste oproep van operaties die tot<br />

een serie van complexe testen leidt.<br />

Laat ons dit uitleggen aan de hand van een klein voorbeeld. Ons voorbeeld heeft drie klasseinvarianten<br />

en een operatie met een postconditie.<br />

Listing 32 voorbeeld<br />

context Class<br />

inv inv1: age > 18<br />

inv inv2: firstName->size()->notEmpty()<br />

inv inv3: lastName->size()->notEmpty()<br />

context Class :: method2()<br />

post post1: lastName = firstName + 'Jr'<br />

In de post-code generatie stap gaan we naar variabelen of objecten kijken die van toestand<br />

veranderen. In ons voorbeeld verandert allen maar de variabele lastName van toestand. Bijgevolg<br />

moeten we alleen inv3 controleren. De corresponderende JAVA code is hieronder<br />

gegeven:


42 HOOFDSTUK 3. METHODOLOGIE<br />

Listing 33 sjabloon post-code<br />

method2(){<br />

//<br />

// body of operation<br />

//<br />

assert(checkPostPost1Method2());<br />

assert(checkInvInv3());<br />

}<br />

In de pre-compilatie stap is de verzameling van klasse-invarianten die gecheckt moeten worden<br />

groter. Hier moeten we naar alle variabelen die betrokken (gerefereerd) zijn in de implementatie<br />

van deze operatie gaan kijken. De variabele betrokken bij inv1 wordt niet gerefereerd<br />

in deze operatie. Daarom beschouwen we deze niet. De variabelen lastName en rstName<br />

worden wel gerefereerd. Deze zijn in inv2 en inv3 betrokken en bijgevolg moeten we deze<br />

twee invarianten controleren. De gegenereerde JAVA code zou zo eruitzien:<br />

Listing 34 sjabloon pre-compilatie<br />

method2(){<br />

//<br />

// body of operation<br />

//<br />

assert(checkPostPost1Method2());<br />

assert(checkInvInv2());<br />

assert(checkInvInv3());<br />

}<br />

3.4.3 String matching<br />

String matching is een lichte versie van de graafconstructie aanpak. Bij deze aanpak wordt geen<br />

expliciete graaf opgebouwd. Hierbij maken we gebuikt van reguliere expressies. Vervolgens<br />

passen we deze reguliere expressies op de postcondities van de operaties toe. Met andere<br />

woorden om te bepalen of een variabele of object in een postconditie van toestand veranderd<br />

is, moet deze aan de linkerkant van een toekenningsoperator zitten of moeten er operaties erop<br />

uitgevoerd worden. Vervolgens wordt het relevante object of variabele (die in een postconditie<br />

van toestand verandert) in alle klasse-invarianten opgezocht. Indien deze in een van de klasseinvariante<br />

betrokken is, dan is deze invariant geselecteerd (toegevoegd aan de verzameling van<br />

relevante klasse-invarianten).<br />

3.4.4 Vertaling van klasse-invarianten<br />

De vertaling van klasse-invarianten is gebaseerd op de sjablonen die we in sectie 3.2 voorgesteld<br />

hebben. Vervolgens zijn deze sjablonen in booleaanse methoden ingekapseld. In subsectie<br />

3.4.4.1 gaan we dat bespreken.


3.5. EVALUATIE 43<br />

3.4.4.1 Inkapseling van een invariant in een booleaanse methode<br />

Inkapseling van klasse-invarianten bij het gebruik van de intelligente aanpak verschilt niet<br />

van de inkapseling van klasse-invarianten bij het gebruik van de naïeve aanpak. Elke klasseinvariant<br />

is in een booleaanse methode ingebakken. Voor meer informatie verwijzen we naar<br />

sectie 3.3.1.1<br />

Wat hier meer aandacht vereist is de inkapseling van de relevante klasse-invarianten in een<br />

gemeenschappelijke booleaanse methode. Dat gaan we hieronder bespreken.<br />

3.4.4.2 Inkapseling van alle relevante klasse-invarianten in een gemeenschappelijke<br />

booleaanse methode<br />

Bij de naïeve aanpak hebben we gezien dat alle klasse-invarianten in een gemeenschappelijke<br />

methode ingepakt waren door een conjunctie van deze te nemen.<br />

Een mogelijke oplossing voor de intelligente aanpak is opnieuw een conjunctie van de relevante<br />

klasse-invarianten te nemen die vervolgens in een gemeenschappelijke methode ingekapseld<br />

worden. Het bepalen van de verzameling van relevante klasse-invarianten hangt af van de<br />

postconditie of de implementatie van een publieke methode. Wat een nadeel hier kan zijn<br />

is dat we telkens voor elke operatie een gemeenschappelijke methode zullen hebben die een<br />

conjunctie van de bijbehorende relevante klasse-invarianten zou bevatten. Daarom stellen we<br />

hieronder een andere oplossing voor.<br />

Een tweede oplossing is om in plaats van een conjunctie van alle relevante klasse-invarianten<br />

te nemen, voegen we elke relevante klasse-invariant op het einde van een methode toe door<br />

gebruik van de assert constructie te maken. Met andere woorden zijn de relevante klasseinvarianten<br />

bij een operatie niet in een gemeenschappelijke methode ingepakt. Op deze manier<br />

verwijderen we de overhead van generatie van methoden die de geldigheid van klasseinvarianten<br />

voor elke operatie gaan controleren.<br />

3.4.5 Vertaling van pre- en postcondities<br />

Voor de vertaling van pre- en postcondities van een methode verwijzen we naar 3.3.2. Het<br />

enige verschil dat hier zou kunnen zijn is dat de gemeenschappelijke methode omtrent het<br />

nagaan van klasse-invarianten op basis van subsectie 3.4.4.2 zou gegenereerd worden. Met<br />

andere woorden kunnen we ofwel een conjunctie van de relevante klasse-invarianten nemen<br />

ofwel de relevante klasse-invarianten afdrukken door de assert constructie te gebruiken.<br />

3.5 Evaluatie<br />

In deze sectie zullen we de naïeve en de intelligente aanpak evalueren in functie van uitvoeringstijd.<br />

Om dat te kunnen doen hebben we een klein lopend voorbeeld bedacht (zie Figuur<br />

3.1). Daarna hebben we manueel de code met de bijbehorende beperkingen voor de naïeve en<br />

de intelligente aanpak gemodelleerd.


44 HOOFDSTUK 3. METHODOLOGIE<br />

Wat wij met dit voorbeeld willen meten is de verhouding van de twee aanpakken ten opzichte<br />

van elkaar. In de naïeve aanpak hebben we op iedere uitvoering van een publieke methode<br />

alle gedenieerde klasse-invarianten getest. Bij de intelligente aanpak hebben we maar een<br />

deelverzameling van alle klasse-invarianten gecontroleerd. Deze deelverzameling is afhankelijk<br />

van de opgeroepen operatie.<br />

Ons lopend voorbeeld bestaat uit vijf klassen met een totaal van 21 klasse-invarianten.<br />

Om betrouwbare uitvoeringstijd te verkrijgen hebben we de testen 100000 keer in een lus laten<br />

draaien. Op deze manier verkrijgen we een acceptabele meting voor onze testverzameling.<br />

Het experiment wordt uitgevoerd op een PC 1.4 Ghz machine met 512 MB RAM geheugen<br />

en Windows XP als besturingssysteem.<br />

De resultaten wijken niet veel van onze veronderstellingen af. We hebben een verschil in<br />

uitvoeringstijd van 1.6 keer meer bij de naïeve aanpak dan bij de intelligente aanpak gemeten<br />

op voorwaarde dat onze methoden geen computationeel intensieve implementaties bevatten.<br />

De gemeten factor van 1.6 kan sterk variëren. In ons experiment is het nagaan van de klasseinvarianten<br />

de dominante operatie in een methode en vandaar komt deze versnelling tot 40<br />

percent bij de intelligente aanpak. Indien onze methoden computationeel intensieve algoritmes<br />

bevatten of grote bestanden aan lezen of wegschrijven zijn dan wordt het nagaan van<br />

consistentie van klasse-invarianten niet meer de dominanten factor. Dan verwachten we bijna<br />

gelijke metingen te krijgen zowel voor de intelligente aanpak als voor de naïeve aanpak.<br />

aanpak gemetentijd met init gemetentijd zonder init<br />

naïeve 8.6 sec 3.4 sec<br />

intelligente 5.2 sec 0.4 sec<br />

Tabel 3.7: De resultaten van de evaluatie van naïeve en de intelligente aanpak<br />

Indien we de initialisatie van de objecten en de oproep van constructoren buiten de lus doen,<br />

hebben we een factor van 7.9 gemeten. In dit geval is de naïeve aanpak tot bijna 8 keer<br />

trager dan de intelligente aanpak. Dit is te wijten aan het feit dat in JAVA de initialisatie<br />

van objecten en de oproep van constructoren veel tijd vraagt. Indien we de initialisatie buiten<br />

de lus laten dan wordt duidelijk dat de dominante factor het nagaan van voldoening van<br />

klasse-invarianten wordt en bijgevolg verkrijgen we deze factor van bijna 8.<br />

Ons voorbeeld bestaat maar uit een model uit 5 klassen en 21 invarianten. In totaal zijn er 8<br />

publieke operaties opgeroepen. We verwachten dat het toepassen van de intelligente aanpak<br />

bij grootschalige systemen toch een voordeel over de naïeve aanpak zou hebben.<br />

De code van ons experiment is terug te vinden op de CD horende bij deze thesis.


3.5. EVALUATIE 45<br />

Figuur 3.2: Klassediagram van het lopende voorbeeld.


Hoofdstuk 4<br />

Realisatie in HAT<br />

In dit hoofdstuk gaan we eerst een inleiding tot het HAT tool geven. Vervolgens gaan we<br />

beschrijven hoe de methodologie die we in hoofdstuk 3 besproken hebben in de context van<br />

het HAT tool kunnen toepassen. Namelijk welke stukken van de methodologie mogen wel<br />

geimplementeerd worden in HAT en welke niet.<br />

4.1 HAT<br />

Het HAT tool van de rma E2S (onlangs hernoemd naar ATO) is een UML tool dat Agile<br />

MDA ondersteunt. De architectuur van dit tool bestaat uit drie stukken.<br />

1. UML editor. Dat is het belangrijkste tool en biedt een grasche interface om applicatiemodellen<br />

te denieren, samenhangendheid van constraints na te gaan, transformaties<br />

van modellen naar andere modellen of naar broncode uit te voeren en documenten te<br />

genereren. Al dat wordt ondersteunt door verschillende proelen. UML proelen worden<br />

in de interactieve prole builder gedenieerd en documentproelen in de interactieve<br />

document generator.<br />

• Een UML proel wordt gebruikt om de vereiste grasche representatie van verschillende<br />

objecten te tonen of beperkingen na te gaan of een model in een ander model<br />

te transformeren en code te genereren.<br />

• Een documentproel wordt gebruikt om de vereiste documenten van een gegeven<br />

UML model te produceren<br />

2. Interactive prole builder. Een UML proel bevat OCL constraints op het model,<br />

modeldenities, modeltransformaties, codegeneratoren, specicaties van diagrammen,<br />

grasche representatie van klassen, stereotypen, ... enz.<br />

3. Interactive document generator. Deze generator maakt gebruik van documentpro-<br />

elen waarin de gebruiker de inhoud van de nodige document denieert en de volgorde<br />

beschrijft waarin de data van een UML model moet verschijnen.<br />

46


4.1. HAT 47<br />

Figuur 4.1: Architectuur van de Agile MDA Tool<br />

Figuur 4.1 geeft een overzicht van de architectuur van dit Agile MDA tool. De modeltransformatie<br />

en codegeneratie gebeurt aan de hand van de UML proelen. Deze proelen<br />

moeten eerst in de UML editor ingeladen worden. Binnen zo'n proel speciceert men een<br />

representatie van een UML model en hoe het model getransformeerd moet worden.<br />

De interactive prole editor biedt een interface om UML proelen te denieren en bewerken.<br />

Deze laat ons toe om zowel modelelementen binnen een domein te denieren als om<br />

beperkingen en codegeneratoren over dit domein te speciceren.<br />

De run-time OCL constraints die in het model zitten mogen ook geëvalueerd worden. Men<br />

moet gewoon voor elke OCL constraint op het UML model de functie GenerateCode() oproepen<br />

die drie argumenten meekrijgt. De eerste is een stringwaarde die de operatie bevat<br />

om een generator op te roepen, de tweede is het tekstbestand waarin de gegeneerde code geschreven<br />

zal worden en de derde is een stringwaarde die gebruikersgedenieerde inhoud bevat<br />

(bijvoorbeeld contextinformatie). We mogen verschillende generatoren voor dezelfde run-time<br />

OCL expressie meegeven indien dat nodig is. Deze operatie transformeert de run-time OCL<br />

expressie naar een expressieboom. De elementen in deze boom zijn OCL modelelementen<br />

die aan het OCL metamodel corresponderen. Dit metamodel denieert verschillende soorten<br />

van OCL expressiemeta-elementen: literalen, if-expressie, let-expressie, enz. Een deel van het<br />

OCL metamodel is te zien in Figuur 4.2. De meegegeven generator aan de GenerateCode()<br />

operatie gaat vervolgens schrijvers voor elk OCL modelelement oproepen. Deze schrijvers<br />

zullen eigenlijk de code voor onze applicatie produceren voor de gegeven OCL expressies.<br />

In volgende sectie zullen we de vertaling van run-time OCL expressie naar JAVA bespreken<br />

met behulp van het HAT tool van E2S.


48 HOOFDSTUK 4. REALISATIE IN HAT<br />

Figuur 4.2: Gesimpliceerde OCL meta-model<br />

4.2 Run-time OCL naar JAVA<br />

In hoofdstuk 3 hebben we een mogelijke methodologie voorgesteld om run-time OCL expressie<br />

naar JAVA te vertalen. We hebben verschillende sjablonen voor verschillende OCL modelelementen<br />

voorgesteld. Nu gaan we deze methodologie in het HAT tool van E2S toepassen.<br />

Om een run-time OCL expressie te kunnen evalueren moeten we eerst van een run-time OCL<br />

expressie een expressieboom maken. In het HAT tool gebeurt dat door de operatie GenerateCode()<br />

op te roepen. Deze expressie boom bevat OCL modelelementen. Voor elk van<br />

deze modelelementen moeten we een representatie naar een doeltaal voorzien, in ons geval<br />

is dat JAVA. Om deze representatie te kunnen produceren geven we een generator aan de<br />

GeneratorCode() operatie mee. Deze generator moet een aantal schrijvers bevatten waarin<br />

voor elk OCL modelelement een representatie naar JAVA voorzien is. De representatie van<br />

deze schrijvers bevat eigenlijk de sjablonen die we in hoofdstuk 3 voorgesteld hebben.<br />

Met andere woorden om broncode in het HAT tool te produceren moet men voor elk OCL<br />

modelelement in de expressieboom de bijbehorende schrijver met zijn bijbehorende representatie<br />

toepassen. Toch is deze oplossing niet altijd van toepassing. In subsectie 4.2.2 gaan we<br />

uitleggen wat er mis kan gaan en wat een mogelijke oplossing zou kunnen zijn.<br />

Nu gaan we voor een aantal run-time OCL modelelementen bespreken hoe we de sjablonen<br />

(voorgesteld in hoofdstuk 3) zullen toepassen.


4.2. RUN-TIME OCL NAAR JAVA 49<br />

Figuur 4.3: Abstract syntax metamodel voor ModelPropertyCallExpr<br />

4.2.1 OCL attribuut-, associatie- en operatiemodelelementen<br />

De sjablonen die we voor attributen en associaties voorgesteld hebben zijn probleemloos toepasbaar<br />

in het HAT tool. Telkens we een attribuut- of associatiemodelelement in een expressieboom<br />

ontmoeten roepen we de bijbehorende schrijvers voor deze modelelementen (resp.<br />

modelelementen van type AttributeCallExpr en modelelementen van type AssocEndExpr zie<br />

Figuur 4.3). Indien we met een operatiemodelelement te maken hebben roepen we dan de<br />

schrijver die bij dit modelelement hoort, namelijk een schrijver van type OperationCallExpr.<br />

4.2.2 OCL collectieiterator modelelementen<br />

In hoofdstuk 3 over de methodologie hebben we grondig besproken dat we voor collectieiteratoren<br />

wat extra code moeten genereren. De reden is dat deze OCL collectieoperaties geen


50 HOOFDSTUK 4. REALISATIE IN HAT<br />

tegenhangers in JAVA API hebben.<br />

Bij het doorlopen van een expressieboom gaan we voor elk OCL modelelement de bijbehorende<br />

schrijver oproepen. Deze schrijvers zullen een JAVA representatie voor het OCL modelelement<br />

produceren. Voor collectieiteratoren moeten we nieuwe hulpmethoden genereren die geen<br />

tegenhangers in JAVA hebben. Bij het doorlopen van een OCL expressieboom willen we<br />

maar een oproep naar deze extra hulpmethoden produceren. Natuurlijk moeten deze extra<br />

hulpmethoden ergens anders gegenereerd worden.<br />

Nu wordt duidelijk dat indien we met een generator te werk gaan komen we terecht in een probleem.<br />

De oproep naar een gewenste hulpmethode wordt wel geproduceerd maar de methode<br />

zelf is nergens gegenereerd.<br />

We hebben dat opgelost door voor elk OCL modelelement dat extra hulpmethoden vereist,<br />

nieuwe generatoren te creëren. Deze nieuwe generatoren zullen voor elk OCL modelelement een<br />

schrijver hebben. Natuurlijk deze schrijvers zullen een verschillende representatie (sjabloon)<br />

bevatten.<br />

Met andere woorden gaan we voor een run-time OCL expressie de operatie GenerateCode()<br />

telkens met verschillende generatoren oproepen. Bij de eerste oproep van de GenerateCode()<br />

operatie wordt een oproep naar een gewenste hulpmethode gecreëerd. Vervolgens wordt opnieuw<br />

de GenerateCode() operatie met een andere generator opgeroepen. Deze generator zal<br />

maar schrijvers voor OCL elementen van type LoopExpr hebben. Deze schrijver zal de sjablonen<br />

voor de verschillende collectieiteratoren bevatten die eigenlijk de hulpmethoden zullen<br />

produceren.<br />

4.2.3 OCL If-then-else en let modelelementen<br />

De voorgestelde sjabloon in hoofdstuk 3 voor OCL if-then-else expressie kunnen we ook<br />

in HAT implementeren. We doen dat door in de schrijvers voor OCL modelelementen van<br />

type IfExpr de sjabloon voor if-then-else expressie toe te voegen. Indien de if-then-else<br />

expressies een of meerdere collectieiteratoren bevatten dan moeten we de aanpak van subsectie<br />

4.2.2 implementeren. Namelijk roepen we een tweede keer de GenerateCode() operatie op met<br />

de generator voor collectieiteratoren.<br />

Voor OCL let-expressies gaan we de bijbehorende sjabloon in een aparte hulpmethode inkapselen<br />

zoals in hoofdstuk 3 uitgelegd was. Om dat te kunnen implementeren gaan we bij<br />

de eerste oproep van de GenerateCode() operatie een oproep naar een let methode produceren.<br />

Vervolgens gaan we een tweede keer GenerateCode() oproepen met een andere generator<br />

(generator voor OCL let expressie) die de let methode zelf gaat genereren.<br />

4.2.4 Inkapseling van collectieoperaties<br />

In subsectie 3.2.3.3 hebben we verschillende oplossingen voorgesteld voor inkapseling van OCL<br />

collectieoperatiesjablonen in JAVA methoden. Voor de transformatie van run-time OCL expressie<br />

naar JAVA in HAT hebben we de eerste oplossing geimplementeerd. We hebben dat<br />

al in subsectie 4.2.2 op de vorige pagina besproken.<br />

De tweede voorgestelde oplossing waarbij we een keer een standaard bibliotheek met alle collectieoperaties<br />

genereren, is moeilijk in de huidige versie van HAT te implementeren. Het idee


4.3. NAÏEVE AANPAK IN HAT 51<br />

van deze oplossing is dat we voor elke collectieoperatie de source (de collectie waarop we<br />

de collectieoperatie zullen toepassen) en de body ( het lichaam van de collectieoperatie in de<br />

vorm van een expressie) moeten als parameters doorgeven. Voor de source is dat geen probleem<br />

maar vermits de body meestal een uitvoerbare expressie is wordt dan de implementatie<br />

onmogelijk.<br />

De derde voorgestelde oplossing is ook niet mogelijk te implementeren in de huidige versie van<br />

HAT. De datastructuur die bijhoudt welke collectieoperatie met de bijbehorende source en<br />

body al gegenereerd was bevindt zich in het OCL metamodel horend bij een gegeven generator.<br />

We hebben al gezien dat de overgang van het UML metamodel naar het OCL metamodel<br />

gaat met de GenerateCode operatie. Maar de GenerateCode operatie wordt telkens met<br />

verschillende generatoren opgeroepen. Op deze manier is de referentie naar deze datastructuur<br />

verloren<br />

4.3 Naïeve aanpak in HAT<br />

De implementatie van de naïeve aanpak in HAT gebeurt aan de hand van een UML proel.<br />

Dit UML proel bevat eigenlijk de transformaties (vertaling van run-time OCL expressies)<br />

naar JAVA.<br />

De geproduceerde code komt overeen met de methodologie die wie in hoofdstuk 3 voorgesteld<br />

hebben. Klasse-invarianten worden in booleaanse methoden ingepakt en er is een gemeenschappelijke<br />

methode gegenereerd die een conjunctie van alle invarianten bevat.<br />

Bij operaties worden zowel pre- als postcondities gegenereerd. Deze zijn in booleaanse methoden<br />

geencapsuleerd. Vervolgens zijn deze pre- en postconditiemethoden bij de horende<br />

operatie (respectievelijk in het begin en op het einde van de operatie) toegevoegd met de<br />

assert constructie. In het begin en op het einde van het lichaam van een operatie is ook de<br />

gemeenschappelijke methode toegevoegd die alle klasse-invarianten nagaat.<br />

4.4 Intelligente aanpak in HAT<br />

Voor de implementatie van de intelligente aanpak in HAT maken we opnieuw gebruik van een<br />

UML proel dat onze transformaties bevat.<br />

Voor de vertaling van klasse-invarianten, pre- en postcondities hebben we de implementatie van<br />

de naïeve aanpak overgenomen en vervolgens hebben we een aantal aanpassingen toegevoegd<br />

om de intelligente aanpak te kunnen implementeren. Met andere woorden inkapseling van<br />

klasse-invarianten, pre- en postcondities gebeurt op precies dezelfde manier als in de naïeve<br />

aanpak: elke invariant, pre- en postconditie is in een booleaanse methode ingepakt.<br />

De aanpassing die we gemaakt hebben betreft de assertie van relevante klasse-invarianten op<br />

het einde van het uitvoeren van operaties in plaats van een conjunctie van alle aanwezige<br />

invarianten te nemen.<br />

Deze aanpassingen zijn gebaseerd op string matching.<br />

Het idee is als volgt: voor elke postconditie van een operatie zoeken we of er een object of<br />

variabele tijdens de uitvoering van de operatie aangepast is. Dat doen we aan de hand van


52 HOOFDSTUK 4. REALISATIE IN HAT<br />

Algorithm 1 Algoritme intelligente aanpak gebaseerd op string matching<br />

foreach operation<br />

if(set of postconditions not empty)<br />

foreach postcondition<br />

pat := search for pattern<br />

foreach invariant<br />

find pat<br />

if(found)<br />

print invariant using assert construction<br />

else do nothing<br />

else do nothing<br />

reguliere expressies. Vervolgens gaan we zoeken of dit object (variabele) ook in een van de<br />

klasse-invarianten betrokken is. Indien dat het geval is gaan we deze invariant afdrukken door<br />

gebruik van de assert constructie. We tonen het algoritme in Algorithm1.<br />

Dat kan in sommige gevallen goed werken maar de mogelijkheid voor het afdrukken van dezelfde<br />

invariant meerdere keren in een operatie is niet uitgesloten. Bijgevolg is onze intelligente<br />

aanpak niet meer intelligent.<br />

We willen dit probleem oplossen door in plaats van elke keer de gevonden invariant af te<br />

drukken, gaan we deze in een collectie opslaan en dan duplicaten weghalen. Vervolgens door<br />

het afdrukken van ieder element van deze collectie krijgen we het gewenste resultaat.<br />

4.5 Evaluatie<br />

Voor de evaluatie van dit tool gaan we opnieuw de voorgestelde criteria van hoofdstuk 2<br />

gebruiken. We hebben al in hoofdstuk 2 gezien dat de geëvalueerde tools geen mogelijkheden<br />

aanbieden om aanpassingen en verjningen aan de gegenereerde code uit te voeren. Wat wel<br />

mogelijk is is allen een model en de bijbehorende beperkingen te modelleren en vervolgens code<br />

te genereren. In HAT is wel mogelijk dat een gebruiker stereotypen, regels en constraints en<br />

code specicatie zelf kan denieren. Dit gebeurt met behulp van UML proelen. Eens zijn deze<br />

UML proelen op UML modellen toegepast dan verrijken deze UML proelen de modellen<br />

en bovendien controleren ze of het model met de opgestelde constraints samengaat. UML<br />

proelen kunnen ook verschillende projectproducten opleveren: documenten, testsequenties,<br />

metrieken enz.<br />

Hieronder vatten we alles samen.


4.5. EVALUATIE 53<br />

Id Criteria Opmerking Ondersteuning<br />

1 invarianten Ja<br />

2 pre-, postcondities Ja<br />

3 attributen, Ja<br />

associaties<br />

4 collecties Voor ieder collectieiterator Ja<br />

een nieuwe methode<br />

5 @pre Neen<br />

6 result Neen<br />

7 assertion Ja<br />

8 slimme controle Ja<br />

klasse invarianten<br />

Tabel 4.1: Evaluatie van HAT


Hoofdstuk 5<br />

Case study - Royal and Loyal<br />

In dit hoofdstuk willen we nagaan hoe de transformatie van OCL expressies naar JAVA die we<br />

met behulp van het HAT tool geimplementeerd hebben in werkelijkheid kunnen toepassen. Om<br />

dat te realiseren hebben we als gevalstudie het voorbeeld van [1] overgenomen. Dit voorbeeld<br />

gaat over een software systeem van een imaginaire bedrijf die Royal and Loyal (R&L) noemt.<br />

5.1 Beschrijving van de case study<br />

R&L behandelt loyaliteitsprogrammas voor bedrijven die aan hun klanten verschillende soorten<br />

van bonussen bieden. Deze toeslagen hebben meestal de vorm van extra punten of air<br />

miles maar zijn er ook andere soorten van bonussen mogelijk. Met andere woorden eender<br />

welke dienst een bedrijf wenst te bieden dan is deze in een loyaliteitsprogramma overgebracht.<br />

figuur 5.1. toont het UML klassemodel dat R&L voor het meest van zijn klanten gebruikt.<br />

De centrale klasse in het model is LoyalyProgram. Een bedrijf dat aan zijn klanten lidmaatschap<br />

in een loyaliteitsprogramma biedt noemen we ProgramPartner. Meer dan een bedrijf<br />

mag gebruik maken van hetzelfde programma. Bijgevolg kunnen klanten van alle diensten<br />

genieten die door de participerende bedrijven aangeboden zijn indien ze in een loyaliteitsprogramma<br />

participeren.<br />

Elke klant van een ProgramPartner kan in een loyaliteitsprogramma toetreden door het invullen<br />

van een formulier en het verkrijgen van een lidmaatschapskaart. De klasse Customer<br />

representeert de klanten die in het programma participeren. De lidmaatschapskaart is door<br />

de klasse CustomerCard voorgesteld. Een CustomerCard is maximaal aan een persoon geassocieerd,<br />

maar kan gebruikt worden door de ganse familie of zaak. De meeste programmas<br />

laten klanten toe om punten te sparen. Elke individuele programmapartner beslist de toekenning<br />

van punten aan zijn klanten voor een bepaalde aankoop. Elke klant kan met zijn/haar<br />

bespaarde punten specieke diensten van een van de programmapartners aankopen. Beheren<br />

van spaarpunten is in klasse LoyaltyAccount opgenomen.<br />

Op een LoyaltyAccount zijn verschillende transacties mogelijk: transacties waarbij een klant<br />

punten verkrijgt en andere waarbij een klant punten besteedt. De eerste soort is in ons systeem<br />

als de klasse Earning modelleert en de tweede als Burning. Deze twee soorten van transacties<br />

zijn als subklassen van de klasse Transaction gemodelleerd.<br />

54


5.2. VERTALING MET BEHULP VAN HAT 55<br />

Figuur 5.1: Het aangepaste model van Royal and Loyal<br />

De klasse ServiceLevel is geïntroduceerd om verschillende niveaus van diensten te besturen.<br />

Deze is gedenieerd door een loyaliteitsprogramma en is door een lidmaatschap gebruikt.<br />

5.2 Vertaling met behulp van HAT<br />

Het oorspronkelijke klasse-diagram van daarboven hebben we licht aangepast om de constraints<br />

van dit model te kunnen transformeren naar JAVA . Uit de associatieklasse Membership<br />

hebben we een gewone klasse gemaakt. De reden voor deze aanpassing was dat veel van de OCL<br />

expressies (die bij dit model horen) konden niet gevalideerd worden in HAT. In de volgende<br />

paragraaf gaan we meer concreet bespreken welke soort van constraints niet gevalideerd kon.


56 HOOFDSTUK 5. CASE STUDY - ROYAL AND LOYAL<br />

Figuur 5.2: Het model van Royal and Loyal<br />

We hebben alle constraints op het model gegenereerd met behulp van het HAT tool met<br />

paar uitzonderingen. Met sommige constraints hadden we moeilijkheden om deze te kunnen<br />

valideren in het tool zelf. Indien een beperking niet gevalideerd is dan kan deze niet gegenereerd<br />

worden. Bijgevolg moesten we de constraints licht aanpassen om deze te kunnen genereren.<br />

We gaan nu de punten bespreken waarop we aanpassingen moesten uitvoeren of gewoon niets<br />

konden doen.<br />

• Indien we in een OCL expressie een associatie hebben die een collectie van objecten<br />

voorstelt (dus multipliciteit is groter dan een) en indien deze associatie op zijn beurt<br />

een tweede associatie oproept dan worden zulke OCL expressie in HAT niet gevalideerd.


5.2. VERTALING MET BEHULP VAN HAT 57<br />

In zulke gevallen zijn er geen mogelijkheden om aanpassingen uit te voeren. Bijgevolg<br />

hebben we OCL expressies van deze soort genegeerd. We geven een voorbeeld van zo'n<br />

OCL expressie in de context LoayaltyProgram zie figuur 5.1<br />

context LoayaltyProgram<br />

inv:<br />

partners.deliveredServices -> forall(x|x.condition = true)<br />

• Indien we twee klassen hebben die met elkaar verbonden worden met een associatieklasse,<br />

dan kunnen we niet navigeren via deze associatieklasse. In OCL navigeert men in<br />

dergelijke situaties door de naam van de associatieklasse te concateneren aan de naam<br />

van het gewenste associatieeinde en deze met een punt uit elkaar te scheiden. De naam<br />

van de associatieklasse moet met een hoofdletter beginnen. In HAT worden deze OCL<br />

expressies niet gevalideerd. Dat was ook een van de redenen waarom we onze associatieklasse<br />

Membership naar een gewone klasse getransformeerd hebben. Voorbeeld van<br />

zulke expressies is de volgende OCL expressie (zie figuur 5.1)<br />

context Customer<br />

inv:<br />

Membership.account -> select(x|x.points>0)->isEmpty()<br />

• Indien we constraints in de context van een associatieklasse willen denieren dan moeten<br />

we deze in HAT denieren bij een van de betrokkene klassen bij deze associatieklasse.<br />

Met andere woorden wordt de context van deze constraint niet de associatieklasse maar<br />

een van de betrokken klassen. Daarvoor hebben we uit de associatieklasse een gewone<br />

klasse gemaakt.<br />

• Veel van de postcondities bevatten sleutelwoorden zoals @pre en result. Voor OCL expressies<br />

die het sleutelwoord result bevatten kunnen we niets doen. Deze expressies zijn<br />

niet gevalideerd. De sleutelwoorden @pre hebben we gewoon niet toegevoegd. Bijgevolg<br />

is ook de betekenis van een OCL expressie veranderd maar deze expressies zijn wel gevalideerd<br />

in HAT en gegenereerd. Indien we zulke OCL expressie negeren dan kunnen we<br />

onze intelligente aanpak niet testen. Daarom hebben we zulke expressies behouden maar<br />

we hebben deze licht aangepast aangepast . Bijvoorbeeld de volgende OCL expressie:<br />

context LoayaltyProgram::enroll(c:Customer)<br />

post:<br />

wordt<br />

participants = participants@pre->including(c)<br />

context LoayaltyProgram::enroll(c:Customer)<br />

post:<br />

participants = participants->including(c)<br />

De aanpakken die we in hoofdstuk 3 ontwikkeld hebben werkten zoals ze beschreven waren.<br />

We konden een groot deel van de code direct van ons model genereren. Indien we nu onze<br />

gegenereerde code met de handgeschreven code gaan vergelijken dan zou er toch een groot<br />

verschil zijn. Een groot deel was hierboven beschreven.<br />

We hebben een inspanning gedaan om het tool te laten evalueren op een gevalstudie. Indien<br />

we sommige aanpassingen niet gedaan hebben op ons model zouden de resultaten niet bevredigend<br />

worden. Maar de tekorten wat betreft associatieklassen kunnen altijd opgelost worden.


58 HOOFDSTUK 5. CASE STUDY - ROYAL AND LOYAL<br />

Telkens we een UML proel creëren wordt deze uit een default proel afgeleid. Deze default<br />

proel heeft een aantal ingebakken constraints (bijvoorbeeld, ). Dat zijn allemaal beperkingen<br />

die een rem kunnen worden om verschillende gevalstudies te reproduceren. Maar dat zou niet<br />

zeggen dat deze gevalstudies niet op een andere manier gemodelleerd kunnen worden in HAT<br />

om de semantiek ervan te behouden.


Hoofdstuk 6<br />

Besluit<br />

MDD zou moeten een revolutionair softwareontwikkelingstijdperk inluiden waarbij alle aandacht<br />

gevestigd wordt op abstracte modellen van een applicatie op verschillende niveaus van<br />

detail in plaats van op de code. Automatische transformaties tussen deze modellen hebben<br />

een centrale rol in MDD namelijk zorgen deze dat bepaalde aspecten correct ingevuld worden.<br />

Eens zijn deze transformaties gedenieerd kan dan code automatisch gegenereerd worden.<br />

6.1 Doelstellingen en problemen<br />

De doelstellingen waren in het begin van de thesis ruim omschreven. We wouden een bepaald<br />

aspect van de modeltransformaties bestuderen, namelijk transformaties van OCL expressies<br />

naar werkende code. De doeltaal van de transformatie moest JAVA zijn. Daarvoor hebben we<br />

twee aanpakken uitgewerkt voor deze specieke transformaties (codegeneraties). Deze twee<br />

aanpakken zijn onafhankelijk van de transformatie naar een doelprogrammeertaal. De eerste<br />

aanpak die we de naïeve noemen controleert alle constraints op ieder stabiel moment van<br />

een systeem. Deze aanpak is ook de meest intuïtieve aanpak. De tweede aanpak is meer<br />

geavanceerd. Bij deze aanpak hebben we een methode ontwikkeld die laat ons toe om op een<br />

slimme manier constraints na te gaan. Deze aanpakken zijn onafhankelijk van de doeltaal<br />

waarmee we deze transformatie (codegeneratie) zullen produceren.<br />

Oorspronkelijk hebben we intensief naar tools gezocht om deze specieke transformaties te<br />

kunnen implementeren. We wilden gebruik maken van MOFScript [23]. Al snel werd duidelijk<br />

dat we deze transformaties niet zouden kunnen implementeren. De reden was dat MOFScript<br />

niet over een OCL parser beschikte.<br />

Het schrijven van een OCL parser en dan integreren in MOFScript was ver van de doelstellingen<br />

van deze thesis. Daarom hebben we dit idee verlaten.<br />

6.2 Oplossing<br />

We hebben het HAT tool van E2S gebruikt om onze doelstellingen te kunnen implementeren.<br />

De resultaten verkrijgen van dit tool waren bevredigend voor de naïeve aanpak. De<br />

doelstellingen wat betreft deze aanpak waren bereikt.<br />

59


60 HOOFDSTUK 6. BESLUIT<br />

De oorspronkelijke mogelijkheden van HAT lieten ons niet toe om de intelligente aanpak te<br />

implementeren. Dat was eigenlijk het moment van de geboorte van de intelligente aanpak<br />

gebaseerd op string matching. Deze methode zoekt voor elke postconditie horend bij een<br />

publieke operatie welke object of variabele tijdens de uitvoering van deze operatie zou moeten<br />

aangepast worden. Vervolgens gaan we de gevonden object of variabele met een of meerdere<br />

klasse-invarianten proberen te matchen. Met deze oplossing hebben we het probleem van de<br />

intelligente aanpak niet kunnen implementeren omgezeild.<br />

Tijdens de implementatie in HAT hebben we samen met E2S naar verschillende oplossingen<br />

gezocht om wat verjningen aan het tool aan te brengen.<br />

6.3 Kritische noot<br />

Een nadeel van het HAT tool is dat er geen ondersteuning is voor sleutelwoorden zoals @pre<br />

en result. Blijkbaar is de complexiteit verhoogd om deze sleutelwoorden te implementeren<br />

dan de voordelen die dat zou opbrengen.<br />

Naast de methodologie die we voor het bereiken van de doelstellingen ontwikkeld hebben,<br />

hebben we ook een evaluatie van bestaande tools gemaakt die run-time OCL ondersteunen.<br />

Voor onze grote verassing wat wij uit de gegenereerde code gemerkt hebben is dat er geen enkel<br />

van de geëvalueerde tools een meer intelligente, slimme implementatie had voor het nagaan<br />

van voldoening van constraints. Alle tools volgen min of meer een aanpak die op onze naïeve<br />

aanpak lijkt. Dat plaats HAT tool een stap voor zijn concurrenten alhoewel nog wat werk<br />

moet gedaan worden om een een deftige implementatie van de intelligente aanpak in HAT te<br />

hebben.<br />

6.4 Toekomstig werk: uitbreidingen en aanpassingen<br />

We hebben aangegeven hoe run-time OCL expressies naar werkende code in HAT getransformeerd<br />

kunnen zijn. We sommen enkele uitbreidingen op die nuttig zijn om het systeem<br />

bruikbaarder te maken.<br />

Het zou interessant zijn om een ondersteuning voor sleutelwoorden zoals @pre en result te<br />

voorzien. Dat zou het tool bruikbaarder maken wat betreft transformaties van run-time OCL<br />

expressies.<br />

Op basis van de methodologie die we in deze thesis ontwikkeld hebben, zouden we generatoren<br />

ook in andere talen moeiteloos kunnen implementeren.<br />

Een volledige beschrijving van OCL taal kan ook beschouwd worden. De methodologie die we<br />

voorgesteld hebben, is niet volledig in de zin dat we maar een deelverzameling van de OCL<br />

taal genomen hebben. We hebben vooral op een aantal aspecten gefocust: klasse-invarianten,<br />

pre- en postcondities. Aeiding regels, initiële waarden, body-of-query operaties hebben we<br />

niet bestudeerd.<br />

Alhoewel onze aandacht in deze thesis op de JAVA programmeertaal gericht was, zou er interessant<br />

zijn om een alternatieve implementatie wat betreft aspect-georiënteerde uitbreidingen


6.4. TOEKOMSTIG WERK: UITBREIDINGEN EN AANPASSINGEN 61<br />

te beschouwen. Aspecten kunnen modularizatie van klasse-invarianten en pre- en postcondities<br />

aanbieden. Op deze manier kunnen deze klasse-invarianten en pre- en postcondities uit de<br />

code afgezonderd worden. Andere voordelen van aspect-georiënteerde programmeertechnieken<br />

moeten nog uitgebreider en dieper bestudeerd worden.


B¼lage A<br />

Lijst Van Afkortingen<br />

API Application Programming Interface<br />

DBC Design By Contract<br />

GME Generic Modeling Enviroment<br />

MDA Model Driven Architecture<br />

MDD Model Driven Development<br />

OCL Object Constraint Language<br />

OMG Object Management Group<br />

PIM Platform Independent Model<br />

PSM Platform Specic Model<br />

UML Unied Modeling Language<br />

62


Bibliograe<br />

[1] A.Kleppe, J.Warmer, The Object Constrait Language, Second Edition, Getting your models ready for<br />

MDA,Addison-Wesley, 2003<br />

[2] David S. Frankel, Model Driven Architecture: Applyoing MDA to Enterprise Computing,Joe Wikert,<br />

2003<br />

[3] A.Kleppe, J.Warmer, W.Bast,MDA explained - The model driven Architecture: practice and<br />

promices,Addison-Wesley, 2003<br />

[4] M.Fowler, Language WorkBenches and Model Driven Architecture,<br />

http://www.martinfowler.com/articles/mdaLanguageWorkbench.html<br />

[5] S.H.Czarnecki, S.Helsen, Feature-based survey of model transformation approaches,IBM SYSTEMS<br />

JOURNAL, 2006, http://www.research.ibm.com/journal/sj/453/czarnecki.pdf<br />

[6] Object Constraint Language OMG Available Specication Version 2.0, 2006,<br />

http://www.omg.org/docs/formal/06-05-01.pdf<br />

[7] J.Oldevik,MOFScript User guide (v0.6),2006, http://www.eclipse.org/gmt/mofscript/doc/MOFScript-<br />

User-Guide.pdf<br />

[8] A.Hovsepyan,S.Van Balen, B.Vanho, W.Jossen, Y.Berbers, Key Research Challenges for Successfully<br />

Applying MDD within Real -Time Embeded Software Development, 2006<br />

[9] A.Kleppe, J.Warmer, W.Bast,MDA explained - The model driven Architecture: practice and<br />

promices,Addison-Wesley, 2003<br />

[10] E2S nv, http://www.e2s.be<br />

[11] Borland Together tool, http://www.borland.com/together<br />

[12] OCL tool, http://lci.cs.ubbcluj.ro/ocle<br />

[13] Octopus tool, http://www.klasse.nl<br />

[14] Programming with assertions, http://java.sun.com/j2se/1.4.2/docs/guide/lang/assert.html<br />

[15] OMG, Unied Modeling Language, http://www.uml.org<br />

[16] OMG, The Object Management Group, http://www.omg.org<br />

[17] GME, The Generic Modeling Enviroment, http://www.isis.vanderbilt.edu/projects/gme/<br />

[18] MetaEdit, Domain-Specic Modeling with MeataEdit+, http://www.metacase.com/index.html<br />

[19] Eiel, http://www.eiel.com/<br />

[20] OMG, OMG Model Driven Architecture, http://www.omg.org/mda<br />

63


64 BIBLIOGRAFIE<br />

[21] OMG, The Object Constrait Language, http://www.omg.org/docs/formal/06-05-01.pdf<br />

[22] No Magic Inc, MagicDraw - visual UML modeling and CASE tool, http://www.magicdraw.com/<br />

[23] Modelbased, MOFScript , http://www.eclipse.org/gmt/mofscript<br />

[24] E2S nv, HAT Manual, https://www.e2s.be/Content/Software_Products/Hat/Download_Data/HatManual.pdf<br />

[25] B.Meyer,Design by Contract, http://se.ethz.ch/~meyer/publications/computer/contract.pdf

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!