blog.smart-java.nl
Ordina J-Technologies – Java Blog

Archief ‘Architectuur’ categorie




Lagen in de referentiearchitectuur

Door: Pieter van Boxtel, 6 October 2008

In de referentiearchitectuur hebben we lagen onderkend, zoals je ze vaak tegenkomt in een J(2)EE applicatie; een presentatielaag voor presentatie en user interface logica, een servicelaag voor remoting en service gerelateerde faciliteiten, een businesslaag waar het echte werk gebeurt en een datalaag voor database mapping. Bij uitwerking van dit model kwamen echter een aantal knellende vragen naar boven rondom afhankelijkheden van het domeinmodel. Hoe kan de datalaag nu afhankelijk zijn van het domeinmodel dat zich in de businesslaag bevindt? Hoe kunnen we ongewenste koppelingen voorkomen? Tijd om een stapje terug te doen. Wat is nu eigenlijk een laag in de software architectuur?

In een lagenmodel wordt software opgedeeld in een aantal lagen die elk hun eigen nivo van abstractie hebben. In principe heeft een laag hierbij alleen kennis van de direct onderliggende laag. Omdat lagen elk een eigen abstractie, een eigen “aandachtsgebied” hebben, hebben ze ook een eigen levenscyclus en zijn ze gevoelig voor andere soorten wijzigingen. Door de applicatie in lagen onder te verdelen wordt de gevoeligheid voor wijzigingen gelokaliseerd en wordt de applicatie in zijn geheel beter onderhoudbaar. En dat is iets waar een software architect een warm gevoel van krijgt.

Het klassieke voorbeeld van een lagenmodel in software is het OSI model voor computer netwerken. Iets complex als internet is mogelijk omdat netwerk protocollen gelaagd zijn (SOAP bovenop HTTP bovenop TCP bovenop IP bovenop Ethernet). Ook voor software architectuur zijn lagen voorgesteld om de complexiteit te verminderen. Het boek “Pattern Oriented Software Architecture” [POSA] introduceert het concept van lagen in de architectuur als een pattern. POSA geeft als voorbeeld van een lagenmodel het OSI model. Het noemt ook kort de toepassing van het lagenmodel in informatiesystemen, maar gaat daar niet diep op in. De gezaghebbende (?) Java architectuur-bijbels als “Core J2EE Patterns” [Alur], “Patterns of Enterprise Application Architecture” [Fowler] en “EJB Design Patterns” [Marinescu] schetsen een opdeling van een applicatie in lagen. “Domain-Driven Design” [Evans] beschrijft hoe het lagen patroon toegepast kan worden in een domeinmodel. Maar tot zover de literatuur.

In een enterprise applicatie kun je, afhankelijk van de richting van waaruit je ernaar kijkt, verschillende soorten lagen onderscheiden:

  1. à la OSI zijn er infrastructurele lagen; de applicatie gebruikt Java/JEE libraries die gebruik maken van een container en JVM die gebruik maken van een OS.

  2. POSA, Fowler, et cetera onderkennen architecturale lagen voor informatie systemen / enterprise applicaties.

  3. Multi-tiering brengt lagen aan in de deployment; een browser praat met een applicatieserver die met een database praat.

  4. Evans beschrijft hoe je lagen kunt gebruiken om het domeinmodel te structureren.

Deze soorten lagen zijn onafhankelijk van elkaar en je zou ze weer kunnen geven in een multi-dimensioneel plaatje, ware het niet dat wij niet zo goed zijn in het tekenen en begrijpen van plaatjes met veel dimensies.

Architecten (met name architecten…) houden van simpele plaatjes. Ze beperken zich in de regel dus tot 1 dimensie; nummer 2 in bovenstaand rijtje. Dit is ook de dimensie waarin in de referentiearchitectuur wordt gekeken. Daarin onderkennen we zoals gezegd 4 lagen; Presentatielaag, Servicelaag, Bussinesslaag en Datalaag.

Echter, die laatste twee lagen, dat zit niet helemaal lekker… Hoe kan een component in de datalaag nu een domeinobject persisteren als het geen domeinobjecten kent? Volgens de lagendefinitie kent een laag immers de onderliggende laag, maar niet de bovenliggende. De oplossing die we in de referentiearchitectuur hebben gekozen blijft achteraf knagen. In de logische view hebben we het probleem genegeerd en in de implementatie view hebben we de domeinobjecten in een afzonderlijke “laag” naast de overige lagen getekend. Daarmee is het lagenplaatje meer een blokkenplaatje geworden met pijlen allerlei kanten op.

Hoe maken we van dit plaatje nu een correct lagenplaatje? Het antwoord is eigenlijk heel simpel; gum het onderscheid tussen business- en datalaag weg. Dit sluit mooi aan bij Evans; onze Data Access componenten zijn gewoon repositories die onderdeel zijn van het domein model. Weg met de datalaag dus.

Maar daarmee zijn we nog niet helemaal klaar. We hebben ook nog die service agents en wat te doen als we moeten koppelen met een database schema dat niet lekker aansluit op ons domeinmodel? Dit vraagt om infrastructurele logica waarmee we ons domeinmodel niet willen vervuilen. Hier hebben we weldegelijk een tussenliggend laagje voor nodig. Laat ik dit laagje Integratielaag noemen. In de Integratielaag vinden we good old DAO’s. Parameters van deze DAO’s zijn DTO’s die een representatie zijn van het datamodel waar de DAO aan koppelt. Ze geven dus geen domeinobjecten of afspiegelingen daarvan terug. De Integratielaag heeft, technisch maar ook conceptueel, geen enkele notie van hoe domeinobjecten eruit zien. Vertaling van extern datamodel naar domeinmodel is verantwoordelijkheid van de domeinlaag.

De Integratielaag hebben we alleen nodig als we willen koppelen met de grote boze buitenwereld. Zolang we doen wat we meestal doen, een databaseschema maken specifiek voor ons domeinmodel en dat met hibernate aan onze domeinobjecten koppelen, hebben we deze niet nodig. Hiermee kom ik uit op onderstaan plaatje. Dit lijkt sterk op het lagenmodel zoals iedereen het kent, maar wel met een kanttekening bij de toepassing van de Integratielaag. (En de businesslaag heb ik omgedoopt tot domeinlaag om te onderstrepen dat ik fan ben van DDD.)

In bovenstaand plaatje zijn ook de systeemgrenzen weergegeven. Wanneer we persisteren naar een database die binnen onze eigen systeemgrenzen valt, en die we naar believen aan kunnen passen, dan hebben we geen integratielaag nodig. Wanneer we moeten integreren met de grote boze buitenwereld dan hebben we (misschien) een integratielaag nodig om de domeinlaag “clean” te houden. In het plaatje zie je ook dat de servicelaag de plek is waar aanroepen vanuit een extern systeem opgevangen worden.

Resten nog twee vragen waar een wakkere lezer nu wellicht nog mee worstelt:

1) Waar zit de hibernatejar dan? Toch niet in de domeinlaag? Nou nee, dit is een infrastructureel ding dat je niet terugziet in dit lagenplaatje. Het zit in een andere dimensie (de eerste in bovenstaand lijstje), in een parallel universum zo je wilt. Het architecturale lagenplaatje toont niet alle spelers. Net zomin als dat de Sun SPARC Enterprise Server waar de applicatieserver op draait zichtbaar is in het plaatje, zijn alle gebruikte 3rd party libraries zichtbaar.

Een architectuurbeschrijving bevat verschillende views waarin de architectuur vanuit verschillende perspectieven beschreven wordt. Voor elk van deze views kunnen we een lagenmodel opstellen. In de deployment view tekenen we een plaatje waarin een plekje is voor onze Sun SPARC Enterprise Server. In de implementatie view kunnen we een plaatje tekenen waarin de hibernatejar zichtbaar is. Een veelgebruikte oplossing is om naast de lagen in bovenstaand plaatje een “common” laag te tekenen voor hibernate, spring en ander spul, maar zoals intussen duidelijk moge zijn ben ik daar geen voorstander (meer) van.

2) Een van de argumenten om de implementatie van persistentie in een afzonderlijke laag te stoppen is dat het dan mogelijk is om het persistentiemechanisme te vervangen door een ander mechanisme. Deze mogelijkheid wil je ons toch niet afpakken? Nee, natuurlijk niet, ik zou niet durven. Hoewel ik het eerste project nog tegen moet komen dat daadwerkelijk een persistentiemechanisme vervangt, hecht ik wel waarde aan encapsulation en loose coupling. Het lagenmodel biedt echter geen goede oplossing voor deze vraag.

We dienen dit op te lossen binnen de domeinlaag en dat kan op niet al te ingewikkelde wijze door interface en implementatie van repositories te scheiden in afzonderlijke packages en eventueel jars. Een specifieke implementatie van een repository injecteren we gewoon in het domein en als we de implementatie willen wijzigen (bijvoorbeeld stub data zodat we kunnen testen) dan injecteren we een andere implementatie. Omdat dit alles onderdeel is van één laag, hoeven we niet moeilijk te doen over het feit dat de repository-implementaties domeinobjecten geven en nemen.




Request in LoginModule

Door: Jan-Kees van Andel, 28 July 2008

Je zult het misschien weleens gewild hebben, vanuit je JAAS LoginModule toegang hebben tot je HttpServletRequest. Helaas biedt JAAS hier geen ondersteuning voor.
Je JAAS LoginModule wordt namelijk door JAAS aangeroepen en je krijgt alleen een Subject, een CallbackHandler implementatie en nog een zootje parameters mee. Maar dus geen servlet objecten.

JACC

Voor deze beperking heeft Sun een oplossing (bestaal al sinds 2003), namelijk JACC. JACC staat voor Java Authorization Contract for Containers en is een specificatie die eigenlijk voor Container leveranciers bedoeld is. Echter, je kunt het als applicatie ontwikkelaar ook gewoon gebruiken.

JACC heeft namelijk de klasse PolicyContext en in deze klasse zit een methode getContext(String).

getContext accepteert de volgende Strings:

  • javax.security.auth.Subject.container
    Geeft het huidige Subject terug.
  • javax.xml.soap.SOAPMessage
    Geeft de SOAPMessage terug bij een EJB Web Service Endpoint (alleen EJB).
  • javax.servlet.http.HttpServletRequest
    Geeft het request terug.
  • javax.ejb.EnterpriseBean
    Idem voor de EJB.
  • javax.ejb.arguments
    Geeft een array terug met de parameters waarmee de EJB aangeroepen wordt. (alleen EJB)

In de spec staat niets over Java EE 5 of EJB 3.0, maar aangezien aan de onderliggende architectuur niets veranderd is, zal het ook op een Java EE 5 container wel werken.

Het HttpServletRequest

Hieronder staat een LoginModule die de HttpSession nodig heeft.

import javax.security.jacc.PolicyContext;
import javax.security.jacc.PolicyContextException;

// Other imports skipped

public class CustomLoginModule implements LoginModule {

    private Subject subject;
    private CallbackHandler callbackHandler;
    private Object object;

    public void initialize(Subject subject,
                           CallbackHandler callbackHandler,
                           Map sharedState,
                           Map options) {

        this.subject = subject;
        this.callbackHandler = callbackHandler;

        // Get an object from the HttpSession.

        try {
            HttpServletRequest req = (HttpServletRequest) PolicyContext.getContext("javax.servlet.http.HttpServletRequest");
            object = req.getSession().getAttribute("someAttribute");
        } catch (PolicyContextException e) {
            LOGGER.error("Unable to retrieve object from user session:", e);
            object = null;
        }
    }

    public boolean login() throws LoginException {
        // Do some login stuff and use the object from the session
    }

    public boolean commit() throws LoginException {}

    public boolean abort() throws LoginException {}

    public boolean logout() throws LoginException {}
}

Zoals je ziet, kun je via PolicyContext.getContext gemakkelijk aan het request komen. En als je een request hebt, is de sessie niet ver meer.

Met deze klasse wordt het dus stukken gemakkelijker om context specifieke zaken te gebruiken bij het inloggen.




Niet verder vertellen hoor, SpringSource heeft een Application Platform

Door: philippe, 15 May 2008

Hebben jullie het al gehoord, er is een nieuwe applicatie server. Of eigenlijk moet ik zeggen SpringSource heeft een applicatie platform (S2AP) uitgebracht. Dit is een applicatie platform gebaseerd op onderandere het Spring Framework en Spring Dynamic Modules. Spring Dynamic Modules is een op Open Services Gateway initiative (OSGi) gebaseerde technologie.

 

Verder maakt het platform, wat momenteel nog in Beta stadium verkeert, gebruik van Apache Tomcat als Servlet container.

 

Wat is nu zo speciaal aan nog een applicatie server/platform. Wat het S2AP zo speciaal maakt is dat het nu de mogelijkheden van OSGi bundels combineert tot een dynamisch applicatie platform.

 

Het is nu niet meer nodig om een WAR file te maken waar alle afhankelijkheden in de WEB-INF/lib directorie zijn geplaatst. Nee afhankelijkheden worden middels zogenaamde bundels in het platform geïnstalleerd. Middels het manifest worden nu de afhankelijkheden aangegeven. In deze afhankelijkheden kunnen ook versie nummer meegegeven worden. Zo is het dus mogelijk om binnen het platform meerdere versies van een bundle te hebben draaien.

 

Een bundle is niets engs of iets kompleet nieuws, een bundle is niets anders dan een standaard jar file maar waarbij het manifest is uitgebreid met een aantal door OSGi en spring gedefinieerde headers.

 

Kijk ook eens op : http://www.springsource.com/web/guest/products/suite/applicationplatform

 

Is dit de toekomst? Ik zie wel voordelen, maar zullen klanten het ook aandurven?