Rekonstrukce OCL z SQL * Karel RICHTA 1 1 Katedra softwarového inženýrství, MFF UK Praha Malostranské nám. 25, 118 00 Praha karel.richta@mff.cuni.cz Abstrakt. Jednou z často citovaných zkratek poslední doby je MDD (Model Driven Development), příp. MDA (Model Driven Architecture), nebo dokonce MDE (Model Driven Engineering). Princip těchto přístupů spočívá v tom, že se při tvorbě aplikace využívají různé modely. Sdružení OMG propaguje myšlenku, že práce s modelem může přinést mnoho nových možností. Model může být použit pro generování struktury dat a kostry řešení, reverzním inženýrstvím lze získat model existujícího systému pro jeho snazší pochopení, či úpravy. Nad modelem lze provádět různé transformace, refaktorizace apod. Pro modelování se v současnosti nejvíce využívá standard UML (Unified Modeling Language [9]). Aby však byl model dostatečně úplný, je třeba doplnit diagramy v UML přesnými popisy různých integritních omezení. Pro tento účel obsahuje notace UML speciální jazyk nazvaný OCL (Object Constraint Language [7]). Tento příspěvek se zabývá možnostmi rekonstrukce OCL z existujícího SQL, jako příspěvek k reverznímu inženýrství pro modelem řízený vývoj. Klíčová slova: MDD, MDA, UML, OCL, SQL 1 Úvod Základní princip modelem řízeného stylu [8] spočívá v tom, že se při tvorbě aplikace využívá nějaký model nebo modely. Model nám umožňuje lepší pochopení situace, neboť je abstraktnější a uchopitelnější, než modelovaná skutečnost. Zpravidla se nevyužívá model jediný, ale spíše sada různých modelů (doménový, konceptuální, logický, implementační, či fyzický, apod.). V čem může být vytváření modelu přínosem, co může přinést nového? Jak říká klasik model zůstává, lidé odcházejí, proto je existence dostatečně vypovídajícího modelu určitě přínosem pro stabilitu řešení. Zdánlivou výhodou zanedbání modelu je, že vývoj produktu nezahrnuje žádné aktivity, které by nevedly přímo k výsledku, nevytvářejí se žádné vedlejší produkty a artefakty, výsledkem je přímo kód zkonstruovaný podle katalogu požadavků (samozřejmě, pokud nepovažujeme za model samotný katalog požadavků zapsaný v přirozeném jazyce). Vývojář produktu odevzdává tyto artefakty a vzápětí odchází k jiné firmě. V témže okamžiku přichází od zákazníka nový požadavek, nebo požadavek na změnu. Zodpovědné osobě nezbývá, než svěřit řešení změny někomu, kdo zatím neměl s tímto produktem nic společného. Nová osoba se musí seznámit s kódem, vytvořit si jeho model v hlavě a poté jej přizpůsobit novým požadavkům. * Tento text vznikl za částečné podpory výzkumného záměru MŠMT č. MSM0021620838, grantových projektů GAČR: GA201/09/0990 a GA201/09/0983. Petr Šaloun (ed.), DATAKON 2010, Mikulov, 16-19. 10. 2010, pp. 1-10.
Co jsme ušetřili na začátku, jsme teď ztratili. Pokud se model vytvořený při realizaci změny opět nezaznamená, bude se situace při další změně opakovat. Zdánlivá úspora na začátku se pak ukazuje jako ztráta. Představme si obrácenou situaci analytik rád modeluje a snaží se vytvořit dokonalý model podle požadavků zákazníka. Neustále jej vylepšuje, aby ho připravil na rozmanité změny, které mohou v budoucnosti nastat. Kód nevzniká, neboť se stále zabývá modelem, který ještě není dokonalý. Obě situace nejsou optimální, správný postup představuje rozumný kompromis - vytvořit jen takový model, který pomůže při analýze, návrhu, implementaci, testování a údržbě produktu, a který navíc zůstane firmě k dispozici pro další změny. Pokud je model udržován současně s produktem, může takto sloužit po celý jeho životní cyklus. Ovšem představa, že by vývojáři, analytici, nebo architekti udržovali modely produktu spolu s jeho vývojem a změnami je ovšem do značné míry iluzorní. Disciplinovaný analytik a vývojář mohou pořizovat dokumentaci modelů alespoň na papíře. Pravděpodobně nikdy však neudrží tuto disciplinu při všech změnách - výsledkem je situace bez aktuálního modelu. Jediným řešením by byl nástroj, který by takovou synchronizaci modelu a kódu dostatečně podporoval. Pokud model vytváříme a udržujeme pomocí nějakého sofistikovaného CASE nástroje, bylo by možné o takové synchronizaci uvažovat (CASE je zkratka pro Computer Aided Software Engineering). CASE nástroj by měl podporovat jak přímé inženýrství, kdy tvoříme model a generujeme z něj kostru kódu, tak i reverzní postup, kdy se snažíme z kódu rekonstruovat kostru modelu. Čím více umí CASE nástroj podporovat oba směry, tím užitečnější je jeho využití v procesu vývoje a údržby. V ideálním případě umožňuje cyklické opakování využití přímého a zpětného inženýrství - používá se zde termín roundtrip okružní jízda [2]. Aktuální problém všech modelovacích technik a nástrojů je míra preciznosti. Na jedné straně by měl být model abstraktní, lehce uchopitelný a srozumitelný. Na straně druhé stojí model, který obsahuje všechny podrobnosti, může být použit pro generování, ale už asi není tak přehledný a uchopitelný. Sdružení OMG řeší tento problém tak [8], že doporučuje vytváření modelů na různých úrovních doménový model (označen CIM Computation Independent Model), konceptuální model (PIM Platform Independent Model), logický model (PSM Platform Specific Model) a nakonec kód - fyzický model (ISM Implementation Specific Model). Na všech úrovních je třeba modely prezentovat pokud možno přesně, ale pouze v rozsahu potřebném pro tuto úroveň náhledu. Samotné diagramy to nikdy neumožňují úplně. Uvažme příklad problému evidence hypoték (viz [10]). Ukázka z katalogu požadavků říká, že: 1. Každá hypotéka bude vždy pro jednu osobu. 2. Osoba si může vzít několik hypoték. 3. Každou nemovitost vlastní právě jedna osoba. 4. Osoba může vlastnit libovolný počet nemovitostí. 5. Každá hypotéka musí být zajištěna nejméně jednou nemovitostí. 6. Nemovitost může být použita k zajištění více hypoték. Uvedené požadavky lze snadno na konceptuální úrovni reprezentovat diagramem tříd uvedeným na Obr. 1. Tento poměrně jednoduchý model může mít zajímavé interpretace, neboť je zde např. přípustné, aby osoba zajistila hypotéku nemovitostí, kterou nevlastní. Model je proto zapotřebí doplnit integritním omezením: Osoby mohou jako zajištění hypotéky použít pouze nemovitosti, které samy vlastní. Integritní omezení lze zapsat v přirozeném jazyce - výhodou takového řešení je, že mu navazující řešitelé rozumí - pokud
např. toto zadání předáme nějaké osobě k řešení. Nevýhodou je, pokud toto zadání chceme předat k řešení programu např. CASE nástroji. Ten takovému zápisu zatím nerozumí. Pokud bychom vyjádřili integritní omezení formálně, bylo by možné CASE nástroj tomuto jazyku naučit. Pro notaci UML [9] představuje takový formální nástroj jazyk OCL [7], který stručně popíšeme v následujícím odstavci. class Hypotéky - PIM skládá_se_z 0..* +je_částí 1 Nemovitost - označení: string - hodnota: penize +v lastní 0..* +je_majetkem 1 - jméno: string - příjmení: string - příjem: peníze Osoba +je_zajištěna 1..* + žádost(peníze, Set{Nemovitost}) : boolean +pro 1 +zajišťuje 0..* +má_půjčenu 0..* Hypotéka - od: datum - do: datum - celková_částka: peníze = 250.000,- - měsíční_splátka: peníze Obr. 1: Jednoduchý konceptuální model hypoték (PIM) 2 Jazyk OCL Jazyk OCL [7] pochází původně z metodiky Syntropy (IBM, [10]). Je to čistě funkcionální jazyk - vyhodnocení výrazu je bez vedlejších efektů - neexistuje žádná globální paměť. Stejná funkce se stejnými argumenty dává vždy stejný výsledek. OCL není programovací jazyk - je určen pro vyjádření invariantů - je to specifikační jazyk. Zápisy v OCL je třeba chápat jako specifikaci pro programy, které budou odpovídající integritní omezení zajišťovat. OCL je silně typovaný jazyk, tj. každý výraz v jazyce OCL má definován typ. To umožňuje silnou statickou typovou kontrolu zapsaných omezení při jejich interpretaci. OCL má předdefinovánu sadu typů jsou to jednak primitivní typy: Integer, Boolean, String, Real, UnlimitedInteger, ze kterých lze vytvářet složené typy jako rozmanité kolekce: množina (Set), multi-množina (Bag), obecná kolekce (Collection), posloupnost (Sequence), atd. V jazyce OCL nezapisujeme programy tento pojem OCL nezná, není to programovací jazyk. Ve specifikačním jazyku OCL zapisujeme požadavky na to, aby v jistém kontextu byla splněna nějaká podmínka. Podmínku vyjádříme pomocí formule zapsané jako výraz v OCL. K ní pak připojíme specifikaci kontextu. Zápis v jazyce OCL má vždy jednotný tvar: context <jméno> [inv pre post]: <výraz> Klíčové slovo context zde slouží pro odkaz na kontext pro <výraz> v OCL, např. zápis: context Hypotéka inv : self.celková_částka > 250000
označuje, že uvedený výraz se vztahuje ke kontextu třídy Hypotéka, tj. na všechny její instance (na konkrétní instanci se lze ve specifikaci odkazovat klíčovým slovem self). Výraz zde vyjadřuje podmínku, že pro každou instanci třídy Hypotéka, musí mít její vlastnost celková_částka hodnotu větší než 250000. V daném kontextu nelze evidovat hypotéky s nižší celkovou částkou. Klíčová slova inv, pre, post zastupují stereotypy <<invariant>> (obecně platné tvrzení), <<precondition>> (předpoklad např. vstupní podmínky operace) a <<postcondition>> (podmínka, která musí platit po provedení příslušné akce). OCL lze použít čistě jako navigační jazyk. Chceme-li označit jakýkoliv element některého diagramu, lze použít výraz v OCL. Např. příjem osoby x:osoba v kontextu modelu hypoték, zapíšeme to jako výraz x.příjem. Tento výraz má hodnotu, která je typu peníze. Chceme-li označit názvy nemovitostí, které osoba x:osoba v kontextu modelu hypoték právě vlastní, zapíšeme to jako výraz x.vlastní. V tomto případě je hodnotou množina nemovitostí výsledek je typu Set{Nemovitost}, neboť osoba může vlastnit více nemovitostí, příp. také žádnou. Nejčastěji se OCL používá pro vyjádření integritních omezení v datovém modelu, zejména v diagramech tříd. Také se používá pro vyjádření typových omezení při definici nových stereotypů. Lze jej ale rovněž použít pro vyjádření předpokládaného efektu operací, pro popis vstupních a výstupních podmínek operací. Jak již bylo řečeno, poskytuje jazyk OCL předefinované primitivní typy, ze kterých lze vytvářet složené typy. Při konstrukci hodnot složených typů lze využívat operátory: collect, select, reject, forall, exists, iterate, include, count, union, intersect, isempty, notempty, isunique a dalších. Volání operátorů se zapisuje ve tvaru inspirovaném jazykem Smalltalk, např. zápis: x.vlastní -> count() označuje počet nemovitostí, které osoba x:osoba vlastní. Podobně: x.vlastní.hodnota -> sum() označuje součet cen nemovitostí, které osoba x:osoba vlastní. Vzhledem k existenci kvantifikátorů (forall, exists), lze usuzovat, že OCL je notace pro zápis formulí predikátového kalkulu 1.řádu v programátorském stylu, smíchaná s množinovou notací. Konkrétní hodnoty kolekcí se konstruují stejně označenými konstruktory, např.: Set {2,4,1,5,7,13,11,17}, OrderedSet {1,2,3,5,7,11,13,17}, Sequence {1,2,3,5,7,11,13,17}, Bag {1,2,3,2,1}. 3 Příklad specifikace v OCL Jako ilustrační příklad použijeme dříve uvedenou jednoduchou evidenci hypoték. Model uvedený na obrázku Obr. 1 ale nevystihuje zdaleka všechny požadované vlastnosti hypoték. Původní požadavky doplnil systémový analytik o další, které by měla data o hypotékách splňovat:
7. Hypotéku lze zajistit pouze nemovitostmi, které osoba vlastní. 8. Cena nemovitostí zajišťujících hypotéku musí být větší, než celková zapůjčovaná částka. 9. Celková zapůjčovaná částka všech hypoték zajištěných danou nemovitostí nesmí přesahovat cenu nemovitosti. 10. Součet měsíčních splátek osoby by neměl přesáhnout 30% jejího měsíčního příjmu a zbytek příjmu po odečtení splátek musí splňovat zákonné požadavky nesmí klesnout pod zákonné minimum. 11. Půjčujeme nejméně 250 tis.kč. Tato integritní omezení již nevyjádříme pouze pomocí diagramů - musíme model doplnit o jejich specifikaci. Specifikaci zapíšeme pomocí výrazů v jazyce OCL. context Hypotéka inv IO7: self.je_zajištěna.je_majetkem = self.pro context Hypotéka inv IO8: self. celková_částka <= self.je_zajištěna.hodnota -> sum() context Nemovitost inv IO9: self.zajišťuje.celková_částka -> sum() <= self.cena context Hypotéka inv IO11: (self.celková_částka >= 250000). Podobným způsobem vyjadřujeme integritní omezení, popisující požadované vlastnosti operací. V našem modelu mohou osoby žádat o hypotéku na určitou částku, zajištěnou nějakou sadou nemovitostí. V modelu je na to určena metoda žádost, přesněji Osoba::žádost. Pro žádosti o hypotéky platí požadavek, který by měl omezit případy, kdy osoba nebude schopna hypotéky splácet, tj. kdy celkový součet měsíčních splátek přesáhne její možnosti: context Osoba::žádost(částka:peníze, zajištění:set{nemovitost}) pre IO10: (self.má_půjčenu.měsíční_splátka -> sum()) + částka <= self.příjem * 0.3 Ještě jedno důležité integritní omezení, které se týká rekurzivních vztahů: 12. Nemovitost se nemůže skládat sama ze sebe (dělíme jen na jedné úrovni). context Nemovitost inv IO12: not(self.skládá_se_z -> iselement(self)) Všechna uvedená integritní omezení zajišťují konzistenci evidovaných dat. Chytrý CASE nástroj může formální definici integritních omezení využít pro generování kódu zajišťující data proti porušení integrity. Např. na relační platformě může generovat relační integritní omezení nebo triggery, které porušení integrity hlídají a nepovolí uložení chybných dat. 4 Jazyk SQL Použijeme-li při vývoji jako platformu relační databázový systém, bude komunikačním jazykem této platformy jazyk SQL. Syntaxe SQL dělí příkazy do 5-ti kategorií: <SQL statement> ::= <QUERY> <DML> <DDL> <TCL> <DCL> Z hlediska našeho problému jsou zajímavé příkazy z kategorie DDL (Data Definition Language), neboť těmi se vytvářejí základní relační objekty tabulky atd. Tabulky a ostatní objekty uložené v databázi byly vytvořeny pomocí těchto příkazů. Ze všech možných druhů objektů se zde budeme zabývat pouze tabulkami, neboť ty jsou nejdůležitější.
CREATE TABLE "table_name" ("column 1" "data_type_for_column_1", "column 2" "data_type_for_column_2",... ) Uvažme např. tabulku osob (nazveme ji Osoby, neboť bude obsahovat záznamy typu Osoba o evidovaných osobách): CREATE TABLE Osoby (jméno VARCHAR2(24),... ) Při reverzním inženýrství můžeme všechny takové DDL příkazy rekonstruovat z katalogu databáze, kde musí být všechny informace o všech objektech uloženy. Konkrétní postup je samozřejmě závislý na struktuře katalogu daného poskytovatele. Tabulky v relační databázi jsou pro rekonstrukci OCL zajímavé pouze jako definice struktury. Pro jednoduchost budeme uvažovat pouze tabulky a ty později převedeme do UML/OCL jako třídy. Sloupce tabulek převedeme na vlastnosti tříd - atributy nebo vztahy. Pro rekonstrukci OCL jsou spíše zajímavá integritní omezení definovaná nad těmito tabulkami. SQL připouští pět typů deklarativních integritních omezení: <CONSTRAINT> ::= <NOT NULL> <UNIQUE> <PRIMARY KEY> <FOREIGN KEY> <CHECK> 5 Převod UML/OCL do SQL Převodem specifikace v UML/OCL do SQL se zabývají např. články [10], či [4]. Princip spočívá zhruba v tom, že třídy převedeme na tabulky, atributy na sloupce, vztahy 1:N realizujeme pomocí primárních a cizích klíčů. Vztahy M:N realizujeme pomocí vztahové tabulky a primárních a cizích klíčů. Příklad relačního logického modelu vytvořeného z konceptuálního modelu hypoték (viz Obr. 1) je zobrazen na obrázku Obr. 2. Byl pořízen automatickým převodem podle standardních pravidel pro transformaci PIM na PSM. Integritní omezení jsou na konceptuální úrovni reprezentována v OCL. Řadu z nich lze převést do SQL poměrně přímočaře. Zápis v OCL: context T inv IOT: <výraz> nahradíme v SQL příkazem: ALTER TABLE T ADD CONSTRAINT IOT CHECK (<výraz>) Uvažme např. integritní omezení č.11: context Hypotéka inv IO11: (self.celková_částka >= 250000) To nahradíme v SQL příkazem: ALTER TABLE Hypoteky ADD CONSTRAINT IO11 CHECK (celkova_castka >= 250000) Pokud výraz obsahuje operace pro práci s kolekcemi, bude převod o něco komplikovanější. Uvažme např. integritní omezení č.12: Nemovitost je majetkem právě jedné osoby, nebo se skládá z částí, které vlastní nějaká osoba (nemovitosti dělíme jen na jedné úrovni). context x:nemovitost inv IO14: (x.skládá_se_z -> isempty() and x.je_majetkem -> size() = 1) or (not (x.skládá_se_z -> isempty()) and (x.je_majetkem -> size() = 0)) and (x.skládá_se_z -> exists( y:osoba y.vlastní -> iselement(x))))
class DDL Nemovitost «column» *PK nemovitostid: NUMBER(8) označení: VARCHAR2(50) hodnota: NUMBER(9,2) FK je_majetkem: NUMBER(8) FK je_částí: NUMBER(8) «PK» + PK_Nemovitost(NUMBER) + FK_je_majetkem(NUMBER) 1 + FK_je_částí(NUMBER) +PK_Nemovitost (nemovitostid = nemovitostid) +FK_Nemovitost 0..* JoinHypotékaToNemovitost «column» *FK nemovitostid: NUMBER(8) * hypotékaid: NUMBER(8) 0..* +FK_je_majetkem 0..* +PK_Nemovitost +skládá_se_z (je_majetkem = osobaid) (je_částí = nemovitostid) +FK_Hypoteka +PK_Hypoteka (hypotékaid = hypotékaid) 1..* +PK_Osoba 1 Osoba «column» *PK osobaid: NUMBER(8) jméno: VARCHAR2(24) příjmení: VARCHAR2(35) příjem: NUMBER(8,2) «PK» + PK_Osoba(NUMBER) +PK_Osoba 1 +FK_pro (pro = osobaid) Hypotéka 0..* «column» *PK hypotékaid: NUMBER(8) od: DATE do: DATE celková_částka: NUMBER(9,2) = 250.000,- měsíční_splátka: NUMBER(8,2) *FK pro: NUMBER(8) + FK_Nemovitost(NUMBER) + FK_Hypotéka() «PK» + PK_Hypotéka(NUMBER) + FK_pro(NUMBER) Obr. 2: Logický relační model hypoték (PSM) Můžeme opět vyzkoušet transformaci na klausuli CHECK, kde případně použijeme určitý trik např. při nahrazování univerzálního kvantifikátoru jej nahradíme pomocí dvojí negace a poté vyjádříme pomocí operátoru exists, který v SQL existuje. ALTER TABLE Nemovitosti ADD CONSTRAINT IO12 CHECK (IS NULL sklada_se_z AND ((SELECT count(*) FROM Osoby WHERE osobaid = je_majetkem) = 1) OR (IS NOT NULL sklada_se_z AND ((SELECT count(*) FROM Osoby WHERE osobaid = je_majetkem) = 0) AND (EXISTS (SELECT 'X' FROM Osoby WHERE nemovitostid in vlastni))) Ve skutečnosti bude převod o něco komplikovanější, neboť žádný poskytovatel systému řízení relační báze dat neumí implementovat klausuli CHECK, ve které se vyskytuje dotaz nad stejnou tabulkou. 6 Převod SQL do UML/OCL Poté, co jsme zkonstruovali PSM, můžeme se pokusit v rámci okružní jízdy o zpětný převod na PIM. Předmětem naší zpětné transformace je logický, relační databázový model (schema), který převádíme do UML/OCL. Výstupem by měl být konceptuální model vstupního schématu. Sloupec v tabulce T, nad kterým je definováno integritní omezení NOT
NULL budeme transformovat na povinný atribut v diagramu tříd UML, tj. atribut s četností [1..1], zkráceně [1] (nepovinný bude mít četnost [0..1]): SQL UML <sloupec> <typ> NOT NULL <sloupec> : <typ> [1] Sloupec v tabulce T, nad kterým je definováno integritní omezení UNIQUE budeme v OCL specifikovat pomocí zabudované metody isunique, kterou se v OCL vyjadřuje právě podmínka unikátnosti: SQL create table T ( <sloupec> <typ> UNIQUE ) OCL context T inv : self.<sloupec> -> isunique() Sloupec, nebo sloupce v tabulce T, nad kterými je definováno integritní omezení PRIMARY KEY budeme v OCL specifikovat jako kombinaci předešlých dvou vlastností: SQL create table T ( <sloupec> <typ> PRIMARY KEY ) OCL context T inv : self.<sloupec> -> isunique() and isdefined() Pro sloupec, nebo sloupce v tabulce T, nad kterými je definováno integritní omezení FOREIGN KEY se jménem <FK>, zavedeme v diagramu tříd vztah mezi tabulkou T a referencovaným objektem, který se bude jmenovat <FK>. Navíc budeme v OCL specifikovat omezení: SQL create table T ( <sloupec> <typ> CONSTRAINT <FK> REFERENCES <nazev>(<tabulka>) ) OCL context T inv : self.<sloupec> -> exists( x:<tabulka> x.<nazev> = self. <FK> ) Sloupec, nebo sloupce v tabulce T, nad kterými je definováno integritní omezení typu CHECK budeme v OCL specifikovat: SQL create table T ( <sloupec> <typ> CHECK(<výraz>) ) OCL context T inv : self.<sloupec> -> forall( x:t <výraz> ) Pokud aplikujeme tato pravidla na logický model PSM našich hypoték, získáme následující model zapsaný lineárně v jazyce USE [10]: model Hypotéky -- classes class Osoba attributes jméno : VARCHAR2(24)... end class Hypotéka attributes... end class Nemovitost attributes... end class JoinHypotékaToNemovitost attributes... end
-- associations association FK_pro between Osoba[1] Hypotéka[0..*] end association FK_je_majetkem between Nemovitost[0..*] Osoba[1] end association FK_Hypotéka between JoinHypotékaToNemovitost[1..*] Hypotéka[1] end association FK_Nemovitost between JoinHypotékaToNemovitost[0..*] Nemovitost[1] end -- OCL constraints constraints... context Hypotéka -- hypotéka musí být zajištěna vlastním majetkem inv IO7: self.je_zajištěna.je_majetkem = self.pro... context Hypotéka -- nejmenší částka je 250.000,- inv IO11: self.celková_částka >= 250000... Z uvedených příkladů je zřejmé, že pro okružní jízdu je třeba si některé informace uchovávat spolu s modely. Např. je to mapování mezi identifikátory na úrovni PIM a identifikátory v relačním modelu na úrovni PSM. Jiný příklad jsou vztahy M:N, které jsme při převodu do PSM nahradili vztahovými tabulkami. Takových informací je celá řada a pokud ji neuchováme, bude problém okružní jízdu realizovat. Jak to zařídit bude předmětem dalšího výzkumu. 7 Závěr V článku je rozebírána tzv. okružní jízda (round-trip) pro případ relační platformy a datového modelu. Uvedené příklady formálních specifikací integritních omezení zapsaných v jazyce OCL a SQL představují ukázku kontextu, ve kterém se bude muset CASE nástroj podporující okružní jízdu pohybovat. Naznačili jsme postup převodu konceptuálního datového modelu (PIM) v notaci UML/OCL do SQL a zpětný převod logického modelu (PSM) z SQL do OCL. Je to samozřejmě jen malý krůček do modelem řízeného vývoje. Existuje několik škol, kde se specifikacemi v OCL intenzivně zabývají, viz. např. [5], či [6]. OCL není samozřejmě jediným způsobem formální specifikace integritních omezení. V současné době se ale zdá být nejperspektivnější. Uveďme si příklad využití formálních specifikací v praxi. V roce 1998 byla uvedena do provozu linka 14 pařížského metra, pro kterou byl požadavek, aby mohla být plně řízena
nejen lidskou obsluhou, ale také pouze softwarem. Protože se jednalo o citlivou věc, byl vývoj a testování tohoto softwaru prováděn za pomoci formálních specifikací. Požadavky byly zformulovány ve specifikačním jazyce B - jednalo se o asi 100 tis. řádků specifikace. Za pomoci různých nástrojů byla tato specifikace testována, bylo provedeno asi 27 tis. důkazů různých vlastností popsaného produktu. Posléze tato specifikace posloužila pro vygenerování kostry kódu v jazyce Ada, který po úpravách představoval asi 87 tis. řádků kódu, tj. méně než byla specifikace. Byť se tento příklad netýká přímo OCL, je z něj vidět, že používání formálních specifikací má v některých případech uplatnění. Vývoj formálních specifikací a nástrojů, které s nimi pracují, probíhá neustále. Např. poslední verze OCL je z února tohoto roku, nejedná se tedy o mrtvý standard. Spíše se hledají cesty, jak formální specifikace v OCL využít v CASE nástrojích. Např. známý Enterprise Architect již dovoluje vkládání omezení v OCL do modelů, umí dokonce kontrolovat správnost syntaxe, ale zatím neumí z těchto formálních zápisů generovat nějaký kód. Před několika lety ale neuměl ani syntaxi OCL. Uvidíme, co se změní za pár let. Literatura [1] Arlow, J., and Neustadt, I.: UML 2 and the Unified Process: Practical Object-Oriented Analysis and Design (2nd Edition), Addison-Wesley Professional Press, 2005. [2] Beličák, M. Pokorný, J. Richta, K.: Open Design Architecture for Round Trip Engineering. In: Proceedings of ISD 2009, Nanchang, Springer-Verlag (v tisku). [3] Botting, R.: Simplex of OCL. URL: http://www.csci.csusb.edu/dick/samples/ocl.html. [4] Cook, S. - Daniels,J.: Designing Object Systems: Object-Oriented Modelling with Syntropy. Prentice Hall, 1994, ISBN 0-13-203860-9. URL: http://en.wikipedia.org/wiki/syntropy. [5] Dresden OCL Toolkit. URL: http://dresden-ocl.sourceforge.net/. [6] Octopus OCL Toolkit. URL: http://octopus.sourceforge.net/. [7] OMG: Object Constraint Language, Version 2.2. February 2010. URL: http://www.omg.org/spec/ocl/2.2/. [8] OMG: MDA Guide, 2003. URL: http://www.omg.org/mda/. [9] OMG: UML 2.2, February 2009. URL: http://www.omg.org/spec/uml/2.2/ [10] Richta, K: Jazyk OCL a modelem řízený vývoj. In: Moderní database 2010, Nesuchyně, Komix Praha 2010. [11] Richters, M. Gogolla, M.: OCL: Syntax, Semantics, and Tools. In: Object Modeling with the OCL, LNCS 2263, Springer Berlin/Heidelberg, ISBN978-3-540-43169-5, pp. 447-450, 2002 [12] Wikipedia: http://cs.wikipedia.org/wiki/14_(linka_metra_v_paříži). Annotation: Reconstruction of OCL from SQL This paper discusses the possibilities of reconstruction of UML classes and OCL constraints from an existing SQL, as a contribution to the reverse engineering process in the model-driven development.