Aspektusok és komponensek

Paller Gábor

1. Komponensalapú programozás

Meglehetősen elterjedt vélemény szerint az objektumorientált programozás komoly problémákkal bír a kód  újrafelhasznalhatósága terén még akkor is, ha a domináns dekompozíció egyeduralmából adódó problémákat figyelmen kívül hagyjuk. Közismert tény, hogy nagyobb programokat nehéz az objektumorientált dekompozíció módszerével elkészíteni. A főbb okokat a következőkben szokás megjelölni.

Ezen problémák kezelésére hozták létre a komponensalapú rendszereket, melyek a következő részletekben különböznek az objektumorientált rendszerektől.
A komponensorientált rendszerek jellemző megoldásai a következők.
A komponensorientált programozás nagyon elterjedt, szinte minden nagyobb programot ebben implementálnak. A komponensek belsejében gyakran objektumorientált megközelítésben írják a programot. Fejlett komponensrendszerek, pl. a Microsoft COM képesek különböző nyelveken írt programokat is összekötni.

Számos komponensrendszer létezik Jávára. A Jáva osztályok jobban kielégítik a komponensalapú rendszerek követelményeit, mint mondjuk a C/C++ osztályai, még a legegyszerűbb komponensrendszerhez is szükség van egy konvenció definiálására a kimenő interfészek csatolására. Ez a JavaBeans specifikáció. Ezen felül az EJB egy specializált komponensrendszernek tekinthető. Önálló, rendkívül teljesítőképes Jáva-alapú komponensrendszer a Fractal [2].

2. JAsCO

A JAsCO rendszer célja, hogy aspektus-szerű működést valósítson meg JavaBeans komponensek között. A JavaBeans egy egyszerű Jáva konvenció, amely megmondja, milyen metódusokat kell tartalmaznia egy metódusnak, hogy JavaBeans kompatibilis legyen. JavaBeans komponensek eseményekkel kommunikálnak egymással. Az eseményfogadó metódus ilyen formátumú interfésszel rendelkezik:

Az eseményfogadó egy EventListener-bôl leszármazott interfészt implementál. Ebben az interfészben fogja össze az eseményfogadó metódusait. Példa:

interface KeyKlickedListener extends java.util.EventListener {
  void KeyKlicked( KeyKlickedEvent ke );
}

Ezeket az eseményfogadókat regisztrálják az eseményküldőknél. Az eseményküldők ilyen metódusokkal rendelkeznek:

set<interfész típus>( <interfésztípus> )

Pl:
setKeyKlickedListener( KeyKlickedListener lst );

Az eseményküldőknél lehetséges több fogadó regisztrálása vagy fogadó eltávolítása más aláírású metódusokkal.

A JAsCO úgy bővíti ki a JavaBeans modelt, hogy két újfajta elemet vezet be. Az aspektus-komponens megmondja, hogy mikor és mi hajtódjon végre.

class AccessManager {
   PermissionDb p db = new PermissionDb();
  User currentuser = null;

  void login(User user, String pass) { //login code }
  void logout() { //logout code }

  void addAccessManagerListener(AML listener) { //adding code }
  void removeAccesManagerListener(AML listener) { //remove code }

  hook AccessControl {
     AccessControl(method(..args)) { execute(method); }
     replace() {
       if(p_db.check(currentuser,cobject) {
          return method(args); }
       else {
         throw new AccessException(); }
     }
  }
}


A hook rész azt mondja meg, hogy mikor hajtódhat végre a szűrő. A tanács rész megmondja, hogy a szűrő végrehajtásakor hogyan változik a végrehajtás. A mi esetünkben az elkapott metódus helyettesítődik egy olyannal, amelyik ellenőrzi egy bizonyos engedély meglétét és kivételt dob, ha az engedély nincs meg.

Az aspektus-komponenst egy konnektor-komponenssel kapcsoljuk a többi komponenshez.

connector PrintAccessControl {

   AccessManager.AccessControl control = new AccessManager.AccessControl( * Printer.*(*));

   control.replace();
}


Ez elfogja a Printer osztályban elhelyezkedő bean (a Printer komponens) összes metódushívását.

A JAsCO el tudja fogni a bean által kibocsátott eseményeket is.

Logging.FileLogger logger = new Logging.FileLogger( onevent Printer.jobFinished(PrintEvent));

Az eddigiek eléggé emlékeztettek az AspectJ metódushívás-elfogó mechanizmusaira. A JAsCO teljesen másképpen szövi az aspektusokat, mint az eddig látott rendszerek, kihasználja a komponensek egy fontos jellemzőjét, a komponensek dinamikus összekapcsolhatóságot, hogy az aspektus-komponenseket és konnektorokat beiktassa a hívási láncba.

jasco

A JAsCO a bean összes hívását egy kapoccsal szereli fel (ezt megteheti, mert az objektum csak az interfészén keresztül érhető el) és ez a kapocs a hívásokat a konnektortárba küldi, ahol a hívást illesztik az aktuálisan aktív konnektorokra és esetleg meghívják a hook-okat az aspektuskomponensben. Ugyanez történik az eseménykibocsátó metódusokban: ott úgy manipulálják az eseménygenerátorok és fogadók közötti kapcsolatokat, hogy az esemény a konnektortárba fusson be, ahol ugyancsak illesztik az onevent konnektorokra.

A JAsCO csak az metódushívásokat ill. az eseménykibocsátásokat tudja elfogni, hiszen a komponensek belseje számára láthatatlan.

3. Fractal-AOP

A Fractal egy komponensrendszer, melynek különböző nyelvi implementációi vannak. Legfőbb jellegzetessége az, hogy hierarchikus, tehát komponensekből újabb komponensek állíthatók össze és ez az "összerakás" tetszés szerinti mélységben folytatható. A Fractal komponensek membránból és tartalomból állnak. A membrán implementálja a komponens menedzseléséhez szükséges interfészeket, teszi elérhetővé a komponens interfészeit ill. kapcsolja a tartalmat a membrán belső felének interfészeihez. A tartalom maga a komponens implementációja.

A Fractalhoz aspektusorientált kiterjesztést alkottak, ez a Fractal-AOP. A Fractal-AOP célja aspektusorientáltsághoz hasonló mechanizmus megvalósítása a Fractal komponensmodell membránjának és hierarchikus komponenskompozíciójának segítségével. Az alábbi kép egy komponenst mutat, amelyhez aspektust illesztettünk.

fractalaop
A Fractal-AOP "becsomagolja" az aspektussal ellátandó komponenst, egy külső membránt húz köré. Ennek a külső membránnak két új interfésze van, a cEc és az sPc. A cEc a külső membrán elfogó (interceptor) mechanizmusához kapcsolódik, elfogja a komponenshez érkező kéréseket és továbbítja a szövő komponens (weaving component) sEc interfészéhez események formájában. A szövő komponens kiértékeli a kapott eseményt, esetleg meghívja a tanács komponenst (advice component), majd a hívást továbbküldi az eredeti komponens sPc interfészéhez. Az sPc interfész a megkapott üzenetet újra hívássá alakítja és az eredeti komponens megfelelő metódusa meghívódik.

A Fractal-AOP arra is képes, hogy a komponensrendszer különböző helyeire illeszkedő aspektusokat egy egységbe fogja össze, így a rendszer akkor is konzisztens állapotban marad, ha  több komponens szükséges egy aspektus megvalósításához. Az alábbi példán pl. az autentikációs aspektust három komponens valósítja meg.

Fractal-AOP példa

4. Összefoglalás

Aspektusokhoz hasonló funkcionalitás komponensekkel is megvalósíthatók. Ezek csak a komponensinterfészeken képesek működni, lévén a komponens belseje fekete doboz. A komponensek szabad összekapcsolhatósága azonban a komponensinterfészekhez illesztett aspektusok beillesztését a rendszerbe egyszerűvé teszik.

[1] Cuno Pfister, Clemens Szyperski: Why Objects Are Not Enough, Proceedings of the First International Component Users Conference, Munich, Germany 1996 July
[2] Fractal
[3] Davy Suvée, Wim Vanderperren and Viviane Jonckers: JAsCo: an Aspect-Oriented approach tailored for Component Based Software Development, AOSD 2003, Boston
[4]  Houssam Fakih, Noury Bouraqadi, Laurence Duchien: