Modulaire webapplicaties met OSGi

22 December 2008 17:38 Rob Schellhorn Java

Als je niet oppast wordt een codebase snel onhandelbaar. Voor je het weet heb je honderden kilobytes aan spaghetti code. Voor webapplicaties is dat niet anders. Door applicaties op te knippen in kleinere delen, elk met een duidelijke taak en API, blijft je code beheersbaar. De OSGi specificatie beschrijft een architectuur om dit te ondersteunen. Dit artikel beschrijft hoe je OSGi kan gebruiken om modulaire webapplicaties te ontwikkelen.

Een module wordt in OSGi termen een bundel genoemd. De kracht van OSGi schuilt hem in de mogelijkheid koppeling tussen bundels laag te houden. OSGi gaat hierin verder dan build tools zoals Maven; ook tijdens runtime wordt integriteit afgedwongen. Wanneer een afhankelijkheid ontbreekt laat OSGi je dat weten tijdens het starten van je applicatie. Daarnaast kunnen bundels onafhankelijk gestart, gestopt, geïnstalleerd en weer gedeïnstalleerd worden. Het is bijvoorbeeld mogelijk een deel van de applicatie te vervangen, zonder dat de hele applicatie herstart hoeft te worden.

Er zijn een aantal implementaties gebaseerd op de OSGi specificatie, waarvan Equinox het meest bekend (en tevens referentie implementatie) is. Op de desktop heeft Equinox zijn kracht al bewezen, met Eclipse gebaseerde producten als grote voorbeeld. Ter illustratie: een doorsnee Eclipse installatie bestaat uit zo’n 600 bundels, die samen de IDE vormen!

Server-side Equinox

Ook in een webserver omgeving wordt OSGi meer en meer gebruikt. De Eclipse foundation steunt bijvoorbeeld de ontwikkeling van Richt Ajax Platform, waar ik eerder over schreef. Een andere bekende speler is Spring, die ondersteuning voor OSGi bundels inmiddels ook aan hun framework heeft toegevoegd.

Wanneer je van de grond af een OSGi webapplicatie bouwt, moet je eerst beslissen wie de applicatie gaat starten, Equinox of de webserver. Beide gaan er van uit dat zij die verantwoordelijkheid hebben, namelijk. Equinox als entry point is wat makkelijker op te zetten, terwijl de andere aanpak backwards compatible is met bestaande applicaties. Op de Equinox pagina’s staat duidelijk beschreven wat je hiervoor moet configureren. Ik kies hier voor een Equinox omgeving met de benodigde bundels voor een embedded Jetty webserver.

OSGi bundels

Eigenlijk is een OSGi bundel een normaal JAR bestand voorzien van wat extra meta-data. Deze meta-data plaats je in de manifest. Naast een naam en een versie nummer definieer je de omgeving waarin je bundel kan werken. De afhankelijkheden, gebruikte Java versie, maar bijvoorbeeld ook het OS wanneer je native code gebruikt. Door access rules te definiëren kan je API en implementatie scheiden; welke packages zijn zichtbaar voor andere bundels? Tot slot kan je een listener klasse opgeven, die geïnformeerd wordt als je bundel gestart of gestopt wordt: de Activator. In de context van een webapplicatie heb je normaal de web.xml waar je onder andere al je Servlets noemt. In een modulaire omgeving wil je deze definities niet op een plek, maar zullen bepaalde bundels deze functionaliteit bieden. De Activator is de aangewezen plek om je Servlets te registreren.

Bij wijze van voorbeeld neem ik de CMS Container. Dit CMS bestaat uit een aantal componenten, waaronder de Portal. Achter één Servlet façade schuilt alle logica van de Portal. De Activator van de Portal bundel kan er als volgt uit zien:

public class Portal implements BundleActivator {
   private final String HTTP_SERVICE = HttpService.class.getName();
 
   public void start(BundleContext context) throws Exception {
      ServiceReference sr = context.getServiceReference(HTTP_SERVICE);
      HttpService hs = (HttpService) context.getService(sr);
      HttpContext hc = new BundleEntryHttpContext(context.getBundle());
      Servlet portal = new CmscPortalServlet();
      hs.registerServlet("/portal", portal, null /*params*/, hc);
   }
 
   public void stop(BundleContext context) throws Exception {
      ServiceReference sr = context.getServiceReference(HTTP_SERVICE);
      HttpService hs = (HttpService) context.getService(sr);
      hs.unregister("/portal");
   }
}

Zowel de start als stop methode halen eerst een referentie naar de HttpService op, die in dit voorbeeld naar Jetty wijst. Vervolgens wordt de CmscPortalServlet in de webcontext gebonden, zodat requests afgehandeld kunnen worden. Equinox gaat eigenlijk nog een stapje verder en biedt tevens een declaratieve manier om webresources te binden: extensies. Als je dit gebruikt is je bundel dus niet meer compatible met de OSGi specs.

Interactie: De console

Testen van je applicatie gaat heel makkelijk in Eclipse. In de manifest editor vind je een link om je applicatie te starten. Om een standalone Equinox omgeving te maken kan je het beste alle org.eclipse.equinox jar bestanden uit je Eclipse folder kopiëren. Plaats deze in een folder samen met je applicatie bundel(s) en eventuele afhankelijkheden. Daarna start je de Equinox:

java -jar org.eclipse.osgi.jar -console

In de console kan je direct commando’s naar de bundels sturen. Eerder beloofde ik dat het mogelijk is bundels te stoppen en starten. Type bijvoorbeeld status om een overzicht van geïnstalleerde bundels en hun status op te vragen:

osgi> status
...
29	initial@reference:file:../../Documents/workspace/com.finalist.cmsc.portal/
  ACTIVE      com.finalist.cmsc.portal_1.0.0

Equinox meldt dat mijn portal bundel versie 1.0.0 actief is, en een id 29 heeft gekregen. Dit id heb je nodig om de bundel te stoppen:

osgi> stop 29
1-dec-2008 11:46:38 com.finalist.cmsc.portal.Portal stop

osgi> status
...
29	initial@reference:file:../../Documents/workspace/com.finalist.cmsc.portal/
  RESOLVED    com.finalist.cmsc.portal_1.0.0

De portal is uiteraard, na het stoppen van de bundel, niet meer te bereiken.

Conclusie

Door je applicaties op te splitsen in delen word je gedwongen goed over de grens van een component na te denken. Wat hoort bij een bepaalde bundel en wat niet? OSGi breidt de JVM uit met een geavanceerd runtime systeem om dit te ondersteunen, en gaat daarmee verder dan build systemen zoals Maven.

Wanneer je kiest voor OSGi, kies je voor een volwassen architectuur om een systeem modulair op te zetten. Veel applicaties laten zich prima lenen om opgedeeld te worden in kleine, herbruikbare services. Voor webapplicaties, zoals de CMS Container, is dat niet anders.

3 reacties »

  1. Een nadeel van ‘ruw’ OSGi gebruiken is dat al je dependencies eigenlijk ook zouden moeten zijn voorzien van OSGi metadata.

    Bij de introductie van de Spring DM Server (http://www.springsource.com/products/suite/dmserver) vertelde men dat SpringSource een OSGi repository aanlegt met daarin vrijwel alle (bevat er ±400 op dit moment) mainstream libraries: http://www.springsource.com/products/suite/repository .

    Overigens is de Spring DM Server helemaal gericht op het ontwikkelen van webapplicaties met OSGi… de server van de toekomst?

    Peter Maas December 30, 2008 9:25

  2. Dat moet zijn:
    http://www.springsource.com/repository/app/

    Maarten Meijer March 19, 2009 9:05

  3. Dat moet zijn:
    http://www.springsource.com/repository/app/

    Maarten Meijer March 19, 2009 9:05

Reageer

RSS feed for comments on this post · TrackBack URI