Utazó ügynökök


Tartalomjegyzék:
Kik is azok az utazó ügynökök
Mire érdemes utazó ügynököket használni
Miért jó mindehez a Jáva
A Voyager rendszer alapjai
Virtuális objektumok
Üzenetátadás
Ügynökök
A bróker
A példaprogram
Az otthon és a kocsma
Az ügynök
A vezérlõ program
Fordítás és futtatás

Szeretném egy személyes "vallomással" kezdeni: meggyõzõdésem, hogy a programozásban a jövõ, legalábbis a közeljövõ az elosztott objektumorientált rendszereké. Kisebb-nagyobb felhasználói és fejlesztõi csoportosulások évek óta foglalkoznak ilyen rendszerek fejlesztésével, legismertebb, legelterjedtebb és sok szempontból legkiforrottabb közülük talán az Object Management Group (OMG) konzorcium által szabványosított CORBA (Common Object Request Broker Architecture) rendszer.

Az objektumorientált rendszerek világába egyszer csak berobbant a Jáva, fenekestül felforgatva ezt a világot. Az idén januárban megjelent JDK 1.1-es verziója komoly lépéseket tett az elosztott objektumorientált rendszerek felé. Ennek az iránynak az egyik képviselõje a JDK 1.1-beli RMI (távoli módszerhívás) könyvtár, amelyet múlt hónapban mutattam be. Sokat töprengtem, mirõl is írhatnék ebben a hónapban, tervezgettem, hogy a Jáva és a CORBA technológiák alakuló összefonódásáról írok, hiszen ez is nagyon érdekes és várhatóan széles körben elterjedõ rendszer, de jelenleg az RMI és a Jáva-CORBA hívek között éles hitvita dúl és én egyelõre nem látok tisztán, nem tudok állást foglalni.

Viszont már néhány hónapja olvastam egy igen érdekes új elképzelésrõl, az "utazó" ügynökökrõl (mobile agent). Az IBM egyik kutatócsoportja (http://www.trl.ibm.co.jp/aglets) igen érdekes eredményeket ért el az ún. aglet-ek (Jávában implementált utazó ügynökök) létrehozását támogató könyvtárak kifejlesztésével. A rendszer izgalmas, igéretes, úgyhogy csaknem belefogtam az ismertetésébe, amikor néhány napja (1997. április 8-án) egyszer csak felbukkant az ObjectSpace (http://www.objectspace.com/) programház Voyager nevû, JDK 1.1-en alapuló ORB környezetének próba változata. Elolvastam a dokumentációkat és alig akartam elhinni, hogy ilyen hatékony, egyszerû rendszert Jávában meg lehet valósítani. Mintha programozástechnológiai témájú sci-fi könyvet olvasnék! De minden igaz, a technológia létezik! Csak még annyit a cégrõl, hogy õk alkották az eddig - méltatlanul - kevés publicitást kapott JGL (Java General Library) adatszerkezet- és algoritmuskönyvtárat. A JGL és mostani Voyager rendszer egyrészt "tiszta Jáva" (követi a Sun által meghirdetett "100% pure Java" ajánlást), másrészt még üzleti felhasználáshoz is teljesen ingyenes! Kemény versenytársa akadt az RMI-nek!

Megjegyzés: nem szeretném elhamarkodottan összehasonlítani az ObjectSpace és az IBM megoldásait, nem azért írok a Voyager-rõl, mert az egyértelmûen jobb, hanem azért, mert beleszerettem!

Kik is azok az utazó ügynökök

Ügynöknek (agent) olyan programot neveznek, amely "önállóan", a felhasználó beavatkozása nélkül, a felhasználó "helyett" hajt végre valamilyen feladatot. Ez persze elég általános definíció, majdnem minden nem interaktív programra érvényes. Ügynök programra példa lehet az elektronikus levelezõ rendszerekben használt továbbító program (ún. MTA, message transfer agent), pl. a Unix sendmail-je. A sendmail - idõnként - megkísérli felvenni a címzett - avagy egy közbülsõ - gépen futó partner sendmail-lel a kapcsolatot és ha sikerül, átadja neki a továbbítandó levelet. Ha pedig olyan levelet kap, amely egy helyi felhasználónak szól, akkor azt elhelyezi a felhasználó postaládájában.

A fent vázolt rendszer jól modellezi a postai levéltovábbítást, legalábbis a posta ügyfelei, a feladó és címzett szempontjából. Azonban az igazi posta "utazó ügynököket", a postásokat alkalmaz a levelek kézbesítéséhez. A postás fizikailag is "odamegy" a címzetthez és maga helyezi el a postaládában a levelet. Miért jó egy ilyen megoldás? Az ügynök elég intelligens lehet ahhoz, hogy helyben a levéllel különbözõ kiegészítõ tevékenységeket hajtson végre. Például ajánlott levélnél aláírathatja a kézbesítési könyvet a címzettel, ha nincs senki otthon, a csomagot beadhatja a szomszédoknak, esetleg megkérdezi a házmestert, tudja-e az elköltözött lakók új címét vagy begyûjtheti a küldendõ postát.

Kissé szakmaibb zsargont használva, az ügynök a levélben tárol információval együtt eljárásokat, algoritmusokat is "hordoz". Persze ezeket az algoritmusokat elhelyezhetnénk a helyi rendszerben tanyázó, statikus, helyhez kötött ügynökökben is, ám így a rendszerünk nagyon nehezen bõvíthetõ, hiszen minden egyes új algoritmust minden lehetséges címzett ügynökkel meg kellene taníttatnunk. Ennél egyszerûbb, ha az algoritmus is utazik. Persze az utazó ügynök ettõl még szóba állhat a helyi ügynökökkel, sõt rendes elosztott rendszerhez méltóan távoli ügynökökkel is kommunikálhat.

Mire érdemes utazó ügynököket használni

Az egész technológia nagyon új, még keresi a helyét, alkalmazási körét. Mindenesetre néhány általános indok az ügynökök használata mellett:

Miért jó mindehez a Jáva

A Jáva nyelv a platformfüggetlen virtuális gépével ideális eszköz vándorlásra képes kód írására. Végül is a programkákkal (applet) is ugyanez történik, csak õket szegényeket a böngészõ rángatja át magához, addig az ügynök "önállóan" is úgy dönthet, hogy ideje "melegebb vidékre" költöznie.

Ezen túl a JDK 1.1-ben megjelent objektum sorosítás (object serialization) eszközt nyújt Jáva objektumok hálózaton átküldésére. A szintén most megjelent Reflection könyvtár pedig lehetõséget adott ahhoz, hogy egy program - itt például az ún. bróker - futás közben is felderíthesse egy másik objektum, illetve osztályának szerkezetét.

A Voyager rendszer alapjai

Virtuális objektumok

A múlt havi cikk olvasóinak nem meglepõ, hogy egy távoli objektummal lebonyolítandó kommunikációhoz helyi segítségre van szükségünk. Az RMI-ben csonknak (stub) nevezett objektumot itt virtuális jelzõvel illetik, de a feladata ugyanaz, a helyi objektumok ezen keresztül érik el a távoli párjukat.

A Voyager érdekessége, hogy a virtuális objektumokat reprezentáló osztályt egy program (vc) hozza létre vagy a .java forráskódból, vagy akár ennek hiányában a már lefordított .class állományból. Nem kell külön interfészeket készítenünk. A virtuális osztály mindent tud, amit az eredeti (legalábbis annak nyilvános felülete), beleértve a konstruktorait is. Ám az összes meglévõ konstruktor kibõvül egy paraméterrel, amelyik a virtuális objektum valós párjának helyét adja meg. Ez lehet akár egy távoli gép is, ilyenkor a helyi virtuális objektum létrehozásával együtt elkészül a távoli párja is. Lehet, hogy azon a gépen nincs is ott az osztály kódja? Sebaj, a bróker ezt automatikusan áttölti, mi észre sem vesszük. Ezen túl lehetõségünk van egy már létrehozott objektumot a move módszerrel bármikor másik gépre átmozgatni, ilyenkor az objektum teljes állapotával együtt átkerül az új címre.

A távoli objektumok ugyanúgy a referenciákat figyelõ szemétgyûjtés hatáskörébe tartozhatnak, mint helyi társaik, de lehetõségünk van az objektumokat idõhöz kötött feltételek alapján automatikusan is megszüntetni.

Üzenetátadás

A Jávában az üzenetátadás módszerek hívásával történik. Ha az objektum távoli, akkor a virtuális partnerével beszélgetünk, ez majd továbbadja az üzenetet és visszaadja a választ. A módszerhívás paramétereiként a Jáva beépített típusain túl tetszõleges sorosítható objektumot is használhatunk, sõt az összes virtuális objektum eleve ilyen.

A Voyager-ben többlet, hogy a - módszerhívásokkal szintaktikailag teljesen azonos - ún. szinkron üzenetátadáson túl - amikor az aktiváló bevárja a távoli módszer lefutását - használható egyirányú (Oneway) illetve aszinkron (Future) üzenetküldés is.

Az üzenetátadás további érdekessége, hogy megtalálja az esetleg tovább vándorolt objektumokat is, mert ezek vándorlásuk közben "titkárokat" hagynak maguk után, akik megszervezik az üzenetek átadását, sõt biztosítják azt, hogy a következõ üzenetváltás már közvetlenül az új helyen lévõ objektummal történjen.

Ügynökök

Ügynököt a Voyager rendszerben egyszerûen az Agent osztályból leszármazással lehet létrehozni. Az ügynökök az egyéb virtuális objektumoktól alig különböznek. Az egyik különbség, hogy az ügynökök élettartama alaphelyzetben "végtelen", külön "le kell lõnünk" (die), ha meg akarunk tõle szabadulni.

A másik lényeges különbség az ügynökök mozgásakor látszik. Mivel egy ügynök aktív objektum, áthelyezés után folytatni szeretné a tevékenységet. Sajnos - néhányak szerint szerencsére - a Jáva sorosító könyvtára csak a kazalon (heap) tárolt információkat (objektumokat) tudja átvinni, a verem tartalmát és ezzel a futás aktuális állapotát nem. Így az ügynöknek a move parancs kiadása elõtt minden fontos információt a kazalon kell tárolnia - ha még nem lenne ott -, valamint a move-nak meg kell adni annak a módszernek a nevét, ahol a futását folytatni akarja, miután az új helyre megérkezett.

A bróker

A bróker az a rendszerkomponens, amely a fenti mágiát véghezviszi. Az egyes gépeken külön el kell indítani (Voyager <kapu>), a többi már "magától" megy. A bróker az objektumok mozgatásán és az üzenetátadások lebonyolításán túl tartalmaz egy - egyelõre egyszerû - "telefonkönyvet" a helyi objektumokról, illetve egy specializált, konfigurálható biztonsági menedzsert, aki a Jávában ismert módon korlátozhatja a távolról érkezett ügynökök tevékenységét.

A bróker implementáció a teljesítményt összehasonlító adatok alapján nagyon jó, az üzenetátadások távoli objektumok esetén 20-30%-kal gyorsabbak, mint pl. az RMI-ben, azonos gépen elhelyezkedõ virtuális objektumok között pedig néha 3 nagyságrenddel (nem tévedés!) is gyorsabb lehet.

A példaprogram

Példánk utazó ügynöke nem más, mint Svejk, aki a háború elõtti boldog békeidõkben rendszeresen végiglátogatta Prága kocsmáit, sehol sem idõzve többet, mint amennyi 1-2 korsó sör felhajtásához elegendõ.

Svejkünk (egy Person típusú objektum) otthonról (egy Home) indul el, egyesével bejárva minden egyes, a listáján (Vector pubs) szereplõ kocsmát (Pub-ok). A "bejárás" azt jelenti, hogy az ügynök átkerül a kocsmát futtató számítógépre, mûködését ott folytatja. A kocsmákban bejelentkezik (visit) és hazaszól (message), majd vár egy kicsit és továbbmegy, végezetül hazamegy (returnHome), ha már az összes kocsmát végigjárta.

A példa terjedelmi okok és a könnyen érthetõség érdekében szándékosan egyszerûsített. A hibakezeléssel nem foglalkoztam, de a Voyager rendszer erre kevésbé is érzékeny, mint az RMI, lévén, hogy az itt elõálló hibák a Jáva futási hibáinak kategóriájába tartoznak, azaz nem kötelezik a programozót hibakezelõk írására, csak lehetõvé teszik azt.

Az otthon és a kocsma

Az otthont (Home.java) és a kocsmát (Pub.java) megvalósító nevetségesen egyszerûek. Akár lehetne egyetlen osztály is, de úgy döntöttem, hogy a kocsmáknak külön nevet adok - otthon úgyis csak egy van - és kissé másképpen hívom a módszereit, amelyeken keresztül az ügynök velük kommunikál. Ebben a két osztályban nincs semmi Voyager-specifikus.

Az ügynök

Kicsit bonyolultabb az ügynököt megvalósító osztály (Person.java) Ne lepõdjünk meg az importált könyvtár nevének hosszán, végre egy cég betartja a Sun által kitalált, de be nem tartott elnevezési konvenciót. A név eleje a cég Internetes neve. A fenti dinamikus tömb tárolja majd a meglátogatásra váró kocsmák listáját, index jelzi, hogy éppen hol tartunk. A konstruktor tárolja a személyünk nevét és otthonát. VHome egy olyan osztályt jelöl, amelyet a vc generátor program a Home osztályból állított elõ. Itt virtuális objektumot kell használnunk, hiszen személyünk a vándorlása során távol kerülhet az otthonától, visszaszólni csak egy virtuális segéd-objektumon keresztül tud majd.

A kocsmák dinamikus tömbjét az addPub-bal lehet bõvíteni. Svejk soha nem feledkezik meg egy kocsmáról, ezért a tömbbõl törlés mûveletét nem valósítottuk meg.

Az ügynökök vándorlásának trükkjét a nextPub módszer belseje rejti. Elõször kivesszük a tömb soron következõ elemét, már ha akad ilyen. A move módszer segítségével az ügynök objektum "átugrik" az elsõ paraméterként megadott kocsma objektum mellé. Az ügynök a tevékenységét az új helyen a proceed eljárással folytatja. Amennyiben nincs több kocsma, az ügynök, hazamegy, azaz a home objektumból megkapott címre költözik, ahol is a returnHome módszert hajtja majd végre.

 A módszer az ügynökök vándorlását lehetõvé tevõ mindkét move módszerre példát mutat, az egyiknél egy távoli objektumot, másikban egy kiszolgáló címét adjuk meg.

Az otthonról elindulás csak akkor sikeres, ha van egyáltalán kocsma a listánkon. Ha nincs, kiírunk egy figyelmeztetõ üzenetet és megállítjuk az ügynök futását.

 A proceed eljárás törzse definiálja a kocsmában zajló tevékenységet. Mivel ide úgy kerülünk, hogy egy objektum mellé ugrunk, a Voyager rendszer a lokális objektumot paraméterként átadja a módszernek.

Elõször beköszönünk az aktuális kocsmába (visit), majd hazaszólunk, hogy hol is vagyunk (message). Ne feledjük, hogy az elsõ helyi-, a második viszont egy távoli módszerhívás! Várakozunk egy kicsit - 5 másodperc elég egy számítógépes Svejknek, hogy 2 sört legurítson -, majd továbbállunk.

 Hazatérve a returnHome módszerre kerül a vezérlés. Ennek a módszernek a proceed-del ellentétben nincs paramétere. Itthon kiírunk egy üzenetet és csendben jobblétre szenderülünk. Persze "valósághûbb" szimulációban inkább várakoznánk egy keveset és a leaveHome-mal kezdhetnénk elölrõl a kocsmázást!

A vezérlõ program

Ahhoz, hogy az egész mûködni kezdjen, létre kell hoznunk a szereplõket. Ez egy igazi Jáva program (PubDemo.java), amely main függvénye fut majd le. Feltételeztem, hogy a parancssorban azon gépek nevét kapja meg, ahol az egyes kocsma objektumok futnak majd. A Home és Person osztályok 1-1 példánya az aktuális, a programot futtató gépen (localhost) jön létre. Figyeljük meg az egyes konstruktorok hívását. Ezek elsõ paraméterei megegyeznek a megfelelõ konkrét osztály (Home illetve Person) konstruktorainak, az utolsó viszont egy gép:kapu/becenév stílusú címdefiníció, ahol a gép és a kapu a brókert azonosítja, a becenév pedig a brókeren belül nevezi el az objektumunkat. (Megjegyzés: a 4000-s helyett használhatnánk csaknem tetszõleges más kaput is.) A "távoli" kocsmák létrehozására hasonlóan történik. A virtuális osztály konstruktorának utolsó, kiegészítõ paramétereként itt a kocsmákat tartalmazó, a program paramétereként megadott gép nevét adjuk meg, kiegészítve egy szabadon választott kapu számával. Ezen a kapun a Voyager brókere kell, hogy várakozzon, viszont így egy távoli gépen hoztunk létre új objektumot. Gondoljunk csak bele, az RMI nem támogatja a távoli objektum létrehozást! Az elkészült kocsmát fel is vesszük Svejkünk listájára.

Az résztvevõ objektumokat elindítva meglökjük Svejket, hogy ideje útra kelni. Eztán a programunkat akár le is állíthatjuk, objektumaink önálló életet élnek

Fordítás és futtatás

A fordításhoz elõször létre kell hozni a segéd osztályokat (rögtön a .class állomány keletkezik!): Megjegyzés: itt a vc fordító a .java forrásállományokból dolgozik, de ezek hiányában hajlandó a .class állományt is használni. Eztán már lefordíthatjuk az összes forráskódunkat Futtatás elõtt az összes részvevõ gépen (ahol a Home illetve a Pub példányok lesznek), el kell indítanunk a brókert a 4000-s kapun: Eztán már csak a program indítása marad hátra: Ennyi az egész, kezdõdhet a kocsmába járás! 
Kiss István

  updated: 97/05/09, http://www.eunet.hu/infopen/cikkek/java/agent.html 1