VOORWOORD SAMENVATTING INHOUDSTAFEL VOORWOORD ..................................................................................................... 2 SAMENVATTING ................................................................................................. 2 INHOUDSTAFEL .................................................................................................. 2 INLEIDING ......................................................................................................... 3 ALFABETISCHE LIJST VAN GEBRUIKTE AFKORTINGEN ....................................... 4 1 QFRAME ............................................................................................... 5 1.1 1.2 1.3 1.4 .NET gespecialiseerd ............................................................................ Behandelen van projecten .................................................................... Aanbieden Consultancy ........................................................................ Werknemers ........................................................................................ 2 STAGEOPDRACHT ................................................................................. 7 2.1 2.1.1 2.1.2 2.1.3 2.1.4 Uitvoering ............................................................................................ 7 Eerste fase ..............................................................................................8 Tweede fase ............................................................................................8 Derde fase ..............................................................................................9 Vierde fase ..............................................................................................9 3 REALISATIE ....................................................................................... 10 3.1 3.2 3.3 Diagram ............................................................................................. 10 Generatie ........................................................................................... 11 Import en export ............................................................................... 11 4 DOMAIN SPECIFIC LANGUAGE ........................................................... 12 4.1 4.2 4.3 4.3.1 4.3.2 4.3.3 4.3.4 4.3.5 Ontwikkelingstools ............................................................................ 13 DSL-Tools ........................................................................................... 13 Belangrijkste vensters ....................................................................... 13 Toolbox ................................................................................................ 13 Hoofdscherm ......................................................................................... 13 Proporties ............................................................................................. 13 DSL Explorer ......................................................................................... 14 DSL details ............................................................................................ 14 5 INSTELLEN DSL-MODEL ...................................................................... 15 5.1 5.2 5.3 5.3.1 5.3.2 5.4 5.4.1 5.4.2 5.4.3 Aanmaken DSL - project..................................................................... 15 Opstarten DSL-Model ......................................................................... 15 Aanmaken nieuwe elementen ............................................................ 16 Elementen ............................................................................................. 16 Connectoren .......................................................................................... 17 Eigenschappen toekennen ................................................................. 17 Type bepalen ......................................................................................... 17 Enumeraties toevoegen .......................................................................... 18 Soort bepalen ........................................................................................ 18 5.4.3.1 5.4.3.2 5.4.3.3 Normal ............................................................................................................................. 18 Calculated ......................................................................................................................... 18 Custom Storage ................................................................................................................. 19 5.4.5.1 Text Decorator .................................................................................................................. 21 5.4.4 5.4.5 5 6 6 6 Sleuteleigenschap bepalen ...................................................................... 20 Decorators toekennen............................................................................. 20 3 5.4.5.2 Icon Decorator................................................................................................................... 21 6 DSL-MODEL BEKIJKEN ....................................................................... 26 6.1 6.2 Elementen toevoegen......................................................................... 26 Overzicht elementen bekijken ............................................................ 26 7 COMMANDO INSTELLEN DSL-MODEL .................................................. 28 7.1 7.1.1 7.1.2 7.1.3 7.1.4 7.1.5 7.2 7.3 7.3.1 7.3.2 7.3.3 Aanmaken menu commando’s ............................................................ 28 Symbols ............................................................................................... 28 Commandplacements ............................................................................. 29 Buttons ................................................................................................. 29 Menu’s .................................................................................................. 29 Groups ................................................................................................. 30 Toewijzen constanten ........................................................................ 30 Acties toekennen aan Commando ...................................................... 30 Toevoegen aan model: ........................................................................... 30 Statusfunctie bepalen: ............................................................................ 31 Actie bepalen......................................................................................... 32 8 GEBRUIK VOOR GENERATIE ............................................................... 33 8.1 8.2 8.3 8.3.1 8.3.2 8.4 8.5 8.6 Instellen processor ............................................................................ 33 Opstellen Templates .......................................................................... 35 Aanmaken Templates ......................................................................... 35 Losse templates ..................................................................................... 35 Templates via constante waarden ............................................................ 35 Template schrijven............................................................................. 36 Methode schrijven .............................................................................. 36 Extra functionaliteiten schrijven ........................................................ 38 9 EXPORTEER DSL-MODEL ..................................................................... 39 9.1 9.2 9.3 Gebruik maken store .......................................................................... 39 Schrijven basisclass ........................................................................... 39 Schrijven export class ........................................................................ 40 10 IMPORTEER NAAR DSL-MODEL ........................................................... 41 10.1 10.2 10.3 Importeer vanuit DSL ......................................................................... 41 Importeren buiten DSL ...................................................................... 42 Positioneren Shapes .......................................................................... 43 5.5 5.6 5.7 5.8 Groeperen van elementen .................................................................. Acties op shapes ................................................................................ Rules en validatie ............................................................................... Custom Editor instellen ...................................................................... 21 22 23 24 BESLUIT .......................................................................................................... 43 LITERATUURLIJST ............................................................................................ 43 BIJLAGEN ......................................................................................................... 44 INLEIDING 4 ALFABETISCHE LIJST VAN GEBRUIKTE AFKORTINGEN DB Database DSL Domain Specific Language EA Enterprise Architecture T4 Text Templating UML Unified Modeling Language XML Extensible Markup Language XSLT Extensible Stylesheet Language Transformation 5 1 QFRAME QFrame is het .NET competence center binnen Cronos NV, de bekende e-business integrator uit Kontich. Cronos NV is een groep van ondernemingen die vaak nauw samenwerken maar dan gespecialiseerd in hun domein. Qframe heeft zich gespecialiseerd in maatwerk voor .NET en Microsoft Office toepassingen en stelt 30 mensen tewerk. De focus ligt op technische kennis en QFrame tracht dan ook continu op de hoogte te blijven van de laatste nieuwigheden op dat gebied. Toch zijn ze bovenal bezig met het zoeken naar de meest pragmatische oplossing in de context van de klant, wat niet altijd betekent de meest recente technologie. Het merendeel van de QFrame-klanten is marktleider of is een belangrijke speler binnen hun bedrijfstak. Deze status aanhouden is vanzelfsprekend geen sinecure en enkel mogelijk mits een strenge bewaking van de verschillende bedrijfsprocessen. Het is dan ook niet verwonderlijk dat deze bedrijven bij de selectie van hun IT-partner nauw toekijken op de ervaring en kwaliteit van de externe medewerkers die men wenst in te schakelen. Wij zijn er van overtuigd dat specialisatie, mits de juiste omkadering en begeleiding, een antwoord vormt op de vraag naar de nodige expertise en kwaliteit. 1.1 .NET gespecialiseerd Microsoft .NET is de laatste jaren uitgegroeid tot hét referentieplatform voor ontwikkelen van software wereldwijd. Deze technologie wordt alom geloofd zijn zeer uitgebreide mogelijkheden, snelheid en productiviteit bij het ontwikkelen. .NET kunnen diverse types toepassingen ontwikkeld worden, wij concentreren echter vooral op bedrijfskritische data-entry en backend systemen. het om Met ons QFrame was trouwens al vóór het ontstaan van .NET erg actief met het ontwikkelen van administratieve maatsoftware, toen nog in COM-technologie. Deze kennis, vooral rond ontwikkeltool Visual Basic 6, is nog steeds in huis en ook veel gevraagd. Sinds de introductie van .NET in 2002 wordt voor nieuwe ontwikkelingen bijna integraal voor .NET gekozen. We ontwikkelen zowel Windows- als Web toepassingen, maar ook de ontwikkeling van Webservices en integratie modules met andere platformen behoren tot de activiteiten. Voor dataopslag wordt bij voorkeur Microsoft SQL Server connectiviteit naar Oracle databases verloopt probleemloos. ingezet, echter ook Voor maatwerk .NET projecten richt QFrame een gestandaardiseerde projectflow in, waarin centraal versiebeheer, geautomatiseerde tests en builds en hiermee geïntegreerde communicatie en rapportage via Visual Studio Team System centraal staan. 6 1.2 Behandelen van projecten QFrame houdt zich vooral bezig met het realiseren van projecten. Elk project krijgt een team toegekend. In dit team zullen alle belangrijkste technische taken op zich worden genomen: developer, technical coach & technical architect, … Wanneer andere zaken nodig zijn kunnen ze altijd beroep doen op gespecialiseerde mensen van andere bedrijven uit de Cronos groep. Het gebeurt ook dat het gemengde projectteams zijn. Deze teams bestaan uit medewerkers van QFrame maar ook medewerkers van de klant. Dit zorgt er voor dat de klant op een korte termijn een uitgebreide ervaring op doet. Steeds wordt er aan de klant duidelijke afspraken rond gemaakt hoe ze QFrame makkelijk kunnen bereiken. Dit gebeurt via het “Single point to contact” concept dat ze hanteren. Steeds een plaats waar ze QFrame kunnen bereiken. 1.3 Aanbieden Consultancy Klanten die nood hebben aan assistentie of technische kennis kunnen ook terecht bij QFrame. Wanneer er een project tijdig afgerond moet worden en ze even fulltime assistentie nodig hebben om dit te realiseren. Vooral om een specialist voor een beperkte tijd in te huren of om meer coaching te hebben bij een project. Maar buiten de .NET en office ontwikkelaars hebben ze een uitgebreid pakket van activiteiten aan te bieden zoals: 1.4 het opstellen van een verkennende studie maken van een (UML gebaseerde) functionele analyse ontwerpen van een applicatie architectuur interne voorstellen realiseren intern project management bugfixing op bestaande projecten, etc. Werknemers Voor QFrame zijn de werknemers ook belangrijk. Ze kiezen ervoor om een goede reputatie te creëren voor hun medewerkers. Omdat voor vele computers een hobby is en sommige medewerkers sleutelposities beschikken op forums en newsgroups van Microsoft. Een paar medewerkers zijn zelf gecertificeerde Microsoft trainers. Medewerkers hebben voluit de kans om zich bij te schaven door middel van cursussen, (inter)nationale congressen en conferenties. 7 2 STAGEOPDRACHT Qframe heeft een framework ontwikkelt met de naam Leaf.net. Dit framework helpt hen om snel bepaalde klassen te genereren die verder helpt om snel applicaties te kunnen starten. Dit gebeurt nu via omzetting van een commit-model naar xml. Uit deze xml-files worden dan via een tool die gebruikt maakt van bepaalde XSLT-bestanden om de xml-files om te zetten naar code. De bedoeling is dat dit via een nieuwe methode te doen. Het commit-model wordt dan omgezet naar een domain specific language model. De opdracht is dus om een dslmodel te ontwikkelen en ervoor te zorgen dat je een commit-model kunt omzetten naar een dsl-model. Het is ook de bedoeling om het dsl-model om te zetten naar code via texttemplating. De stap om het commit-model om te zetten naar een dsl-model moet ook in de omgekeerde richting gebeuren. Dit is namelijk voor het feit dat er bepaalde noodzakelijke scripts bestaan die gebruik maken van het Commit-model, vooral de scripts die de tabellen opvullen met de informatie uit het Commit-model. Dit zou ook helemaal in het bestaande gedeelte moeten worden opgenomen. Dus dat het via hun tool gemakkelijk kan worden gebruikt om code te genereren want de andere opties moeten nog steeds beschikbaar zijn als mensen daar voor kiezen. Dit is wordt in de toekomst wel anders, het wordt de bedoeling dat ze in de toekomst enkel met DSL gaan werken en de stappen om code te genereren reduceren naar twee stappen. Namelijk het ontwikkelen van het model en van daaruit dan code te generen Als extra kan het nog zijn dat het via Guidance Automation Toolkit mogelijk moet zijn om via de xml-file van de dsl-model en de templates om daarmee de code te genereren. 2.1 Uitvoering Qframe heeft in de loop van de jaren een aantal tools ontwikkelt die hen helpt in het ontwikkelen van een applicatie. Zo is er een framework ontstaan met de naam “LeaF.net”. Dit staat voor “Large Enterprise Application Framework”. Het is een soort van uitbreiding voor het .net framework van microsoft. Leaf.net framework is een uitgebreid framework dat hen helpt bij het creëren van uitgebreide zoekmogelijkheden, rolebased security of meertaligheid. Dit zijn niet de enige functies want hier boven is eigenlijk ook de codegenerator ontwikkeld. Dit helpt hen verder in het schrijven van de classes rond de data invoer van een applicatie. Hierbij zal dus de ontwikkeltijd verkorten en zal de kwaliteit aardig toenemen. Omdat dit voor mij de belangrijkste functionaliteit is omdat hier mijn nieuwe functionaliteit behoort. 8 Hier is een schema met de functionaliteiten van nu en wat het zou moeten worden: Om dit te realiseren is het verdeeld in vier fases. De eerste fase is de belangrijkste fase omdat dit centraal staat in de nieuwe generatie. Fase drie en vier zijn minder belangrijk omdat deze stappen in de toekomst misschien overbodig worden. Fase 1 en 2 blijven dan de belangrijkste stappen in de generatie van code. 2.1.1 Eerste fase Aanmaken van het model zelf. Het model is de basis voor alles, je kan niet beginnen aan de generatie voordat je model af is. Je kan ook niet beginnen aan de import of export als er geen model is. Eerste fase is dus om het model zo op te stellen dat het voldoet aan alle noden voor het Leaf.NET framework. Alles wat in het bestaande commit-model zit zou je moeten terugvinden in het nieuwe DSL-model. Ook moet er voor gezorgd worden dat het een duidelijk overzicht heeft en dat je rekening houdt met alle soorten relaties tussen alle elementen. 2.1.2 Tweede fase Generatie is redelijk belangrijk omdat anders het DSL-model nutteloos is (buiten het bekijken ervan). Allereerst moet ik ervoor zorgen dat je vanuit het DSL-model kan genereren naar meerdere files. Daarna moet ik zorgen dat de T4-scripts worden aangemaakt voor elk soort van bestand. Daarna moet ik zorgen dat het mogelijk dat ik het resultaat van de generatie rechtstreeks naar bestaande projecten kan genereren. 9 2.1.3 Derde fase Derde fase is in de toekomst misschien niet meer nodig maar momenteel is het nog wel een belangrijke stap. Het importeren van een commit-model naar je DSL-model. Dit zou vanuit de bestaande generator moeten kunnen gebeuren zonder dat je het DSL project moet opstarten. In principe zou je dan niets meer moeten aanpassen aan je DSL-model om te kunnen genereren naar de juiste code. Omdat DSL een object georiënteerde taal is moet de import best gebeuren via objecten want je kan het ook via xml doen maar dit is niet zo gebruiksvriendelijk voor de aanpasbaarheid. Later kunnen er zaken aan het commitmodel wijzigen zodat het snel kan worden aangepast. 2.1.4 Vierde fase De vierde fase en de derde fase kunnen worden omgewisseld. Omdat de medewerkers vertrouwd zijn met het Commit-model en omdat er nog tooltjes bestaan die gebruik maken van een Commit-model moet het mogelijk zijn om een bestaand DSL-model te exporteren naar een Commit-model. Dit Commit-model kan je dan makkelijk gebruiken in de bestaande tools. Importeren en exporteren zijn gelijkaardig en wanneer je één stap kan, zal de omgekeerde stap via dezelfde manier lukken. In principe zou je een model kunnen exporteren en nadien weer importeren. Dit zou dan hetzelfde resultaat moeten geven dan voordien. 10 3 REALISATIE Voor de grootste gedeelte van de opdracht heb ik me bezig gehouden met fase 1 en 2 van mijn opdracht. Ik kon vertrekken van een bestaand model dat standaard werd meegeleverd met de DSL-Tools. Dit was natuurlijk het minimum van het minimum dat nodig was. Een uitbreiding was noodzakelijk om alle elementen die Qframe gebruikt in hun generatie te tonen. 3.1 Diagram Een diagram bestaat meestal uit classes maar kan ook tabellen bevatten. Tussen beide elementen bestaat er eventueel een link. Elke class heeft de mogelijkheid om attributen en methodes toe te kennen. Een tabel bevat dan weer velden en bevat foreign keys en primary keys. Tussen beide soort van elementen kan je relaties trekken. Er bestaan twee soorten relaties tussen dezelfde soort van elementen. Tussen twee tabellen of twee classes kan je relaties leggen die één richting uitgaan of relaties leggen die gelden langs beide richting. Er is wel een speciale soort van relaties namelijk relaties met een veel op veel multipliciteit. Dit is enkel tussen twee classes mogelijk omdat tabellen dit niet kunnen bevatten. De link tussen beide is dan weer enkel mogelijk tussen één tabel en één class. Je kan geen meerdere tabellen aan één class hangen. Weer heb je hier het speciaal item voor veel op veel relaties. Hier heb je steeds een tabel die gelinkt is met de veel op veel relatie. Dit moet in DSL met een tussenstuk omdat je geen associaties kon leggen tussen associaties en elementen. Het tussenstuk bevat maximum twee classes en één tabel als link. Zo kan een diagram er uitzien: 11 3.2 Generatie Voor het generatie gedeelte was het lang een zoekwerk hoe ik voor elke class een aparte file kon genereren. Dit kon uiteindelijk door een commando toe te kennen en zo via een bepaalde methode de generatie te regelen. Standaard zal de generatie gewoon gebeuren in het model maar er is de mogelijk om een andere locatie te selecteren. Zo kan je snel kiezen om het resultaat van de generatie te gebeuren in een bestaand project of op een bepaalde locatie. Wanneer een bestand bestaat zal hij het bestand overschrijven. Zo zijn er baseclasses die de grootste informatie bevatten van de modellen. Voor elke baseclass bestaat er een class die gebruikt maakt van de baseclass. Een baseclass moet bij elke generatie worden aangepast maar de class die gebruik maakt van deze baseclass niet. In deze class wordt er eigen code bijgeschreven die zeker niet mag worden verwijderd door een nieuwe generatie. Dit wordt voorkomen door te controleren of het bestand bestaat of niet. Wanneer het al bestaat zal hij het niet uitvoeren, anders zal hij een nieuw bestand aanmaken met de gepaste code. Via verschillende commando’s kan je bepalen welke taal en welke classes je kunt genereren. Je kan ook per tabel beslissen of je wilt dat het wordt gebruikt in de generatie. 3.3 Import en export Import en export gebeurt op dezelfde manier. Telkens wordt er voor elke class of tabel een object aangemaakt. Die wordt dan opgevuld met de correcte informatie. Wanneer alles over het object is ingevuld zal hij het object toevoegen aan de algemene collectie. Een verschil is dat import buiten het DSL-model wordt gebruikt en dat zorgt voor een lastiger pakket. Een DSL-bestand is eigenlijk een XML-bestand, maar omdat je het model kunt bekijken in een speciale designer bevat het een hoop extra informatie. Alle elementen worden in een soort van collectie opgeslagen. Het toewijzen in een collectie gaat nog wel maar om een collectie toe te kennen aan een bestand is veel moeilijker. Een XML-bestand bevat geen extra instellingen. Dit is voorkomen door een bepaald element te gebruiken van het DSL-model. Je kan een store zo toekennen aan bestand. Het importeren gebeurt via de bestaande generator. Je kan nu een nieuwe optie kiezen “Commit To DSL” tussen de opties. Er zal dan een formulier worden getoond waar je informatie kunt wijzigen zoals de locatie en de naam. Zo kan je dan bevestigen zodat er een nieuw DSL-model word aangemaakt. Het exporteren gebeurt gewoon via een commando. Je moet dan de naam en locatie invullen. Wanneer je bevestigt, wordt er een nieuw Commit-model aangemaakt op de locatie. 12 4 DOMAIN SPECIFIC LANGUAGE Domain specific language is een ruim begrip. Het is eigenlijk een soort van abstracte taal die gebruikt wordt om ontwikkelde systemen duidelijker te maken. Het is een soort van analysetaal waarbij je modellen verduidelijkt. Het is mogelijk om schema’s op te stellen die bepaald zijn naar uw eigen eisen. Het hangt ook niet vast aan één bepaalde programmeertaal, het staat volledig los daarvan en kan dus zowel gemaakt worden voor Java schema’s, .net schema’s of andere talen. De naam zegt ook waarvoor het dient, het is een taal die veel gericht is op een bepaald domein. Elk model is dan ook anders en is gebaseerd op het systeem dat ontwikkelt moet worden. Het geeft dan ook een heel goed beeld over het toekomstige systeem. Het kan ook voor andere zaken gebruikt worden dan voor programmeerzaken weer te geven. Je kan het echt puur gebruiken om analysezaken weer te geven. Bijvoorbeeld om de structuur van je website te ontwikkelen of zelfs helemaal niets met informatica te maken hebben. Wanneer je een elektrische schakeling wilt tonen aan klanten. Maar het dient vooral dus voor programmeren. Met de domain specific language tools is het mogelijk om je eigen modellen te maken en vanuit die modellen code te genereren. Dit bestond al wel voor UML modellen maar die modellen zijn vast bepaald en bij dsl kan je de modellen zo aanpassen naar je systeem. Domain specific language zal nooit alles verduidelijken maar het is gewoon veel gerichter op je behoeftes dan programma’s. Het is ook een vrij nieuw begrip dus momenteel staat de ontwikkeling van Dsl-tools nog niet helemaal op punt. 13 4.1 Ontwikkelingstools Om domain specific language te ontwikkelen bestaan er verschillende tools want het is geen vast gedefinieerde taal. Doordat er geen vast stramien voor de taal is, kan eigenlijk Word al ideaal zijn. Soms is het maar tekstueel weergeven van een systeem. Maar om het visueel toch iets beter voor te stellen en om sneller te kunnen werken heeft Microsoft een tool ontwikkelt. Het heeft de simpele naam meegekregen “Dsl tools”. Dit zit niet standaard in Visual studio. Dit zit wel in de sdk van Visual studio die je gratis kan downloaden van de microsoft site. Opgelet: Visual studio moet de professional edition zijn. Anders zal je dsl tools wel kunnen installeren maar niet gebruiken. In 2005 versie was het nog in de kinderschoenen en zullen er wel vaak stabiliteitsproblemen opduiken. Sinds 2008 is het beter maar je merkt wel weinig verschil maar hij zal veel stabieler werken. 4.2 DSL-Tools Dsl-tools is eigenlijk een soort verzameling van classes in c# die samen met een achterliggende compiler zorgen voor de weergave van het klassemodel. Elk object dat je aanmaakt zal ook zijn eigen classes krijgen. De structuur van de tool is altijd uit twee c#-solutions namelijk DSL en DSLpackage. DSL is de verzameling van de objecten met al hun classes. Hierbij zul je dus geen classes vinden die te maken hebben met het creëren van het model. Dat is aanwezig in DSLpackage. Hier vind je alles dat te maken heeft met de weergave van het dsl-model maar niets rond de objecten die getoond worden. 4.3 Belangrijkste vensters Dsl-tools is bijna identiek aan Visual studio maar heeft natuurlijk extra vensters die gericht zijn op domain specific language. 4.3.1 Toolbox Toolbox heeft elk Visual studio project ook maar voor dsl is er een aparte categorie aan toegevoegd die alle elementen bevat voor het aanmaken van een dsl-model. Ook alle elementen die niet tot een class diagram behoren zijn hier in weergegeven. 4.3.2 Hoofdscherm Het hoofdscherm is in principe gewoon een scherm waar je bestanden kan wijzigen. Standaard staat hier dsldefinitions.dsl open. In dit bestand worden de nieuwe elementen toegevoegd voor je model. Dit is een bestand waar je de elementen van de toolbox naar toe sleept. Eigenlijk is het een dsl-model op zich. 4.3.3 Proporties Dit is ook identiek aan Visual studio. Hier vind je niets speciaal in buiten dat de proporties gebaseerd zijn op elk element van het model. 14 4.3.4 DSL Explorer Dsl Explorer bestaat uit de verzameling van elementen in het dsl-model. Elk soort collectie vind je hier terug. Bepaalde zaken kan je alleen hier instellen. Alles is hier ingedeeld in collecties. Hier vind je ook gewoon de verzameling terug van elementen en relaties maar ook kan je hier een overzicht krijgen hoe de xml in elkaar zit. Elk element kan je bekijken welke attributen en relaties er zijn. 4.3.5 DSL details Dit vind je standaard onderaan terug. Hier kan je gedetailleerde informatie wijzigen. Vooral rond decorators, compartimenten en ook alle informatie rond relaties wijzigen. 15 5 INSTELLEN DSL-MODEL 5.1 Aanmaken DSL - project Het aanmaken op zich is geen moeilijk proces. Alleen sommige elementaire zaken zijn belangrijk dat je die goed kiest. Bijvoorbeeld welke extensie je diagrammen gaan hebben. Deze moet uniek zijn en nog niet bestaand. Daarom kan je beter iets langer en een bepaalde afkorting gebruiken. 1. Je opent Visual studio en selecteert “New project” 2. Je kiest bij Other project types onder de categorie extensibility voor: Domain specific language designer 3. Selecteer in het keuze venster voor het gewenste diagram. (Voor mijn opdracht is het Class Diagram) 4. Je kiest een naam voor je project 5. Je kiest je unieke extensie. (Bij bestaande extensies ga je problemen krijgen) 6. Daarna vul je een naam van project in en tot wie het behoort en de namespace 7. Kies voor New key of voor bestaande keyfile (assembly informatie file) 8. Druk op finish 5.2 Opstarten DSL-Model Standaard wordt er een basis gemaakt voor een class diagram. In Visual studio is er een class diagram viewer aanwezig voor elk project. (rechtermuisknop -> view as class diagram). Dit class diagram wordt als basis genomen voor de dsl-tools. Wanneer je het standaard class diagram wil bekijken, hoef je enkel op het groene pijltje of menuoptie start debugging te kiezen in het menu debug. Er zal een nieuwe Visual studio geopend worden. Het is geen normale Visual Studio maar een Experimental Hive versie. Dit is de versie waar je zaken kunt proberen die invloed hebben voor de Visual Studio omgeving. Omdat het nogal kritisch is om de gewone Visual Studio te gebruiken, gebruiken ze een versie die bij beschadiging gemakkelijk kan hersteld worden zonder dat je de hele Visual Studio moet herinstalleren. Wanneer je nog niets aangepast hebt, zal hij altijd een voorbeelddiagram aanmaken. Dit vind je terug in de solution Explorer van je model met de naam: sample.”extensie”. Dit bevat een voorbeelddiagram waar alle elementen aanwezig zijn van het model. De omgeving is vertrouwd. Standaard bestaat de omgeving uit een toolbox aan de linkerkant, centraal dan de ruimte voor bekijken van de modellen. Aan de rechterkant bevind zich dan het proporties venster en de solution Explorer. Onderaan bevind er zich nog de error-list. 16 Opmerkingen: In xp kunnen er fouten gebeuren en kan het zijn dat je geen Diagram editor kan openen van je bestand. Dit moet je oplossen door de buildopties van DSLpackage aan te passen in je project. Je volgt deze stappen om er voor te zorgen dat dit gebeurd: 1. Selecteer proporties bij DSLpackage 2. Kies build events 3. Vul in: "C:\Program Files\Microsoft Visual Studio 2008 SDK\VisualStudioIntegration\Tools\Bin\regpkg.exe" /root:Software\Microsoft\VisualStudio\9.0 “$(TargetPath)” 4. Rebuild voor uittesten of het werkt In principe zou dit standaard moeten gebeuren. Standaard zal hij bij stap 3 9.0exp kiezen. Maar bij XP wordt deze map soms niet gevonden. Daarom zal hij het niet uitvoeren zoals je wenst. Een foutmelding geeft hij niet maar wanneer je opstart krijg je een “Package Load Failure”. Het is belangrijk om ervoor te zorgen dat je telkens twee acties uitvoert: “transform all templates” en dat je daarna het project build via “Build solution”. Daarom kan je best een macro opbouwen die de twee acties uitvoert. 1. Selecteer tools -> macros -> new macro project 2. Rechtermuisknop op nieuwe macro -> Set as recording project 3. Selecteer tools -> macros -> recording temporaryMacro 5.3 Aanmaken nieuwe elementen Omdat het noodzakelijk is om nieuwe elementen toe te voegen die meer tot uw noden behoren moet je alles eens grondig doornemen. Meestal kan je de basis wel gebruiken en moet je enkel nieuwe elementen toevoegen. Een nieuw element kan je gewoon slepen vanuit de toolbox. Je hebt keus tussen drie verschillende types: 5.3.1 Elementen Een element is een item dat kan toegevoegd worden aan het diagram zonder echt afhankelijk te zijn van andere elementen. Natuurlijk is dit enkel het geval wanneer het element mag toegevoegd worden aan het rootelement. Elk diagram heeft één rootelement die eigenlijk de verzameling vormt van alle elementen. Sommige 17 elementen zijn wel speciaal. Zij behoren niet tot het rootelement maar tot een basiselement. Dit is vaak een embedded element: voorbeeld is een modelattribuut van een class. Wanneer je dus het basiselement verwijderd, zal hij alle subelementen mee verwijderen. Om een element te tonen moet je er een Geometric shape of een image shape aan koppelen. Zonder shape zal hij het niet tonen. Een geometric shape is een bepaalde vorm: een vierkant, cirkel, ruit, … en een image shape is een afbeelding die je zelf wil gebruiken voor het element. Een compartiment shape is een speciale shape die bedoelt is om subelementen weer te geven. Elk compartiment wordt dan gelinkt aan een subelement en zo zullen de subelementen worden weergegeven in het hoofdelement. 5.3.2 Connectoren Connectoren zijn de relaties tussen de elementen. Zonder connectoren kan je geen elementen met elkaar verbinden. Er zijn twee types: embedded connectoren en referenced connectoren. Hier bepaal je dus of het element een alleenstaand geval is of het element een onderdeel is van een ander element. Een referenced connector is altijd afhankelijk van twee elementen. Dit kan twee verschillende elementen zijn maar kan ook hetzelfde element zijn. Bij elke relatie kan je dan bepalen welke multiplicity het bevat. Wanneer aan beide kanten 0..* is geselecteerd, zal hij geen extra proportie voorzien maar bij een 0..1 zal hij in het element een proportie aanmaken waarbij je een element kan selecteren dat voldoet aan de relatie. Ook een connector heeft een connector shape nodig om het te tonen. Wanneer dit niet gebeurd, kan je wel relaties leggen maar kan je ze niet zien. Dit kan problemen geven wanneer je nieuwe relaties wil leggen en relaties wilt verwijderen. 5.4 Eigenschappen toekennen Eigenschappen kan je aan alles toekennen. Zowel aan connectoren, elementen en zelfs aan shapes. Elk ingesteld eigenschap kan je standaard eigenschappen toekennen. Eigenschappen kunnen echt dienen als statische informatie voor het element. Een eigenschap kan van elk soort type zijn: boolean, string, integer of een eigen type. Types kan je definiëren in de dsl explorer bij domain types. Hier hoef je enkel de naam en namespace ingeven. Dus wanneer je een eigen class heb aangemaakt en je wil objecten daarvan gebruiken moet je hier de naam van de class ingeven en de namespace. 5.4.1 Type bepalen Standaard ontbreken er een paar dus als voorbeeld kan je zorgen je het type color kunt toevoegen. Dit zal er voor zorgen dat je bij je eigenschap nu een listbox krijgt met alle mogelijke kleuren. 18 1. Je selecteert dsl explorer 2. Je klikt met je rechtermuisknop op het hoofdelement en selecteert “add external type” 3. Je vult als naam in: Color 4. Je vult als namespace in: System.drawing Vanaf nu kan je bij het type in plaats van string of integer ook color selecteren. 5.4.2 Enumeraties toevoegen Enumeraties zijn lijsten met mogelijke keuzes. Het is mogelijk dat een eigenschap enkel vier mogelijkheden mag bevatten. Dit kan je best oplossen door een enumeratie toe te voegen. Enumeraties bevinden zich gewoon tussen de domain types. Hierbij kan je dus gewoon de enumeratie selecteren als type. 1. Je selecteert dsl explorer 2. Je klikt met je rechtermuisknop op het hoofdelement en selecteert “add enumeral type” 3. Je vult als naam in van de enumeratie 4. Je kan nu via de rechtermuisknop steeds nieuwe elementen aan de enumeratie toevoegen 5.4.3 Soort bepalen Een eigenschap kan afhankelijk zijn van andere eigenschappen. Daarom is er een proportie “Kind”. Deze optie heeft drie mogelijkheden: 5.4.3.1 Normal De eigenschap is van niets afhankelijk. Dit zal gewoon een eigenschap zijn dat je kan aanpassen naar wat je wilt. Deze wordt standaard geselecteerd als je een nieuwe domainproperty aanmaakt. Wanneer je van een andere optie voor deze optie kiest, dan zal hij geen rekening meer houden met de aangemaakte methodes die nodig zijn voor de andere opties. 5.4.3.2 Calculated Wanneer dit geselecteerd is, betekend dat de eigenschap afhankelijk is van andere eigenschappen. Vanaf nu is de eigenschap ook read-only. Je kan de eigenschap niet meer manueel aanpassen. Het zal wel telkens aanpassen als je de afhankelijke eigenschappen aanpast. Je moet hier wel een methode schrijven waar je bepaald welk de gerelateerde eigenschappen zijn. Het kan ook dat je gewoon een functie schrijft die een bepaalde formule uitvoert zonder dat er een gerelateerde eigenschap achter hangt. De naam van de functie is niet standaard te kiezen. Je kan best eerst alles builden om de naam te achterhalen. Hij zal dan een foutmelding geven dat er een bepaalde methode ontbreekt. Die methode schrijf je dan in een aparte class die dezelfde naam heeft als het element van de eigenschap. 19 1. Selecteer de gewenste domain property 2. Verander de property kind naar calculated 3. Transform all templates en rebuild 4. Krijg je foutmelding 5. Maak nieuwe klasse aan in DSL 6. Zorg voor de juiste klasse bij “public partial XXX” -> xxx is domain class name 7. Schrijf de functie die ontbreekt (zie foutmelding voor de naam) 8. Voer dan je acties toe en return het resultaat Stel dat: De maxlength van een attribuut van een class is afhankelijk van het type. Dan moet je deze class schrijven: Public partial class ModelAttribute { Public Int GetMaxlengthValue() { If(this.Type.equals(“String”)) { Return 255; }else{ Return 50; } } } 5.4.3.3 Custom Storage Dit gaat eigenlijk een stap verder als calculated. Het verschil is dat dit de eigenschap niet read-only maakt. Je kan het attribuut aanpassen maar hier is het mogelijk dat wanneer je het attribuut aanpast, dat je dan ineens de afhankelijke attributen aanpast. Hier is natuurlijk voorzichtigheid geboden want als je het verkeerd invult, zal hij misschien één van de twee afhankelijke eigenschappen niet mee aanpassen. 1. Selecteer de gewenste domain proportie 2. Verander de proportie kind naar customStorage 3. Transform all templates en rebuild 4. Krijg je foutmelding 5. Maak nieuwe klasse aan in DSL 20 6. Zorg voor de juiste klasse bij “public partial XXX” -> xxx is domain class name 7. Schrijf de functie die ontbreekt (zie foutmelding voor de naam) 8. Voer dan je acties toe en return het resultaat Hier heb ik in je in plaats van een Get-methode een Set-methode nodig. Om het voorbeeld van hierboven aan te vullen: Public void SetMaxLength(int newValue) { If(newValue==255){ this.Type=”String”; }else{ this.Type=”Integer”; } } 5.4.4 Sleuteleigenschap bepalen Sleuteleigenschappen zijn standaard niet nodig omdat elk element een ID toegewezen krijgt. Maar ID’s zijn niet echt bruikbaar wanneer je interacties gaat doen in code later. Daarom is het handig om een domainproperty als vervanging te kiezen. Hiervoor moet je bepaalde instellingen aanpassen. 1. Selecteer de gewenste domainproperty 2. Verander de proportie “IsElementName” naar true 3. Ga naar de DSL explorer 4. Zoek in de categorie “XML Serialization Behavior” naar het bijhorende element 5. In element data selecteer je dan de element data waar je “IsElementName” verandert hebt. 6. Verander “IsMonikerKey” naar true Vanaf nu zal de domainproperty gelden als ID in je model. IsElementName moet niet op true staan maar is wel belangrijk wanneer je meerdere items aanmaakt. Want dit moet namelijk identiek zijn anders kan je problemen krijgen wanneer je het voor de tweede keer wilt openen. 5.4.5 Decorators toekennen Eigenschappen kunnen soms iets bepalend zijn voor je diagram. Standaard zal een bijhorende shape niets tonen van gegevens. Dit kan je oplossen door decorators. Een decorator kan je op alle soorten shapes toevoegen. Dus ook op connectoren is het mogelijk om bijhorende tekst te voorzien. Er bestaan twee types: text decorator en icon decorator. 21 5.4.5.1 Text Decorator Wanneer je bijvoorbeeld de naam wil weergeven van een class moet je een decorator aanmaken in de bijhorende shape. Dit doe je steeds door via rechtermuisknop op add text decorator. Je bepaalt dan de naam van de decorator en waar dat de decorator moet komen op de plaats. Een text decorator moet ook nog gelinkt worden aan een eigenschap. Dit doe je niet in de shape zelf maar in de link tussen de shape en het element. 1. Selecteer de link 2. Ga naar het venster “Dsl Details” 3. Ga naar het tabblad “Decorator maps” 4. Selecteer de decorator 5. Selecteer bij display proportie de gewenste eigenschap 6. Bepaal eventueel een filter (dit is alleen voor enumeraties) wanneer het geldt. Vanaf nu zal dus de eigenschap te zien zijn op de plaats die je bepaald. Wanneer je twee decorators op eenzelfde plaats zet, zal hij het op elkaar zetten. Daarom is het best om eerst na te denken waar je het plaatst. Hij houdt dus geen rekening van: hier staat al een decorator dus moet ik naar beneden. Je kan wel manueel bepalen waar het moet komen via de verticaal of horizontal offset. Hiermee kan je echt bepalen waar de decorator moet komen. Opgelet: dit gaat niet met grote stappen. Wanneer je twee zaken ondereen wil plaatsen is het voldoende om een vertical offset te nemen van 0.15. 5.4.5.2 Icon Decorator Hier is eigenlijk niet veel verschil met de text decorator. Het enige verschil is misschien dat een icon decorator meestal niet af hangt van een eigenschap. Hier kan je gewoon een icoon plaatsen in het element. Het icoon zal dan in elk element identiek zijn. Het kan wel dat je het laat afhangen van een eigenschap. Wanneer je bv een icoon wil tonen als de eigenschap multiplicity op 0..* moet je een filter instellen op de icon decorator op dezelfde manier als bij een text-decorator. 5.5 Groeperen van elementen Het is mogelijk om elementen te groeperen. Hierbij moet je een abstract element aanmaken. Dit doe je door de proportie “inheritance modifier” in te stellen op abstract. Elk element kan je een base class toe verwijzen. Dit gaat enkel met abstracte elementen. Het handige aan gegroepeerde elementen is dat je relaties kunt leggen naar meerdere elementen door gewoon een relatie te leggen tussen een element en de groep. Een groep is meestal een groep van gelijkaardige objecten. Het is ook mogelijk één domainproporty op de groep aan te maken zodat die overal bestaat in de subelementen. 22 Een gegroepeerd element moet niet per sé verbonden zijn met een element. Het kan ook gewoon dienen als een verzameling voor bepaalde elementen die dezelfde eigenschappen hebben. Je kan dus een boomstructuur ontwikkelen zodat groepen van elkaar overerven. Ook voor decorators kan dit handig zijn. Een decorator kan je dan maar één keer toewijzen aan een gegroepeerde eigenschap. Let wel op dat je dan ook een gegroepeerde structuur van shapes voorziet. Je moet dan ongeveer dezelfde structuur uitbouwen met een abstracte shape. Relaties kan je ook groeperen. Als je verschillende types van relaties hebt tussen dezelfde elementen kan je een extra relatie leggen maar een abstracte. Het verschil is dat je zo eigenschappen kan toekennen aan alle relaties zonder dat je dat meerdere keren opnieuw moet doen. 5.6 Acties op shapes Shapes dienen enkel voor het uiterlijk van elementen. Maar het is mogelijk dat het uiterlijk afhankelijk is van sommige eigenschappen. Daarom kan je zorgen dat wanneer je de eigenschap aanpast. Dat de lay-out automatisch mee wijzigt. 1. Maak dus de nieuwe class aan 2. Schrijf een functie die alles initialiseert. protected override void InitializeResources(StyleSet classStyleSet) { base.InitializeResources(classStyleSet); AssociationConnector.AssociateValueWith(this.Store, Association.TypeDomainPropertyId); } 3. Schrijf een algemene functie “onPropertyChanged”, dit is de functie die wordt opgeroepen wanneer je iets verandert aan een proportie van het element waartoe de shape behoort. protected override void OnAssociatedPropertyChanged(PropertyChangedEventArgs e) { } 4. Maak een if-methode om de juiste proportie te halen. Je vergelijkt eigenlijk gewoon de naam tussen “” met de e.propertyName via de equals – methode. 5. Schrijf dan een switch methode die de nieuwe waarde opvangt en cast naar het gewenste type. Je vergelijkt het dan met mogelijke waardes per case. 6. Verander het object door this.(item) = ..... 23 5.7 Rules en validatie Niet alles is toegelaten, daarom moet je soms via code alles controleren. Om een voorbeeld te nemen: Overerving kan niet in beide richtingen gebeuren, daarom moet je ervoor zorgen wanneer je een nieuwe overerving tekent, dat er wordt gecontroleerd of er al één bestaat tussen de twee classes. Dit geldt ook voor overerving van zichzelf, dit wordt niet toegelaten. Daarom moet je dus een regel schrijven dat dit verbied. Aanmaken regel: [RuleOn(typeof(Generalization), FireTime = TimeToFire.TopLevelCommit, InitiallyDisabled = true)] internal sealed class CyclicInheritanceAddRule : AddRule { public override void ElementAdded(ElementAddedEventArgs e) { string message = string.Empty; Generalization g = e.ModelElement as Generalization; if (g != null) { if (!CyclicInheritanceAddRule.TestValidInheritance(g.Subclass, g.Superclass, ref message)) { throw new InvalidOperationException(message); } } base.ElementAdded(e); } Testmethode: internal static bool TestValidInheritance(ModelClass sourceClass, ModelClass targetClass, ref string errorMessage) { if (sourceClass != null && targetClass != null) { if (object.Equals(sourceClass, targetClass)) { errorMessage = "Reflexive inheritance detected."; return false; } ModelClass current = targetClass.Superclass; // Loop until we detect an exisiting loop or the root of the hierarchy. while (current != null && current != targetClass) { if (object.Equals(current, sourceClass)) { errorMessage = "Inheritance loop detected."; return false; } current = current.Superclass; } } return true; } 24 5.8 Custom Editor instellen Omdat je niet altijd voor alles een vaste enumerator kan je een eigen editor schrijven. Dit zorgt ervoor dat je bijvoorbeeld een listbox kan maken met alle namen van de aanwezige classes. Dit kan dus handig zijn als je informatie wil bijhouden rond bepaalde elementen zonder dat er noodzakelijk een link ligt. Wanneer je zoals bij een attribuut van de class wil dat je een eigen lijst hebt met types dan kan je dit hier ook bepalen. Meestal zal dit een listbox zijn. Het voordeel is dan dat je ook nieuwe waarden kan ingeven die niet in de listbox staan. Bij standaard enumeraties heb je enkel de keuze uit de mogelijkheden van de enumeratie. Hierbij is het mogelijk dat je met nieuwe elementen komt zonder dat je die moet gaan toevoegen in de listbox. Voorbeeld lijst met types: 1. Maak een nieuwe class aan 2. Instellen van using references using using using using using using using using using using using System; System.Collections; System.ComponentModel; System.ComponentModel.Design; System.Diagnostics; System.Drawing; System.Drawing.Drawing2D; System.Drawing.Design; System.Windows.Forms; System.Windows.Forms.Design; Microsoft.VisualStudio.Modeling.Design; 3. Overerven van base UITypeEditor 4. StandaardCode toevoegen (voor listbox toch) private IWindowsFormsEditorService _wfes; public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context) { if (context == null) { return base.GetEditStyle(context); } return UITypeEditorEditStyle.DropDown; } protected void List_Click(object pSender, EventArgs pArgs) { if (_wfes != null) { _wfes.CloseDropDown(); } } private DialogResult ShowForm(IServiceProvider provider, Form form) { IUIService service = (IUIService)provider.GetService(typeof(IUIService)); if (service != null) { return service.ShowDialog(form); 25 } return form.ShowDialog(); } 5. Main Methode toevoegen public override object EditValue( ITypeDescriptorContext context, IServiceProvider provider, object value) { if ((context == null) || (provider == null) (context.PropertyDescriptor == null)) { return base.EditValue(context, provider, value); } || _wfes = (IWindowsFormsEditorService)provider.GetService(typeof(IWindowsFormsEditor Service)); ListBox listBox = new ListBox(); listBox.Sorted = true; listBox.Click += new EventHandler(List_Click); listBox.Items.Add("Boolean"); listBox.Items.Add("Byte"); listBox.Items.Add("Char"); listBox.Items.Add("Currency"); listBox.Items.Add("DateTime"); listBox.Items.Add("Decimal"); listBox.Items.Add("Document"); listBox.Items.Add("Double"); listBox.Items.Add("Email"); listBox.Items.Add("Guid"); listBox.Items.Add("HyperLink"); listBox.Items.Add("Integer"); listBox.Items.Add("Object"); listBox.Items.Add("Password"); listBox.Items.Add("Picture"); listBox.Items.Add("PrimaryKey"); listBox.Items.Add("RichString"); listBox.Items.Add("Single"); listBox.Items.Add("String"); listBox.Items.Add("TimeSpan"); listBox.Items.Add("ForeignKey"); listBox.SelectedItem = value; _wfes.DropDownControl(listBox); return listBox.SelectedItem; } 6. Custom attribute toekennen aan proportie: System.ComponentModel.EditorAttribute typeof(QFrame.DSLModel2.PropertyTablePropertyEditor) typeof(System.Drawing.Design.UITypeEditor) 7. Transform all templates en buid solution 26 6 DSL-MODEL BEKIJKEN Wanneer je een model hebt ontwikkelt wil je het natuurlijk bekijken. Een model is eigenlijk een platform waarbij je elementen kunt op slepen. Het model is zo groot als je maar wenst, er zijn geen echte grenzen. Een model wordt altijd opgestart wanneer je een DSL-project runt. Op zich lijkt dit echt op een gewoon project want alles is er aanwezig van een gewone Visual Studio. Er is een toolbox, solution Explorer, Proporties, … maar het verschil zit vooral de eigen elementen. Je toolbox is volledig aangepast aan de elementen die jij hebt toegevoegd. Er is de mogelijkheid om een menuoptie bij te creëren in de menubalk of een eigen contextmenu als je op je rechtermuisknop klikt. 6.1 Elementen toevoegen Een element toevoegen kan meestal door het slepen van elementen uit de toolbox. De editor zal het element ook plaatsen waar dat je het sleept. Het is niet zoals bij het ontwerpen van DSL dat de elementen automatisch ondereen komen. Je bent hier echt vrij om te slepen. Je kan zelfs elementen op elkaar plaatsen. Sommige elementen hangen natuurlijk vast aan een bepaald element. Wanneer je dan een verkeerde actie doet, zal je een verbodsteken krijgen. Dit betekent dus dat het element hier niet hoort. Subelementen zijn zo een voorbeeld die je enkel kan toevoegen aan compartimenten. Wanneer die ontbreken kan je geen subelementen aan je model toevoegen. Om connnectoren toe te voegen heb je steeds twee elementen nodig. Een element dat als bron dient en een element dat als target dient. Dit hoeven wel geen twee verschillende elementen te zijn, je kan ook een connector aanmaken tussen één element waarbij de bron en target identiek zijn. 6.2 Overzicht elementen bekijken 27 Er bevindt zich in het dsl-model een apart scherm. Dit dient ervoor om een overzicht te krijgen van alle elementen. Wanneer je grote schema’s hebt en je kan niet alles direct terugvinden kan je dat zeker met de Class Diagram Explorer . Dit is eigenlijk een overzicht uit xml. Hier zijn alle elementen gewoon gerangschikt zonder al die tekeningen. Wanneer je dus een element zoekt kan je het hier opzoeken en kan je dezelfde acties doen die je anders op het element kunt doen. Bij kleine schema’s is het beter om in het diagram te doen dan hier. Relaties kan je hier ook niet leggen dus dat ben je wel verplicht in het model. 28 7 COMMANDO INSTELLEN DSL-MODEL De tweede stap eigenlijk om er voor te zorgen dat je DSL-model klaar is voor generatie van code of voor andere zaken. Anders blijft je model toch op zichzelf en is er buiten de weergave van modellen geen andere functie. Standaard zijn er geen commando’s verzien buiten op een compartiment shape. Dus bijvoorbeeld op een class om attributen toe te voegen. Maar het is mogelijk om dus hier extra methoden te voorzien. Commando’s kunnen ofwel in het contextmenu als je op rechtermuisknop klikt of in de menubar zelf. Je kan ook de menu’s indelen per categorie. Achter een menu-item kan je dan code toevoegen om bepaalde acties uit te voeren. Voorbeelden rond mogelijke commando’s zijn om connectoren van stijl te veranderen. Je kan voor elke stijl een menucommando voorzien. Een menu commando zit altijd gespreid over drie bestanden: - 7.1 Commands.vsct Constants.cs Commandset.cs Aanmaken menu commando’s Alle commando’s worden gedefinieerd en gecatalogiseerd in het bestand: Commands.vsct. Standaard zit er één bestand in DSLpackage maar die is leeg buiten de zes basisitems die je zeker nodig hebt in een vsct-bestand. <Extern href="stdidcmd.h"/> <Extern href="vsshlids.h"/> <Extern href="msobtnid.h"/> <Extern href="virtkeys.h"/> <Extern href="DSLToolsCmdID.h"/> <Include href="GeneratedCode\GeneratedVsct.vsct"/> Dit is een soort van xml-file waarbij je vijf categorieën hebt: 7.1.1 Symbols Hier maak je eigenlijk het object aan. Elk item moet hier gedistantieerd worden anders kan je het niet gebruiken in de andere categorieën. Je moet bijna altijd twee items creëren voor één menucommando. Een commando moet je altijd toekennen aan een bepaalde groep. Een groep heeft ook altijd een item nodig. Bij veel commando’s kan je best in groepen verdelen om een beter overzicht. Daarom moet je zelfs de groep nog eens toekennen aan een groep. Een symbol bestaat steeds uit een naam en een waarde. Die waarde moet verplicht uniek zijn anders ga je problemen krijgen later. Je moet ook rekening houden dat je best de basisitems voor de commands de laagste waarden toekent. Dit enkel om structuur te houden want die waardes heb je nodig in het bestand constants.cs. Er is ook een standaard symbol om je collectie in op te slagen. Dit heeft als waarde een registerwaarde. Dit is nodig omdat de menu-items eigenlijk worden opgeslagen in het register. <GuidSymbol 9f30973980ff}" > name="guidCmdSet" value="{322191bb-83c0-4781-a974- 29 Er zijn wel enkele uitzonderingen. Standaard bied Visual studio al een uitgebreide set van Commands. Er zijn meer dan honderden standaardwaarden. Echt een lijst is hier niet van opgesteld, je vindt ze wel terug als je in de subfolder van de Visual studio SDK gaat kijken: Visual studio integration/inc. Hier vind je veel .h bestanden, je zoekt hier de vijf bestanden die bovenaan in het .vsct worden toegevoegd en in die bestanden vind je al de gebruikte ID’s. 7.1.2 Commandplacements De naam zegt veel: hier plaats je eigenlijk de commando’s in de juiste groep. Bij elk commando moet je de correcte IDSymbol naam toekennen aan de ID. Omdat een commandplacement zelden alleen voorkomt, ken je het toe aan een parent-element waarbij je dan de juiste IDSymbol invult. Guid is steeds de verbinding tussen alle elementen. <Naam> = naam <parent>= waar de groep toe behoort <volgorde> = volgorde van de items <CommandPlacement guid="guidCmdSet" id="<naam>" priority="<volgorde>" > <Parent guid="guidCmdSet" id="<parent>"/> </CommandPlacement> 7.1.3 Buttons Elk item dient als een knop want je moet in staat zijn om er op te klikken. Daarom moet je hier ook definiëren om bepaalde standaardwaarden toe te kennen. Hier is het mogelijk om ervoor te zorgen dat de menu standaard is gedisabled of niet zichtbaar is. Je bepaalt ook de tekst die wordt weergegeven. <Button guid="guidCmdSet" id="<naam>" priority="<volgorde>" type="Button"> <Parent guid="guidCmdSet" id="<parent>"/> <CommandFlag>DefaultDisabled</CommandFlag> <CommandFlag>DefaultInvisible</CommandFlag> <CommandFlag>DynamicVisibility</CommandFlag> <Strings> <ButtonText><titel></ButtonText> </Strings> </Button> 7.1.4 Menu’s Hierbij maak je menu’s aan. Dit zowel voor contextmenu’s als voor menu’s bovenaan. Bij menu’s kan je ook werken met gegroepeerde items. Ofwel plaats je dus een groep in het menu ofwel plaats je gewoon een item in een menu. Elke groep in de contextmenu werkt dus ook met een menu-item. <Menu guid="guidCmdSet" id="<Naam>" priority="<volgorde>" type="Context"> <Parent guid="guidCmdSet" id="<parent>"/> <Strings> <ButtonText><titel></ButtonText> </Strings> </Menu> 30 7.1.5 Groups Een group is eigenlijk een collectie van menucommands. Hierbij bepaal je dus tot welke group de group eventueel zelf behoort. Een van de belangrijkste items want zonder een Group kan je geen menucommando’s toevoegen. Hier instantieer je alleen maar de groups. In “Menus” en “Button” voeg je items toe aan de groepen. <Group guid="guidCmdSet" id="<Naam>" priority="<volgorde>"> <Parent guid="guidCmdSet" id="<parent>"/> </Group> 7.2 Toewijzen constanten De tweede stap bij het aanmaken van menucommando’s. Elk menucommando kan niet herkend worden als er geen constante voor gedefinieerd wordt. Een constante is de link tussen Commands.vsct en Commandoset.cs. Veel lijnen bevat dit bestand niet, per commando bevat dit één lijn. De structuur van een commando is als het volgt: <naam> = elk commando heeft een naam nodig <id> = deze naam vind je terug in de constants.cs bij generatedCode. <waarde> = dit is de waarde van het item. Dit vind je terug bij commands.vsct in de categorie symbols. public static readonly CommandID <naam> = new CommandID(new Guid(<ID>), <waarde>); 7.3 Acties toekennen aan Commando De laatste stap in het maken van een commando. Elk commando heeft een achterliggende actie. Standaard is die niet aanwezig wanneer je een nieuwe commando aanmaakt. Zonder wijzigingen in het commandoset.cs zal je niets zien in het model. Want commandoset.cs bevat de belangrijkste zaken voor een commando. Hier volgt hoe je een commando nu echt toevoegt aan je model en hoe je er acties toekent. Alles gebeurt in de file “commandoset.cs”. 7.3.1 Toevoegen aan model: 1. Override de menuoptie: GetMenuCommands () 2. Begin onder de baselijn: IList<MenuCommand> commands = base.GetMenuCommands(); 3. Voeg een command toe via commands.Add() 4. Als parameters geef je mee: new Microsoft.VisualStudio.Modeling.Shell.DynamicStatusMenuCommand(a,b,c) 5. DynamicStatusMenuCommand bevat zelf ook drie parameters. 31 a. Eerst geef je de functie die bepaald wanneer het menu getoond wordt b. De functie die bepaalt wat het commando moet doen c. Hier geef je de constante in die behoort tot de menucommando. Elk constante begint met constants en dan de naam van de constante. Dit vind je terug in constants.cs. 6. Zo ga je verder voor elk commando 7.3.2 Statusfunctie bepalen: Statusfunctie is iets belangrijk maar kan voor meerdere commando’s dienen. Dit moet je maar één keer schrijven als het voor drie commando’s geldt. Hier kan je bijvoorbeeld controleren of het bestand wel een model is of dat het menucommando enkel geldig is wanneer je een class selecteert. 1. Schrijf de hoofding 2. Vang het menucommando op: MenuCommand command = sender as MenuCommand; 3. Schrijf een if-functie om te controleren of het niet null bevat 4. Bepaal welke status het heeft Voorbeeld uit mijn project: internal virtual void OnStatusSelect(object sender, EventArgs e) { MenuCommand command = sender as MenuCommand; if (command != null) { command.Visible = true; if (this.CurrentDocData.Store.ElementDirectory.FindElements<ModelRoot>().Count 0) { command.Enabled = true; } else { command.Enabled = false; } } } > Dit zal er dus voor zorgen dat de menucommando’s die deze functie als status gebruiken enkel zichtbaar zijn als het een model is. Een model bevat altijd een modelroot. 32 7.3.3 Actie bepalen Actie is eigenlijk de hoofdfunctie van een commando. Deze code wordt uitgevoerd als je het commando selecteert. Hier kan je van alles uitvoeren: formulieren tonen, objecten toevoegen, objecten onzichtbaar maken, …. 1. Schrijf de hoofding 2. Bepaal de acties naar wat je wenst Voorbeeld uit mijn project: internal virtual void OnMenuShowClass(object sender, EventArgs e) { foreach (TableShape table in this.CurrentDocData.Store.ElementDirectory.FindElements<TableShape>()) { table.Hide(); } foreach (ClassShape classe in this.CurrentDocData.Store.ElementDirectory.FindElements<ClassShape>()) { classe.Show(); } foreach (ManyToManyAssociationShape many in this.CurrentDocData.Store.ElementDirectory.FindElements<ManyToManyAssociation Shape>()) { many.Show(); } } Bij dit commando gaat hij al de soorten objecten af. Wanneer het een tabel is zal hij de tabel onzichtbaar maken. Een class of een manytomanyassociation zal hij laten tonen. Natuurlijk is hier een gelijkaardige functie op die het omgekeerde doet en een functie die alles toont. 33 8 GEBRUIK VOOR GENERATIE Generatie van bestanden is geen standaard voor een DSL-Model. Er zijn wel twee kleine voorbeelden aanwezig maar dat gaat steeds over één bestand. Maar het is meestal niet de bedoeling om alles in een bestand te generen. Eigenlijk kan je alles integreren in DSL door middel van de commando’s. Generatie is een van de belangrijkste doelen voor een DSL-Model in mijn project. Genereren gebeurt via T4-templates. Dit is een methode die je kan gebruiken voor alle soorten bestanden zoals .html, .cs, .vb, .jsp, … wanneer je het bestand beziet zal het vrij gelijkaardig zijn aan het type bestand dat je wenst. Enkel zal je stukken code in het bestand zien staan tussen <# #> tekens. Je hebt drie soorten: - <# #> wanneer je variabelen wil toekennen of iets in code wil uitvoeren. <#= #> schrijft iets neer in het bestand. Hiermee kan je variabelen afdrukken in het bestand <#+#> is bedoeld om methodes te schrijven. Hier schrijf je alle methodes die je kan gebruiken in je template. Het is mogelijk om met If-structuren en lussen te werken zodat je dezelfde code kunt gebruiken voor een heel collectie. Ook kan je methodes schrijven die je bijkomende code vergemakkelijken. Eigenlijk is het herkenbaar voor iemand die C# schrijft of een andere programmeertaal. Alles kan je hiervan gebruiken. Je kan ook Libraries gebruiken door ze te importeren, zo kan je zelfs eigen gebruikte methodes schrijven zodat je de templates zoveel mogelijk spaart van extra code. Templates worden opgeslagen in het model zelf. Je kan dus de templates niet bekijken wanneer je het model opgestart hebt. Eigenlijk bepaal je het zelf maar voor de commando’s is het gemakkelijker dat je ze in de resources map bewaard onder DSLpackage. Een template omzetten naar code gebeurt niet zomaar. Je hebt een processor nodig. Dit is een soort van omzetter voor de templates. Standaard wordt er telkens één aangemaakt wanneer je een nieuw DSL-model opstelt. Maar de processor kan geen filter aan dus daarom zal je deze processor moeten aanpassen zodat je kunt zorgen dat de templates enkel gelden voor één element of één categorie uit het model. 8.1 Instellen processor Wanneer je iets wil aanpassen moet je altijd een extra class maken die dezelfde naam gebruikt als de bestaande class. Hij zal dan rekening houden met beide classes. Zo kan je de functies schrijven die dienen om een parameter toe te voegen aan de class DirectiveProcessor. 1. Aanmaken eigen class 2. Verander hoofding van de class naar : public sealed partial class <modelnaam>DirectiveProcessor 3. Schrijf de methode voor de extra property. Dit is van het type required omdat dit een verplicht veld is. Het moet ingevuld worden anders zal het fout lopen. protected override void InitializeRequiresDictionary(string directiveName, System.Collections.Generic.IDictionary<string, string> requiresDictionary) { 34 base.InitializeRequiresDictionary(directiveName, requiresDictionary); requiresDictionary.Add("name", Guid.Empty.ToString()); } 4. Schrijf eventueel een methode wanneer je wenst als je met twee modellen in één template wil werken. Bepaald ook de naamgeving van this.(argument). (optioneel: leeg laten betekend dat je gewoon de standaard gebruikt this.Table) protected override void InitializeProvidesDictionary(string directiveName, System.Collections.Generic.IDictionary<string, string> providesDictionary) { base.InitializeProvidesDictionary(directiveName, providesDictionary); providesDictionary.Add("Table", "Table"); } 5. Als je helemaal wil gebruik maken van “this.<naam>” in je templates moet je een variabele toevoegen en een proportie. Dit gebeurt in de override methode GenerateTransformCode protected override void GenerateTransformCode(string directiveName, StringBuilder codeBuffer, System.CodeDom.Compiler.CodeDomProvider languageProvider, System.Collections.Generic.IDictionary<string, string> requiresArguments, System.Collections.Generic.IDictionary<string, string> providesArguments) { base.GenerateTransformCode(directiveName, codeBuffer, languageProvider, requiresArguments, providesArguments); codeBuffer.AppendLine("private Table _" + providesArguments["Table"] + ";"); codeBuffer.AppendLine("public Table " + providesArguments["Table"] + "{ get { return _" + providesArguments["Table"] + " ; } }"); } 6. Als laatste moet je dan de methode schrijven die enkel de tabel die je wenst filtert. protected override void GeneratePostInitializationCode(string directiveName, System.Text.StringBuilder codeBuffer, System.CodeDom.Compiler.CodeDomProvider languageProvider, System.Collections.Generic.IDictionary<string, string> requiresArguments, System.Collections.Generic.IDictionary<string, string> providesArguments) { base.GeneratePostInitializationCode(directiveName, codeBuffer, languageProvider, requiresArguments, providesArguments); // Initialize the ModelClass property codeBuffer.AppendLine(@"foreach (Table eachTable this.Store.ElementDirectory.FindElements<Table>())"); codeBuffer.AppendLine(@"{"); codeBuffer.AppendLine(@" (StringComparer.Ordinal.Compare(eachTable.Name, """ requiresArguments["name"] + @""") == 0)"); codeBuffer.AppendLine(@" {"); codeBuffer.AppendLine(@" this._" + providesArguments["Table"] + " eachTable;"); codeBuffer.AppendLine(@" break;"); codeBuffer.AppendLine(@" }"); in if + = 35 codeBuffer.AppendLine(@"}"); } 8.2 Opstellen Templates Templates bestaan meestal uit twee delen. Eventueel een derde deel kan als je extra methodes nodig hebt. Een template heeft altijd een hoofding waar je alles toevoegt van libraries en ook bepaal je welke processor je nodig hebt om de templates te laten omzetten naar code. Een ander deel is de code zelf. Dit deel bevat meestal een hoop tekst met delen code. Het derde deel kan als je met uitgebreide functies zit om informatie op te halen. 8.3 Aanmaken Templates Er zijn twee manieren: ofwel kies je ervoor om met losse templates te werken of je kan zorgen dat je aan de templates een constante toewijst. Je hebt sowieso een soort van collectie nodig die alle templates bijhoudt. Daarom kan je een Dictionary aanmaken in code waarbij de locatie en de naam bijgehouden wordt van de templates. Zo kan je snel de juiste template achterhalen. 8.3.1 Losse templates Je kan ervoor kiezen om met losse locaties te werken. templates nodig hebt is dit een goede keuze. Vooral templates kan dit handig zijn. Dan moet je de locatie wel gaat zo sneller dan er steeds constante waarde aan vast te Wanneer je telkens andere bij het testen van nieuwe telkens aanpassen maar dit hangen. In je templatedictionary plaats je de locatie van de templates. Elk template moet je zeker een naam geven om later de juiste template terug te kunnen vinden. Wanneer je werkt met één folder waar alle templates zich bevinden, werk je dus best met een variabele waar je de locatie invult. Zo moet je dat niet op twintig plaatsen aanpassen. Voorbeeld van een templatedictionary: Dictionary templates = new Dictionary() templates.Add(new KeyValuePair<”Action_cs”,”c://”>()); templates.Add(new KeyValuePair<”Action_vb”,”c://”>()); templates.Add(new KeyValuePair<”BL_vb”,”c://”>()); 8.3.2 Templates via constante waarden Er is een mogelijkheid om de templates in een bestand te steken en er een constante aan toe te kennen. Dit heeft het voordeel dat je niet heel de locatie moet overtypen om de template te bemachtigen. Het is veel gebruiksvriendelijker in je systeem. Zo maak je minder kans op fouten in de locatie. Wanneer je lange locaties hebt, kan het zijn dat je typefouten maakt en zo krijg je natuurlijk last dat hij een template niet vindt. 1. Open het bestand VSPackage.resx 2. Ga naar de categorie Files 3. Voeg de templates toe 36 Nu kan je de templates makkelijk bereiken door VSPackage.action bijvoorbeeld. Dit zal dan de achterliggende file ophalen. 8.4 Template schrijven Een template schrijven begint altijd met een hoofding. De hoofding bevat de belangrijke lijnen voor de omzetting. Dit bevat voornamelijk het type processor. In mijn project was dat een aangepaste processor met twee parameters: één die de naam van het bestand bevatte en een die de naam van de tabel bevatte. Voorbeeld: <#@ DSLModel2 processor=”DSLModel2DirectiveProcessor” requires=”filename=’<@@filename@@>’,tablename=’<@@tablename@@>’” #> Het speciale is dat de beide parameters toegekend zijn met een soort van variabele. Deze variabele zal door de methode worden omgezet naar de juiste gegevens. Het is mogelijk om namespaces te declareren zodat je in de code niet de volledige naam van types moet ingeven. Dit doe je door de namespace te importeren: Voorbeeld: <#@ import namespace=”System.Collections.Generic” #> Wanneer je een dll wil gebruiken in je templates kan je die dan toekennen door een assembly toe te voegen: Voorbeeld: <#@ assembly name=”System.Drawing.dll” #> Meestal kan je automatisch de extensie bepalen en de encoding van het bestand. Dit is enkel noodzakelijk wanneer je de template gebruikt voor een heel model. Wanneer je met de methode werkt zal je de extensie toekennen in de methode en niet in de template. Voorbeeld: <#@ output extension=”.cs” encoding=”utf-8” #> Templates kan je ook combineren door een template te includen. Dit is misschien handig las je een template in meerdere templates kan gebruiken. Zo vermijd je herhaling: Voorbeeld: <# include file=”FileToInclude.tt” #> 8.5 Methode schrijven Er is natuurlijk een methode nodig die zorgt dat je de template kan gebruiken voor meerdere files te genereren. In feite gaat hij de parameters vervangen door de juiste gegevens. Dus zal hij steeds de tabelnaam en de bestandsnaam bepalen door <@@filename@@> en <@@tablename@@> te vervangen met de correcte waarden. Hij overloopt alle tabellen. Bij elke tabel zal hij de twee variabelen vervangen via een replacefunctie. Daarna zal hij door middel van de aanwezige templateservice de template omzetten naar code. Dit resultaat zal dan via een streamwriter worden weggeschreven naar het bestand met de juiste naam op de gekozen locatie. Hier kan je natuurlijk zorgen dat je met bepaalde if-structuren of extra for-lussen ervoor zorgen dat het resultaat iets verschilt maar dit hangt er vanaf hoe uitgebreid dat je het wenst. 37 De eenvoudigste code ziet er als volgt uit: private void GenerateTemplate(String extra, String baseTemplate, string genCodeDir, Table eachTable) { // Replace the marker text in the template with the name of the class to generate and the model file to load string specificTemplate = baseTemplate.Replace("@@CLASSNAME@@", eachTable.Name); specificTemplate = specificTemplate.Replace("@@MODELFILE@@", _genSettings.Dte.ActiveDocument.FullName); string output = _genSettings.TemplatingService.ProcessTemplate("", specificTemplate, null, null); string filePath = Path.Combine(genCodeDir, eachTable.Name + extra + "." + _genSettings.Extension); if ((eachTable.ManyToManyAssociation!=null) && (filePath.Contains("Collection"))){ }else{ if (! File.Exists(filePath)) { using (StreamWriter writer = new StreamWriter(filePath)) { writer.Write(output); writer.Flush(); } } else { using (StreamWriter writer = new StreamWriter(filePath)) { writer.Write(output); writer.Flush(); } } } try { _genSettings.Project.ProjectItems.AddFromFile(filePath); } catch { } } 38 8.6 Extra functionaliteiten schrijven Er bestaat natuurlijk de mogelijkheid om er voor te zorgen dat de generatie zo optimaal mogelijk gebeurd. Je wilt niet altijd aan de standaardeisen voldoen. Je kan bijvoorbeeld voorzien dat je kunt zorgen dat je elk element kan laten bepalen of het standaard wordt mee gegeneerd. Wanneer je dan genereert moet je wel een if-functie aanmaken in je generatie methode. Die controleert dan de aangemaakte proportie van de tabel of het true of false is. Wanneer het false is, zal hij de tabel overslagen. Je kan er ook voor kiezen om het resultaat naar een andere locatie te sturen dan naar de standaardlocatie. Dit heb ik opgelost door een commando die een folderbrowserdialog toont. Wanneer je dan een locatie selecteert zal dit worden bijgehouden in een algemene proportie. Dit kan je ook doen met bijvoorbeeld het path van de templates. Wanneer je templates wil gebruiken die niet op de standaardlocatie staan. Dit kan zijn als je lokaal wil testen of je templates in orde zijn voor generatie. Een derde extra functie is dat je zelf de templates kunt selecteren. Wanneer je bijvoorbeeld maar één aangepaste template hebt, kan je de template selecteren via een formulier. In het formulier wijs je een categorie aan de template toe en geef je mee voor welke taal deze template dient. De gegevens worden dan bijgehouden in een collectie. Omdat collecties nog niet volledig worden ondersteund, zal hij de gegevens niet bijhouden wanneer je afsluit. 39 9 EXPORTEER DSL-MODEL Een DSL-model exporteren kan omdat het eigenlijk een verzameling is van objecten. Je kan gegevens ophalen uit de objecten en ze dan omzetten naar andere soorten elementen. Je hebt enkel een project nodig die dit voor je regelt. Elk element wordt ingelezen en omgezet naar het nieuwe element. Het enige moeilijke is eigenlijk de verzameling. Alle elementen zitten in een bepaalde store. In mijn project heb ik de store in een proportie gestoken van de export class zodat ik makkelijk de store kon gebruiken in de exportfunctie. Hij leest nadien alle elementen in en plaats die dan in de overeenkomende elementen. In de exportmethode kan je dan bepalen welke elementen er moeten worden geëxporteerd. 9.1 Gebruik maken store Een store is een verzameling van alle aanwezige elementen. Dit wil niet zeggen alle zichtbare elementen. Het kan zijn dat je elementen toegekend hebt aan een store maar niet toegekend hebt aan een object. Dan loop je later het gevaar dat je met foute gegevens zit in een geëxporteerde resultaat. Om u een overzicht te geven wat een store eigenlijk is: U ziet hier eigenlijk gewoon een soort van boekenkast. Alle elementen staan hier in een bepaalde volgorde in. Ik heb ze gerangschikt via afhankelijkheid: groep 2 behoort tot groep 1 en groep3 behoort tot groep 2. 9.2 Schrijven basisclass Je kan best met een basis class werken. Dit is een class die je makkelijk kan hergebruiken. Wanneer er verschillende mogelijkheden zijn om te exporteren, kan je deze class makkelijk gebruiken bij elke mogelijkheid. Dit werkt natuurlijk enkel voor tussen dezelfde type elementen. Wanneer je wenst te exporteren naar een ander soort van objecten dan moet je een nieuwe basis class schrijven die gebaseerd is op het andere model. Een basis class bevat voor elk mogelijk object een functie en wanneer er verschillende importmogelijkheden zijn kunnen er meerdere functies voor hetzelfde object zijn. Deze functies kan je dan gebruiken in andere classes. 40 9.3 Schrijven export class Een export class zorgt meestal voor de invoer en voor de structuur. Dit erft alles over van de basis class. Je overloopt hier alle elementen van het model dat je wil overlopen. Op basis van je noden bepaal je welke functies je nodig hebt en hoe dat je ze gebruikt. Wanneer je bijvoorbeeld twee opties hebt om te exporteren kan je dus een verschillende export classes schrijven die wel gebruik maken van dezelfde basis class. De code verschilt wel maar de gebruikte functies blijven hetzelfde. Dit is voor hergebruik een groot voordeel. Je moet niet opnieuw elke functie gaan herschrijven als ze al bestaat. Het voordeel is ook als je de basis class gebruikt voor andere projecten dat je niet dezelfde code op tien plaatsen moet wijzigen. 41 10 IMPORTEER NAAR DSL-MODEL Importeren gebeurt op dezelfde manier als exporteren. Het is een gebruik van objecten. Het enige verschil is dat ik hier twee mogelijkheden heb uitgewerkt. Hier heb ik een project geschreven die een DSL-model aanmaakt. Maar dit gebeurt nu niet in de DSL-editor. De basiscode blijft wel hetzelfde, maar de aanroepcode verschilt. Het importeren is belangrijk voor oudere modellen of andere soorten modellen om te zetten naar DSL. Omdat het logisch is dat de bestaande generator voor een deel wordt hergebruikt, dat je hier ook een optie biedt om meteen te exporteren naar DSL. Er wordt dan een nieuw bestand aangemaakt op een gekozen locatie. Dit bestand heeft de extensie van het DSL-model en hier wordt de store aan toegevoegd. 10.1 Importeer vanuit DSL Het importeren vanuit DSL vereist niet echt moeilijke code. Je zorgt ervoor dat de store van het bestaande bestand wordt doorgegeven aan de import-project. Zo wordt de store opgevuld met de correcte gegevens. In een formulier kies je dan het model dat je wenst te importeren. Dit model zal worden gebruikt voor importatie. De importfunctie zal alle elementen overlopen en toevoegen. Natuurlijk zal je een foutmelding krijgen als het model niet voldoet aan de eisen. Je kan enkel modellen importeren van hetzelfde type. In principe is importeren hetzelfde als exporteren maar de omgekeerde weg. Het speciale is wel als je iets toevoegt moet je met twee zaken steeds rekening houden. Bij het aanmaken van een object, ken je het automatisch toe aan een store. Nadien vul je het nieuwe object gewoon op met de gegevens. Het object zit dan al wel in de store maar is niet toegekend aan de root bijvoorbeeld. Je gebruikt dan de ADD-functie van een collectie om dit object toe te kennen aan de root. Wanneer je dus tijdelijk een object nodig hebt, kan je beter zorgen dat je zorgt dat het wordt verwijderd op het einde. Dit voorkomt foute gegevens in de store. Voorbeeld: Protected virtual ImportClass(string name, Table table) { ModelClass newClass = new ModelClass(store); newClass.Name=name newClass.Table=table; Root.types.Add(newClass); } 42 10.2 Importeren buiten DSL Je zou denken dat als je kunt importeren in DSL dat je dit ook automatisch kan buiten DSL. Niets is minder waar, wanneer je in DSL importeert gebruik je automatisch de correcte store. Maar als je niet meteen beschikt over een store moet je een nieuwe aanmaken. Dit is niet het grote probleem, het is vooral het toekennen van de store aan een bestand. De store opvullen gebeurt op een identieke manier als in DSL eigenlijk automatisch doet wanneer je een DSL-model aanmaakt. System.Runtime.Serialization.SerializationBinder binder = new DSLModelBinder(); NewModel = model; Store store = new Store(); Type[] modelTypes = new Type[] { typeof(Microsoft.VisualStudio.Modeling.Diagrams.CoreDesignSurfaceDomain Model), typeof(QFrame.DSLModel2.DSLModel2DomainModel)}; store.LoadDomainModels(modelTypes); //CoreDesignSurfaceDomainModel m1 = new CoreDesignSurfaceDomainModel(store); //DSLModel2DomainModel newModel = new DSLModel2DomainModel(store); string fileName = name+".leafDSL"; string filePath = Path.Combine(location, fileName); using (StreamWriter writer = new StreamWriter(filePath)) { writer.Flush(); } using (Transaction t = store.TransactionManager.BeginTransaction("Creating new diagram")) { DSLModel2SerializationHelper.Instance.LoadModel(store, filePath, null, null); StoreModel = store; Root = new ModelRoot(StoreModel); Root.AuditFields = false; Root.Name = NewModel.Name; ImportClasses(); ImportTables(); ImportRelations(); SetGeneralizations(); SetTableParent(); SetMultiplicity(); t.Commit(); } // Save the model SerializationResult result = new SerializationResult(); DSLModel2SerializationHelper.Instance.SaveModel(result, Root, @filePath); 43 10.3 Positioneren Shapes Omdat je toch een beetje structuur wenst in de objecten wanneer je iets imponeert, kan je ervoor kiezen om een bijkomende functie te schrijven die alle objecten overloopt en ze op een bepaalde logica rangschikt. Je kan er voor kiezen om alle gelijkaardige objecten onder elkaar te plaatsen. Dit zorgt voor een duidelijkere structuur dan wanneer alle objecten door elkaar staan. Een echt diagram ga je moeilijk kunnen maken omdat een element geen vaste locatie heeft in een diagram. Maar eigenlijk heb je het niet echt in de hand, ook al schrijf je een degelijke functie, je zou bijna extra plaats moeten houden om zaken te scheiden. Hij doet het niet echt perfect, maar iets is beter dan niets zeggen ze vaak. Voorbeeldcode hoe je een shape van locatie verandert: Double x = diagram.AbsoluteBounds.Left; Double y = diagram.AbsoluteBounds.Top; int aantal = 0; foreach (ClassShape shape in this.CurrentDocData.Store.ElementDirectory.FindElements<ClassShape>()) { shape.AbsoluteBounds = new RectangleD(x, y, shape.Bounds.Width,shape.Bounds.Height); y += shape.Bounds.Height; aantal++; if (aantal == 10) { x+=shape.Bounds.Width; y = 0; } } BESLUIT LITERATUURLIJST 44 BIJLAGEN 1. Gegevens behandelen Hij/zij kan gegevens verzamelen, opslaan en ter beschikking stellen, zodanig dat deze op een correcte en gebruiksvriendelijke manier kunnen worden opgevraagd. Dit gaat over verschillende projecten. Elk project heeft wel oplossingen nodig en niet alle oplossingen zijn meteen aanwezig. Daarom is het steeds vereist om een bepaalde zaken op te zoeken op internet. Internet heeft niet altijd het juiste resultaat. Daarom moest ik altijd met gerichte zoektermen leren werken om tot de juiste oplossingen te vinden. Ook was het handig om bepaalde resultaten te bewaren om herhaling te vermijden. In verband met het omgaan van gegevens voor een project kan ik als voorbeeld het asp-project nemen. Dit project had niet een kant en klare uitleg. Hier moest je over nadenken hoe je alles ging uitwerken door alle gegevens te verzamelen en die gegevens dan te verwerken in een paar modellen. Gegevens uit grote gehelen halen was vooral nodig uit alle informatie uit het internet. Wanneer ik iets op zocht moest je steeds rekening houden met de echtheid van de gegevens. Daarom maak ik altijd een samenvatting met allemaal kleine puntjes zodat ik het begrijp zonder alle tekst te herlezen. Gegevens moeten meestal via een login ter beschikking komen. In het asp-project moet alles wat aangepast kan worden of belangrijke informatie kon bevatten beveiligd worden met de juiste login. Elke login had zijn eigen rechten. 45 2. Analyseren Hij/zij kan, zelfstandig of onder begeleiding en eventueel in teamverband, de informatiebehoeften van een organisatie gestructureerd en overzichtelijk weergeven. Voor analyse was er eigenlijk een vak dat zich leidde naar juiste analyses. Elk project dat ik maakte had een analyse nodig. In begin is dat maar een kleine oppervlakkige analyse maar in de loop van mijn opleiding werd die analyse uitgebreider en gebruikte ik modellen die speciaal bedoelt waren om project vereisten te analyseren. Het business project in het derde jaar was eigenlijk de grootste analyse. Dit project was eigenlijk een analyse van 13 weken om een file management systeem te ontwikkelen. Alle informatie om dit project te voltooien moest worden omgezet in een deftig plan van aanpak. Dit is een methode waar vele soorten informatie duidelijk wordt weergegeven zodat de klant gemakkelijk kan volgen. Dit zorgt er ook ineens voor dat ik bepaalde gegevens duidelijk en gestructureerd kon weergeven in een document. Dit project had verschillende mogelijkheden voor een oplossing. Daarom was het ook nodig om elke optie duidelijk onder de loep komen en een vergelijkende studie te verrichten. 46 3. Oplossingen uitwerken Hij/zij kan voor de organisatie nieuwe IT-oplossingen uitwerken, zodanig dat de opdrachtgever tevreden blijft. Hier kan ik mijn stageopdracht goed gebruiken. Dit is een behoorlijk grote opdracht die toch de nodige structuur vereist. Voorwaarden waren bijvoorbeeld dat alles goed kan worden hergebruikt wanneer er veranderingen komen bij één van de stappen. Ook de code moet zo duidelijk mogelijk zijn. Ik heb ook rekening gehouden met de aanwezige structuur. Ik heb bekeken hoe het programmeren ginder werkte en heb uit de code geleerd om mijn code beter te structureren. Ook heb ik met allerlei trukken geleerd om code zo proper en om wijzigingen te doen in projecten. Mijn project was ook een materie waar weinig informatie over beschikbaar is daarom was het vaak lang zoeken om tot een goede oplossing te komen. Dit heb ik zelfstandig allemaal moeten opzoeken en implementeren. Om dit allemaal duidelijk te houden voor andere heb ik alles wat niet echt duidelijk was om toe te passen gedocumenteerd in een handleiding. Er is ook voor de technische mensen een technical documentation opgesteld, deze is bedoeld voor aanpassingen aan de code. Ik heb mijn project vaak getest door alle mogelijke manieren eens uit te testen. Ik had een checklist gemaakt waar alle opties aanwezig waren. Ik ben alles één voor één afgegaan om echt geen fouten te voorkomen. Dankzij de testen van mijn stagebegeleider kon ik ook weten hoe het systeem werkt op andere computers. 47 4. Oplossingen beheren Hij/zij kan op een adequate wijze IT-oplossingen configureren, beveiligen en aanpassen, zodanig dat ze blijven beantwoorden aan de veranderende behoeften van de organisatie. 48 5. Projectmatig werken Hij/zij is in staat om een opdracht op een projectmatige wijze aan te pakken, zodanig dat de planningen gerespecteerd worden. 49 6. Communiceren Hij/zij kan mondeling en schriftelijk communiceren met alle betrokkenen, zodanig dat hij/zij zijn/haar gesprekspartners correct begrijpt en zijn/haar boodschappen helder overkomen. 50 7. Eigen gedrag aanpassen Hij/zij is in staat om over het eigen gedrag te reflecteren en op basis daarvan het aan te passen zodanig dat hij/zij in wisselende omstandigheden optimaal kan functioneren. 51 8. Kwalitatief handelen Hij/zij streeft naar kwaliteitsvolle taakuitvoering zodanig dat het resultaat voldoet aan de eisen van een steeds wisselende economische en maatschappelijke omgeving.