niedziela, 10 stycznia 2010

EMF, edytory graficzne i generowanie kodu: Część I

To pierwszy odcinek z serii postów dotyczących modelowania i generowania kodu przy użyciu narzędzi skupionych wokół Eclipse Modeling Project. Ich celem będzie pokazanie jak w łatwy sposób można zrezygnować z tradycyjnego programowania na rzecz modelowania i generowania kodu. Zaznaczę tylko, że nie mam tutaj na myśli tworzenia modeli przy pomocy ogromnych kombajnów do UMLa - modelujemy w edytorach graficznych(które sami stworzymy) w języku dziedzinowym specjalnie stworzonym do rozwiązania danego problemu.



Ok, ale dlaczego mielibyśmy się dodatkowo męczyć? Przecież można sobie spokojnie programować... Otóż zalety tego podejścia są następujące:

  • modelowanie możemy zrzucić na analityków (jeżeli ich mamy ;) ) - wtedy zadanie programistów sprowadza się od stworzenia narzędzi i naciskania magicznego przycisku uruchamiającego proces generowania kodu... a w prawdziwym życiu dochodzi jeszcze dopisanie kilku kawałków których analitycy nie zamodelują

  • model jest zdecydowanie czytelniejszy od kodu - chyba każdy zna to uczucie kiedy po miesiącu musimy coś poprawić w naszej pracy... i musimy prawie od początku przeanalizować jego działanie

  • mając raz napisany model można kilkukrotnie z niego korzystać generując kilka elementów systemu

  • wprowadzając zmiany wystarczy ze wprowadzimy je wyłącznie do modelu

  • poprawa błędów sprowadza się do poprawy modelu lub szablonów przy pomocy których będzie generowany kod - w tym drugim przypadku poprawiamy od razu wszystkie wystąpienia tego błędu w całej aplikacji


Załóżmy, że chcemy modelować interfejs graficzny aplikacji. Powiedzmy, że składa się on wyłącznie z okien, przycisków, etykiet i pól tekstowych, a kontrolki są pozycjonowane bezwzględnie przez jawne wskazanie ich rozmiaru i położenia (czyli nie korzystamy z layout managerów). Oczywiście w przyszłości będzie można rozszerzyć możliwości narzędzia w dowolnym stopniu.

Pierwszym krokiem jest stworzenie projektu (typu "Plug-in Project") z modelem naszej aplikacji. Podajemy nazwę aplikacji (np: "ui.model"), a na następnej stronie kreatora odznaczamy wszystkie checkboxy w sekcji "Options". Na kolejnej stronie (o nazwie "Templates") odznaczamy checkbox "Create a plug-in using one of the templates" i kończymy działanie kreatora.

W katalogu projektu tworzymy nowy katalog o nazwie "model". Klikamy na nim prawym przyciskiem myszy i wybieramy z menu: "New" -> "Other" - "Eclipse Modeling Framework" -> "Ecore Model". Nazwę pliku podajemy jako "ui.ecore". Na ostaniej stronie kreatora jako "Model Object" pozostawiamy "EPackage", a kodowanie jako "UTF-8" i kończymy działanie kreatora.

Nasz projekt powinien wyglądać następująco:



Teraz naszym celem będzie opracowanie metamodelu reprezentującego interfejs graficzny aplikacji. Model musi spełniać następujące wymagania:

  • w aplikacji można w nim zdefiniować dowolną ilość okien

  • okna mogą zawierać dowolną ilość następujących kontrolek: przycisk, etykieta, pole tekstowe

  • każda z kontrolek ma określoną wysokość, szerokość oraz wsþółrzędne x i y

  • każda z kontrolek posiada właściwość tekst reprezentującą napis na przycisku lub etykiecie, albo zawartość pola tekstowego



Wystarczy, że powyższe wymagania przeniesiemy do edytora pliku ecore, aby mieć gotowy metamodel. Zanim zabierzemy się do pracy sugeruję wyświetlić eclipse'owy panel z właściwościami ("Properties"), gdyż wykonuje się w nim znaczną część pracy.

Edytor pliku ecore ma strukturę drzewa. Jego korzeń (nazwa zaczyna się od "platform:") odpowiada dokumentowi z modelem. Poniżej widnieje fioletowy element EPackage. Klikamy na niego i uzupełniamy pola "Name", "Ns prefix", "Ns URI" (na panelu właściwości). Najistotniejsze jest pole nazwa - będzie ono odpowiadało nazwie pakietu w modelu. Pola z prefiksem i uri nie wydają się być istotne, jednakże sugeruje je uzupełnić. Zapobiega to problemom podczas generowaniu kodu metamodelu i umożliwia serializację modelu w formacie XMI.



Ponieważ struktura elementów EPackage będzie odpowiadała wygenerowanym pakietom w języku java to, aby zachować porządek wewnątrz ui utworzę nowy element EPackage o nazwie model. Klikamy prawym przyciskiem na elemencie ui i z menu kontekstowego wybieramy "New child" -> "EPackage".



Z wymagań wprost wynika, że w metamodelu będą następujące byty: aplikacja, okno, kontrolka, przycisk, etykieta, pole tekstowe. Ponadto elementy przycisk, etykieta oraz pole tekstowe dziedziczą z elementu kontrolka. W pakiecie model dodajemy elementy EClass odpowiednio podając właściwość "Name". Właściwość "Abstract" elementu Kontrolka ustawiamy na true, a dla przycisku, etykiety i pola tekstowego jako atrybut "ESuper Types" wskazujemy element kontrolka.



Teraz do elementu kontrolka dodajemy nowe elementy EAttribute o nazwie tekst(ustawiając właściwość EType na EString), szer, wys, x, y(wszystkim czterem ustawiając właściwość EType na EInt). Ponadto elementom szer, wys, x, y ustawiamy dolną liczność(Lower Bound) na 1, przez co stają się obligatoryjne.



Pozostaje jedynie zamodelować, iż aplikacja posiada wiele okien, a okno posiada wiele kontrolek. Robimy to dodając do elementu aplikacja nowy element EReference o nazwie okna, a do elementu okno o nazwie kontrolki. Właściwość EType ustawiamy odpowiednio na Okno i Kontrolka, a górną liczność (Upper Bound) na -1 (czyli dowolnie dużą).



W ten sposób utworzony został metamodel naszego narzędzia. Pozostało jedynie wygenerować odpowiadający mu kod. W katalogu model tworzymy nowy plik typu "EMF Generator Model" o nazwie np: "ui.genmodel". W oknie kreatora "Model importers" wybieramy "Ecore model", dalej wskazujemy plik ui.ecore, by ostatecznie zakończyć działanie kreatora. Plik .genmodel pozwala dostosować proces generacji kodu, jednakże w tym przypadku ograniczymy się do zmiany katalogu w którym zostanie umieszczony wygenerowany kod. Zaznaczamy korzeń w edytorze genmodel i we właściwościach, w grupie "Model" zmieniamy "Model Directory" z "/ui.model/src" na "/ui.model/src_gen". Po tej drobnej modyfikacji z menu kontekstowego elementu root w edytorze genmodel wybieramy "Generate Model Code".

Powinniśmy zobaczyć w projekcie nowy katalog src_gen z pakietami: "ui.model", "ui.model.impl", "ui.model.util". Jest to implementacja naszego metamodelu z wykorzystaniem biblioteki EMF.

W kolejnej części utworzymy edytor pozwalający nam na tworzenie modeli zgodnych z utworzonym wyżej metamodelem.

Brak komentarzy:

Prześlij komentarz