Content extract
Kecskeméti Fıiskola Gépipari és Automatizálási Mőszaki Fıiskolai Kar Kecskemét .NET komponensorientált szoftverfejlesztés bemutatása egy menedzser szoftveren keresztül Készítette: Pótári Tamás Mihály 2007 Pótári Tamás Mihály .NET komponensorientált szoftverfejlesztés bemutatása egy menedzser szoftveren keresztül 2 Pótári Tamás Mihály .NET komponensorientált szoftverfejlesztés bemutatása egy menedzser szoftveren keresztül 1. BEVEZETÉS 5 2. A KOMPONENSORIENTÁLT PROGRAMOZÁS 6 2.1 A NET OSZTÁLY, MINT KOMPONENS 6 2.2 AZ OBJEKTUMORIENTÁLT ÉS KOMPONENSORIENTÁLT PROGRAMOZÁS 7 2.21 A FEHÉR-DOBOZOS ÉS FEKETE-DOBOZOS KÓD-ÚJRAFELHASZNÁLÁSI MODELL 8 2.3 A KOMPONENSORIENTÁLT PROGRAMOZÁS ALAPELVEI 8 2.31 Az interfészek és implementációk szétválasztása 9 2.32 A bináris kompatibilitás 10 2.33 Programnyelv függetlenség 10 2.34 Kötetlen elhelyezkedés 11 2.35 Egyidejőség kezelése 12 2.36 Verziókövetés 12 2.37
Komponens alapú biztonság 13 2.4 Az alapelvek betartása 13 3. A MEGRENDELÉS 14 3.1 A MENEDZSER ALKALMAZÁS 14 3.2 A PÁLYÁZAT 15 3.3 A POTENCIÁLIS JELÖLT 15 3.31 Újra feltalálni a kereket? 16 3.32 A komponensszolgáltatók 16 3.4 A VÉGSİ KIVITELEZÉS 17 4. A KOMMUNIKÁCIÓS KOMPONENSEK MODELLEZÉSE 18 4.1 A KOMMUNIKÁCIÓ ELMÉLETI MEGVALÓSÍTÁSA 18 4.2 A KÖVETELMÉNYMODELLEZÉS 19 4.21 A szereplık meghatározása 20 4.22 A feladatok meghatározása 20 4.23 Feladatok és kockázatkezelés 22 4.3 DINAMIKUS VISELKEDÉSMODELLEZÉS 23 4.31 A tevékenységdiagramok 24 4.32 A sorrenddiagramok 25 4.4 FELÉPÍTÉSMODELLEZÉS 27 4.41 Interfészek 27 4.42 A szerelvények 32 5. A KOMMUNIKÁCIÓS KOMPONENSEK NET-BELI KIVITELEZÉSE 34 5.1 AZ ÜZENET 34 5.11 Csak olvasásra 35 5.12 A klónozás lehetısége 36 5.13 A sorosíthatóság 36 5.14 A formázhatóság 38 5.15 Egyéb üzenetek 39 5.2 ESEMÉNY KÖZZÉTÉTELT SEGÍTİ KOMPONENSEK 40 5.3 AZ ÜZENETEK
ARCHIVÁLÁSA 43 5.31 Objektumok tárolása adatbázisban 44 5.3 A SZERVER OBJEKTUM 47 5.31 A NET Remoting rövid jellemzése 47 5.32 A Server komponens 51 5.4 A KLIENS OBJEKTUM 54 5.41 A Client komponens 55 5.5 A TESZTELÉS 57 5.51 Alrendszerek tesztelése 57 5.52 Együttmőködés tesztelés 59 5.53 Rendszertesztelés 59 5.6 VERZIÓK ÉS DOKUMENTÁLÁS 60 5.7 ÖSSZEFOGLALÁS 61 3 Pótári Tamás Mihály .NET komponensorientált szoftverfejlesztés bemutatása egy menedzser szoftveren keresztül 7. A MENEDZSER ALKALMAZÁS MODELLEZÉSE 62 7.1 A KÖVETELMÉNYMODELLEZÉS 62 7.2 DINAMIKUS VISELKEDÉSMODELLEZÉS 63 7.3 MIT KAPOTT A SECRET ROOM? 64 7.31 MENNYIBE KERÜLT A TERMÉK? 64 8. A MENEDZSER ALKALMAZÁS NET-BELI KIVITELEZÉSE 66 8.1 A HATÁRIDİNAPLÓ KOMPONENSEI 66 8.11 A határidı komponens 67 8.12 A határidı kezelı és az üzenetolvasó komponens 67 8.2 A WINDOWS FORMS ÉS A SZÁLAFFINITÁS 68 8.3 AZ ABLAKOK KIVITELEZÉSE 69 8.4 FEJLESZTÉS J# NYELVEN 71
8.5 A SZERELVÉNYEK ÉS KAPCSOLATAIK 72 9. AZ ALKALMAZÁS TELEPÍTÉSE ÉS KARBANTARTÁSA 73 9.1 MIT HASZNÁL A KLIENS, ÉS MIT HASZNÁL A SZERVER? 73 9.2 A TELEPÍTÉS ÉS KONFIGURÁLÁS 74 9.21 A szerver telepítése és konfigurálása 74 9.22 A kliens telepítése és konfigurálása 76 9.3 EGY EGYSZERŐ KARBANTARTÁSI MŐVELET 76 9.4 A TESZTELÉS 78 10. ÖSSZEFOGLALÁS 79 I. SZ MELLÉKLET 80 II. SZ MELLÉKLET 82 III. SZ MELLÉKLET 84 IV. SZ MELLÉKLET 85 V. SZ MELLÉKLET 87 IRODALOMJEGYZÉK: . 88 4 Pótári Tamás Mihály .NET komponensorientált szoftverfejlesztés bemutatása egy menedzser szoftveren keresztül 1. Bevezetés Szakdolgozatom célja, hogy betekintést nyújtsak a komponensorientált szoftverfejlesztésbe a Microsoft .NET Framework segítségével Ismertetem a komponens alapú szemlélet alapvetı koncepcióját, és gazdasági jelentıségét a mindennapi problémák megoldásában. Bemutatom a NET technológia lehetıségeit, és
sokoldalúságának kihasználását a gyakorlatban. Elismert fejlesztık és szakértık tervezési mintáit elemezve és felhasználva egy saját ötletbıl alkotott szoftver tervezésének, kivitelezésének, tesztelésének és karbantartásának problémáit szemléltetem. A dolgozatom sajátságos jellegét tükrözi, hogy a fejlesztett alkalmazás nem egy piacra szánt termék, hanem egy életbıl kiragadott probléma megoldásának produktuma. Egy képzeletbeli vállalat különleges problémával találja magát szemben. Újonnan szerzıdtetett kutatócsoportja számára kutatási segédeszközöket kell beszereznie. A beszerzendı berendezések, szakirodalom és szoftverek között egy különlegesség is szerepel; egy menedzser (személyi-asszisztens) alkalmazás. A vállalat pályázat formájában próbálja beszerezni a szükséges terméket, melyre több képzeletbeli szoftverfejlesztı vállalkozás is jelentkezik. A kiválasztott pályázó a rá jellemzı, mégis
célratörı technikájával olcsón, gyorsan és jó minıségben végzi el a munkát. A technika egyszerő: más képzeletbeli szoftverfejlesztı cég által készített alkotóelemekbıl építi fel a megrendelt terméket. Minden alkotóelem kivitelezését pontosan szemléltetem, egyes szolgáltatások implementációját gyakran részletesebben. Betekintést nyújtok a képzeletbeli vállalatok tervezési módszereibe, tükrözve a gazdasági másodszándékot, hogy újrahasznosítható alkotóelemeket készítsenek. A komponensekbıl végül egy alkalmazás épül fel, mely végsı próbatétele egy karbantartási probléma, és annak leküzdése. Az alkalmazás fıbb feladatai az egymás közötti on-line felhasználói kommunikáció és az interaktív határidınapló megvalósítása melynek eseményei közzétehetık. A .NET megoldást nyújt a többnyelvő fejlesztésre, a verziókövetésre, a kötetlen elhelyezkedésre, a teljes bináris kompatibilitásra és a
karbantartható komponensek tervezésére. Az eddig felsoroltakat elemzi és értékeli ki a szakdolgozatom 5 Pótári Tamás Mihály .NET komponensorientált szoftverfejlesztés bemutatása egy menedzser szoftveren keresztül 2. A komponensorientált programozás A komponensorientált programozás, mint szoftverfejlesztési módszer az elmúlt évtizedben jelentıs szerepet töltött be a szoftveriparban. A fejlesztık rájöttek, hogy a monolitikus, egy egységként kezelendı alkalmazások fejlesztése, bıvítése és karbantartása nehézkes és rendkívül költséges. A fizikailag elkülönülı alkotóelemekbıl felépített rendszereknél viszont ezek sokkal könnyebben megoldhatók. Ebben a fejezetben röviden szemléltetem a komponens- és objektumorientált programozás közötti lényeges különbségeket. Bemutatom a komponensorientált programozás alapelveit, és hogy azok miként valósulnak meg a .NET-ben 2.1 A NET osztály, mint komponens A
szakdolgozatomban a .NET-beli osztályokat tekintem komponenseknek A szakirodalomban [1] néha másképp szerepel ez az állítást, de a .NET technológia szempontjából érdemes volt ehhez tartanom magam. Ha már a modellezés kapcsán a komponenst egy fizikai állományként – például .dll fájlként – értelmezzük és ábrázoljuk, miért ne lehetne ezt egy osztályra leszőkíteni? Hiszen egy osztály szintén fizikailag kicserélhetı, önállóan mőködtethetı építıeleme lehet egy rendszernek (és a .NET-ben legtöbb esetben az is) E nézıpont szerint az osztály logikai építıeleme az alkalmazásoknak, és a komponens pedig a fizikai megvalósítása az osztálynak. Talán a legfıbb különbség a két elmélet között, hogy a cserélhetı, egymástól függetlenül mőködı kódmodulok belsı felépítését nem szükséges ismernünk, ha fel akarjuk használni ıket. Ezt a szemléletet követve képes voltam elkerülni a nagymérető, rengeteg osztályt
tartalmazó fizikai állományok építését, melyek jelentıs mértékben ronthatják egy alkalmazás (vagy több egymással kapcsolatban álló alkalmazás) karbantarthatóságát, bıvíthetıségét. A .NET technológiában elismert szakértık és fejlesztık a könyveikben [2] legtöbbször ezt az irányelvet követik, és ezt javasolják a fejlesztıknek is. 6 Pótári Tamás Mihály .NET komponensorientált szoftverfejlesztés bemutatása egy menedzser szoftveren keresztül 2.2 Az objektumorientált és komponensorientált programozás A dolgozatomban megvalósított szoftver és építıelemei tervezésekor különbséget kellett tennem az objektumorientált és komponensorientált programozás között, elkerülve a nehezen újrahasznosítható és nehezen karbantartható kód írását. Ha objektum központú alkalmazást szerettem volna építeni, akkor minden általam tervezett komponenst (osztályt) egyetlen speciális probléma köré építettem volna. Ebben az
esetben az osztályokat szinte lehetetlen lenne újrahasznosítani más alkalmazásokban, még akkor is, ha egyszerő részfunkciókat valósítanának meg. E problémán kívül a következık is fellépnének: • Egyetlen monolit .exe (vagy dll) állományba fordulna le minden osztály Így nehezen tesztelhetı és sérülékeny lenne az alkalmazás. • Frissítéskor ki kellene cserélnem az osztálykönyvtárat vagy a futtatható állományt, azaz szinte újratelepíteni a szoftvert. De ami speciális esetekben a legproblémásabb, hogy meg kellene szakítanom az alkalmazás futását. • Ha egy másik kliensszoftver használja a lecserélt osztálykönyvtárat, legrosszabb esetben újra kellene fordítani a klienst, és az újratesztelést is végre kellene hajtani. Amellett, hogy költségessé válna a fejlesztés és a karbantartás, még a komponensek árusítása is lehetetlen lenne, sıt még a saját céljaimra sem használhatnám fel ıket. Az építıelemeket
elırelátóan kellett megterveznem, hogy azokat más alkalmazások számára is hasznosíthatóvá tegyem, illetve belsı szerkezetük módosításakor (új verzió készítésekor) ne kelljen a felhasználó (kliens) alkalmazás kódját módosítani, esetlegesen újratesztelni. Az a feltétel, hogy más rendszerek is képesek legyenek használni ugyanazon komponenseket, megköveteli, hogy eltérı eredető – más szolgáltatásokat nyújtó – komponenseket is össze lehessen kapcsolni egymással. Ezt úgy értem el, hogy tervezéskor általánosságokban gondolkodtam, és nem egy adott alkalmazás számára tervezem az építıelemeket. Mindazonáltal be kellett tartanom a komponensorientált programozás alapelveit, melyeket a késıbbiekben ismertetek. 7 Pótári Tamás Mihály .NET komponensorientált szoftverfejlesztés bemutatása egy menedzser szoftveren keresztül 2.21 A fehér-dobozos és fekete-dobozos kód-újrafelhasználási modell Az elızıekben már
említést tettem az újrafelhasználás gazdaságos lehetıségérıl. A fehér-dobozos [3] modell az objektumorientált programozáshoz kötıdik és a már meglévı osztályokból történı származtatást jelenti. Az így kapott leszármazott osztályt specializálva azt hihetném, hogy gazdaságosan végeztem kód-újrafelhasználást, holott ez lehet a legveszélyesebb hibák forrása. Például nem tudhatom, hogy egy metódus felülbírálása milyen hatással lehet egy ıs típust paraméterül váró metódusra. Ahhoz, hogy biztonságos legyen az új osztály, ismernem kell az alaposztály részletes felépítését. A tanulmányozás rengeteg idıt vehet igénybe, gyakran még akkor is, ha én voltam az alaposztály fejlesztıje. Az elızı módszer helyett érdemes volt olyan komponenseket létrehoznom, amik jóval tartósabbak (robosztus), és addig használhatom ıket, amíg bizonyos feltételeknek eleget tesznek. A fekete-doboz módszere a gyakorlatban azt diktálja,
hogy olyan komponenseket állítsak elı, melyeknek a belsı felépítése a felhasználó számára lényegtelen, sıt egyenesen rejtett. Csak elıre meghatározott szolgáltatásokat vehetnek igénybe rajtuk, amelyek interfészekben vannak definiálva. Így kihasználhatom azt a lehetıséget, hogy több rendszer közös komponenseket használjon, illetve ne okozzon problémát, ha kicserélek egy-egy komponenst újabb verziókra anélkül, hogy a felhasználó alkalmazást újra kellene fordítani – esetlegesen le kellene állítani. A dolgozatomban a komponensek tervezésekor az utóbbi modellt alkalmaztam. Ebben az esetben nem osztályhierarchiák, hanem a jól definiált interfészek és azok hierarchiáinak modellezését és kivitelezését tekintettem a legfontosabbnak. 2.3 A komponensorientált programozás alapelvei A tervezés és kivitelezés során a következı alapelveket [4] próbáltam betartani: • Az interfészek és implementációk szétválasztása. • A
bináris kompatibilitás. • Programnyelv függetlenség. • Kötetlen elhelyezkedés. • Egyidejőség kezelése. 8 Pótári Tamás Mihály .NET komponensorientált szoftverfejlesztés bemutatása egy menedzser szoftveren keresztül • Verziókövetés. • Komponens alapú biztonság. 2.31 Az interfészek és implementációk szétválasztása Az interfészek a szerzıdés szerepét töltik be a kliens és kiszolgáló objektumok között. Az interfészt megvalósító kiszolgáló objektum azokat a szolgáltatásokat teszi elérhetıvé az ügyfél objektumok számára, melyek az interfészben definiáltak. Ez esetben a kiszolgáló objektum egy olyan bináris komponens példánya, ami teljes mértékben elrejti a szolgáltatásainak megvalósítását a külvilág felıl. Így a kliens objektumok csak az interfészen keresztül képesek kommunikálni a kiszolgálóval, ami rengeteg elınnyel jár. Ilyen gyakorlati elıny, amit már az elızıekben említettem;
ha az interfész definícióját nem módosítom, akkor a kiszolgáló komponens szerkezetét nyugodtan megváltoztathatom, anélkül, hogy az ügyfél komponens kódjába beavatkoznék (bináris kompatibilitás). Mindez a gyakorlatban annyit jelent, hogy a komponensben megvalósított szolgáltatások (metódusok) nevét minısítem az interfész nevével. Noha az így kapott komponensek nehezebben kezelhetık (gyakori explicit típuskonverzió), mégis igaz lesz a következı: „Minél több részletét rejtjük el a megvalósításnak, annál valószínőbb, hogy az adott objektum tulajdonságait vagy metódusait úgy módosíthatjuk, hogy ez nem lesz kihatással az ügyfélkódra.” [5] Juval Löwy Talán az összes alapelv közül ez a legfontosabb és a szakdolgozati munkám során is ezt részesítettem elınyben. Az .NET-beli interfészek és megvalósításuk szétválasztásának elvéhez tartoznak a csak tisztán interfészeket tartalmazó assembly-k, melyek
létrehozását és hasznosságát a késıbbiekben fogom bemutatni. 9 Pótári Tamás Mihály .NET komponensorientált szoftverfejlesztés bemutatása egy menedzser szoftveren keresztül 2.32 A bináris kompatibilitás Az elızı alfejezetben utaltam rá, hogy az ügyfél által használt kiszolgáló komponens kicserélhetı újabb verzióra. Természetesen ez csak akkor tehetı meg, ha fennáll a kliens és a kiszolgáló közötti bináris kompatibilitás. Ez a bináris építıelemek alapfeltétele. Ha a régi kiszolgáló kódot egy újabb verzió helyettesíti, ami már nem felel meg a két fél által használt szerzıdésnek (interfész), akkor megszőnik a bináris kompatibilitás és az együttmőködés hibás, esetlegesen a kliens módosítása nélkül kivitelezhetetlen lesz. A .NET a bináris kompatibilitást az assembly-k és a metaadatok segítségével valósítja meg. A NET assembly-ben szereplı típusdefiníciók önleíróvá [6] teszik azt, végrehajtás
szempontjából fizikailag függetlenné minısítve egymástól a komponenseket. A .NET assembly Típusdefiníciók Manifeszt IL/natív kódú implementáció Erıforrások 1. ábra Egy általános szerelvény felépítése, alkotóelemei Az 1. ábra szemlélteti egy általános szerelvény felépítését, ami nem minden esetben így néz ki. Megeshet ugyanis, hogy a szerelvény csak erıforrásokat tartalmaz (típusdefiníciók nélkül), vagy egyáltalán nem rendelkezik erıforrásokkal. Viszont kötelezıen tartalmaznia kell manifesztet még akkor is, ha a szerelvény több állományból áll. A bináris kompatibilitás fontossága a sorosítási és távelérési problémáknál merül fel a dolgozatomban. 2.33 Programnyelv függetlenség A .NET lehetıvé teszi a többnyelvő fejlesztést Ez azt jelenti, hogy Visual Basic.NET nyelven megírt komponenst nyugodtan felhasználhatja egy J# vagy C# nyelven írt ügyfél. Közismert tény, hogy a NET által támogatott
valamely magas szintő nyelven 10 Pótári Tamás Mihály .NET komponensorientált szoftverfejlesztés bemutatása egy menedzser szoftveren keresztül megírt kód nem közvetlenül natív kódra fordul le, hanem köztes kódra (MSIL1). A JIT2 fordító ezt a kódot fordítja le környezetspecifikus futtatható kódra. Ebbıl eredıen futás idıben megmarad a bináris kompatibilitás az eltérı nyelven írt komponensek példányai között, és hiba nélkül kommunikálhatnak. A többnyelvő fejlesztés lehetıséget nyújt arra, hogy a fejlesztıket ne kelljen kötelezni új programozási nyelv elsajátítására egy projekt miatt. Így gyorsabb és olcsóbb fejlesztést lehet végezni. A szakdolgozatomban a többnyelvőség alkalmazására is példát hozok és szemléltetni fogom a CLS 3 kompatibilis szerelvények építésének módszereit, segédeszközeit. 2.34 Kötetlen elhelyezkedés A kötetlen elhelyezkedés röviden annyit jelent, hogy az ügyfél komponensben
semmi olyan információ nincs, ami a kiszolgáló komponens elhelyezkedésére utalna, így más folyamatokban (alkalmazástartományokban), más számítógépen aktivált objektumokat is képesek az ügyfelek elérni. E lehetıség legnagyobb szerepe az elosztott alkalmazásoknál jelenik meg. Az ilyen alkalmazások mind kiváló teljesítménnyel (áteresztıképesség), skálázhatósággal és karbantarthatósággal büszkélkednek. 2. ábra A kötetlen elhelyezkedés nyújtotta lehetıségek A 2. ábra bemutatja a kötetlen elhelyezkedés felhasználási lehetıségeit A kliens objektum nemcsak a kliens számítógépen futó más folyamatok objektumaival képes 1 Microsoft Intermediate Language Just In Time fordító 3 Common Language System 2 11 Pótári Tamás Mihály .NET komponensorientált szoftverfejlesztés bemutatása egy menedzser szoftveren keresztül kommunikálni, hanem más számítógépen futó folyamatok objektumaival is. (A kliens számítógép
ábrája alatt látható dokumentum a .NET Remoting – távelérés – kliens oldali, adminisztratív konfigurációjához szükséges XML kódrészlet.) Az általam tervezett komponenseknek meg kellett felelniük ennek az alapelvnek is. A dolgozatomban a .NET távelérési problémáknál részletesen kifejtem a kötetlen elhelyezkedés lehetıségeit és használati módjait. 2.35 Egyidejőség kezelése Vitathatatlan, többszálúság) hogy indokolt a végrehajtás szétválasztása esetben teljesítménynövekedést (aszinkron hívások, és maximális erıforrás kihasználást eredményezhet. De ehhez a komponenseimet úgy kellett megterveznem, hogy ne legyenek szálhoz kötöttek (szál affinitás), azaz konkurens szálak probléma nélkül érhessék el az objektumokat, és változtathassák meg azok állapotait. Annak érdekében, hogy a több szál által módosított objektum ne kerüljön inkonzisztens állapotba, szinkronizációt kellett alkalmaznom. Ebben az
esetben viszont megeshetett volna, hogy az egymás erıforrásait, objektumait elérı szálak deadlock-ra jutnak. Illetve nagyon egyszerően beleeshettem volna abba a hibába, hogy a rendszer átviteli sebessége jelentısen lecsökken. E problémákra a megfelelı szinkronizációs módszer kiválasztása és helyes alkalmazása adott választ, melynek tárháza a .NET-ben rendkívül kiterjedt. 2.36 Verziókövetés Az elızıekben már többször is utaltam arra a lehetıségre, hogy a használatban lévı komponenseket ki lehet cserélni újabb verziókra, illetve, hogy több alkalmazás egyidejőleg is ugyanazon komponenseket használhatja. Ez a lehetıség egyértelmően megköveteli, hogy a komponenseket párhuzamosan, egymástól függetlenül lehessen fejleszteni. A dolgozatomban kitérek a telepítési modellekre és az azokkal összefüggı verziókövetési szabályokra, lehetıségekre. Szemléltetem, hogy a privát és osztott assembly-k miképp állíthatók elı, és
milyen hasznot nyújtanak már egy egyszerő alkalmazás építésekor és karbantartásakor is. 12 Pótári Tamás Mihály .NET komponensorientált szoftverfejlesztés bemutatása egy menedzser szoftveren keresztül 2.37 Komponens alapú biztonság A .NET rendkívül jó biztonsági infrastruktúrát nyújt a tervezık számára Segítségével meg lehet akadályozni a káros komponensek beépülését a rendszerbe már mőködés közben, illetve elı lehet állítani engedélyeket, felhasználói jogosultságokat. A .NET biztonsági architektúra napról-napra fejlıdik és használata rendkívül kiterjedt. Szakdolgozatom méretkorlátaiból adódóan, csak minimális funkciókat tudok bemutatni, noha komoly komponensek tervezésekor ennek az ellenkezıje alapvetı feladatom lenne. Becslésem szerint csak a .NET biztonság bemutatásáról egy újabb szakdolgozatot lehetne készíteni. Ezt igazolja, hogy az ismeretterjesztı szakkönyvek [7] is gyakorta 70-80 oldalakat
írnak a biztonságról. 2.4 Az alapelvek betartása Habár az alapelvek közismertek mégis a szakdolgozati munkám során nélkülözhetetlennek bizonyultak. Minden tervezési cselekedetem miértjét ezek betartásával magyarázom, tehát akarva-akaratlanul a szakdolgozat körülrajzolta volna ıket. Így legalább strukturált formában vannak jelen a dolgozatban, melyekre közvetlenül hivatkozhatok a késıbbiekben. 13 Pótári Tamás Mihály .NET komponensorientált szoftverfejlesztés bemutatása egy menedzser szoftveren keresztül 3. A megrendelés Napjainkban gyakori és korántsem elképzelhetetlen probléma, amikor egy vállalat, avagy azon belül egy csoport speciális igénnyel áll elı. Képzeljük csak el, hogy egy gépipari vállalat ideiglenesen „külsıs” gépészmérnököket, villamosmérnököket, vegyészeket és egyéb szakértıket szerzıdtet egy speciális termék elıállításához. A képzelet szüleményeként legyen a speciális
termék egy fontos repülıgép alkatrész, a szárny. Ezt kell megtervezni és kivitelezni Viszont a csapat a munka elkezdése elıtt megköveteli a vállalattól, hogy mihamarább minden szükséges segédeszközt szerezzen be. Ezek az eszközök a szakterület minden pontján fontos szerepet betöltı gépek, szerszámok, szoftverek és szakirodalom. Szoftverek kapcsán természetesen felmerül az igény a modellezı és egyéb bonyolult számításokhoz szükséges termékek beszerzésére, gyakran egyéni igény szerint. Ez utóbbi kritérium szüleménye egy menedzser, azaz személyi-asszisztens alkalmazás. 3.1 A menedzser alkalmazás A menedzser alkalmazás megkönnyíti a kommunikációt a projektben résztvevık és kívülállók között, mindemellett segítséget nyújt a felhasználóknak a munkák ütemezésére, a fontos határidık feljegyzésére, közzétételére. A mérnökcsapat az egyeztetések során megállapodott egymás között a szoftver
szolgáltatásairól. Mivel ık nem szoftverfejlesztık, így a feladatleírásuk is csupán alapvetı, elvont. Kérésük egy olyan szoftvercsomag, mely a munkahely minden személyi számítógépre feltelepíthetı úgy, hogy azok egymással kommunikáljanak. Operációs rendszer követelményük általános, a mindenki által jól ismert és alkalmazott Microsoft Windows XP Professional termék beszerzését javasolták a munkahelyük vezetıségének. A szoftver által kínált szolgáltatások: • On-line szöveges kommunikáció. A kommunikáció tartalmának tárolása, archiválása késıbbi visszaolvasásra. • Határidık feljegyzése és közzététele. felhasználókat a határidık bekövetkezésérıl. 14 Értesítı funkció, mely értesíti a Pótári Tamás Mihály .NET komponensorientált szoftverfejlesztés bemutatása egy menedzser szoftveren keresztül Mint ahogy a felsorolás is tükrözi, nem egy átlagos szolgáltatásokkal rendelkezı
rendszert várnak el a munka elkezdése elıtt. Nem is vitás, hogy a piacon nem található ilyen jellegő komplex szoftver, ezért egy fejlesztı cégre vagy személyre bíznák az elıállítását. 3.2 A pályázat A gépipari vállalat pályázat formájában rendelkezik a szoftver beszerzésérıl. A pályázatra jelentkezı fejlesztıi vállalkozások és magánszemélyek az elızı fejezetben ismertetett, meglehetısen szegényes kritériumok alapján hozhatnak döntéseket a kapcsolatfelvételrıl, illetve az azt követı megegyezésrıl. A megbízó szigorú követelményként szabja meg a gyors fejlesztést, esetlegesen a mielıbbi prototípus bemutatást. Hiszen a projekt érdeke, hogy minél hamarabb kezdetét vegye. Mindemellett fontos, hogy minıségi, minden kritériumnak megfelelı rendszert kapjanak kézhez, természetesen az anyagi vonzatokat is figyelembe véve. 3.3 A potenciális jelölt Nem nehéz elhinni, hogy a képzeletbeli pályázatra többen is
jelentkeznek, így a vállalatnak ki kell választani a számára legmegfelelıbbet (noha lehet több kiválasztott is). A szintén képzeletbeli SecretRoom Bt. nyerte el a bizalmat, felülmúlhatatlan ajánlatával A kis szoftverfejlesztı társaság a konkurensekkel szemben a leggyorsabb és hozzávetılegesen a legolcsóbb munkát ajánlotta fel. Noha a pályázatában szerepelt a fejlesztési technikája, errıl a konkurensek mit sem sejtettek. A dolgozat ezen pontján – némileg a jövıbe tekintve – le kell szögezni, hogy ez a társaság tökéletesen teljesítette a megbízást. Azaz a gépipari vállalat idıben megkapta a szoftverét, még a többi munkát segítı erıforrás beszerzése elıtt. A kivitelezı a kész alkalmazást a munkahelyi számítógépekre telepítette, és a felhasználókat megtanította a használatára. Az ottani rendszergazdák is oktatásban részesültek az alkalmazás karbantartásáról, melyre egy alkalommal a mérnöki munka során
szükségük is volt. A szoftver készítı csapat a mérnöki tevékenység során állandóan rendelkezésre állt, segítve ezzel a gördülékeny munkát. 15 Pótári Tamás Mihály .NET komponensorientált szoftverfejlesztés bemutatása egy menedzser szoftveren keresztül A munka sikerrel zárult, és a repülıgép alkatrész felvásárolásra, majd felhasználásra került. A SecretRoom pedig további bizalmat és elismerést nyert, nem is beszélve a bıvülı referenciákról. 3.31 Újra feltalálni a kereket? Jogosan merül fel a kérdés, hogy mi lehetett az a bizonyos titok, ami meggyızte a megbízó vállalat szakértıit a SecretRoom melletti döntéshozatalról. A betéti társaságnak volt egy mottója: „Minek újra feltalálni a kereket?”. Igaz ez csak egy kérdés, de újabb kérdéseket vet fel, jogosan. Megéri gazdasági szempontból egy teljesen új, egyéni tervezéső építıelemekbıl elıállított rendszert kivitelezni? A válasz logikusan:
nem. Vajon mi akadálya van annak, hogy a kritériumokat némiképp módosítva, már elıre legyártott, létezı építıelemekbıl készítsünk alkalmazást? Ha más szoftverfejlesztı cégektıl meg lehet vásárolni a komponenseket és azoknak késıbbi fejlesztési jogát, akkor az egésznek semmi akadálya. A SecretRoom így tett. A pályázati kiírás olvasását követıen felvette a kapcsolatot néhány konkurens vállalkozással. Mivel ismerte ezen cégek tevékenységi körét, céltudatosan érdeklıdött szolgáltatási információk és árak után. Mivel a megfelelı építıelemeket megtalálta, mondhatni félig-meddig már végzett is a munkával. 3.32 A komponensszolgáltatók A megvásárolt építıelemek – nevezzük nevükön: assembly-k avagy a .NET-beli szerelvények – fejlesztıi és tulajdonosai egyértelmően úgy tervezték meg a korábban piacra dobott szoftvereiket, hogy azok szerelvényei más alkalmazásokban is könnyedén
felhasználhatóak, és kiválóan karbantarthatóak. Az építıelemek megvalósításáról a dolgozatom késıbbi fejezeteiben adok részletes leírást. 16 Pótári Tamás Mihály .NET komponensorientált szoftverfejlesztés bemutatása egy menedzser szoftveren keresztül 3.4 A végsı kivitelezés Az elızıekben leírt gondolatmenet a képzelet szüleménye, ami segít a dolgozat felépítésének megértésében, céljának és fontosságának kifejezésében. A dolgozatban a hangsúlyt a kitalált probléma megoldására fektetem, a Microsoft .NET Framework felhasználásával. Annak érdekében, hogy a dolgozat továbbra is hő maradjon az elızıekben ismertetett fikcióhoz, le kell szögeznem, hogy a SecretRoom és a többi kitalált szoftverfejlesztı vállalat a Microsoft e technológiájával dolgozik. A dolgozat következı fejezeteiben bemutatom az elızményeket, a komponensek fejlesztését vállalatról vállalatra. Betekintést nyújtok a gárdák eltérı
fejlesztési módszereibe, legyen szó a többnyelvő fejlesztésrıl, illetve a verziókövetésrıl. Elsısorban a .NET elınyeit emelem ki, felvetve néhány hátrányt is Szemléltetem néhány érdekes szolgáltatás megvalósítását, elmélyülve az implementációs részletekben. A komponensek elkészítésének menetét követıen a SecretRoom feladata azok egyesítése, közös rendszerré formálása; a kezelıfelület és egy meglehetısen egyszerő adatbázis létrehozása, majd a rendszer telepítése. Legvégsı feladatnak egy karbantartási probléma megoldását tőztem ki, szemléltetve, hogy a megfelelı tervezés és kivitelezés a késıbbiekben garantáltan könnyít a fejlesztık helyzetén. 17 Pótári Tamás Mihály .NET komponensorientált szoftverfejlesztés bemutatása egy menedzser szoftveren keresztül 4. A kommunikációs komponensek modellezése A fejezetben leírom a kommunikációs komponensek fejlesztésének menetét a modellezéstıl a
végsı megvalósításig. A fejezet elején nagy hangsúlyt fektetek a képzeletbeli fejlesztı cég; a Delphoi Kft. gazdasági háttérszándékaira, amik már a kezdeti modellezéskor is jelen vannak. A Delphoi Kft komponenseit fogja a SecretRoom Bt megvásárolni. 4.1 A kommunikáció elméleti megvalósítása A komponensek üzenetküldést valósítanak meg távoli számítógépek között. Azaz a kliensek a Server számítógépen (vagy Server számítógépeken) keresztül üzenetet küldhetnek egymásnak. Az üzenetküldés módja lehet szórt, privát, vagy csoportos, illetve az üzeneteket archiválni is lehet. (A 3 ábra egy mőködését szórt üzenetküldés szemlélteti) elméleti Modernebb alkalmazásokban, mint a Windows Live 3. ábra A kommunikáció elméleti mőködése Messenger, üzenet utóértesítés is mőködik, azaz a nem kézbesített üzeneteket a kliensek utólag megkaphatják. Az ilyen rendszerek között a belsı felépítés, az
üzenetkezelı egységek mőködése, a kliensek nyilvántartása stb. jelent különbséget. Némileg megelılegezve leírom röviden, hogy valójában milyennek képzeltem el a .NET-beli implementáció mőködését a modellezéskor. Az interneten és a szakirodalomban [8] rengeteg .NET példakód és elméleti anyag található távoli eseményeken (visszahívás) alapuló üzenetküldı programokról. Persze ezek nem kifinomult megoldások, viszont a .NET Remoting-gal ismerkedıknek – mint én – rendkívül élvezetes 18 Pótári Tamás Mihály .NET komponensorientált szoftverfejlesztés bemutatása egy menedzser szoftveren keresztül tanulmányt jelent. A rendszerem alapvetı mőködési elve, némiképp hasonlít ezen 4 elméletekhez. Azaz a kliens objektumok metódusai feliratkoznak távoli objektumok eseményeire, majd egy esemény bekövetkezésrıl minden feliratkozott értesülni fog. Természetesen az esemény közzétételét a kliensek végzik, és
paraméterként juttatják el egymásnak az üzeneteiket. 4.2 A követelménymodellezés A követelménymodellezés [9] rendkívül fontos momentuma a tervezésnek, ami kötelezıen a modellezés legelsı lépése. Viszont felmerülhet a kérdés, hogy miért kell komponensek esetén követelményekkel foglalkozni, amit „úgyis csak az alkalmazásoknál végeznek”. Egyesek véleménye szerint ez teljesen szükségtelen, de az én meglátásom ezzel ellenkezik. Az általam tervezett komponensekre úgy tekintek, mint egy komplex egységre, majdnem úgy, mint egy szoftverre. A következı okok azok, melyek miatt indokoltnak véltem követelményeknek megfeleltetni a komponenseim: • Képes voltam bizonyítani, hogy a projekt eredménye – a termék – megfelel a mások által felállított követelményeknek – a Delphoi Kft szemszögébıl. • Volt célom. Tudtam, hogy mikor lesz kész a termék, és elkerültem a hatáskörduzzadás5 jellegzetes problémáját. • Ha
egy vásárló a jövıben megtekinti a követelménymodellt, tudni fogja, hogy a termék mire képes, milyen feladatokat lát el. Így elısegíthettem a termék forgalmazását. A követelményeket magam találtam ki – pontosabban a Delphoi Kft. Modellezésükhöz pedig UML feladatdiagramot (use-case) alkalmaztam. Fontos megjegyeznem, hogy a modellezéskor bizonyos esetekben úgy tekintettem az építıelemekre, mint egy mőködı – kezelıfelülettel rendelkezı és telepített – szoftverre. Ez 4 A kommunikációs komponenseim nem un. „copy-paste” féle, internetes fórumokból lopott kód-darabok összessége. Ezt a technikát teljességgel nélkülöztem a munkám során, és a saját kreativitásomra és szakértelmemre támaszkodva dolgoztam. 5 A hatáskörduzzadás problémája akkor lép fel, amikor rossz, hiányos követelmény-specifikációval rendelkezünk, és céltalanul végezzük a munkánkat. Ebben az esetben nem tudjuk, hogy mikor ér véget a
projekt és a megbízóink az idı végtelenségéig utasítgathatnak minket a módosításokra, finomításokra, stb. (Sok idı- és pénzpazarlás fölöslegesen.) 19 Pótári Tamás Mihály .NET komponensorientált szoftverfejlesztés bemutatása egy menedzser szoftveren keresztül nagyban segített nekem, hogy feltérképezzem a lehetséges végfelhasználókat (akik az építıelemekbıl felépített alkalmazást használni fogják). 4.21 A szereplık meghatározása A szereplık olyan személyek – vagy dolgok –, akik kapcsolatba lépnek a rendszerrel, annak funkcióit használják. A szereplık meghatározása nem feltétlenül a legelsı lépése a követelménymodellezésnek. Viszont ha hozzávetılegesen ismertek a lehetséges felhasználók, akkor érdemes ıket beazonosítani még a feladatok meghatározása elıtt. Mindenesetre nem felejthettem el a tényt, hogy a szereplık a legfontosabbak, hiszen átvitt értelemben nekik készítettem terméket. A
feltételezésem az volt, hogy a végsı rendszert (tehát a komponensekbıl alkotott szoftvert) két szereplı típus használja: • Felhasználó • Adminisztrátor A szereplıket – azaz a szerepüket – egy kérdéssel határoztam meg: Mit csinál? (Azaz milyen szerepet játszik?) A felhasználó a komponensekbıl (más szoftverfejlesztık által) felépített rendszert használja, szolgáltatásait igénybe veszi. Egy kommunikációs szoftver esetén több ilyen felhasználó is lehet. Az adminisztrátor pedig a szoftver mőködését felügyeli. 4.22 A feladatok meghatározása A feladatok olyan forgatókönyveket határoznak meg, amik bemutatják, hogy a szereplık miként használhatják a rendszert. A feladatok meghatározásához elismert szakértık módszerét alkalmaztam: a MiSzHaT próbát [10]: • A feladat azt írja le, hogy Mit kell csinálni, nem pedig azt, hogy hogyan? • A feladatot a Szereplı nézıpontja szerint írtuk le? • A feladat Hasznos a
szereplı számára? • Az eseményfolyam Teljes forgatókönyv? Ezzel a módszerrel megfelelıen skálázni tudtam a rendszerbeli feladatok hatókörét. Az így meghatározott feladatok megfelelıen elvontak és együttesen sokat mutatnak a 20 Pótári Tamás Mihály .NET komponensorientált szoftverfejlesztés bemutatása egy menedzser szoftveren keresztül komponensek valós funkcionalitásából. Itt kell leszögeznem, hogy csak a mőködésbeli követelményeket modelleztem, azaz csak azzal foglalkoztam, hogy a rendszernek mit kell csinálnia, nem pedig azzal, hogy milyennek kell lennie. 4. ábra A komponensek rendszerének feladatdiagramja A 4. ábra szemlélteti a komponensek rendszerének feladatdiagramját Noha a diagram rendkívül egyszerőnek tőnik, végeredményben a komponensek csak ezeket a funkciókat látják el. Az „Üzenetek küldése és fogadása” feladat talán a legérdekesebb, ugyanis itt nyugodtan felmerülhet a kérdés, hogy miért nem
„Üzenetek küldése” és „Üzenetek fogadása” feladatok állnak a helyén. Azért, mert egyik sem feladat Az utóbbin alkalmazva a MiSzHaT próbát, a következı eredményekkel lehet szembesülni: Ténylegesen azt írja le, hogy mit kell csinálni, nem pedig azt, hogy hogyan. A szereplı nézıpontjából lett leírva nem pedig a rendszer nézıpontjából. Mint ahogy korábban említettem, nem feledkezhetek meg a szereplıkrıl. Sajnos csak az, hogy „Üzenet fogadása” nem hasznos a szereplı számára. Nem feledkezhetek meg arról, hogy egy kommunikációs rendszerrıl (annak alkotóelemeirıl) van szó, így igenis fontos a szereplı számára, hogy lehetısége nyíljon üzenetek küldésére is. Az elızı állításból kiindulva nem tekinthetı teljes eseményrendszernek sem. Vajon van értelme ábrázolni csak az üzenetfogadás folyamatát? Vajon tesztelésnél használható olyan tevékenységdiagram vagy sorrenddiagram, amin csak az
üzenetfogadás esemény forgatókönyve szerepel? Az „Üzenetek archiválása” és az „Üzenetek küldése és fogadása” feladatok között beillesztéses társítás van. Az okok a következık: • Nem szabadon választható feladat. (Feladat, tehát megfelel a MiSzHaT-nak) • Az alapfeladat nem teljes a feladat nélkül. 21 Pótári Tamás Mihály .NET komponensorientált szoftverfejlesztés bemutatása egy menedzser szoftveren keresztül • Nem feltételhez kötött a feladat végrehajtása. • Nem változtatja meg az alapfeladat viselkedését. A „Hozzáférés az archivált üzenetekhez” feladatot olyan funkcióként lehetne elképzelni, mint egy adatbázis adatainak megjelenítése (napló). Ezt a funkciót az összes szereplı igénybe veheti. A lényeg, hogy a rendszer olyan archívumot használ, mely mindenki számára elérhetı. Az „Utóértesítés” feladatnak adhattam volna a „Nem kézbesített üzenetek utólagos elküldése” nevet
is, de az eredeti jóval általánosabb és megfelel a MiSzHaT-nak. Mint ahogy az alfejezet elsı soraiban említettem, csak a mőködésbeli követelményeket ábrázoltam. Azzal, hogy kihagytam a nem mőködésbeli követelményeket, a komponenseimet megvásárló szoftverfejlesztınek segítek. Hiszen neki is kötelessége a végfelhasználók igényeit figyelembe venni, ráadásul közvetve ugyan, de a termékemet ily módon a végfelhasználónak kínálom. Természetesen a követelménymodellezés „kukacoskodás”, mindemellett jelentıs idıt használ fel a munkából. És a 42-es fejezetben szemléltetett elınyök sem feltétlenül ellensúlyozzák a befektetett munkamennyiség értékét – fıleg, hogy programozás-technikai szempontból aligha van haszna. A következı alfejezet kihangsúlyozza a követelménymodellezés kifizetıdı oldalát. 4.23 Feladatok és kockázatkezelés A feladatok megvalósítását valamilyen sorrend szerint kellett elvégeznem.
Ha rossz sorrendben láttam volna neki a kivitelezésnek, rengeteg idıt és energiát vesztegettem volna el. Ez akkor következett volna be, ha a modellezéskor (vagy már a kódoláskor) egy olyan problémával találtam volna szembe magam, ami hatalmas szakértelmet igényel. A probléma leküzdéséig az elemzési bénultság állapotába kerültem volna, és kétségbeesetten 5. ábra A kockázatkezelés egyik lehetséges és egyszerő módszere dolgoztam volna át az addigi alapvetı 22 Pótári Tamás Mihály .NET komponensorientált szoftverfejlesztés bemutatása egy menedzser szoftveren keresztül koncepcióimat. A következı módszer [11] konkrétabban szemlélteti ezt a problémát: Az 5 ábra egy olyan diagramot jelképez, amiben nehézség és fontosság szerint vannak elhelyezve a kielégítendı követelmények. A munka a jobb felsı negyeddel kezdıdik és balra haladva a jobb alsó negyedben végzıdik. Mint látható, a legnagyobb kockázattal az „Üzenetek
küldése és fogadása” feladat bír. Ennek az oka, hogy ez a fejlesztés buktatója – ha nem tudjuk megvalósítani. Hiszen a kommunikációs infrastruktúra elkészítése nélkül nem lehet üzeneteket küldeni és fogadni, nincs üzenet, amit utóértesítésnél lehet használni stb. Ugyanakkor ha itt hibáztam volna, akkor alapvetı elképzeléseimet kellett volna megváltoztatnom, elvetve az addig elkészült terveimet, esetlegesen kódjaimat. Az „Üzenetek archiválása” továbbfejlesztése az „Üzenetek küldése és fogadása” feladatnak. Fontossága alig szorul magyarázatra, hiszen az archivált üzenetekre épül a jobb alsó negyedben található feladatok mindegyike. A „Hozzáférés az archivált üzenetkehez” a megvalósítási sorrendben mondhatni, hogy a harmadik helyen van. Az „Utóértesítés” megköveteli, hogy az üzenetek archiválva legyenek, míg az értesítendı felhasználó be nem jelentkezik. Ez a feladat a bal alsó „Elvetés”
negyedbe csúszik. Ebbe a negyedbe olyan feladatok kerülnek, melyek kivitelezése olyan nehézkes, hogy felülmúlja annak hasznosságát. Ha a projekt túl sok pénzt és idıt emésztett fel, akkor az itt elhelyezkedı feladatokat nélkülözni kell. A következı fejezet a feladatok által meghatározott forgatókönyvek dinamikus modellezésével foglalkozik. Leírom, hogy a tevékenységdiagramok és sorrenddiagramok miként segítettek feltérképezni a lehetséges objektumokat, azok mőködésbeli terheltségeit, szerkezeteit és egymásközti kommunikációit. 4.3 Dinamikus viselkedésmodellezés A rendszer felépítésének modellezése elıtt fontosnak éreztem a mőködést modellezni. A mőködés modellezésével szemléltetni tudtam magamnak, hogy valójában mit is szerettem volna létrehozni. Definiálni tudtam, hogy milyen lépésekbıl épülhet fel, és hogyan mőködhet egy kommunikációs csatorna több felhasználó között, illetve, hogy annak milyen logikai
alkotóelemei vannak. Tevékenységdiagramok segítségével ábrázolni 23 Pótári Tamás Mihály .NET komponensorientált szoftverfejlesztés bemutatása egy menedzser szoftveren keresztül tudtam a kommunikációt a felhasználó és a központi Server-alkalmazás között. A sorrenddiagramokkal pedig teljes részletességgel képes voltam megjeleníteni a szükséges objektumokat, és a köztük megvalósuló dinamikus kapcsolatokat. Noha a modellekben le tudtam írni az alapvetı mőködést, a késıbbi .NET-beli megvalósításuk némiképp eltér ezektıl. A modellekkel egy olyan általános folyamleírást tudtam elıállítani, mely technológia-független, azaz tetszıleges programozási nyelven implementálható. 4.31 A tevékenységdiagramok A voltam tevékenységdiagramokkal képes megjeleníteni a a feladatok Noha a diagramok részletekbe legegyszerőbben menı részleteit. nem nyújtanak információkat a rendszer felépítésérıl, de annak
elméleti viselkedését mőködését, pontosan ábrázolni tudtam. A szakdolgozati munkám során több alkalommal is átdolgoztam a diagramokat, finomítva a terveket a késıbbi kivitelezés számára. 6. ábra A bejelentkezés és kijelentkezés tevékenységdiagramja ahogy az 6. ábra is Mint mutatja, a bejelentkezés és kijelentkezés két fél között valósul meg. Noha az „Alkalmazás” több felépítési egységbıl áll, az elvont ábrázolásnak köszönhetıen kiindulópontot kaptam a többi modell elkészítéséhez – a sorrenddiagramokra gondolva. A modellezés e pontjánál már rengeteg ötlettel gazdagodtam a statikus felépítés elemei kapcsán – mint feliratkozó azonosító, feliratkozó lista, üzenet, üzenettár. Mindemellett teszteseteket tudtam felállítani a késıbbi teszteléshez. A fekete-dobozos tesztelést a tevékenységdiagramok segítségével tudtam elvégezni. Ebben az esetben nem volt szükséges ismernem a rendszer belsı
felépítését, egyszerően csak alkalmaznom kellett a diagramok leírta eseményfolyamokat, és meg kellett figyelnem a kimeneteket. 24 Pótári Tamás Mihály .NET komponensorientált szoftverfejlesztés bemutatása egy menedzser szoftveren keresztül Az I. sz Melléklet egy némiképp bonyolultabb tevékenységdiagramot tartalmaz A mellékletben szereplı diagram már kivételekre és azok kezelésére is fel van készítve. 4.32 A sorrenddiagramok A sorrenddiagramok segítségével meg tudtam határozni a rendszert alkotó objektumokat, azok feladatait és egymás közti kommunikációját. A terveim alapján a felhasználók a kliens objektumon keresztül tartják a kapcsolatot a Server objektummal. A Server objektum fıbb tulajdonságai a következık: • Mindig elérhetınek kell lennie. • Rendelkeznie kell felhasználói listával, melyben szerepelnek a felhasználói azonosítók (illetve proxy-k, melyeken keresztül el lehet érni a visszahívandó ügyfeleket,
de ez .NET implementációs részletkérdés) • A felhasználói listát saját magának kell karbantartania (hibakezelés, szinkronizáció). • Aszinkron módon értesíti az ügyfélobjektumokat az értesítési fennakadások elkerülése révén. Ennél a megállapításnál már kijelenthettem, hogy NET távoli visszahívásra lesz szükségem (távoli, aszinkron események). • Kapcsolatban áll az üzenettár objektummal. Az üzenettár objektum lehet egy adatbázis, file (file-rendszer), vagy egy tényleges memóriabeli objektum – bár ez utóbbi igencsak abszurd. Fontos megjegyeznem, hogy a modellezéskor elemezni tudtam a Server objektum terheltségét, ebbıl eredıen vettem le a válláról az utóértesítés terhét. Külön objektum végzi el az utóértesítés feladatát, mely akár egyszer hívható is lehet. Azaz, amikor a kliens objektum hívást intéz az utóértesítı objektumhoz, paraméterül adja az ügyfél azonosítóját. Ebbıl eredıen nem
kell perzisztensnek lennie az utóértesítınek, akár a hívás hatására is létrejöhet, majd annak végeztével megszőnhet (.NET kiszolgáló által aktivált SingleCall 6 objektum). Az utóértesítı szintén kapcsolatban áll az üzenettárral, ebbıl eredıen szinkronizálni kell annak elérését. Szintén jellegzetessége az üzenettárnak, hogy minden beérkezı 6 A .NET-beli kiszolgáló által aktivált, egyszer hívható objektumok jellegzetessége, hogy annyi példány van belılük a memóriában, ahány hívás egyidejőleg intézve van feléjük. Kliens általi hívás hatására létrejönnek, majd a visszatéréskor megszőnnek. A dolgozatomban késıbb részletesen tárgyalom ezt az aktiválási módot 25 Pótári Tamás Mihály .NET komponensorientált szoftverfejlesztés bemutatása egy menedzser szoftveren keresztül (archiválásra kerülı) üzenetet – legyen az szöveg vagy objektum – el kell látnia egy egyedi azonosítóval. 7. ábra A
bejelentkezés, utóértesítés és kijelentkezés sorrenddiagramja két felhasználóval (Ez egy normál, kedvezı eset) A 7. ábra szemlélteti a bejelentkezés, utóértesítés és kijelentkezés kedvezı esetének sorrenddiagramját. Noha itt csak egyetlen Server objektum van jelen, lehet belılük több is 26 Pótári Tamás Mihály .NET komponensorientált szoftverfejlesztés bemutatása egy menedzser szoftveren keresztül A II. sz Melléklet tartalmaz egy olyan sorrenddiagramot, melyen a kliensek egymáshoz intéznek üzeneteket. 4.4 Felépítésmodellezés „Minden szoftverrendszernek van felépítése, függetlenül attól, hogy azt szándékosan alakították-e ki. Az a fı kérdés, hogy jó-e ez a felépítés?”[12] Grady Booch A logikai felépítésmodellezéssel elméleti képet alkothattam az általam tervezett rendszer szerkezetérıl, illetve az alkotóelemek jellemzıirıl. A felépítésmodelleknek általánosnak kell lenniük annak érdekében, hogy
bármilyen technológiával, avagy programozási nyelvvel elı lehessen állítani a megtervezett terméket. Mégis a dolgozatom ezen pontján rátérnék a .NET specifikus felépítés modellezésre, melyben a Microsoft Visual Studio 2005 nagy segítséget nyújtott, mint CASE eszköz7. 4.41 Interfészek Mint ahogy korábban említettem, az interfész hierarchiák megalkotása volt számomra a legfontosabb. A logikai felépítésmodellezést is itt kezdtem el, hiszen a rosszul definiált interfészek megpecsételhetik a komponenseim karbantarthatóságát és újrahasznosíthatóságát a jövıre tekintve. A tervezés elsı lépéseiben megpróbáltam a funkcionalitást elıtérbe helyezni a megvalósítás helyett. Tehát nem a kódoláson gondolkodtam – azaz osztály hierarchiák tervezésén és azok feladatainak implementációin – hanem a ténylegesen szükséges szolgáltatásokon és azok csoportosításain. A munkám így sokkal egyszerőbb volt, hiszen a
tényleges komponensek megalkotásakor már tudtam, hogy azok hogyan fognak viselkedni és milyen kapcsolatban fognak állni egymással. Azaz az interfészekhez terveztem a komponenseim, és nem fordítva, mint ahogy az sajnos gyakorta történik. Ráadásul így nem 7 Noha a VS (Visual Studio) grafikus modellezı szolgáltatása (Class Diagram) szép megjelenéső és nagyban segít a kódgenerálásban, mégis az UML-ben alkalmazott fontos társítások (halmaz, összetétel) és azok jellemzıi (szerepnév, minısítı, számosság, megszorítás, stb) nem támogatottak. A dolgozatomban szereplı diagramokhoz külön kellett megrajzolnom a felsoroltakat a modellezéskor. 27 Pótári Tamás Mihály .NET komponensorientált szoftverfejlesztés bemutatása egy menedzser szoftveren keresztül feledkeztem meg a jövendıbeli felhasználókról, akiknek fontos, hogy egyszerően használható építıelemeket kaphassanak, és azok megfeleljenek a követelménymodellnek. Furcsa lehet
a következı osztálydiagramot figyelve (8. ábra), hogy csak interfészek, felsorolás típusok és metódusreferencia típusok találhatók rajta társításokkal, mintha komponensek lennének. (A III sz Melléklet nagyobb méretben tartalmazza az alábbi ábrát.) 8. ábra A rendszer fı interfészei és azok kapcsolatai Mégis nekem egy ilyen diagram elkészítése volt az elsı lépés, az elızıleg felsorolt okok miatt. Az ábra bal oldalán találhatóak a .NET kínálta ıs interfészek Jobbra haladva a leszármazottak hierarchiája figyelhetı meg. Legvégül, a jobb oldalon található néhány típus, melyeknek jellemzésével a késıbbiekben foglalkozom. Szürke, üres nyílhegyő vonalak jelzik az öröklıdés irányát, a sötétebb vonalak más társításokat jelölnek, gyakran mennyiséggel és szerepnévvel. Habár a diagramon jelenlévı interfészek a valóságban ısei más használatban lévı specializált interfészeknek, azokat nem volt szükséges
ábrázolnom, hiszen a rendszer – némiképp elvontan szemlélve azt – az ıs felületekkel dolgozik. 28 Pótári Tamás Mihály .NET komponensorientált szoftverfejlesztés bemutatása egy menedzser szoftveren keresztül A diagram részletes értelmezésére rátérve könnyen észrevehetı, hogy a modell három fı egységbıl áll: a kliens, a szerver és az üzenet, amit egymásnak tudnak küldeni. Az üzenetküldés és fogadás mővelete viszont igényel még néhány építıelemet, mint a felsorolástípusok (SubscriberEventType, PublisherEventType) és az egyik delegált (UniformDelegate). Az IClient és IServer felületek csakis az azonosításhoz szükségesek. Belılük származnak a tényleges funkcionalitások. Az IClient rendelkezik egy long ID és egy string Name tulajdonsággal. Ezek a kliensek adatai, melyek közül az ID nélkülözhetetlen az azonosításukhoz. Az IServer szintén rendelkezik ID tulajdonsággal, habár int kivitelben, és található
mellette egy DateTime StartDateTime tulajdonság, mely jelöli, hogy a szerver mikor indult el. Itt már észrevehetı, hogy a késıbbiekben több szerver objektum is alkalmazható. (Fontos megjegyeznem, hogy minden interfészben szereplı tulajdonságot csak olvasni lehet, ennek okaira még késıbb visszatérek.) Mint ahogy leolvasható, az IClient és az IServer egyaránt a System.IFormattable felületbıl származnak. Ennek legfıbb oka, hogy így formázott és formázható szöveges megjelenítési móddal rendelkeznek. Ez jelentısen segít a tesztelésben, és a mezık kiírásában még Windows Forms esetén is. Ennek a megvalósítására szintén kitérek a késıbbiekben. A IClient még megvalósít két generikus interfészt: a System.IEquatable<IClient> IClient típusú objektumok összehasonlításánál használatos, mely fontos a generikus győjteményekben történı keresésénél (például: a
System.CollectionsGenericDictionary<TKey,TValue> győjtemények Values mezıjében) A System.IComparable<IClient> szintén összehasonlítást tesz lehetıvé IClient-ek között, de az elızıvel ellentétben a kliensek sorba rendezésénél van haszna. Az IClientFunctions és az IServerFunctions felületek már a tényleges funkcióit tartalmazzák a klienseknek és a szerver(ek)-nek. A kliensek kapcsolódhatnak a szerverhez és igénybe vehetik annak szolgáltatásait. Az OnUniformEvent() mondhatni, hogy kulcsszerepet játszik a kommunikációs infrastruktúrában. „On”8 karakterekkel kezdıdik a metódus neve, tehát események kezelését végzi el. Pontosabban UniformDelegate féle események kezelését, hiszen a visszatérési értéke és a szignatúrája 9 is megegyezik vele. Az IServerFunctions-re tekintve, eseményekre történı feliratkozást és leiratkozást végzı metódusok találhatók meg: 8 Az On<eseménynév> konvenció mondhatni, hogy
standard a .NET-ben, még ha a Visual Studio nem is támogatja azt. 9 A „szignatúra” alatt a továbbiakban a metódusok argumentum listáját értem. 29 Pótári Tamás Mihály .NET komponensorientált szoftverfejlesztés bemutatása egy menedzser szoftveren keresztül • void SubscribeUniformEvent ( IClientFunctions subscriber, SubscriberEventType eventType) • void UnSubscribeUniformEvent ( IClientFunctions unsubscriber, SubscriberEventType eventType) Mindkét metódus egyazon típusú paramétereket vár. Az elsı paraméter magát a kliens objektumot várja. Implementációtól függetlenül megemlítem, hogy a szerver objektum a UniformDelegate típusú eseményeire ilyen módon jegyzi fel a kliensek OnUniformEvent() metódusát. És hogy a kliens a szerver nyújtotta események közül melyekre iratkozhat fel, azt a második SubscriberEventType felsorolás típusú paraméterben adhatja meg. Ennek a módszernek [13] rengeteg elınye van: • Sok esemény esetén
nem kell az interfészeket teleírni ilyen szolgáltatásokkal. • Sokkal jobb, ha az objektum maga dönti el, hogy rendelkezzen-e eseményekkel, vagy sem. Mivel egyes esetekben eseményelérıket (event accessor) rendel a NET a felületet implementáló típusba. • Felsorolás típusoknál bitmezıket alkalmazva (System.FlagsAttribute-tal és manuális érték megadással) könnyedén végezhetı feliratkozás több eseményre. • Új eseménytípus bevezetésekor nem kell bolygatni az interfész definíciót, csupán elég a felsorolás típust bıvíteni. Tehát azzal, hogy nem módosítom a felület szerkezetét, megmarad a bináris kompatibilitás a régebbi és újabb verziójú komponensek, és azok példányai között. Mindezek után, példaként egy 3 eseményre történı feljelentkezés a feliratkozó oldaláról így nézhet ki: SubscribeUniformEvent(,SubscriberEventType.MessageEvent | SubscriberEventType.PeldaEsemeny1 | SubscriberEventTypePeldaEsemeny2);
Ellenkezı esetben 3 soros kódra lenne szüksége a kliens objektumnak leiratkozás esetén is. Az üzenetküldés úgy valósul meg a kliensek között, hogy azok meghívnak egy eseményközzétevı metódust a szerveren, és paraméterként átadják az elküldendı üzenetüket. Errıl szintén két metódus gondoskodik: • void RaiseUniformEventBroadcast(IUniformMessage message, SubscriberEventType eventType) • void RaiseUniformEventPrivate(System.CollectionsICollection targetSubscribers, IUniformMessage message, SubscriberEventType eventType) 30 Pótári Tamás Mihály .NET komponensorientált szoftverfejlesztés bemutatása egy menedzser szoftveren keresztül Mint ahogy korábban említettem a szórt üzenetek lényegét, némiképp magyarázatot igényelnek a privát üzenetek. Privát értesítések nem csak két feliratkozó között keringhetnek. Egy feladó értesíthet több célpontot is egyszerre Ebbıl a célból van jelen a System.CollectionsICollection
targetSubscribers paraméter. IClient objektumokat tartalmazó győjteményt lehet átadni abból a célból, hogy részesüljenek az üzenetbıl. Jogosan felmerülhet a kérdés, hogy miért nem IClient specifikus generic ICollection<T>-t használok. A válasz, hogy a NET 20 Remoting nem támogatja teljes mértékben a konstruált típusokat. SerializationException10-t dob a távelérési architektúra formázó eleme, hivatkozva a típusra. Trükkökkel ugyan meg lehet oldani azt a problémát, mi szerint: „Ki tudja, mit rejt a győjtemény?”, de jelentısen rontanám a rendszerem skálázhatóságát. Ilyen trükk lenne, ha IClient [] tömböt várna a metódus, viszont nem tudni, hogy a jövendıbeli kódfelhasználó milyen győjteményt szeretne használni. Kicsit betekintve az implementációba, a rendszer felkészült az olyasfajta szabotázsokra, amikor a targetSubscribers nem várt elemeket tartalmaz. Az eventType-nak itt is ugyanaz a szerepe, mint a
feliratkozásnál. Az ICollection Subscribers a jelenlévı, üzenetküldésre és fogadásra (SubscriberEventType.MessageEvent) feliratkozott kliensek adatainak listáját képviseli A long GetNewClientID(IClientFunctions client)-vel a szervertıl lehet garantáltan egyedi azonosítót kérni. Ezek után visszatérve egy kicsit az elızıekben pár szóban említett void OnUniformEvent(IServer server, IUniformMessage message, PublisherEventType eventType) metódusra, már alig érdemel magyarázatot a szervertıl kapott paraméter lista. A server azonosítja az értesítı központi objektumot – hasonlóan az EventHandler object sender-jéhez – , a message maga az üzenet, amit egy távoli feliratkozó vagy a szerver küldött és végül az eventType határozza meg, hogy milyen esemény következett be. Az IUniformMessage-rıl a következı fejezet részletesen beszámol. Az IUniformMessageArchive viszont sokkal érdekesebb entitás. Az interfész olyan
szolgáltatásokat sorakoztat fel, melyek nélkülözhetetlenek a rendszerben keringı üzenetek tárolásához és visszaolvasásához (ez ugyebár követelménye a komponenseimnek). A felület magában hordozza annak a lehetıségét, hogy broadcast és privát üzeneteket lehessen eltárolni majd kiolvasni. A tároláskor természetesen idıpontok is tárolódhatnak 10 Az MSDN Library is felhívja a figyelmet arra, hogy a SOAP formázó SerializationException-t dob generikus objektum sorosításakor, és ez a gyakorlatban is így van. 31 Pótári Tamás Mihály .NET komponensorientált szoftverfejlesztés bemutatása egy menedzser szoftveren keresztül A bool toNotify paraméter jelzi, hogy az üzenet utóértesítésre vár az ICollection targetClients számára. Kiolvasáskor megadhatjuk az azonosítót, hogy kinek az üzeneteit akarjuk lekérdezni például utóértesítésre, napokkal, hónapokkal korábbról (DateTime fromDateTime). Ha valami hiba történne, például
az adatbázissal, azt egy DatabaseErrorDelegate típusú ErrorrEvent közzétételével adja az ügyfélobjektum tudtára. Meg kell jegyeznem, hogy a delegált támogatja több üzenetarchiváló objektum együttmőködését, hiszen van egy sender paramétere. Az IUniformMessageArchiveAsynchronous a már felsorolt szolgáltatásokkal rendelkezik, csak éppen aszinkron hívási lehetıséggel, amivel a kódfelhasználóknak már nem kell bajlódniuk. Az System.IDisposable jelzi, hogy a komponensnek rendelkeznie kell determinisztikus finalizációs sémával, melyrıl késıbb szintén említést teszek. Az IConnectionData szöveges paramétereket tartalmaz adatbázis kapcsolatok kialakításához. Az interfész azért született meg, hogy a szöveges paraméteren túl, más mezıket is tartalmazhasson egy kapcsolati objektum – mint például fájlnevek, jelszavak, stb. Így skálázhatóbbá vált a rendszer. Mint látható, az
System.RuntimeSerializationISerializable interfészbıl származik, melynek oka, az egyéni sorosítás megvalósításának szükséglete, mely a következı fejezetekben részletes tárgyalásra kerül. 4.42 A szerelvények A komponenseimet hat fı szerelvénybe csoportosítottam. Ebbıl az egyik (Interfaces) csupán interfészeket és az azokhoz szükséges egyéb típusokat tartalmazza. Ezt a bizonyos interfész szerelvényt ismertettem az elızı fejezetben, noha említést a szerelvény létezésérıl nem tettem. Nyomós okom volt arra, hogy egy szerelvénybe soroltam a fıbb interfészeket. Ugyanis a kliens- és szerveralkalmazásoknak közösen hivatkozniuk kell erre az assembly-re, bizonyos távelérésbıl eredı, könnyebb karbantarthatósági lehetıségek elnyerése végett. 32 Pótári Tamás Mihály .NET komponensorientált szoftverfejlesztés bemutatása egy menedzser szoftveren keresztül A következı komponensdiagramra11 (9. ábra) kicsit furcsán kell
tekinteni, hiszen szerelvények alkotják azt, és mint említettem, komponensnek a .NET-beli osztályt nevezem. 9. ábra A komponenseket tartalmazó szerelvények és azok kapcsolatai A szerelvények közti társítások jelölik egymás hivatkozásait, amit a szerelvények manifesztjébıl is ki lehet olvasni. A diagramban szereplı szerelvények osztálykönyvtárak Mint látható, központi szerepet tölt be az Interfaces assembly, hiszen a másik ötbıl négy szerelvény hivatkozik rá. A következı fejezetben a tényleges .NET-beli implementációját mutatom be a kommunikációs komponenseknek. A komponensek bemutatását azok szerelvényeik szerint végzem el. 11 Talán szerelvénydiagram elnevezést lenne érdemes használnom, de az nem lenne UML kompatibilis. 33 Pótári Tamás Mihály .NET komponensorientált szoftverfejlesztés bemutatása egy menedzser szoftveren keresztül 5. A kommunikációs komponensek NET-beli kivitelezése Ebben a fejezetben a
tényleges megvalósítást mutatom be a teszteléssel és dokumentálással. Szinte minden általam tervezett komponenst jellemezni fogok, néhol mélyebben is. Bár az elızıekben nem ismertettem a fizikai felépítést, ez a fejezet bıven tárgyalni fogja azt, a komponensek ismertetését követıen. A fejlesztéskor a közismert C# nyelvet alkalmaztam, .NET 20-ás verzióval Meg kell jegyeznem, hogy a kommunikációs komponensek a Communication névtérben helyezkednek el. 5.1 Az üzenet A szerver és kliens komponensek bemutatása elıtt érdemesnek véltem az üzenetrıl írni. Hiszen az üzenet egy olyan építıeleme a rendszernek, amit a kliensek, a szerver és annak archiváló egysége is használ. Az üzenet komponenseket a MessageTypes szerelvény tartalmazza. Mindenek elıtt le kell szögeznem, hogy az üzenet bármi lehet. Bármi, ami megvalósítja az IUniformMessage interfészt. Ebbıl eredıen az üzenet lehet olyan típus, ami adatfolyamokat tartalmaz (képek,
hanganyagok), vagy adatbázis tábláit, ha DataSetekben gondolkozunk. Ez az elmélet lehetıséget ad arra, hogy a kód késıbbi felhasználói ne csak egy elıre definiált üzenetformát alkalmazhassanak. Tehát az üzenet a legdinamikusabban módosítható építıeleme a rendszernek. Az üzenet felület alapvetı szolgáltatásokkal rendelkezik (ezt a 10. ábra szemlélteti) Ilyen a feladó adatai és a küldés pontos idıpontja. A bool ToArchive jelöli, hogy az üzenet archiválandó-e, azaz bekerülhet-e az üzenettárba. De ezek az adatok nem elegendıek, 10. ábra Az általános üzenetforma hogy rendelkezzenek, jövendıbeli a bármiféle feladás információforrással céljáról. üzenettervezıknek új Ezért típust a kell létrehozniuk, amiben bízok, hogy felületörökléssel végeznek el. Az ITextMessage is így készült (a 11 11. ábra Egy szöveges üzenetforma 34 Pótári Tamás Mihály .NET komponensorientált szoftverfejlesztés
bemutatása egy menedzser szoftveren keresztül ábra mutatja). Célja egy szöveges adat tárolása A komponenseim között természetesen jelen van egy elıre elkészített, alkalmazható üzenet típus is. Ez a TextMessage (12 ábra) Észrevehetı, hogy a komponensbıl nem lehet származtatni. A fekete-dobozos kód-újrahasznosítás elvét követve nem engedélyezem a típusból történı öröklést. Mivel, ha egy hanyag programozó venné kézbe ezt a komponenst „bıvítés” szándékával, akkor több kárt tenne, mint amennyi 12. ábra A szöveges üzenet komponens elınyre számítana. Ennek a legfıbb oka, a típus által implementált interfészek megvalósítása. A problémára a továbbiakban még kitérek. 5.11 Csak olvasásra Mint ahogy korábban utaltam rá, minden felületben definiált tulajdonság csak olvasható. Itt is fontos, hogy az eseményargumentum szerepet betöltı üzenet objektum minden mezıje csak olvasható legyen, ellenkezı
esetben az értesítettek megváltoztathatják azok értékeit. Katasztrofális következményekkel járhat egy ilyen szabotázs, hiszen a módosított adatot fogják megkapni a soron következı értesítettek – még ha azok aszinkron módon is lesznek értesítve. Ez a szabály minden eseményre vonatkozik, legyen az EventArgs-al dolgozó standard EventHandler-rel vagy saját tervezéső delegálttal megvalósított. Ez az elv kihat a klónozás lehetıségére is, melyet a következı fejezetben kifejtek. A csak olvasható mezıknek még több kedvezı tulajdonságuk is van, ilyen például az egyidejőség kezelése. Azaz „nem kell” foglalkoznom szinkronizációval; több szál egyidejőleg is elérheti az objektumot, hiszen csak olvasni tudják azt, módosítani nem. 35 Pótári Tamás Mihály .NET komponensorientált szoftverfejlesztés bemutatása egy menedzser szoftveren keresztül 5.12 A klónozás lehetısége A klónozás a jövıre tekintve rendkívül hasznos
dolog, hiszen mély másolást (deep copy) alkalmazva teljesen új példányát hozhatnánk létre az IUniformMessage-et megvalósító típusok objektumainak. De valóban szükség van egy üzenet másolatra? Logikusan gondolkozva, egy másolat akkor igazán hasznos, ha a másolatok közül párat módosítunk, azaz az állapotukat megváltoztatjuk (biztonsági mentés, stb.) Jelen esetben egy IUniformMessage, vagy egy már kliens által alkotott ITextMessage alapú osztály esetén ez kivitelezhetetlen – legalábbis reflexió nélkül. Hiszen az interfészekben szereplı tulajdonságok csak olvashatók, és bízzunk benne, hogy ez a késıbbiekben is így marad, gondolván az elızıekben említett esemény alapú üzenetküldésre. A System.ICloneable interfész megvalósítása is problémákkal járhat Az object ICloneable.Copy() metódusban alkalmazhatjuk a TextMessage osztály object MemberWiseClone() metódusát a sekély másolat elkészítésére (azaz csak az elsı
szintő értéktípusok másolódnak: shallow copy), de a referencia típusok beállítása igen nehézkes a csak olvasható megszorítás révén. Gondolok itt a védett másoló konstruktorok alkalmazására, esetlegesen a reflektálásra, vagy mezıkként tartalmazott referenciatípusok szükségtelen ICloneable megvalósítására. Noha az ICloneable alkalmazása kihat a leszármazott osztályokra is, a TextMessage-bıl nem lehet származtatni. Bár nem tudni, hogy a késıbbi felhasználók milyen üzenet típusokat hoznak létre, jelenlegi esetben nem fogom rájuk erıltetni a klónozás megvalósításának terheit [14], fıleg úgy, hogy jelen esetben nincs is ilyen szolgáltatásra szükség. Ezen okokból eredıen nem szerepel az interfész hierarchiákban a System.ICloneable 5.13 A sorosíthatóság A késıbbiekben kitérek a .NET Remoting architektúrájának rövid ismertetésére, mely mondhatni szükséges lenne a sorosíthatóság okainak szemléltetésére. Amit
üzenetek kapcsán érdemes tudni a távelérésrıl, hogy a hivatkozás szerinti hívástovábbításban résztvevı objektumok (például paraméterek) sorosítás segítségével jutnak el az egyik alkalmazástartományból a másikba. Az IUniformMessage megvalósítja a System.RuntimeSerializationISeralizable felületet. Ezzel a célom, hogy a késıbbiekben létrehozandó üzenettípusok kötelezıen 36 Pótári Tamás Mihály .NET komponensorientált szoftverfejlesztés bemutatása egy menedzser szoftveren keresztül rendelkezzenek egyéni sorosítás megvalósításával. Ebbıl eredıen egy okos fejlesztı képes a verziókövetési problémákat áthidalni. A 13. ábra szemléltet. egy Az üzenettípus egyszerő 1.0-ás példánya példát verziójú sorosítva lesz (például egy állományba). Majd egy késıbbi verziójú (1.1) típusként szeretnénk kiolvasni azt. De mivel az int m ValamiAdat mezı nem szerepel a sorosított adatfolyamban (pontosabban
a 13. ábra Sorosítási hiba az eltérı verziójú objektumoknál sorosított típus nem tartalmazza), kivétel keletkezik visszasorosításkor. Természetesen a helyzet fordítottan is hasonló. Ha 11-es verziójú típust sorosítunk és 1.0-ásként szeretnénk kiolvasni azt, szintén SerializationException lesz a vége, noha az 1.0-ás verzió minden adattagot megtalál, amire szüksége van Az ok mégis egyszerő; megszőnt a bináris kompatibilitás. Az egyéni sorosítással meg tudtam oldani ezt a jellegzetes problémát. Mindössze annyit kellett tennem, hogy megvalósítottam az ISeralizable interfészt és létrehoztak egy private láthatóságú konstruktort12, melynek konstrukciós paraméterei: • System.RuntimeSerializationSerializationInfo info • System.RuntimeSerializationStreamingContext context A belsı megvalósításban minden mezıt úgy tárolok el és olvasok ki az info paraméterbıl, ahogy én szeretném. Így egy újabb TextMessage verzió
készítésekor – azaz adattagjainak kibıvítésekor – elég a speciális konstruktorban try-catch blokkba helyeznem az új adattagok kiolvasásának lépéseit. 11-es tárolt típus esetén, 11-es verzió deszérializálásakor nem fog kivétel keletkezni, 1.0-nál viszont igen Ezt a kivételt pedig úgy érdemes kezelni az 11-es osztály túlterhelt konstruktorában, hogy a m ValamiAdat mezınek egy standard kezdıértéket kell megadni. A kivétel kezeléses módszer [15] rendkívül egyszerő, de van ennél jóval frappánsabb lehetıség is [16], amikor az info konstrukciós paraméterbıl kiolvassuk az 12 A private, vagy protected láthatóságú konstruktor alkalmazásakor kötelezıen létre kellett hoznom legalább egy public konstruktort. 37 Pótári Tamás Mihály .NET komponensorientált szoftverfejlesztés bemutatása egy menedzser szoftveren keresztül assembly verziószámát, és az alapján végezzük el a mezık visszasorosítását. Ez a módszer
némiképp nagyobb odafigyelést és kicsivel több munkát igényel. Nagyobb teljesítményt és jobb karbantarthatóságot nyújtott volna egy harmadik megoldást, ami ciklus segítségével térképezi fel a sorosítandó és kiolvasandó mezıket. Bár ez utóbbi elmélet a meglátásom szerint nehezebben átlátható kódot eredményez, valószínőleg több tárolandó mezı esetén mégis hasznos lehet – értem ez alatt, hogy nem kell minden mezınevet, referenciát és értékadást lekódolni a konstruktorba, illetve új mezık létrehozásakor nem kell módosítani a konstruktor definícióját. Sajnos a ciklusban a nem sorosítandó mezık kezelését meg kell oldani, ami a legrosszabb esetben lassú reflexió használatot igényelne. Az üzenettípusból történı származtatás újabb fejtörést okozhat. Ez is egy ok, hogy jelen esetben nem engedélyezem az üzenetobjektumokból történı öröklést. A .NET Remoting okos Tudja, hogy egy távoli objektumhoz küldött
objektum típusa eltérhet a célpontnál várt típustól. Tehát az elızı 10 és 11-es példa nem okozna RemotingException-t vagy SerializationException-t, sıt a nem sorosított értéktípusoknak automatikusan kezdıértéket is ad (int m ValamiAdat esetén 0-át, stb). Viszont a referencia típusok ebben az értelemben null értéket kapnak, amin egy metódushívás kivételhez vezet. Tehát a távelérés esetén is kötelezı volt, hogy gondoskodjak a megfelelıen kialakított egyéni fejlesztéső sorosítási mechanizmusról. Fontos megjegyeznem, hogy a .NET Remoting megköveteli a System.SeralizableAttribute álegyedi attribútum (pseudo-custom [17]) megadását, ha egy típust továbbítani szeretnénk távoli objektumok felé. Ez nincs kihatással a ISerializable megvalósítására. 5.14 A formázhatóság Korábban említettem, hogy a formázás alatt elsısorban az objektum szöveges megjelenítését értem. A SystemIFormattable megvalósítása hosszadalmas
munka volt, de viszont a kód felhasználók munkáját megkönnyítettem vele. A string ToString(string format, System.IFormatProvider formatProvider) metódus paraméterül kaphat egy szöveges formátum leírást, ami például a TextMessage esetén a következı lehet: • ”t” az üzenet szövegének visszaadása • ”d” az üzenet küldés pontos dátumának visszaadása 38 Pótári Tamás Mihály .NET komponensorientált szoftverfejlesztés bemutatása egy menedzser szoftveren keresztül • ”dct” a dátum, az üzenetküldı neve és az üzenet szöveg együttes megjelenítése Természetesen ezen lehetıségeknél többet is definiáltam, sıt ha ezek a formátumok nem megfelelıek a felhasználók számára, akkor készíthetnek saját IFormatProvider és ICustomFormatter alapú osztályokat, saját formázóval. Érdemes megemlítenem, hogy a .NET az objektumok IFormattable féle ToString() metódusát hívja meg az objektum kiíratáskor feltéve, ha ez
az interfész implementálva van – ellenkezı esetben az object féle ToString() vagy annak felülbírált változatai lépnek érvénybe. Ezt a lehetıséget minden információt hordozó típusnál kihasználtam. 5.15 Egyéb üzenetek Megfigyelhetı, hogy az IUniformMessage-ben szerepel a feladó ügyfél adata. Ez csakis adat, nem pedig hivatkozás az ügyfél objektumra. (Ez a távelérésnél rendkívül fontos dolog.) Az a komponens, ami megvalósítja az IClient szolgáltatásait, a ClientData. (A 14 ábra képviseli a ClientData-t.) Erre a komponensre üzenetként 14. ábra Kliens adatokat tartalmazó komponens tekintek, hiszen mondhatni, hogy utazik a kommunikációs infrastruktúrán keresztül, bár nem valósítja meg az IUniformMessage-t. A ClientData hasonló jellemzıkkel bír, mint a TextMessage: • Egyéni sorosítás. • Formázhatóság. És ezek mellett, mint ahogy korábban említettem, • Összehasonlíthatóság. Az IServer megvalósítása, azaz
a ServerData is hasonló okokból született 15. ábra A szerver adatait tartalmazó komponens meg, mint a ClientData, bár szőkösebb szolgáltatáslistával rendelkezik. (A 15 ábra szemlélteti a ServerData-t.) Míg az IServer, 39 pontosabban a ServerData az Pótári Tamás Mihály .NET komponensorientált szoftverfejlesztés bemutatása egy menedzser szoftveren keresztül IClientFunctions.OnUniformEvent() legelsı paramétereként használatos, addig az IClientFunctions.Server tulajdonság nem adatot tárol a szerverrıl, hanem egyenesen egy proxy a szerverhez. (Gondolván, hogy az IClientFunctions az IClient-bıl származik, ezt az implementációs részletet a dolgozatom e pontján meg kellett említenem.) Utólag jogosan felmerülhet a kérdés, hogy az IServer és az IClient miért nem valósítja meg az ISerializable interfészt, ha a ClientData és a ServerData utólag implementálja azt. A válasz: nem lenne humánus a késıbbi fejlesztıkre
erıltetni az egyéni sorosítás szükségletét, fıleg akkor, ha ık szerver- vagy klienskomponenseket akarnának létrehozni. Elég abszurd és haszontalan dolog lenne egy szerverobjektum állapotát elmenteni, ha az jelszavas adatbázis kapcsolatokat, távoli, visszahívandó objektumok proxyjait tárolná magában. 5.2 Esemény közzétételt segítı komponensek Mivel a komponensek alkotta rendszer eseményalapú, gyakorta van szükség események közzétételére. Az if(valamiEvent!=null) valamiEvent(); technikánál kicsit pontosabbra és hatékonyabbra van szükség: • Az eseményeket aszinkron módon „szinte egyszerre” lehessen közzétenni, a forrás blokkolása nélkül – ez a dinamikus modellezésnél már jelen volt. • Kezelni kell a feliratkozóknál – távelérés kapcsán a visszahívandó ügyfeleknél– fellépı kivételeket, nehogy a forrás összeomoljon. • Tudomást kell szerezni a feliratkozóknál fellépı kivételekrıl, esetlegesen a
nem elérhetı – azaz nem visszahívható – ügyfelekrıl. Ez egy oka annak, hogy nem használok System.RuntimeRemotingMessagingOneWayAttribute attribútumot [18]. (A hibák észlelése szintén jelen volt a dinamikus modellezésnél) Logikusan egy komponens tartalmazza ezeket a szolgáltatásokat, melyet „Ha lúd, akkor legyen kövér” elvén úgy készítettem el, hogy más projektekben is fel lehessen használni, ebbıl eredıen más alkalmazások is közösen tudják használni. (A komponenst a SupportServices szerelvény tartalmazza.) Az IRemotingEventHelper interfész tipikusan táveléréssel mőködı rendszerek számára fejlesztettem ki, bár nem remoting-gal mőködı 40 Pótári Tamás Mihály .NET komponensorientált szoftverfejlesztés bemutatása egy menedzser szoftveren keresztül egyszerő alkalmazások is nyugodtan használhatják. (Az IRemotingEventHelper-t a 16 ábra mutatja.) 16. ábra A távoli objektumok aszinkron visszahívásában segédkezı
interfész Az IRemotingEventHelper.RaiseEvent() túlterhelt Általánosságban a következı paramétereket várják a metódusok: • Delegate del: a delegált, melyben több feliratkozott metódus referenciája is megbújhat. • ICollection<Delegate>: delegált győjtemény, melyben akár több metódus referenciával rendelkezı delegáltak is szerepelhetnek. • params object [] args változó hosszúságú paraméterlista: mely a delegáltak dinamikus közzétételére szánt paramétereket tartalmazza. A RaiseEventSkipSender() a broadcast közzététel hatékony fegyvere. A Delegate toSkipDel paraméterben megadható az a metódusreferencia, amit szeretnénk, hogy kimaradjon az értesítési listából – már ha az szerepel benne. Furcsa lehet, hogy a kódfelhasználó miért nem olyan győjteményt vagy delegáltat ad át, amelyben már nem szerepel az értesítendı metódus referenciája, hiszen a takarékosság szempontjából kifolyólag kétszer lesz egy
adatcsomag továbbítva a metódushoz – fölöslegesen. Ráadásul több kódolási munkát igényel a metódus megvalósítása, és a benne szereplı ciklikus ellenırzés terhelheti a számítógépet is. Sajnos ha ezt a lehetıséget mégsem alkalmaztam volna, akkor a hívó félnek kellett volna jó elıre elkészítenie a paraméterül átadandó delegált vagy győjtemény másolatát, melybıl ugyebár ki kellett volna hagyni a nem kívánatos példányt. Ez kényelmetlenség a kódfelhasználónak, és terhelés az ügyfélobjektumnak. Persze másolat alkalmazása nélküli megoldás is létezik, azaz az eredeti győjteménybıl, vagy a delegáltból el kellene távolítani a delikvenst, majd a metódushívást követıen vissza kellene helyezni azt. Ha 41 Pótári Tamás Mihály .NET komponensorientált szoftverfejlesztés bemutatása egy menedzser szoftveren keresztül belegondolunk, hogy az aszinkron hívás a végrehajtás szétválasztását jelenti, majd
megfeledkezve a szinkronizálásról, egy egyidejőleg elérendı objektumon olvasási és írási mőveleteket végzünk, katasztrofális következményekhez és inkonzisztenciához jutunk. Ez már komoly kockázat és többletmunka lenne a komponensem felhasználója számára. Ezt nem engedhetem meg A felület még rendelkezik egy eseménnyel, mely akkor következik be, ha egy feliratkozó értesítése során kivétel keletkezik, vagy esetlegesen 17. ábra Nem elérhetı, vagy hibás kliensek eltávolításához használható delegált nem elérhetı. A RemoveUnavailableSubscriberDelegate Delegate unSubscriber paramétere maga a hibás feliratkozó delegáltja (17. ábra) Így lehetıség nyílik utólag eltávolítani a feliratkozók listájából a nem értesíthetı egyedet. Erre az eseményre teljesítmény és szinkronizációs okok miatt csak egyetlen metódus iratkozhat fel. A bool RemoveInUse tulajdonság jelöli, hogy foglalt-e az esemény. Az interfészt az
RemotingEventHandler valósítja meg, mely manuális szinkronizációt foglal magában, a szálaffinitás elkerülése végett (18. ábra) A szinkronizációs objektum a System.ThreadingReaderWriterLock, melyrıl késıbb részletes betekintést nyújtok. 18. ábra A távoli esemény közzétételre specializált segédkomponens 42 Pótári Tamás Mihály .NET komponensorientált szoftverfejlesztés bemutatása egy menedzser szoftveren keresztül Létezik még EventHandler egy szimpla komponens is ugyanebben a szerelvényben, melynek statikus metódusai aszinkron esemény 19. ábra Aszinkron esemény közzétételt végzı osztály közzétételt végeznek el, kiegészítı szolgáltatások nélkül (19. ábra) 5.3 Az üzenetek archiválása A logikai felépítésmodellnél említettem az IUniformMessageArchive és annak leszármazottjának az IUniformMessageArchiveAsynchronuos interfész szerepét. Ezeket az interfészeket, pontosabban az utóbbit a
MessageArchive komponens valósítja meg, mely az Archive szerelvényben helyezkedik el. A MessageArchive teljes mértékig az IUniformMessage üzenetobjektumok adatbázisban történı tárolására („Store” kezdető metódusok) és onnan visszaolvasásra („Load” kezdető metódusok) szolgál. Ez a komponens Microsoft SqlServer specifikus Bár, mint ahogy a késıbbiekben fény derül annak lehetıségére, más komponensekkel helyettesíthetı a rendszeremen belül – amik már OLEDB-n vagy ODBC-n keresztül csatlakoznak adatbázisokhoz. A MessageArchive-ot a 20 ábra szemlélteti 20. ábra Az üzenet archiváló objektum 43 Pótári Tamás Mihály .NET komponensorientált szoftverfejlesztés bemutatása egy menedzser szoftveren keresztül A komponens csak egy SqlServer kapcsolatot tart fent, bár erre az interfészen belül semmi sem utal, így a késıbbiekben szabadon módosítható, bıvíthetı ez a jellemzı. Az objektum létrehozásakor, a konstruktornak
paraméterül kell adni egy IConnectionData connectionData paramétert. Az IConnectionData felület szintén saját fejlesztéső, mely már szerepelt a logikai felépítésmodell bemutatásánál. Feladata, hogy kapcsolati paramétereket tároljon magában, amiket archiválni lehet (például sorosítással), illetve ne okozzon problémát neki a bıvíthetıség és a késıbbi verziók alkalmazása – hasonlóan a TextMessage példához. Ezt a felületet a ConnectionData valósítja meg példányosításkor (21. ábra), mely konstrukciós para- méterként egy string connectionStringet vár. Ez egy adatbázis eléréséhez szükséges kapcsolati karakterlánc, amit 21. ábra A speciális kapcsolati objektum, melyet az archiváló konstruktora vár paraméterül az archiváló objektum ügyfele állít elı. (Mint ahogy a késıbbiekben kitérek rá, a szerver sorosítással készíti elı ezt az objektumot.) 5.31 Objektumok tárolása adatbázisban A MessageArchive
különlegesen tárolja el az archiválandó üzeneteket. Mindenki azt gondolná, hogy az adatbázis olyan táblákat tartalmaz amikben a IUniformMessage interfészben szereplı – kicsit hiányos tartalmú – információk mezıkként szerepelnek. Tehát: • SenderName : text • SenderID : bigint • SendingDateTime : datetime • toNotify : bool ami jelöli, hogy a rekord utóértesítendı üzenetet tárol • és nyílván egy TextMessage : text ami valami formán a TextMessage objektum string Text-jét tárolja. 44 Pótári Tamás Mihály .NET komponensorientált szoftverfejlesztés bemutatása egy menedzser szoftveren keresztül Ez elsı ránézésre remek, hiszen bármilyen lekérdezést alkalmazhatnánk, és két tábla segítségével akár a broadcast, illetve privát üzeneteket is elkülönítve lehetne tárolni. Privát üzeneteknél jelölni kellene az értesített vagy értesítendı kliensek ID-jét is, mivel az adatbázisban lévı klienseknek a long
IClient.ID-je van eltárolva Ez alapján történik az azonosítás. Sajnálatos módon mégis ki kell jelentenem, hogy ez a módszer több sebbıl is vérzik: • Az egyik, hogy a komponens TextMessage függı lesz. Tehát ha más üzenetet tartalmazó komponenst készítene egy kódfelhasználó – ami nem tartalmaz string Text-et –, akkor nem lesz belıle semmi se tárolva, csak ami az IUniformMessageben szerepel – legrosszabb esetben pedig konverziós hibát szülne minden alkalommal. • Ha mégis olyan üzenetobjektum mezıit szeretnénk eltárolni, melyek adatbázisbeli megfelelıje nem szerepel a táblákban, akkor át kell alakítanunk az adatbázis tábláinak szerkezetét – nem beszélve a MessageArchive belsı mőködésérıl. És ezzel még mindig nem oldottuk meg a problémát, ami a vegyes üzenettárolásból eredhet. Sok karbantartási munka, nehéz skálázhatóság a tárolt adatok állapotának veszélyeztetése. Szerencsére napjaink adatbázisai
képesek bináris adatokat, SqlServer esetén image-ket tárolni. Így lehetıségem nyílt arra, hogy az adatbázisba sorosított állapotban helyezzem el az IUniformMessage objektumok. A beérkezı 22. ábra Egy egyszerő adatbázis, melyben szórt és privát üzenet objektumokat lehet tárolni üzenet objektum bináris sorosításon esik át a memóriában, majd „nyers” bináris adatként lesz eltárolva az adattábla image típusú mezıjében. (Az adattáblákat a 22 ábra részletezi.) Majd az adatbázisból lekérdezve – mondjuk küldési dátum alapján – deszerializáláson esik át, és a tárolt típus meghatározása futás idıben történik meg (errıl a .NET assembly névfeloldója gondoskodik) Azaz a MessageArchive-nek fogalma sincs arról, hogy milyen üzenettípus van eltárolva, csak azt tudja – legalábbis fordításkor –, hogy IUniformMessage típussal dolgozik. 45 Pótári Tamás Mihály .NET komponensorientált szoftverfejlesztés
bemutatása egy menedzser szoftveren keresztül Ez a mőködés ellensúlyozza az elızıleg felsorolt, hagyományos módszer hátrányait. Habár itt is szembesülhetünk problémákkal: • Nem tudunk „csak” üzenetet lekérdezni. Noha erre nincs is szükség, hiszen mint jóval korábban említettem, az üzenet bármi lehet. Ha mégis valami módon szeretnénk a tárolt objektum szövegébe beleolvasni, ahhoz a bináris formázás helyett használhatunk SOAP vagy XML formázást. Így szöveges alakban lesznek az objektumok eltárolva, melyeken speciális szövegorientált lekérdezéseket alkalmazhatunk. Ehhez a módszerhez az image típusú mezıt text (vagy egyéb) típusúra kell alakítanunk. • Lassú. A sorosítás és a vissza sorosítás nem gyors dolog, ez természetesen a sorosítandó információ mennyiségtıl és a formázótól is függ – e szempont miatt használok bináris formázót. Bár érdemes elgondolkozni azon, hogy egy objektum szerializálása
vagy deszerializálása mennyivel lassabb, mint létrehozni egy „tiszta” üzenet objektumot, majd minden adattagjának egyenként értéket adogatni az adatbázisból. • Bizonyos adatokat kétszer is el kell tárolnom, mellyel terhelem az adatbázist és lassítom a tárolási és kiolvasási folyamatokat. Ezen adatok alatt az üzenet küldı adatait és a küldési dátumot értem, hiszen a komponens ezen információk alapján végez üzenet kiolvasást és ezek már egyszer tárolva vannak az üzenet objektumban. Mint látható van pro és kontra, de én mégis a könnyebben karbantarthatóbb, rugalmasabb rendszer mellett döntöttem a teljesítménnyel és némiképp a takarékossággal szemben. Az adatbázist olvasó és módosító sql parancsokat programozottan ágyaztam be a komponensbe, mivel az sql parancs paramétereit a .NET illeszti be Ehhez paraméterhelyırzıket tartalmazó utasításokat alkalmaztam a parancsobjektumok (SqlCommand) létrehozásánál [19]. Ez
egy rendkívül hatékony és karbantartható parancsparaméterezési forma, mellyel különbözı oszlopértékeket adhatunk meg futási idıben. A privát üzenet behelyezést tárolt eljárás végzi. A lekérdezéseket SqlDataReader objektummal végzem el, mivel általában gyorsabb, mint a DataSet-es adatbázis olvasás és számomra úgyis a tárolt objektumok kinyerése számított. Szintén a hatékonyságra és az átlátható, karbantartható kód készítésére törekedtem, amikor a SqlDataReader használatakor nem szöveges formában adtam meg a 46 Pótári Tamás Mihály .NET komponensorientált szoftverfejlesztés bemutatása egy menedzser szoftveren keresztül kinyerendı adatbázismezı nevét, hanem SqlDataReader.GetOrdinal()-lal már jó elıre elkészítettem annak int megfelelıjét [20]. A MessageArchive adatbázis kapcsolatot tart fent, tehát rendelkeznie kell megfelelı erıforrás felszabadítással, determinisztikus finalizációval. Ebbıl eredıen
rendelkezik destruktorral és IDisposable felülettel. A destruktor és a Dispose() is egyaránt egy void cleanUp() metódust használ az adatbázis kapcsolat felszabadítására. A komponensemben a szakirodalom által javasolt finalizációs sémát alkalmaztam [21]. A komponensnek szálfüggetlennek kellett lennie, azaz rendelkeznie kellett bennfoglalt szinkroizációval. A szinkronizációs objektum itt a SystemThreadingMonitor volt, melyet a System.RuntimeCompilerServicesMethodImplAttribute álegyedi attribútummal használok, MethodImplOptions.Synchronized paraméterrel [22] Sajnos a Monitor e használati formája az objektumot olvasáskor és íráskor is egyaránt zárolja más konkurens szálak elıl. Viszont elég nehéz lett volna megállapítani, hogy mely szolgáltatások végeznek tényleges írási, avagy olvasási mőveleteket az objektumon. Azzal, hogy a kliensek egy távoli objektumon keresztül érik el az adatbázist, képes voltam elrejteni az adatok
hollétét. Azaz csakis a szerver objektum tud az adatbázis – vagy adatbázisok – típusáról és elhelyezkedésérıl. 5.3 A szerver objektum Mint ahogy a dinamikus viselkedésmodellezésnél már utaltam rá, a szerver objektum küldi tovább a kliensektıl beérkezett üzeneteket és tárolja el azokat egy üzenetarchívumban. De még mielıtt részletekbe menıen leírnám a szerver objektum mőködését, ki kell térnem a korábban már hivatkozott .NET távelérés lényegére, és annak használatára az én esetemben. 5.31 A NET Remoting rövid jellemzése A .NET távelérésrıl minden valamirevaló NET-es szakirodalom említést tesz, sıt vannak szakkönyvek, amik csakis ezzel a témakörrel foglalkoznak. Ebbıl eredıen 47 Pótári Tamás Mihály .NET komponensorientált szoftverfejlesztés bemutatása egy menedzser szoftveren keresztül rendkívül nehéz a szakdolgozatom kapacitásainak határain belül leírnom, hogy mi is az a általam sokszor említett
távelérés. Közismert tény, hogy a .NET fizikai folyamatok alkalmazástartományokból (appdomain) épülnek fel – avagy épülhetnek fel, ha csak egyetlen alapértelmezett alkalmazástartományból állnak, mint a legtöbb esetben (sajnos). Nem említve a környezeteket, egy folyamat objektumai a saját alkalmazástartományaiban helyezkednek el. Az eltérı alkalmazástartományokban lévı objektumok távelérés segítségével hívhatják meg egymást. Tehát a remoting, „az alkalmazástartományon kívül esı objektumok elérését jelenti” [23]. Ahhoz, hogy egy ügyfél objektum egy másik appdomain-ben lévı kiszolgáló objektumot elérjen, rendelkeznie kell a kiszolgáló objektum proxyjával – amit már korábban említettem. Ez egy virtuális referencia egy távoli objektumra Ha hívást intézünk a proxyra, akkor az továbbítani13 fogja a hívást a távoli objektumhoz. Egy objektum pedig csak akkor fogadhat távoli ügyfelektıl érkezı hívásokat, ha
annak osztálya a System.MarshalByRefObject-bıl származik és regisztrálva van a NET felé A típus regisztrációjára azért van szükség, hogy a .NET tudomást szerezzen arról, hogy milyen objektum, milyen aktiválási móddal illetve milyen elérhetıséggel váljon részévé a távelérési infrastruktúrának. A hívástovábbítás típusaiból eredıen, a .NET két lehetıséget ad, hogy egy objektumot hogyan lehessen elérni más alkalmazástartományból (a 23. ábra ábrázolja a .NET távelérés hívástovábbítási lehetıségeit és az objektumok aktiválási módjait): • Érték szerinti hívástovábbítás: mely objektumok egyik appdomain-bıl a másikba történı másolgatásával mőködik. Ez nem egy közkedvelt módszer, én sem alkalmazom, ebbıl adódóan a dolgozatomban nem fejtem ki bıvebben. • Hivatkozás szerinti hívástovábbítás: a proxy-s módszer, melyet elızıleg 23. ábra A NET Remoting hívástovábbítás lehetıségei és
objektum aktiválási módjai röviden ismertettem. A projektem ezt a módot támogatja 13 A hívástovábbítást nevezzük marshaling-nak. 48 Pótári Tamás Mihály .NET komponensorientált szoftverfejlesztés bemutatása egy menedzser szoftveren keresztül A hivatkozással elért távoli objektumoknak is két fajtájuk van: • Ügyfél által aktivált objektumok: ezeket ügyfélobjektumok aktiválják más alkalmazástartományokban. Rendelkezhetnek paraméterezett konstruktorral, és a készenlétükrıl bérleti mechanizmus gondoskodik. Ezek az un Activated objektumok. Annyi példány van belılük a memóriában – ez persze lehet másik számítógép memóriája is –, amennyit az ügyfelek létrehoztak. Noha egyes komponenseim használhatóak ebben a módban is (természetesen gondoskodva a bérleti mechanizmusról) nem ezt használom a szakdolgozatomban, így részletesen nem térek ki a jellemzıire. • Kiszolgáló által aktivált objektumok: mint ahogy a
nevük is hordozza, távoli kiszolgáló aktiválja ıket. Ezek az úgynevezett WellKnown 14 objektumok. Jellemzıjük, hogy hamarabb aktiválva kell lenniük a .NET felé, mint ahogy a kérések megérkeznének hozzájuk. Ami fontos volt számomra a modellezéskor, hogy nem érdemes paraméterezett konstruktorokat alkalmazni náluk. Dolgozatomban ezt a módot használom. A jó ismert objektumoknak is két típusa van: • Egyszer hívható objektumok: ezek az objektumok akkor jönnek létre a memóriában, amikor az ügyfél hívást intéz hozzájuk. A hívás visszatérésével, azon nyomban megszőnnek. Tehát a memóriában annyi példány van belılük, ahány ügyfélhívás az adott pillanatban folyamatban van. Elsısorban az erıforrás takarékosság és a jó skálázhatóság jellemzi ıket. Legfıbb felépítésbeli jellemzıjük, hogy az állapotukat minden hívás után – azaz megsemmisülés elıtt – elmentik, majd a következı híváskor visszanyerik.
Ez jelentıs teljesítménybeli hátrányhoz vezethet • Singleton objektum: egy egyedülálló objektum. Jellegzetessége, hogy csak egyetlen példány jön létre belıle a memóriában, és minden ügyfélobjektumot ı maga szolgál ki. Ebbıl eredıen állandóan elérhetınek kell lennie, azaz a remoting infrastruktúrából sosem kerülhet ki – pontosabban örök bérletidıvel rendelkezik, amit sosem kell szponzorok által meghosszabbítani. Az egyszer hívható objektumoknál sokkal rosszabb skálázhatósággal rendelkezik, hiszen a singleton célja, hogy az általa lefoglalt erıforrások (például adatbázis kapcsolatok) csak akkor szabaduljanak fel, amikor maga az objektum is elpusztul. Viszont nagyobb 14 Az egyszerőség kedvéért a késıbbiekben a kiszolgáló által aktivált objektumokat „jól ismert” objektumnak is fogom nevezni. 49 Pótári Tamás Mihály .NET komponensorientált szoftverfejlesztés bemutatása egy menedzser szoftveren keresztül
teljesítményt nyújthat, mint az egyszer hívható objektumok, mivel az állapotát nem kell újból visszanyernie. A szakirodalom nem javasolja a singleton használatát, arra hivatkozva, hogy jelentıs fejtörést okozna egy ilyen objektum köré épített rendszer átalakítása. Viszont, a kommunikációs vagy naplózó objektum szerepét tökéletesen játssza. Mivel viszont több hívó fél egyidejőleg is elérheti, szinkronizációt kell megvalósítani benne (ellenben az egyszer hívható objektumokkal). Jellegzetessége, hogy az objektum nem a kliens általi konstrukciós hívásra készül el a távoli alkalmazástartományban, hanem az elsı tényleges szolgáltatás igénybevételkor fut le a singleton konstruktora. Így a konstrukciós paraméterek sosem jutnának el hozzá, ebbıl eredıen szintén haszontalan paraméterezett konstruktort definiálni a típusban. A dolgozatomban szereplı szerver komponenst kiszolgáló által aktivált, singleton mőködésre
optimalizáltam. Még egy rendkívül fontos momentuma van a távoli objektumok elérésének, avagy elérhetıvé tételének, ami pedig nem más, mint a csatornaregisztráció. Mindazonáltal, hogy a két kommunikáló fél között bolyongó üzenetek szerializáción és deszerializáción esnek át – a formázó és a veremépítı között –, kell még egy transzport csatorna is, amin a sorosított üzenetek közlekedni tudnak. A klienseknek regisztrálni kell a csatornát, amin kimenı távoli hívásokat intéznek, illetve a hoszt-alkalmazástartományoknak is regisztrálniuk kell a csatornát, amin a bejövı hívásokat óhajtják fogadni. A NET 10-ás verziója óta lehetıség van TCP és HTTP protokollok igénybevételére csatornaregisztrációkor. Ezeken bináris vagy SOAP formázott adatokat küldhetünk át Mindezek mellett biztosítani kell a távoli objektumok URL-jét, hogy a .NET tudomást szerezzen azok elérhetıségérıl, illetve URI-jét a
jól ismert objektumok azonosításához. Mind a típusregisztráció és a csatornaregisztráció elvégezhetı programozott és adminisztratív módon. A programozott regisztrációs forma mondhatni minden beállításával lefordul a kódba. Az adminisztratív regisztráció konfigurációs állományokkal kezelhetı, mely sokkal jobb skálázhatóságot nyújt, így a dolgozatomban is ezt preferálom. 50 Pótári Tamás Mihály .NET komponensorientált szoftverfejlesztés bemutatása egy menedzser szoftveren keresztül 5.32 A Server komponens Az interfészeket bemutató fejezetben már elemeztem az IServerFunctions interfész szolgáltatásait, de a belsı implementációról csak minimális kitérıt tettem. A feliratkozók tárolásának (nyilvántartásának) módjáról viszont ez idáig még nem esett szó. A nyilvántartás megértésének legelsı lépésében érdemes megvizsgálni a SubscriberEventType enum-ot. A felsorolt típus csak két elemet tartalmaz:
MessageEvent és AllEvent. Mondhatni, hogy a kliens – azaz a feliratkozó – csak ezekre az eseményekre tud feliratkozni (jelenleg). De a szervernek jóval több eseménye létezik, amelyet a PublisherEventType foglal magában. Érdemes visszaemlékezni az IClientFunctions.OnUnformEvent() metódusra, mely által paraméterként kapja meg a kliens a szerveren bekövetkezett esemény típusát. A PublisherEventType meglehetısen sok eseményt foglal magában, holott a Server assembly szintén Server nevő komponensére tekintve egyet sem lehet megtalálni (24. ábra) 24. ábra A Server komponens, melynek példánya más alkalmazás tartományból is elérhetı 51 Pótári Tamás Mihály .NET komponensorientált szoftverfejlesztés bemutatása egy menedzser szoftveren keresztül A trükk az, hogy a PublisherEventType által definiált eseménytípusok szöveges értesítést adnak a klienseknek egy történésrıl (UniformDelegate). Ebbıl eredıen nem kell külön
eseményeket alkalmazni, amelyekre még egyenként fel is kell iratkozni, hiszen csak azok részesülhetnek ilyen értesítésekben, akik a PublisherEventType.MessageEvent-re elıjegyeztek. Tehát a Server minden eseménye egyetlen UniformDelegate típusú eseményen keresztül kerül közzétételre. Például egy kliens bejelentkezésekor – azaz amikor feliratkozik a MessageEvent-re – közzé lesz téve egy broadcast, PublisherEventType.ClientConnectedEvent paraméterő esemény, mely magában hordozza az esemény szöveges üzenetét, hogy ki és mikor csatlakozott. Viszont még mindig nem található az a bizonyos univerzális esemény a Server definíciójában. Valójában a Dictionary<Delegate,IClient> m MessageEventDictionary mezı tartalmazza a feliratkozó IClientFunctions.OnUnformEvent()-jének UniformDelegate típusú metódus referenciáját és IClient típusú adatait (csak adatot, nem pedig proxyt: ClientData). Több oka is volt annak, hogy
Dictionary<> generikus győjteményt alkalmaztam például hagyományos esemény helyett: • Egy helyen vannak tárolva a kliensek adatai és a visszahívásukhoz szükséges delegáltak. Így könnyő eltávolítani az egyértelmő azonosítást végzı delegált alapján (Key) a klienst a győjteménybıl. • Lehetıség nyílik delegált keresést végezni Value szerint – hiszen az IClient avagy a ClientData megvalósítja a System.Equatable<IClient>-et Így a kliens adatok alapján is el lehet távolítani a feliratkozót a győjteménybıl. • Az ICollection IServerFunctions.Subscribers tulajdonság egyszerően megvalósítható, hiszen csupán a m MessageEventDictionary.Value 15 -t kell visszaadni. Persze a UniformDelegate esemény is tárolja a célpont adatait (object UniformDelegate.Target) de ez valójában proxy a távoli ügyfél objektumhoz, amit nem szabad a ICollection IServerFunctions.Subscribers révén más kliensek számára
hozzáférhetıvé tenni. A proxyból ClientData-vá való átalakítás hosszadalmas folyamat, és 15 Mint korábban említettem, a .NET Remoting nem támogatja maximálisan a generikus típusokat Így a generikus győjtemények átküldése elıtt új (nem generikus) győjteménnyé kell formálni azokat. Mégis a konstruált típusokat használom a rendszeremben, bízva abban, hogy a Microsoft a jövıben több energiát fordít a távelérés fejlesztésére. 52 Pótári Tamás Mihály .NET komponensorientált szoftverfejlesztés bemutatása egy menedzser szoftveren keresztül az object típus révén sok konverzióval is jár. Szintén konvertálást igényel az eseményben történı IClient objektum szerinti keresés. A feliratkozást („subscribe” kezdető) és a közzétételt („raise” kezdető) végzı apró metódusok a JIT fordító munkájának megkönnyítésére [24] születtek meg. A Server magában foglalja egy IUniformMessageArchiveAsynchronuos
referenciát, melyen keresztül egy MessageArchive objektummal tárolja a beérkezett üzeneteket, aszinkron módon – mint ahogy a dinamikus modellezésnél is hangsúlyozva volt. A nem értesíthetı ügyfelek üzeneteit bool toNotify=true paraméterrel adja IUniformMessageArchiveAsynchronuos.StorePrivateUniformMessage()-nek át az Adatbázis hiba esetén az onDatabaseErrorEvent() indul el, ami meghívja a raiseErrorEvent()-et, átadva neki egy üzenetet a nem elérhetı szerverrıl. Ha értesítés során hiba keletkezik, vagy egy értesítendı ügyfél fizikailag nem elérhetı, akkor az onRemoveUnavailableSubscriberEvent(Delegate unSubscriber) metódus lesz meghívva az IRemotingEventHelper m RemEventHelper objektum eseménye által. A metódus paraméterül kapja a nem elérhetı kliens delegáltját, mely alapján el lesz távolítva a központi győjteménybıl. Gondoskodnom kellett a Server objektum singleton létérıl, azaz állandó elérhetıségérıl. Ehhez
a MarshalByRefObject-bıl örökölt object InitializeLifetimeService() felülbírálását kellett elvégeznem, mely null értéket ad vissza. Így 5 perc után is elérhetı marad a singleton objektum. A singletonnak ugyan nem kell rendelkeznie determinisztikus finalizáció sémával, de destruktorral igen – gondolva a m MessageArchive-ra. Mivel a kliensek külön szálról érik el az objektumot, szinkronizáltnak kell lennie annak. A szinkronizációt a SystemThreadingReaderWriterLock manuális szinkronizációs objektummal végeztem el [25]. Ez az objektum lehetıséget ad a több olvasó egy író mőködésre, mely jelentısen csökkenti a szálkészlet kimerülésének és a deadlock-ok 16 kialakulásának esélyét, mindazonáltal növeli a rendszer átviteli sebességét a Monitor-hoz vagy Mutex-ekhez [26] képest. A ReaderWriterLock m RwLock használatát minden 16 Fontos megjegyeznem, hogy több szinkronizációs módszerrel is próbálkoztam. Elsınek az
automatikus szinkronizációt próbáltam ki, a szinkronizációs tartományokkal [27]. Ebben az esetben a System.ContextBoundObject-bıl kellett származtatnom a Server-t, hogy annak példánya környezethez kötött legyen. (A Server továbbra is elérhetı maradt más alkalmazástartományokból, mivel a ContextBoundObject a MarshalByRefObject-bıl származik.) Ez a mód arra hivatott, hogy csökkentse a deadlock-ok kialakulását, de a teljesítménye némiképp hagyott kívánni valót maga után. Mint a szakirodalom is említést tesz róla, a manuális szinkronizáció nem óv meg senkit a deadlock-ok kialakulásától, én mégis ezt használtam a teljesítmény miatt. 53 Pótári Tamás Mihály .NET komponensorientált szoftverfejlesztés bemutatása egy menedzser szoftveren keresztül szolgáltatásba beágyaztam. Amire ügyelnem kellett, hogy meg tudjam különböztetni azokat a metódusokat és tulajdonságokat, melyek írási vagy olvasási mőveleteket végeznek el
a Server objektum mezıin, illetve, hogy minden zárolás után (még hiba esetén is) szabaddá kell tennem a szinkronizációs zárat. Egyszerőbb esetekben System.ThreadingInterlocked-ot használtam [28] Például a long IServerFunctions.GetNewClientID(IClientFunctions client) szinkronizáltan, Interlocked.Increment()-tel megnövelt long m ClientIDCounter-t ad vissza, ha a client által azonosított kliens nem szerepel a m MessageEventDictionary.Value-ban Ezzel is növelve a hatékonyságot. A formázásnak itt is ugyanolyan szerepe van, mint az elızıekben. A szerver objektum adatait és a kliensek adatainak listáját lehet szöveges formátumban megjeleníteni vele. A következı fejezet a Server-t használó Client komponenst jellemzi. 5.4 A kliens objektum A Client komponens példányának feladata, hogy kapcsolatba lépjen a Server objektummal, és a felhasználó üzeneteit eljuttassa ahhoz. Viszont a szerver feladata, hogy a kliens objektumot visszahívja, azaz
értesítse eseményekrıl. A rendszeremben a kliens szintén dinamikus entitás. Kicserélhetı más felhasználók által definiált kliens típusokra. Erre azért van lehetıség, mert a Server assembly nem hivatkozik a Client komponenst tartalmazó Client assembly-re (4.42 fejezet) Azaz a szervernek nincs tudomása arról, hogy milyen típusú kliens iratkozott fel az eseményeire. Csakis futás idıben szerez tudomást a szerver objektum a kliens típusáról, sıt továbbmenvén a szerveralkalmazásnak – ami a szerver komponenst példányosítja és regisztrálja a .NET remoting infrastruktúrában – nem szükséges még csak a kliens komponenst tartalmazó szerelvényhez sem hozzáférnie. Tehát 25. ábra A két kommunikáló számítógép által használt osztálykönyvtárak a jelenlegi helyzetben egy kommunikációs rendszer a 25. ábra szerint 54 Pótári Tamás Mihály .NET komponensorientált szoftverfejlesztés bemutatása egy menedzser
szoftveren keresztül épülhetne fel. Megfigyelhetı, hogy a szerverre nem kell Client assembly-t telepíteni. Viszont a kliensre ajánlott a Server szerelvényt elhelyezni, de nem kötelezı. Ez attól függ, hogy a kliensalkalmazás miként regisztrálja az igényét a távoli szerver objektum elérése kapcsán [29]. Mindezen lehetıségek azért fontosak, mert így a szerver leállítása és alkotóelemeinek újrafordítása nélkül lehet a klienseket frissíteni. Illetve új üzenet típusok bevezetésekor csak az új assembly-t kell elhelyezni a szerver számítógépen, szintén a leállítás és kódmódosítás nélkül. Ez a példa már jól tükrözi, hogy micsoda lehetıségek rejlenek a megfelelı tervezésben. 5.41 A Client komponens A Client komponens ezek után már inkább egy megvalósítási sémára hasonlít, ami az IClientFunctions-t definíciójának felel meg. Tehát a késıbbi kódfelhasználók olyan kliens osztályt tervezhetnek, amilyet csak akarnak,
a lényeg egyedül, hogy közvetve vagy közvetlenül valósítsa meg az IClientFunctions-t. Az interfészek elemzésénél már leírtam a IClientFunctions szolgáltatásait (4.41 fejezet). Ebbıl eredıen több újdonságot nem tudok felmutatni Talán sémaként lehetne tekinteni a szintén Client assembly-ben lévı IExtendedClientFunctions felületre (26. ábra) 26. ábra A kiterjesztett kliensfunkciók interfésze Az interfész két szolgáltatást definiál: feliratkozást és leiratkozást a ClientEventType-ban eseménytípusokra, felsorolt amikhez a MessageDelegate típusú delegáltat kell átadni. (Az elızı két típust a 27 ábra 27. ábra A kliens komponens által támogatott eseménytípusok és azok delegáltja 55 Pótári Tamás Mihály .NET komponensorientált szoftverfejlesztés bemutatása egy menedzser szoftveren keresztül mutatja.) Az eseménytípus enum valójában bitmezı Tehát mint korábban már más példában említettem, több eseményre
történı együttes feliratkozás így néz ki a gyakorlatban: kliens.SubscribeEvent(ClientEventTypeMessageEvent | ClientEventType.ClientConnectedEvent | ClientEventTypeClientDisconnectedEvent, new MessageDelegate(onUniformEvent)); Ahol az onUniformEvent() a Client komponenst felhasználó által elıállított metódus, ami megfelel a MessageDelegate szignatúrájának. (A kliens komponenst a 28 ábra szemlélteti.) 28. ábra A kliens komponens A Client komponens sem tartalmaz mezıkként eseményeket, azok a System.ComponentModelEventHandlerList m Events-ben sorakoznak a karbantarthatóság révén. A szinkronizáció itt is ReaderWriterLock segítségével valósult meg 56 Pótári Tamás Mihály .NET komponensorientált szoftverfejlesztés bemutatása egy menedzser szoftveren keresztül A szerverre mutató referenciát (proxyt) nem ez a komponens állítja elı, hanem készen kell megkapnia konstrukciós paraméterként. Hogy ezt hogy oldja meg egy alkalmazás,
az már a kódfelhasználóra van bízva. Szintén a programozókra van bízva a lehetıség, hogy honnan szerezzen a kliens objektumuk azonosítót (long m ClientData.ID): • Ez megtörténhet a szerver által, a diagramon jelzett elsı konstruktort választva. A konstruktor az IServerFunctions m Server inicializálását követıen meghívja annak long GetNewClientID(IClientFunctions client) szolgáltatását pataméterül adva saját referenciáját (this). Teljesen egyedi, új ID-t csak akkor kaphat a kliens, ha ı nem szerepel a szerver m MessageEventDictionary-jében. Az ID igénylés ellenben nem szerencsés dolog, mert az utóértesítendı üzeneteket ebben az esetben nem fogja megkapni. • Az ügyfélalkalmazás valami úton-módon megırzi a kliens azonosítóját és nevét. Ez már egy hasznosabb út, amit a második konstruktor tesz lehetıvé. A harmadik konstruktor már automatikus feljelentkezésre ad lehetıséget a szerver eseményeire, ami szintén hasznos
funkciója a komponensnek. 5.5 A tesztelés A tesztelésnél két alapvetı módszert alkalmaztam: a fehér-dobozos és feketedobozos tesztelést. Mindkét tesztelési módszerhez kötelezıen terveznem kellett egy kliensés szerveralkalmazást Mindkettı egyszerő konzol felülető program volt, melyek az elızıekben ismertetett formában használták a szerelvényeket. A tesztelésnél Microsoft Windows XP Professional (SP2) operációs rendszert és egy régebbi, bár ingyenes Microsoft SqlServer MSDE-t (ver. 08002039) használtam A következıkben röviden összefoglalom a rendszer-, együttmőködés- és alrendszertesztelés stratégiáját és eredményeit. 5.51 Alrendszerek tesztelése Az alrendszerek tesztelését a komponensek egyenkénti ellenırzésével kezdtem (fehér-doboz). Azaz a megfelelı konstrukciós paraméterek megadásával elkészült 57 Pótári Tamás Mihály .NET komponensorientált szoftverfejlesztés bemutatása egy menedzser szoftveren
keresztül komponenspéldányok szolgáltatásait végigellenıriztem. Például a TextMessage esetében megfigyelhettem a string ToString() mőködését és a tárolt adatokat debugger segítségével. Szintén ide sorolom a komponensek sorosíthatóságát, és azok reakcióit új verziójú típusok bevezetésekor. A megfelelı tervezésnek köszönhetıen beigazolódott, hogy a sorosítandó komponensek jól karbantarthatók, azaz új verzióik megjelenésekor megmarad a bináris kompatibilitás a régebbi típusokkal. Szintén az alrendszer teszteléséhez sorolom a MessageArchive vizsgálatát. Ez a komponens is meg tudott birkózni a paraméterül kapott adatok tárolásával és visszaolvasásával még aszinkron módon is. Az aszinkron mőködést visszahívandó metódusok delegáltjának megadásával ellenıriztem – mivel ez a leggyakoribb aszinkronhívás kezelési mód. Az adatbázis elvesztésekor tökéletesen mőködött a hibajelentı mechanizmus. Az adatbázis
visszanyerésekor pedig folytatta tovább a munkáját (Ennek a tesztnek az eredményét szemlélteti a 29. ábra) 29. ábra Az adatbázist bizonyos ideig leállítva a MessageArchive objektum jelzett, hogy az adatbázis nem elérhetı A szinkronizáció megfelelınek bizonyult, az aszinkron hívások nem okoztak inkonzisztenciát, sem az adatbázisban sem az objektumban. Ezzel a teszttel valójában ellenıriztem a SupportServices assembly EventHelper komponenst is. A Client komponens mőködése is megfelelı volt, a bitmaszkolás tökéletesen mőködött az eseményekre történı feliratkozás és leiratkozás során. Ezt több szál 58 Pótári Tamás Mihály .NET komponensorientált szoftverfejlesztés bemutatása egy menedzser szoftveren keresztül segítségével is ellenıriztem, és nem történt anomália. Az értesítések megfigyelésénél könnyített a helyzetemen, hogy több kliens objektumot hoztam létre, amik eltérı módon értesítették ugyanazt a
metódust. A Server tesztelésekor is a Client-nél alkalmazott módszert használtam. A több száltól érkezı hívásokra megfelelıen reagált a komponens. Fel és le lehetett jelentkezni, illetve eközben értesítéseket lehetett végezni. A RemotingEventHelper is megfelelıen végezte az aszinkron hívást (noha még nem tudtam szimulálni a kliensek eltőnését). 5.52 Együttmőködés tesztelés Az együttmőködés tesztelésnél legelsı lépésben a Server és Archive mőködését vetettem össze, ami szintén eredményesen zárult. A tesztelés úgy zajlott, hogy megfigyeltem milyen adatok kerülnek a szerver objektumtól az Archive-hoz és legvégül az adatbázishoz (bár ez utóbbi folyamatát az aszinkron jelleg miatt nehézkes volt a nyomon követni). Ez a tesztelés szintén magában foglalta az üzeneteket és az eseménysegítıket A kliensek és a szerver együttmőködési ellenırzése még egy kicsit váratott magára, azt a rendszertesztelésnél
végeztem, ahol már jelen volt a .NET Remoting 5.53 Rendszertesztelés Itt már alkalmazhattam a fekete-doboz módszerét is, hiszen a jövıbeli mőködési állapotukba helyeztem a komponenseket. Mindössze pár soros kódból meg lehet oldani egy egyszerő, szórt üzenettel mőködı, elosztott kommunikációs alkalmazás elkészítését. (A IV sz. Melléklet tartalmazza egy egyszerő alkalmazás elkészítésének módját) A fekete-dobozos rendszertesztnél az általam készített tevékenységdiagramokat alkalmaztam. A fehér-dobozos tesztelésnél pedig végig próbáltam a sorrenddiagramokat, beékelve néhány kritikus eseményt, mint az adatbázis kikapcsolását és egy-két kliens eltávolítását. Noha a tesztelésnél nem figyeltem fel rendellenességekre, biztos vagyok benne, hogy voltak olyan tesztesetek, amiket nem próbáltam ki. 59 Pótári Tamás Mihály .NET komponensorientált szoftverfejlesztés bemutatása egy menedzser szoftveren keresztül 5.6
Verziók és dokumentálás Már a komponensek tervezésekor figyelnem kellett arra, hogy CLS kompatibilisek legyenek, lehetıséget adva más .NET-beli nyelven készülı alkalmazások számára Ehhez minden assembly-t el kellett látnom a System.CLSCompliantAttribute-tal, mely paraméterül true-t kapott [30]. Így már kódolás közben kiderült, hogy ha nem CLS kompatibilis kódot írtam. Verziószámok elıállításánál a fordítóprogramra támaszkodtam, a szerelvényeknek System.ReflectionAssemblyVersionAttribute attribútumainak „10*” értéket adva. Így minden assembly 1.0-ás verziónak tekinthetı legelsı alkalommal, ami a késıbbiekben még módosulhat. De ami a lényeg, hogy két egyforma verziójú, utólag módosított szerelvény sosem fog keletkezni. A szerelvények erıs névvel rendelkeznek. Hagyományos módon az SNexe segítségével generáltam a vállalati kulcsokat. Noha az így kapott assembly-k privát assembly-ként is használhatóak, mégis a
jövıben a GAC-be szánom ıket fıleg a szervernél, ahol így a szerver- és egy esetleges kliensalkalmazás is közös verziójú komponenseket használhatna. Gondolván a MessageTypes-ra, megeshet, hogy a jövıben új verzió jelenik meg belıle, amit a kliensek bıszen fognak használni. De bizonyára meg fog történni azon eset is, amikor nem minden kliens fog új verziós üzenetobjektumokat küldözgetni a szerver felé. Így a szervernek ismernie kell a régi és új verziós komponenseket is – legalábbis azoknak a metaadatait, visszautalva a MessageArchive-ra – melyek elérése sokkal könnyebb a GAC-bıl. Ráadásul konfigurációs állományokkal, vagy a NET konfigurációs paneljével könnyedén lehet egyéni verziókövetési szabályoknak alárendelni az alkalmazásokat (verzió átirányítás [31]). Némiképp a biztonságról is említést kell tennem, noha a szakdolgozatom nem öleli fel a .NET biztonság témát Az erıs nevő assembly-khez hozzá
kellett rendelnem a System.SecurityAllowPartiallyTrustedCallersAttribute attribútumot, annak érdekében, hogy az erıs névvel nem rendelkezı szerelvények is el tudják érni azokat – ez a távelérés esetén nélkülözhetetlen. A dokumentálásnál nagy segítséget nyújtott a Visual Studio, hiszen automatikusan elkészítette számomra az osztálydiagramokat. Szintén hatékony fegyver a fejlesztés közben használható dokumentációgeneráló, mely a minden típushoz hozzárendelt összegzést külön .xml állományba mentette Az állomány, párosulva a szerelvényével, interaktívan 60 Pótári Tamás Mihály .NET komponensorientált szoftverfejlesztés bemutatása egy menedzser szoftveren keresztül megkönnyítheti a kódfelhasználók dolgát, hiszen nem kell szöveges fájlokban kutakodniuk, a keresendı típus vagy annak szolgáltatásainak leírását igényelve. Ráadásként, egy idegen nyelvő dokumentáció elıállítása csak az xml fájlban lévı
megjegyzések átírását követelné meg. 5.7 Összefoglalás Jogosan merülhet fel a kérdés, hogy mire jó az általam tervezett komponensgyőjtemény. Itt kell kijelentenem, hogy nem csak Chat-re, azaz szöveges üzenetküldözgetésre szolgál. Mint említettem, ez egy kommunikációs infrastruktúrát magában foglaló rendszer, ami a .NET Remoting-ra épül Szintén említést tettem róla, hogy az „üzenet” bármi lehet. Érdemes belegondolni, hogy egy „egyszerő” interneten közösen játszható kártyajáték, például egy Póker játék, hogyan készülne el. A programozónak mindenképp ki kell találnia egy kommunikációs formát, például remoting-gal vagy hagyományos socketekkel. Majd csak ezt követıen vághat bele a tényleges pókerparti tervezésébe, illetve a kezelıfelület megalkotásába. A komponenseimmel egy jelentıs problémának a megoldására lelhet a programozó. Hiszen nem kell sokat tennie azért, hogy aktiválja az
objektumokat illetve, hogy új üzenet típusokat hozzon létre – mint például a kártya és a tét üzenet. Viszont mindenki számára nem szükséges az „Üzenetek archiválása” feladat. Például egy pókerparti számára egyenesen fölösleges. Ebbıl eredıen a Delphoi Kft piacra dobhat Low Edition változatot is a komponensgyőjteménybıl, mely nem tartalmazza az Archive komponenst. Ellenben kiadhat egy Professional Edition változatot, melyben már egyéni fejlesztéső komponensszolgáltatások (környezeti attribútumok [32]) végeznek naplózást, híváselfogás alapján. Ez nagymértékben megkönnyítené a fejlesztık dolgát és segítene nekik az alkalmazásuk karbantartásában. 61 Pótári Tamás Mihály .NET komponensorientált szoftverfejlesztés bemutatása egy menedzser szoftveren keresztül 7. A menedzser alkalmazás modellezése A dolgozat elején említett gépipari vállalat újonnan szerzıdtetett szakemberei némiképp hiányos
követelményeket vázoltak fel a pályázati kiírásban. De miután a pályázatot megnyerte a SecretRoom Bt. a szoftverfejlesztıi és menedzserei azon nyomban munkának láttak. A fı feladat a követelmények pontosítása és tisztázása volt, a többi procedúra mellett – mint a megvalósíthatósági tanulmány stb. 7.1 A követelménymodellezés A dolgozatomban a 4.2-es fejezet is ilyen címet viselt, de az ott leírt fogalmak már nem fognak megismétlıdni. 30. ábra A menedzser alkalmazás feladatdiagramja A követelmények elıállításában a képzeletbeli gépipari vállalat mérnökei és a megbízott szoftverfejlesztı cég mőszaki menedzserei vettek részt. A munka eredménye 62 Pótári Tamás Mihály .NET komponensorientált szoftverfejlesztés bemutatása egy menedzser szoftveren keresztül egy mindent magába foglaló feladatdiagram (30. ábra) és több szöveges feladatleírás, melyek a dinamikus viselkedésmodellezésnél tevékenység- és
sorrenddiagramokká alakultak. A feladatdiagram itt is a mőködésbeli követelményeket ábrázolja A feladatdiagram egy része nagyban hasonlít a Delphoi Kft. által kínált kommunikációs komponensek feladatdiagramjára, noha a SecretRoom csak késıbb, a dinamikus viselkedésmodellezést követıen fog ténylegesen komponenseket vásárolni. Itt újból meg kell említenem, hogy a dolgozat története a képzeletem szüleménye, melyben ilyen véletlen egybeesések megeshetnek. 7.2 Dinamikus viselkedésmodellezés Szintén szerepelt ilyen fejezet a dolgozatomban, így a 4.3-as fejezet fogalmai nem fognak megismétlıdni. Természetesen az általam tervezett alkalmazást is modellezni kellett mőködésében és viselkedésében. A dinamikus modellezést viszont úgy végeztem el, hogy nem vettem tudomást a már elkészített kommunikációs komponensekrıl, ugyanis kíváncsi voltam, hogy milyen mértékben kellett volna megváltoztatni a modelljeimet, amikor igénybe vettem
a már elıre elkészített építıelemeket. Szerencsére minimális változtatásokat kellett alkalmaznom, azaz a kommunikációs komponenseim pontosan azokat a feladatokat látják el, amelyekre az alkalmazásomnak szüksége van. Viszont a határidınapló egy teljesen új feladatcsoportot foglal magában, melyre nem terjed ki a képzeletbeli Delphoi Kft. komponens győjteménye. Rövid idejő modellezést és elméleti munkát követıen rá kellett ébrednem, hogy a kommunikációs komponensek és azok adatbázisa (üzenet archívum) nem használhatóak a határidınapló problémáinak megoldására. A 31. ábra tevékenységdiagramja ábrázolja egy határidı felvételét és lehetséges közzétételét. 63 31. ábra Új határidı felvételének tevékenységdiagramja Pótári Tamás Mihály .NET komponensorientált szoftverfejlesztés bemutatása egy menedzser szoftveren keresztül A modellezés e pontján már világossá vált számomra, hogy adatkezelı
komponenseket kell készítenem, még az alkalmazás megvalósítása elıtt. De a komponensek elkészítése hasonló mintát követ, mint a kommunikációs építıelemeké, így azok használata már ennél a pontnál praktikussá vált. Tehát a dolgozatom képzeletbeli történetét követve a SecretRoom Bt. ekkor vásárolta meg a Delphoi Kft termékét 7.3 Mit kapott a Secret Room? A kisvállalkozás a komponensek megvásárlásakor nem a forráskódot kapta meg, csupán a szerelvényeket és azok dokumentumait, mellékelve néhány példaprogramot, amely a komponensek alapvetı felhasználási módját szemlélteti (IV. sz Melléklet) Felmerülhet a kérdés, hogy a SecretRoom Bt. a forráskód nélkül, hogyan tudna bármiféle frissítést vagy javítást végrehajtani a vásárolt terméken. A válasz: sehogy Ahhoz, hogy a megvásárolt komponenseken módosításokat végezzen el, jeleznie kell az igényét a Delphoi Kft. felé, aki a karbantartási munkát elvégzi –
persze, csak ha ténylegesen szükséges –, és megfelelı szaktanácsadást nyújt. Természetesen ekkor egy új verzió lát napvilágot az érintett szerelvényekbıl. Jelenlegi helyzetben a SecretRoom-nak tökéletesen megfelelnek a komponensek nyújtotta szolgáltatások a késıbbi munkához. Ami talán feltőnhet a betéti társaság fejlesztıinek, hogy a megvásárolt osztályok hasznavehetetlenek az interfészeik nélkül. Ebbıl eredıen csak az interfészeken keresztül lehet ıket alkalmazni, mely némiképp nehezítheti a felhasználást. A másik furcsaság az lehet, hogy a komponensekbıl nem lehet származtatni, bár erre nem is volt szükségük a késıbbiekben. 7.31 Mennyibe került a termék? Napjainkban, amikor az ingyenes, nyílt forráskódú rendszerek fejlıdésének és terjedésének világát éljük, igen nehéz árakról beszélni. Mégis a kommunikációs építıelemekben a Delphoi Kft. szellemi munkája lakozik, melyért igenis joga van pénzt
kérni. 64 Pótári Tamás Mihály .NET komponensorientált szoftverfejlesztés bemutatása egy menedzser szoftveren keresztül Ez utóbbi kijelentésem egyesekbıl ellenszenvet válthat ki, viszont érdemes elgondolkozni a következın: Ha 1 órának vesszük a kommunikációs komponensek fejlesztésének teljes idıtartamát – a modellezéstıl, a tesztelésig – akkor a SecretRoom által fejlesztett alkalmazás elıállítása – ami ezen építıelemekre épül – csupán 10 perc lenne. Ha pedig nem lennének „elıre legyártva” a felhasznált építıelemek, akkor valószínőleg a kisvállalkozásnak kellene elkészítenie azt, ami jelentıs idıbe és pénzbe kerülhet, fıleg akkor, ha nem elosztott alkalmazások tervezésével töltik a mindennapjaikat a fejlesztık. Ez az elızı hasonlat némiképp tükrözi az idımennyiségek eloszlását, amelyet a komponenseim és az alkalmazás megvalósításával töltöttem. Jogosan merülhet fel a kérdés, hogy
mennyi idıbe telt volna az egész szakdolgozati projektem elkészítése, ha egy „Solution”-ben, objektumorientáltan állítottam volna elı azt. A dolgozatom bevezetıjében említett objektumorientált fejlesztési módot követve, valószínőleg gyorsabb lett volna a fejlesztés, hiszen nem kellett volna általánosságokban gondolkoznom. Minden metódus „konkrét” típusú paramétereket kapott volna, és adott volna vissza – gondolok itt a győjteményeket váró és visszaadó metódusokra, ahol az ICollection helyett már ArrayListet használhattam volna. A SupportServices assembly lehet, hogy meg se született volna A benne szereplı EventHelper-ek szolgáltatásai nyilvánvalóan UniformDelegate típusokat vártak volna, sıt lehetséges, hogy a győjteményeket teljességgel nélkülözték volna. Interfészekkel se kellett volna foglalkoznom, noha így teljesen más felépítésmodellezést kellett volna használnom. Gyorsabb és könnyebb objektumorientáltan
fejleszteni, mint komponensorientáltan, de nehezen karbantartható és rendkívül összetett rendszert kaptam volna, melynek alig lenne olyan osztálya, ami más projektekben újrahasznosítható lehetne. 65 Pótári Tamás Mihály .NET komponensorientált szoftverfejlesztés bemutatása egy menedzser szoftveren keresztül 8. A menedzser alkalmazás NET-beli kivitelezése A kommunikációs komponensek meglétével már egyszerő volt egy Windows Forms alapú alkalmazás összeállítása. Mégis, aki elosztott alkalmazást szeretne készíteni számolnia kell néhány problémával. Ezeket a problémákat a határidı kezelı bemutatása után szemléltetem. 8.1 A határidınapló komponensei Ahhoz, hogy tárolni tudjam a határidıket a kommunikációs komponensek használta adatbázisban, néhány táblával és egy tárolt eljárással kellett kibıvítenem azt. Mindezek mellett újabb adatbázis kezelı komponenseket kellett alkotnom, melyeknek
különlegességük, hogy kiszolgáló által aktivált, egyszer hívható objektumokként mőködnek. (A komponensek interfészeit a 32 ábra szemlélteti) 32. ábra Az ArchiveHandler névtér interfészei 66 Pótári Tamás Mihály .NET komponensorientált szoftverfejlesztés bemutatása egy menedzser szoftveren keresztül 8.11 A határidı komponens A Deadline komponens (33. ábra) és az elıbb ábrázolt interfészek is az ArchiveHandler névtérben helyezkednek el négy külön szerelvényben. Ennek a szétszórtságnak és interfész centralizáltságnak az oka ugyanaz, mint a kommunikációs komponenseknél volt. A határidı komponens különálló (Deadline) szerelvényben helyezkedik el, hasonlóan a MessageTypes assembly típusaihoz. Noha nem az IUniformMessage-bıl származik, üzenetként kezeli ráadásul hasonló implementál, 33. ábra A határidı komponens mégis a mint határidınapló a Deadline-t, interfészeket például a
Communication.TextMessage 8.12 A határidı kezelı és az üzenetolvasó komponens A DeadlineArchive és a MessageArchiveHandler különleges komponensek, ugyanis nincsenek mezıik. Ezek a komponensek a szolgáltatásaikból „élnek”, azaz ha meghívódik egy metódusuk, akkor épül fel az adatbázis kapcsolat, az adatbázis lekérdezı parancs, és ugyanakkor hajtódik végre a lekérdezés, illetve az adatbázis módosító utasítás is. Ennek a legfıbb oka, hogy a komponensek egyszer hívható objektumként üzemelhessenek. Minden távoli hívás lebonyolításakor létrejön egy példány belılük, végbemennek az elızıleg elsorolt mőveletek, majd elpusztulnak. A DeadlineArchive egy önálló komponens melynek feladata: határidık tárolása és kinyerése, határidı tulajdonosok kiolvasása. A MessageArchiveHandler viszont a Communication.Archive-re támaszkodik Létrehozza egy példányát a hívás közben és igénybe veszi annak üzenetolvasó
szolgáltatásait. Így mondhatni, hogy az Archive-nak egy távoli példánya jön létre, igaz csak közvetetten. 67 Pótári Tamás Mihály .NET komponensorientált szoftverfejlesztés bemutatása egy menedzser szoftveren keresztül 34. ábra A határidı kezelı és az üzenetolvasó komponens 8.2 A Windows Forms és a szálaffinitás A fejezet bevezetıjében említett problémák leírása itt kezdıdik. Közismert tény, hogy a Windows Forms és alaposztályainak példányai csak arról a szálról17 érhetıek el, amely létrehozta ıket. Ellenkezı esetben a próbálkozás futásidejő kivételhez vezet Amikor a szerver objektum távoli visszahívást végez, mondhatni, hogy az a kliensnél külön szálon történik meg, mely nem manipulálhatja az UI szál által létrehozott vizuális objektumokat. Ilyen problémákra szolgál a System.ComponentModelISynchronizeInvoke [33] felület, melyet a System.WindowsFormsControl komponens és minden leszármazottja
megvalósít. A szolgáltatásai révén más szálak is képesek állapotmanipuláló metódusokat indítani egyéb szinkronizációs kód írása nélkül. Legegyszerőbb esetben elég volt az ISynchronizeInvoke.Invoke()-nak paraméterül adni a végrehajtandó metódus referenciáját és annak paramétereit. Ehhez a módszerhez folyamodtam, amikor kezelni kellett a szervertıl érkezı üzeneteket. Némiképp idıigényes volt a delegáltakkal történı munka, de így nem kellett 17 A Form-okat létrehozó szálat nevezhetjük UI szálnak. 68 Pótári Tamás Mihály .NET komponensorientált szoftverfejlesztés bemutatása egy menedzser szoftveren keresztül szinkronizációval foglalkoznom, hiszen a dialógusaim nem kerülhetnek inkonzisztens állapotba. Noha a szakirodalomban nem találtam rá magyarázatot, a Windows Forms-ból kinyert információkat (még ha azok értéktípusok is voltak), bizonyos esetekben a távoli szerveralkalmazás nem tudta feldolgozni. Ebbıl
eredıen egy-két alkalommal kerülı utat kellett bejárnom. 8.3 Az ablakok kivitelezése Az ablakok komponenseinek fejlesztésénél nagy figyelmet fordítottam azok telepítési modelljére, azaz a szerelvényeikre. Itt is ugyanaz volt a célom, hogy jól karbantartható alkotóelemek szülessenek. A komponensek, pontosabban azok fontos szolgáltatásai interfészeken keresztül érhetık el, habár a felületek nem explicit lettek implementálva a kommunikációs komponensekkel ellentétben. (A 35 ábra szemlélteti az interfészeket a szerelvényeikkel) 35. ábra A menedzser alkalmazás interfészei és metódusreferencia típusai, szerelvények szerint csoportosítva 69 Pótári Tamás Mihály .NET komponensorientált szoftverfejlesztés bemutatása egy menedzser szoftveren keresztül (A V. sz Melléklet nagyobb méretben tartalmazza a fenti ábrát) Könnyen észrevehetı, hogy az IManagerApplicationForm interfész a domináns a felépítésben, hiszen ı kezeli a
többi felületet, pontosabban azok megvalósításait. Szintén észrevehetı, hogy léteznek a modellben üres interfészek. Némiképp a szabványosság vett rá arra, hogy üresen álló interfészek is létrejöjjenek, de elsısorban a jövıre gondolva alkottam meg ıket. Hiszen ha a jövıben újabb szolgáltatásokkal kell kibıvítenem a komponenseket, akkor újabb interfészeket már nem lesz kötelezı létrehoznom, ami némiképp a karbantarthatóságot javítja. Az IConfiguration interfész konfigurációs adatokat tároló komponensek interfésze, ami egyéni sorosítást valósít meg, így a verziókövetésnek is megfelel. Az IMessageCenterForm a központi ablak interfész, melyen aktiválható a többi szolgáltatás. Az IDeadlineHandlerForm leírja a határidınaplót, ami rendelkezik egy listával mely határidı objektumok győjteményével frissíthetı. Az IDeadlineNotifyForm a határidık értesítését teheti lehetıvé az implementáló komponensen
keresztül. Az IDeadlineMakerForm a határidık létrehozásáért felelıs. A határidınapló beállításait a IDeadlineConfigurationForm szolgáltatásai teszik lehetıvé. A határidık és üzenetek dátum szerinti lekérdezését (vagy létrehozását) az ICalendarForm biztosítja, melynek implementációja egy dátumválasztót rejt magában. Az elızıekben többször hivatkozott szolgáltatások elsısorban események. Az egész alkalmazás események hálózata, mely biztosítja az egységek függetlenségét (fizikai függetlenségét). Így a komponensek nem egymásra épülnek, azaz közvetlenül hozzák létre egymás példányait, hanem egy központi (IManagerApplicationForm típusú) objektum események hatására alkotja meg azokat. A diagramban szereplı típusok a Messaging névtér tagjai, melybe még néhány fontosabb típus is beletartozik, melyeket a diagramon nem ábrázoltam. Ezek a hiányzó típusok J# programozási nyelven lettek kivitelezve, és az
üzenetek megírására és megtekintésére szolgálnak. İket a következı fejezetben mutatom be Az ablakok felépítése egyszerő, „minden egy helyen” típusúak. Némiképp hasonlítanak a webes felületekhez. A halványkék színvilág a SecretRoom Bt logoja Fontos újból hivatkoznom rá, hogy a szakdolgozati munkámnak a lényege a komponensorientált szoftverfejlesztés bemutatása .NET alatt. Ebbıl eredıen a dolgozatomban nem térek ki részletesebben a felhasználói felületek kivitelezésére, és a Windows Forms-ból eredı (további) problémákra. 70 Pótári Tamás Mihály .NET komponensorientált szoftverfejlesztés bemutatása egy menedzser szoftveren keresztül 8.4 Fejlesztés J# nyelven A dolgozatomban említést tettem a .NET alatti többnyelvő fejlesztés lehetıségérıl, ebben a fejezetben a gyakorlati alkalmazásáról írok. A C# mellett a napjainkban szépen fejlıdı J# -ot választottam „társ nyelvnek” a fejlesztésben. A
NET-beli Java nyelv már a Visual Studio 2003 óta támogatott, mely szintaxisában hasonló a Java-hoz, és a Java programozók .NET alatti fejlesztését hivatott megkönnyíteni. Noha a dolgozatomban csupán egy szerelvény (MessagingForm) készült el J# nyelven, mégis érdekes és izgalmas kihívásnak bizonyult. Megismerkedtem a J#-beli események létrehozásával és kezelésével. Szintén megtanultam, hogy a tulajdonságok milyen formában használhatók és hogyan hozhatóak létre úgy, hogy egy C#-os kód használhassa azokat. Új referencia típusokat, interfészeket és delegáltat is alkottam, mindazonáltal automatikus verziószámmal láttam el a szerelvényt (36. ábra) 36. ábra A MessagingForm szerelvény interfészei Érdekességképpen megjegyzem, hogy nem nehéz a fejlesztés a J# nyelvvel, de a .NET alapismeret nélkülözhetetlen hozzá Hiszen egy Java fejlesztınek mégiscsak tudnia kell a .NET-beli metódusreferenciákról és a szerelvényekrıl annak
érdekében, hogy egy 71 Pótári Tamás Mihály .NET komponensorientált szoftverfejlesztés bemutatása egy menedzser szoftveren keresztül MessagingForm-hoz hasonló szerelvényt készíthessen. Pozitívumként kell megemlítenem, hogy a Windows Forms Designer és a Class Diagram, azaz a VS szolgáltatásai szinte teljes mértékben megegyeznek a C# alatti fejlesztésnél megszokottakkal, A negatívumnak számítanak a C#-ban megszokott egyszerő dokumentálás hiányosságai és a telepítési kényelmetlenségek. Ugyanis ha valaki csak a NET Framework-ot telepíti a számítógépére, nem biztos, hogy képes lesz futtatni a J#-beli kódot. Ahhoz ugyanis még egy .NET kiegészítıt kell installálnia 8.5 A szerelvények és kapcsolataik 37. ábra A menedzser alkalmazás szerelvényei és azok kapcsolatai Az elızıleg ismertetett szerelvények kapcsolatai (37. ábra) könnyedén átláthatóak, hiszen, mint ahogy már korábban már utaltam rá a központban a
ManagerApplication futtatható assembly áll. A ServerApplication is szintén egy futtatható állomány, ami csak futás idıben hivatkozik a diagramban látható szerelvények némelyikére. Ezt ugyan nem jelöltem a diagramon, mivel túl bonyolulttá válna az. Szintén ebbıl az okból kifolyólag nem jelöltem a felhasznált kommunikációs komponensek szerelvényeit, bár nem nehéz elképzelni, hogy szinte minden diagram elem az Interfaces assembly-re hivatkozik. 72 Pótári Tamás Mihály .NET komponensorientált szoftverfejlesztés bemutatása egy menedzser szoftveren keresztül Ezek a szerelvények nem rendelkeznek erıs névvel, mivel még úgymond fejlesztés alatt állnak. 9. Az alkalmazás telepítése és karbantartása A SecretRoom Bt. az alkalmazás elkészítésével egy prototípust nyújtott át a gépipari vállalat mérnökeinek. A telepítést a fejlesztıcég végezte el, a megrendelı vállalat rendszergazdáival közremőködve – beavatva ıket a
telepítés és konfigurálás rejtelmeibe. Ebben a fejezetben az alkalmazás telepítési modelljét és módját mutatom be röviden, majd egy egyszerő karbantartási mőveletet végzek el annak egyik pontján. 9.1 Mit használ a kliens, és mit használ a szerver? Az interfészek és megvalósításaik szétválasztása lehetıséget adott arra, hogy függetlenné tegyek szerelvényeket a kliens és a szerver között (38. ábra) A NET Remoting erre természetesen több lehetıséget is kínál [34], de ha tervezéskor nem éltem volna ezzel a hasznos modellel, akkor valószínőleg a Server szerelvényt a kliensalkalmazásnál is el kellett volna helyeznem. (Ennek kliensalkalmazásnak 38. ábra A kliens- és szerveralkalmazás által használt állományok az oka, hogy a fordításkor a és futásidıben is szüksége van a Server komponens metaadataira.) Így mondhatni, hogy a kliens elıl rejtve marad minden, azaz az implementáció és az adatbázis is. Ez
esetben a kliens semmit se tud az adatbázisról és a szerver is szabadon frissíthetı, módosítható kliensoldali beavatkozás nélkül. Még a szerver objektum aktiválási módja (Singleton vagy SingleCall) is titkos marad, ami egy újabb kulcs a skálázhatósághoz. 73 Pótári Tamás Mihály .NET komponensorientált szoftverfejlesztés bemutatása egy menedzser szoftveren keresztül A szerver szintén vak, semmit se tud a kliens típusáról, így a kliensek szabadon fejleszthetıek a szerver módosítása, sıt leállítása nélkül. Az üzeneteket már meg sem említem, hiszen a szerver és az archiválója nem törıdik az üzenet típusával, csak futásidıben kell megszereznie az üzenetek meta információit (esetleg azok IL-jeit). Ezt pedig a GAC-ben tárolt üzenettípusok szerelvényei könnyen áthidalhatják. Mint észrevehetı, minden a jól definiált, központilag elhelyezett interfészeken múlott. 9.2 A telepítés és konfigurálás Az alkalmazás
telepítése és konfigurálása némiképp bonyolult, amit egyetlen telepítıprogram elindításával nem lehet elvégezni. Noha a konfigurációs állományok, perzisztens állományok és a szerelvények a megfelelı helyre települnek, a szerver installációs csomagjában lakozó adatbázisról még gondoskodni kell. Ha a kliensek és a szerver(ek) telepítése megtörtént, még el kell végezni a konfigurációkat; az URL-ek és URI-ket meg kell adni a .config fájlokban 9.21 A szerver telepítése és konfigurálása Logikusan két telepítı csomag látott napvilágot, melyet a Visual Studio-val állítottam elı. A szervertelepítı az elızıekben szemléltetett ábra (38 ábra) elemeit tartalmazza. 39. ábra A GAC tartalma a szerelvények telepítését követıen 74 Pótári Tamás Mihály .NET komponensorientált szoftverfejlesztés bemutatása egy menedzser szoftveren keresztül A telepítést követıen a SecretRoom Bt. féle szerelvények és egyéb file-ok a
megadott elérési útvonalra települnek, de a Delphoi Kft. szerelvényei a GAC tagjai lesznek (39. ábra) Így ezeket a assembly-ket más alkalmazások is elérhetik, sıt a GAC-be azonos nevő, bár más verziószámú szerelvények is telepíthetık. Mint azt korábban említettem manuálisan kell feltelepíteni az adatbázist, és az adatbázis ConnectionString-jét bele kell írni a databaseConnectionData.xml állományába A ServerApplication.execonfig konfigurációs állomány a NET Remoting adminisztratív konfigurációját segíti [35]. Benne szerepelnek az aktiválandó típusok, az aktiválási módok, a csatorna típus és annak portja, illetve a formázási mód. 40. ábra A ServerApplicationexeconfig konfigurációs állomány és a távoli objektumok regisztrálása (Érdemes megfigyelni az erıs és barátságos névvel rendelkezı szerelvények hivatkozásait) A konfigurációs állományban (40. ábra) az erıs névvel rendelkezı szerelvényre (Server) teljes
névvel kell hivatkozni (már ha az a GAC-ben van), ami a kultúrán és a nyilvános kulcson kívül magában foglalja a pontos verziószámot is. Mint látható, a nem erıs nevő szerelvényekre elég csak a „barátságos nevükkel” hivatkozni18. Tehát ha egy újabb verziója kerül ki a Server-nek, akkor a konfigurációs állományt át kell írni a verziószámnál. Természetesen új verzióról is vissza lehet lépni régebbire Összegezve: ez lehetıség szintén egy kulcs a skálázható alkalmazások építéséhez. 18 Nem véletlen, hogy a menedzser alkalmazás komponensei nem rendelkeznek erıs névvel, hiszen így is megpróbáltam szemléletesebbé tenni, hogy mekkora különbségek vannak az erısnevő és barátságos nevő assembly-k között, illetve, hogy milyen lehetıségeket kínálnak az osztott assembly-k a privát társaikhoz képest. 75 Pótári Tamás Mihály .NET komponensorientált szoftverfejlesztés bemutatása egy menedzser szoftveren
keresztül 9.22 A kliens telepítése és konfigurálása A kliensek telepítése már egyszerőbb az adatbázis hiányában. Persze a Delphoi Kft szerelvényei itt is a GAC-ben lesznek elhelyezve. Itt viszont a konfigurációs állomány tartalmazza a távoli objektumok URL/URI-ját (41. ábra) 41. ábra A ManagerApplicationexeconfig konfigurációs állomány és a távoli objektumokra történı hivatkozás (Itt már nem szükséges az erıs nevő hivatkozás, a szerver dönti el, hogy milyen verziójú objektumot tesz elérhetıvé) 9.3 Egy egyszerő karbantartási mővelet Még korábban amikor az Archive szerelvényt bemutattam, kitértem rá, hogy a MessageArchive Microsoft Sql Server specifikus. Azt is említettem, hogy alig van akadálya annak, hogy egy olyan komponenst alkossak, ami ODBC-n vagy OLEDB-n keresztül egy Oracle adatbázist érjen el. De ha elkészítem ezt az új komponenst, hogyan fogom implementálni a rendszerembe anélkül, hogy a Server és az
ArchiveHandler assembly-t újra kellene fordítanom? Itt jön a képbe a GAC ereje. A GAC osztott assembly-k tárolója, amelyben a szerelvények más alkalmazásokból egyszerre is elérhetıek, és nem lehet úgymond felülírni ıket (DLL hell). Felülírást nem lehet végezni, de verzió felülbírálást igen, ezt hívják egyéni verziókövetési szabálynak. Például a GAC-be telepített Archive (1.0269031305) assembly mellé be lehet telepíteni egy Oracle orientált Archive-ot (1.0269040113) Ehhez a NET Configuration 76 Pótári Tamás Mihály .NET komponensorientált szoftverfejlesztés bemutatása egy menedzser szoftveren keresztül segédalkalmazás könnyedén alkalmazható. Ugyanitt megadható a 10269031305-ás Archive átirányítása újabb verzióra: 1.0269040113 (42 ábra) 42. ábra Az Archive szerelvény verzióátirányítása, ami azt eredményezi, hogy az Archive-ot használó más alkalmazások és szerelvények újrafordítás nélkül veszik
használatba az új Archive-ot. Innentıl kezdve a Server és az ArchiveHandler szerelvény az 1.0269031305-ás Archive-ra hivatkozik, de mégis a 1.0269040113-est kapja kézhez. A databaseConnectionData.xml állományt módosítva (verziószám és kapcsolati karakterlánc), máris csatlakozhat a szerver az Oracle adatbázishoz. Persze minderrıl a kliensek semmit se tudnak. Ami a legszebb az egészben, hogy a rendszergazdák képesek így az alkalmazást dinamikusan frissíteni régebbirıl újabb verzióra, újabb verzióról régebbire (ha hibás az új assembly). A nem erıs nevő privát szerelvényeket persze hagyományos fájl felülírással lehet lecserélni, ami sajnos rendkívül kockázatos, és gondoskodni kell a régebbi verzió megırzésérıl, illetve arról, hogy más alkalmazás ne használja azt a szerelvényt. 77 Pótári Tamás Mihály .NET komponensorientált szoftverfejlesztés bemutatása egy menedzser szoftveren keresztül 9.4 A tesztelés
Valójában a tesztelést egy részét már a kommunikációs komponensek vizsgálatakor elvégeztem. Az újabb archiváló komponenseket szintén egyenként teszteltem, megfigyelve az adatbázisba kerülı adatokat. A vezérlés és a kezelıfelület is megfelelıen mőködött, bár a további fejlesztés és finomítás indokolt lehet a késıbbiekben. A karbantartási problémák leküzdésekor szintén megfigyeltem a rendszer viselkedését (fekete-doboz). Az alkalmazás fejlesztése egy számítógépen történt és itt is zajlott a fejlesztés közbeni ellenırzés. Természetesen a végsı tesztelést két, lokális hálózatba kapcsolt számítógépen is elvégeztem. Mint érezhetı, a dolgozatom közel 60-70%-át teszi ki a kommunikációs komponensek modellezésének, kivitelezésének és tesztelésének bemutatása. A menedzser alkalmazás csak egy „végtermék” ami az elıre elkészített komponenseken alapul. Dolgozatomban a SecretRoom Bt. módszerét akartam
bemutatni, miszerint; gazdaságos dolog már elıre legyártott alkotóelemekre támaszkodni. A Delphoi Kft-nek pedig egyenesen jövedelmezı eladható komponenseket tervezni az alkalmazásaihoz, a komponensorientált szoftverfejlesztés segítségével. 78 Pótári Tamás Mihály .NET komponensorientált szoftverfejlesztés bemutatása egy menedzser szoftveren keresztül 10. Összefoglalás A szakdolgozatomban betekintést nyújtottam a komponensorientált szoftverfejlesztésbe a Microsoft .NET Framework segítségével Szemléltettem, hogy milyen gazdasági jelentısége van, ha egy vállalat más alkalmazásokban újrahasznosítható építıelemeket tervez saját szoftvereihez, és ha ezen komponenseket késıbb el is adja más szoftverfejlesztı cégeknek. Munkám eredményei nagyrészt a kommunikációs komponensek, azaz elosztott alkalmazásokban felhasználható, kommunikációs infrastruktúrát biztosító építıelemek voltak. Az alkotóelemek tervezésekor
ismertettem a követelménymodellezést, a dinamikus viselkedésmodellezést, a felépítésmodellezést és ezek jelentıségét az UML segítségével. Majd ezt követıen részletesen elemeztem a .NET-beli megvalósítást, szem elıtt tartva a komponensorientált programozás alapelveit és a gazdasági szempontokat. Végezetül a .NET Remoting-on alapuló komponenseket egy menedzser alkalmazás elkészítésnél használtam fel. A kis alkalmazás modellezésének és kivitelezésének elemzését követıen, egy egyszerő karbantartási mőveletet végeztem el azon, szemléltetve, hogy a megfelelı tervezés egy jól karbantartható terméket eredményez. A dolgozatom egy különleges történetet foglal magában, melyben fejlesztıcégek termékei cserélnek gazdát, egy végsı cél elérése érdekében. Ez a történet csupán fikció, a képzelet szüleménye, de bízom benne, hogy érthetıbbé és élvezetessé tette a munkám bemutatását. 79 Pótári Tamás Mihály
.NET komponensorientált szoftverfejlesztés bemutatása egy menedzser szoftveren keresztül I. sz Melléklet Az M43. ábra az üzenet küldés és fogadás eseményfolyamát ábrázolja A modell a lehetséges kivételes események bekövetkezésére is fel van készülve. Természetesen az összes hibalehetıségre nem lehet kezelıket építeni, hiszen még az alapos tervezés is figyelmen kívül hagyhatja azokat. Ennél a pontnál már újabb ötletekkel gazdagodtam és nemcsak a statikus felépítés modellezés, hanem a kódolás kapcsán is, hiszen elıre tudtam, hogy milyen kivételeket illetve kivételkezelést kellett alkalmaznom a kódolásnál. M43. ábra A kivételkezeléssel ellátott üzenet küldés és fogadás tevékenységdiagramja Fontos megjegyeznem, hogy az üzenetek archiválása tevékenység (ami a feladatdiagram egy különálló feladatának lépése) az értesítést követıen kerül végrehajtásra. 80 Pótári Tamás Mihály .NET
komponensorientált szoftverfejlesztés bemutatása egy menedzser szoftveren keresztül Ennek a legfıbb oka, hogy az üzenettárban külön tárolódnak el az utóértesítendı üzenetek az egy vagy több nem elérhetı ügyfél késıbbi bejelentkezéséig. Ha az értesítés elıtt lennének az üzenetek eltárolva, akkor nem tudnánk utóértesítést végezni. 81 Pótári Tamás Mihály .NET komponensorientált szoftverfejlesztés bemutatása egy menedzser szoftveren keresztül II. sz Melléklet Az M44. ábra bemutat egy olyan sorrenddiagramot, amelyen a kliensek üzenetet küldenek egymásnak. M44. ábra Két kliens egymásközti üzenetküldésének sorrenddiagramja A diagram érdekessége, hogy egy kapcsolati hiba van beiktatva, így a Server objektum nem tudja értesíteni a nem elérhetı kliens objektumot. A kapcsolati hiba – mint ahogy a diagram megjegyzése is leírja – többféleképpen is elıidézhetı: kliens számítógép 82 Pótári Tamás Mihály
.NET komponensorientált szoftverfejlesztés bemutatása egy menedzser szoftveren keresztül leállása, hálózati kapcsolat meghibásodása, stb. A Server objektumnak kezelnie kell a hibát, és jeleznie kell azt a küldı ügyfél felé. Ezt követıen a nem kézbesített üzenetet el kell tárolnia a nem elérhetı felhasználó számára, utóértesítésre. Újból meg kell jegyeznem, hogy az üzenetküldést aszinkron módon (egyidejőleg) hajtja végre a kiszolgáló objektum, és egy esetleges kliens oldali kivétel (legyen az kapcsolati hiba) legrosszabb esetben csak 1-2 másodperc múlva jelentkezik. Ez idı alatt már rengeteg üzenetküldési tranzakció bonyolódhat le, melyet nem lehet blokkolni. Tehát a kiszolgáló objektumot úgy kellett megterveznem, hogy ne várja meg minden üzenet sikeres kézbesítését. 83 Pótári Tamás Mihály .NET komponensorientált szoftverfejlesztés bemutatása egy menedzser szoftveren keresztül III. sz Melléklet A rendszer
fı interfészei és azok kapcsolatai. 84 Pótári Tamás Mihály .NET komponensorientált szoftverfejlesztés bemutatása egy menedzser szoftveren keresztül IV. sz Melléklet A mellékletben bemutatom egy egyszerő elosztott rendszer elkészítését a komponenseim segítségével. Az M45 ábra mutatja a ClientApplicationexe kódját Természetesen azokat az assembly-ket kell referenciául adni, amelyekrıl már szó esett az 5.4-es fejezetben A konfigurációs állomány csatolva van a szerelvényekhez M45. ábra A kliensalkalmazás kódja A szerver alkalmazás kódja lényegesen egyszerőbb (M46. ábra) M46. ábra A szerveralkalmazás kódja 85 Pótári Tamás Mihály .NET komponensorientált szoftverfejlesztés bemutatása egy menedzser szoftveren keresztül Az így készült alkalmazás a következıkre képes: • Szórt üzenetküldés minden csatlakozott felhasználónak. • Értesítés kliens csatlakozásáról. • Értesítés kliens
lecsatlakozásáról. • Értesítés a nem elérhetı kliensrıl • Üzenetek archiválása (BroadcastMessages adatbázis tábla) Az üzenet utóértesítéshez még szükséges lenne egy MessageArchive objektum, ami plusz 3-4 sor a kliensalkalmazás kódjában. A következı ábrák szemléltetik, hogy a kis program mire is képes a gyakorlatban (M47. ábra és M48 ábra) M47. ábra Üzenetküldés a két fél között M48. ábra Az egyszerő alkalmazás is jelzi, hogy a kliens lecsatlakozott 86 Pótári Tamás Mihály .NET komponensorientált szoftverfejlesztés bemutatása egy menedzser szoftveren keresztül V. sz Melléklet A menedzser alkalmazás interfészei és metódusreferencia típusai, szerelvények szerint csoportosítva. 87 Pótári Tamás Mihály .NET komponensorientált szoftverfejlesztés bemutatása egy menedzser szoftveren keresztül Irodalomjegyzék: [1] Dr. Raffai Mária – UML2 Modellezı nyelvi kézikönyv (4) – Palatai Nyomda és Kiadó,
2005, 6.22 fejezet, 331 oldal : A komponens mint osztály [2] Juval Löwy – .NET komponensek programozása – Kossuth Kiadó, Budapest, 2004, 1. fejezet, 19 oldal: Alapterminológia Ingo Rammer – Advanced .NET Remoting (C# Edition) – APress, 2002 Fiach Reid – Network Programming in .NET (With C# and Visual BasicNET) – Elsevier Digital Press, Oxford, 2004 [3] Juval Löwy – .NET komponensek programozása – Kossuth Kiadó, Budapest, 2004, 1. fejezet, 23 oldal: Az interfészek és az öröklés összehasonlítása [4] Juval Löwy – .NET komponensek programozása – Kossuth Kiadó, Budapest, 2004, 1. fejezet, 24 oldal: A komponensorientált programozás alapelvei [5] Juval Löwy – .NET komponensek programozása – Kossuth Kiadó, Budapest, 2004, 1. fejezet, 21 oldal: Alapterminológia [6] Albert István – A .NET Framework és programozása – Szak Kiadó, Budapest, 2004, 2.1 fejezet, 65 oldal: A szerelvények felépítése [7] Albert István – A .NET
Framework és programozása – Szak Kiadó, Budapest, 2004, 3.2 fejezet, 111 oldal: Biztonság Juval Löwy – .NET komponensek programozása – Kossuth Kiadó, Budapest, 2004, 12. fejezet, 360 oldal: Biztonság [8] Juval Löwy – .NET komponensek programozása – Kossuth Kiadó, Budapest, 2004, 10. fejezet, 311 oldal: Példa távoli visszahívásra [9] Robert A. Maksimchuk, Eric J Naiburg – UML földi halandóknak – Kiskapu Kiadó, Budapest, 2006, 3. fejezet, 49 oldal: Követelménymodellezés [10] Robert A. Maksimchuk, Eric J Naiburg – UML földi halandóknak – Kiskapu Kiadó, Budapest, 2006, 3. fejezet, 59 oldal: A MiSzHaT próba [11] Robert A. Maksimchuk, Eric J Naiburg – UML földi halandóknak – Kiskapu Kiadó, Budapest, 2006, 9. fejezet, 172 oldal: Feladatok és kockázatkezelés [12] Robert A. Maksimchuk, Eric J Naiburg – UML földi halandóknak – Kiskapu Kiadó, Budapest, 2006, 4. fejezet, 76 oldal: Mi a felépítés? [13] Juval Löwy – .NET
komponensek programozása – Kossuth Kiadó, Budapest, 2004, 6. fejezet, 134 oldal: Feliratkozók interfészeinek létrehozása 88 Pótári Tamás Mihály .NET komponensorientált szoftverfejlesztés bemutatása egy menedzser szoftveren keresztül [14] Bill Wagner – Hatékony C# – Kiskapu Kiadó, Budapest, 2005, 3. fejezet, 148 oldal: Kerüljük az ICloneable felületet [15] Bill Wagner – Hatékony C# – Kiskapu Kiadó, Budapest, 2005, 3. fejezet, 139 oldal: Használjunk sorosítható típusokat [16] Juval Löwy – .NET komponensek programozása – Kossuth Kiadó, Budapest, 2004, 9. fejezet, 248 oldal: Egyéni szerializáció és verziókövetés [17] Albert István – A .NET Framework és programozása – Szak Kiadó, Budapest, 2004, 5.64 fejezet, 550 oldal: Álegyedi attribútumok [18] Juval Löwy – .NET komponensek programozása – Kossuth Kiadó, Budapest, 2004, 7. fejezet, 163 oldal: Egyirányú metódusok [19] Jason Price – C# adatbázis
programozás – Kiskapu Kiadó, Budapest, 2004, 8. fejezet, 248. oldal: Parancsok paraméterezése [20] Jason Price – C# adatbázis programozás – Kiskapu Kiadó, Budapest, 2004, 9. fejezet, 273. oldal: Sorok beolvasása az SqlDataReader objektumból [21] Juval Löwy – .NET komponensek programozása – Kossuth Kiadó, Budapest, 2004, 4. fejezet, 90 oldal: Determinisztikus finalizációséma Bill Wagner – Hatékony C# – Kiskapu Kiadó, Budapest, 2005, 2. fejezet, 85 oldal: Az erıforrások felszabadításához használjuk a using és try/finally kulcsszavakat [22] Juval Löwy – .NET komponensek programozása – Kossuth Kiadó, Budapest, 2004, 8. fejezet, 200 oldal: Szinkronizált metódusok Albert István – A .NET Framework és programozása – Szak Kiadó, Budapest, 2004, 6.54 fejezet, 644 oldal Nyelvi segítség (MSIL és C#) [23] Juval Löwy – .NET komponensek programozása – Kossuth Kiadó, Budapest, 2004, 10. fejezet, 260 oldal: Alkalmazástartományok
és távelérés [24] Bill Wagner – Hatékony C# – Kiskapu Kiadó, Budapest, 2005, 4. fejezet, 170 oldal: Használjuk rövid, egyszerő függvényeket [25] Juval Löwy – .NET komponensek programozása – Kossuth Kiadó, Budapest, 2004, 8. fejezet, 212 oldal: A ReaderWriterLock [26] Juval Löwy – .NET komponensek programozása – Kossuth Kiadó, Budapest, 2004, 8. fejezet, 209 oldal: A Mutex [27] Juval Löwy – .NET komponensek programozása – Kossuth Kiadó, Budapest, 2004, 8. fejezet, 184 oldal: Automatikus szinkronizáció 89 Pótári Tamás Mihály .NET komponensorientált szoftverfejlesztés bemutatása egy menedzser szoftveren keresztül [28] Juval Löwy – .NET komponensek programozása – Kossuth Kiadó, Budapest, 2004, 8. fejezet, 211 oldal: Az Interlocked osztály [29] Juval Löwy – .NET komponensek programozása – Kossuth Kiadó, Budapest, 2004, 10. fejezet, 314 oldal: A kiszolgáló kódjának és metaadatainak szétválasztása [30]
Albert István – A .NET Framework és programozása – Szak Kiadó, Budapest, 2004, 4.3 fejezet, 307 oldal: CLS-kompatibilitás Bill Wagner – Hatékony C# – Kiskapu Kiadó, Budapest, 2005, 4. fejezet, 165 oldal: Használjunk CLS-megfelelı szerelvényeket [31] Juval Löwy – .NET komponensek programozása – Kossuth Kiadó, Budapest, 2004, 5. fejezet, 108 oldal: Egyéni verziókövetési szabályok [32] Juval Löwy – .NET komponensek programozása – Kossuth Kiadó, Budapest, 2004, 11. fejezet, 342 oldal: Egyénileg fejlesztett komponensszolgáltatások [33] Juval Löwy – .NET komponensek programozása – Kossuth Kiadó, Budapest, 2004, 8. fejezet, 222 oldal: ISynchronizeInvoke [34] Juval Löwy – .NET komponensek programozása – Kossuth Kiadó, Budapest, 2004, 10. fejezet, 314 oldal: A kiszolgáló kódjának és metaadatainak szétválasztása [35] Juval Löwy – .NET komponensek programozása – Kossuth Kiadó, Budapest, 2004, 10. fejezet, 299 oldal:
Adminisztratív konfiguráció 90 Pótári Tamás Mihály .NET komponensorientált szoftverfejlesztés bemutatása egy menedzser szoftveren keresztül 91