5. Cvičenie - Interné jazyky a kompozícia jazykov (Úloha 3)

Ciele
  1. Oboznámiť sa s prístupmi k tvorbe interných doménovo-špecifických jazykov.
  2. Oboznámiť sa s modelom jazyka obmedzení pre vlastnosti entít.
  3. Rozšíriť jazyk obmedzení o ďalšie jazykové konštrukcie definujúce obmedzenia na abstraktnej úrovni.
  4. Rozšíriť konkrétnu syntax jazyka obmedzení o pridané jazykové konštrukcie.
  5. Prepojiť model jazyka entít s modelom jazyka obmedzení.
  6. Rozšíriť rozhranie jazyka obmedzení entít o kompozíciu a overenie správnosti viet.
  7. Otestovať funkčnosť kompozície jazykov výpisom modelu systému.
Úvod
    Na dnešnom cvičení vytvoríme interný jazyk obmedzení a využijeme kompozíciu jazykov na zlúčenie vytvoreného jazyka s jazykom entít vytvoreným na predchádzajúcich cvičeniach.

    Oboznámte sa s princípmi tvorby interných jazykov:

    Jazyk obmedzení slúži na definovanie množiny obmedzení pre jednotlivé vlastnosti entít. Obmedzením pre vlastnosť je napríklad minimálna resp. maximálna dĺžka reťazca pre vlastnosť typu reťazec (priezvisko má minimálne 2 znaky ale maximálne 32 znakov). Iným obmedzením môže byť požadovaný rozsah hodnôt pre číselné typy (vek je minimálne 0 rokov ale maximálne 150). Tento jazyk nedefinuje entity ani ich vlastnosti ale bude používaný spolu s jazykom entít prostredníctvom odkazov na entity a vlastnosti na základe ich mena.

    Teraz bude systém, ktorý generujeme, definovaný vetami v dvoch jazykoch - jazyk entít a jazyk obmedzení.

    Model jazyka obmedzení pre definovanie systému CRUD je nasledovný:
    • EntityRef - predstavuje referenciu na entitu (trieda Entity) na základe mena v modeli.
    • PropertyRef - predstavuje referenciu na vlastnosť (trieda Property) na základe mena v modeli.
    • Constraint - predstavuje abstrakciu obmedzenia vlastnosti entity.
    • Required - konkrétne obmedzenie definujúce vlastnosť ako požadovanú pre všetky výskyty entity v generovanom systéme, rozšírenie abstraktnej triedy Constraint.
    Obr.: Model tried jazyka obmedzení
Postup
  1. Model jazyka obmedzení implementovaný v jazyku Java má nasledujúce vyjadrenie metamodel2.zip. Oboznámte sa s balíkom.
  2. Pre rôzne vlastnosti je možné definovať rôzne obmedzenia. Môžu to byť obmedzenia na dĺžku reťazca, rozsah hodnôt, formát reťazca definovaný regulárnym výrazom ale aj mnohé ďalšie. V tomto kroku teda rozšírime jazyk obmedzení entít o ďalšie triedy predstavujúce obmedzenia.
    Úloha: Rozšírte jazyk obmedzení o triedu Length predstavujúcu obmedzenie dĺžky reťazca hodnoty vlastnosti.


    Pošli
    Poznámka: Obmedzenie dĺžky reťazca môže byť určené jeho minimálnou a maximálnou dĺžkou.
    Úloha: Rozšírte jazyk obmedzení o triedu Range predstavujúcu číselný rozsah hodnoty vlastnosti.


    Pošli
    Úloha: Rozšírte jazyk obmedzení o triedu Regex umožňujúcu definovať obmedzenie obsahu vzhľadom na definovaný regulárny výraz.


    Pošli
    Obr.: Model tried jazyka obmedzení po pridaní nových tried
  3. Keďže je cieľom cvičenia porozumieť a naučiť sa vytvárať interné jazyky, budeme konkrétnu syntax tohto jazyka definovať ako interný jazyk podľa vzoru vnorených funkcií (angl. Nested Function). Hostiteľským jazykom bude programovací jazyk Java. Pre zjednodušenie vytvárania viet využijeme možnosti vývojového prostredia a jeho vlastnosť automatického dopĺňania. Tomu podriadime aj návrh konkrétnej syntaxe jazyka - budeme sa snažiť maximalizovať využite vlastností vývojového prostredia pri automatickom dopĺňaní. Základom riešenia bude abstraktná trieda ConstraintBuilder, ktorá definuje konštrukcie jazyka obmedzení ako aj spôsob ich kompozície s jazykom entít. Ak budeme vytvárať vetu v jazyku obmedzení, budeme dediť od uvedenej triedy a predefinujeme metódu void define(). Zdrojový kód kostry ConstraintBuilder sa nachádza v builder.zip.
    Úloha: Rozšírte konkrétnu syntax jazyka obmedzení definovanú triedou ConstraintBuilder prostredníctvom metód o zápisy zodpovedajúce pridaným konštrukciám.
    • Obmedzenie na dĺžku Length - metódy Length length(int minLength, int maxLength), Length min_length(int minLength), Length max_length(int maxLength)
    • Obmedzenie na rozsah Range - metóda Range range(int minValue, int maxValue)
    • Obmedzenie na formát reťazca Regex - metóda Regex regex(String regex)


    Pošli
    Poznámka: Postupujte podľa implementácie konštrukcie Required.
  4. Vety z jazyka obmedzení sa zapisujú do metódy protected void define() triedy, ktorá dedí od triedy ConstraintBuilder. V našom prípade to bude nová trieda PersonalistikaObmedzenia.
    Poznámka: Vytvorená trieda obmedzení síce patrí k definícii modelu, pre obmedzenia Maven nástroja ju však musíme umiestniť do adresára src/main/java projektu magsa-generator.
    Nasledujúci zápis je príkladom vety v definovanom jazyku obmedzení. Táto veta definuje vlastnosť priezvisko entity Zamestnanec ako požadovanú (vyjadrené pomocou required()) s max. dĺžkou hodnoty 16 znakov (vyjadrené pomocou max_length(16)).
    
    public class PersonalistikaObmedzenia extends ConstraintBuilder {
        protected void define() {
            entity_ref("Zamestnanec",
                property_ref("priezvisko",
                    required(),
                    max_length(16)
                )
            );
        }
    }
    
    Poznámka: Nainštalujte si zásuvný modul pre Netbeans iDSLAddon.zip pre podporu tvorby viet v internom jazyku.

    V prostredí NetBeans IDE otvorte dialóg pre správu zásuvných modulov ([Tools]->[Plugins]). V záložke [Downloaded] zvoľte tlačidlo [Add Plugins...], otvorí sa dialóg pre výber súboru s príponou ".nbm". Nájdite súbor so zásuvným modulom iDSLAddon a postupujte podľa pokynov inštalácie.

    Pri vytváraní nových viet v našom internom jazyku obmedzení novú vetu vytvoríte kliknutím pravým tlačidlom na balík, do ktorého chcete nový súbor pridať a výberom [New]->[Other] v kontextovom menu. V dialógu na pridanie nového súboru nájdete novú kategóriu [MaGSA] a v nej je šablóna na vytváranie nových viet. Ďalej stačí postupovať podľa pokynov dialógu.

    Modul je vytvorený pre Netbeans verzie 7.2 a vyššie.

    Úloha: Zapíšte vetu v jazyku obmedzení, v ktorej použijete všetky definované konštrukcie.


    Pošli
    Poznámka: Všimnite si, ako je možné pri zápise vety v jazyku obmedzení využívať vlastnosť automatického dopĺňania kódu vývojovým prostredím (CTRL+SPACE).
  5. Pre kompozíciu vytvorených jazykov je potrebné rozšíriť model jazyka entít o metódy pre naviazanie obmedzení na vlastnosti entít. Tieto metódy budú využívané neskôr pri overení správnosti viet jazyka obmedzení a ich kompozície s vetami jazyka entít.
    Úloha: Do triedy Model pridajte metódu public Entity findEntity(String name) na vyhľadávanie entity podľa mena.


    Pošli
    Úloha: Do triedy Entity pridajte metódu public Property findProperty(String name) na vyhľadávanie vlastnosti entity podľa mena.


    Pošli
    Úloha: Do triedy Property pridajte premennú objektu pre množinu obmedzení danej vlastnosti private Constraint[] constraints. Vytvorte aj príslušné get a set metódy.


    Pošli
    Úloha: Do triedy Property pridajte metódu na získanie obmedzenia vlastnosti podľa typu public <T extends Constraint> T getConstraint(Class<T> clazz). V prípade, že vlastnosť neobsahuje obmedzenie daného typu, je návratová hodnota null. V prípade, že existuje viacero obmedzení toho istého typu, je návratová hodnota ľubovoľné z týchto obmedzení.


    Pošli
    Príklad použitia: Range range = property.getConstraint(Range.class);
    Úloha: Do triedy Property pridajte metódu na overenie, či množina obmedzení danej vlastnosti obsahuje obmedzenie daného typu public boolean hasConstraint(Class<? extends Constraint> clazz).


    Pošli
    Príklad použitia:
    
    boolean b = property.hasConstraint(Required.class);
    
  6. Ďalší krok spočíva v rozšírení triedy ConstraintBuilder o metódy potrebné pre kompozíciu viet jazykov entít a obmedzení a overenie správnosti viet jazyka obmedzení s ohľadom na kompozíciu. Na kompozíciu slúži metóda public void compose(Model model) throws ConstraintProcessingException. Úlohou kompozície, je priradenie konkrétnych obmedzení vlastnostiam entít. Súčasťou kompozície je aj overenie platnosti referencií na entity a vlastnosti (triedy EntityRef a PropertyRef). Použité mená entít a vlastností pri zápise viet v jazyku obmedzení musia prislúchať menám existujúcich entít a ich vlastností vo vete jazyka entít.
    Úloha: Implementujte metódu void validate() throws ConstraintProcessingException, ktorá overí či sú použité správne mená entít a vlastností s ohľadom na väzbu na vety jazyka entít.


    Pošli
    Ladenie: Nezabudnite, že pri kompozícii dvoch jazykov je nutné vložiť do príslušnej vlastnosti Property definované obmedzenia cez setConstraints().
  7. Otestujte funkčnosť kompozície jazykov výpisom modelu systému, ktorý vznikol kompozíciou viet jazykov entít a obmedzení.
    
    public class Make {
        public static void main(String[] args) throws Exception {
            //... povôdný obsah spracovanie viet jazyka entít
    
            /* Internal language - constraints */
            ConstraintBuilder builder = new PersonalistikaObmedzenia();
            builder.compose(model);
    
            //... povôdný obsah generovania
        }
        //...
    }        
    
  8. Vymažte súbory z disku a zrušte všetky vami vytvorené nastavenia vo vývojovom prostredí!
Zdroje
  1. Princípy tvorby interných jazykov:
    • interne_dsl.pdf
      • implementácia interných jazykov.
      • konštruovanie viet jazyka (ExpressionBuilder).
  2. Zdrojové kódy:
  3. Zásuvný modul pre podporu tvorby viet v internom jazyku pre prostredie Netbeans:
Doplňujúce úlohy
    Úloha: Pokúste sa definovať a implementovať ďalšie typy obmedzení vlastností entít.
    UkončenáPoznámka


    Pošli
    Úloha: Pridajte kontrolu na testovanie správneho použitia obmedzení vzhľadom na typ vlastnosti entity. Napríklad dĺžku je možné obmedziť pre vlastnosti entity typu string a rozsah pre vlastnosti typu integer.
    Poznámka: Úlohu je možné riešiť napríklad pridaním abstraktnej metódy abstract boolean supportsType(Type type) v triede Constraint a jej implementáciou v jednotlivých obmedzeniach.
    UkončenáPoznámka


    Pošli
comments powered by Disqus