UvodDoKomponent: ParkovisteOsgi |
from Wiki KIVu |
V tomto tutoriálu se používá SpringSource Tool Suite.
V tomto případě by nemělo moc smysl procházet všechny části implementace, protože je k dispozici jako Attach:ParkovisteOsgi.zip archiv. Zaměřím se tedy hlavně na novinky v Activatoru a eventy.
Je samozřejmé, že mezi sebou budou jednotlivé bundly provázány díky importům a exportům. Jakým způsobem je logické a vyplývá to ze zadání úkolu.
Tady bych chtěl pouze upozornit na jednu věc. V MANIFESTu? v záložce Dependencies jsou dvě možnosti jak vložit nějaký projekt. Buď se dá vložit přes Required Plug-ins nebo přes Imported packages.
Položky v této části budou vyžadované pro běh a jsou implementačně závislé. Pokud tedy potřebuji k běhu jeden určitý bundle, použiji tento typ vložení. Kvůli vznikající "tvrdé" závislosti na konkrétní bundle je tento způsob nedoporučovaný.
Tato volba se naopak používá pokud se nechci vázat na určitou implementaci. Je vhodné importovat package s rozhraními. Implementační část mne pak vůbec nemusí zajímat. Pracuji s rozraními a to je vše, co potřebuji - je mi jedno kdo udělá (nebo udělal) bundle, který implementuje mnou používané rozhraní.
Návrh Parkoviste říká, že Tabule a Brana budou obě implementovat rozhraní IZapVyp?
. Určitě by to šlo i jednoduše obejít, ale zaregistrovat obě služby pod stejným rozhraním bude zajímavější.
Abychom mohli používat oba dva objekty, budeme muset použít parametrů pomocí hashovací tabulky. Vytvoříme si tedy tabulku s jediným parametrem: type = tabule.
A tuto službu zaregistrujeme.
Hashtable<String, String> ht = new Hashtable<String, String>();
ht.put("type", "tabule");
context.registerService("cz.zcu.kiv.cosi.parkoviste.konfigurace.IZapVyp?", tabule, ht);
Obdobně zaregistrujeme i bránu, jen s tím rozdílem, že parametr bude: type = brana.
Abychom mohli službu získat, musíme zavolat metodu getServices()
, která získá všechny služby rozhraní IZapVyp?
a díky druhému Stringovému parametru profiltruje. V našem případě je filtr dost jednoduchý - chceme ty služby, jejich parametr type se rovná hodnotě tabule.
Pro podrobnější informace k filtrování se podívejte na JavaDoc příslušného rozhraní.
tabule = (IZapVyp?) context.getService(context.getServiceReferences("cz.zcu.kiv.cosi.parkoviste.konfigurace.IZapVyp?", "(type=tabule)")[0]);
Obdobně pro bránu, samozřejmě budeme chtít type=brana.
Zjistit jak fungují eventy v OSGi bylo opravdu složité. Samotný princip je pak ovšem velice jednoduchý a skládá se pouze ze tří bodů.
EventAdmin?
a a zveřejnění události
V OSGi nemusíme implementovat žádné rozhraní, ani třídu. Stačí získat službu EventAdmin?
a. Tomu ale předchází několik kroků.
1) V MANIFEST.MF přidat mezi Imported packages balíček org.osgi.service.event (pozor, vyhledávač porovnává od začátku (ne fulltextově), takže pokud budete přidávat, musíte psát org....)
2) Získat službu EventAdmin?
this.messageService = (EventAdmin?) context.getService(context.getServiceReference("org.osgi.service.event.EventAdmin?"));
3) Vytvořit událost. Pomocí HashMap?
se dají vkládat i parametry. Není to však nutné a dá se poslat i událost bez dalších parametrů.
HashMap?<String, Integer> hm = new HashMap?<String, Integer>(); hm.put("volnaMista", volnaMista); messageService.sendEvent(new Event("parkoviste/zbyva", hm));
4) Posílat události přes metody postEvent()
(asynchronní) nebo sendEvent()
(synchronní).
messageService.postEvent(new Event("parkoviste/plne", new HashMap?<String, Integer>()));
I zde je nutné provést několik kroků.
1) V MANIFEST.MF přidat mezi Imported packages balíček org.osgi.service.event (pozor, vyhledávač porovnává od začátku (ne fulltextově), takže pokud budete přidávat, musíte psát org....)
2) Třída, která bude zpracovávat události musí implementovat rozhraní EventHandler?
, které vyžaduje přetížení metody handleEvent()
.
Typ zprávy pak získáme pomocí metody event.getTopic()
.
A proměnnou pak získáme pomocí metody event.getProperty()
, samozřejmě s vyplněným názvem proměnné.
public void handleEvent(Event event) { if ("parkoviste/zbyva".equals(event.getTopic())) println("Zbyva mist : " + event.getProperty("volnaMista")); else println("Parkoviste plne!"); }
3) Zaregistrovat listener, tedy EventHandler?
. Pokud jde o třídu, která je zaregistrovaná už jako jiná služba nevadí, prostě ji zaregistruji znovu, ale tentokrát pod tímto rozhraním.
Jako vstupní parametr určuji typ událostí, které chci zpracovávat. Jsou povoleny wildcards, tedy "parkoviste/*" bude zachytávat jakékoliv události začínající na "parkoviste/"
Hashtable<String, String> hm = new Hashtable<String, String>(); hm.put(EventConstants?.EVENT_TOPIC, "parkoviste/*"); listenerSR = context.registerService(EventHandler?.class.getName(), pult, hm);
Je potřeba spustit bundle, který poskytuje jeho implementaci. Volba implementace je na Vás, já jsem používal equinoxovou verzi a následující část bude právě k ní.
Zde popisuji konkrétně získání equinoxové implementace, pokud chcete jinou, hledejte jinde.
Po importu bude bundle dostupný v Run -> Run configurations ... -> OSGi framework a tedy bude i spustitelný. Je nutné nastavit jeho spuštění před bundle, který ho jako první používá.