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

Archief ‘Algemeen’ categorie




Boekbespreking: Programming in Scala

Door: Hedzer Westra, 12 April 2009

Programming in Scala

Auteurs: Odersky, Spoon & Venners, publicatiejaar: 2008 (1e druk november, 2e druk binnenkort), uitgever: Artima, pagina’s: 736, ISBN-13: 978-0-9815316-0-1, website: http://www.artima.com/shop/programming_in_scala, prijzen: Jolt Productivity Award 2009 for Technical Books.

Belofte maakt schuld: het is tijd voor mijn eerder aangekondigde boekbespreking van “Programming in Scala”.

Ik vond het een prettig & helder boek. In 33 goed leesbare en goed geordende hoofdstukken worden (bijna) alle onderdelen van de taal en de bijbehorende bibliotheek beschreven.

De hoofdstukken zijn goed gebalanceerd – niet te lang en niet te kort, niet te simpel en niet te ingewikkeld. “Programming in Scala” is helder van structuur, bevat een uitgebreide woordenlijst en slechts een korte bibliografie.

De auteurs hebben het niet gedaan, maar je kunt wat mij betreft de hoofdstukken ruwweg in 6 delen onderverdelen: inleiding, basis, standaardelementen, gevorderd, extra’s en frameworks.

De tekst bevat veel vooruitverwijzingen en voetnoten. Het onderwerp van veel hoofdstukken wordt een aantal hoofdstukken later weer opgepakt, zodat dat onderwerp even wat tijd heeft gehad om te bezinken. De ‘fast tracks’ maken het mogelijk om lastiger of verdiepende stukken over te slaan.

Naast uitleg over wat Scala is, wordt ook veel duidelijk gemaakt over wat je er mee kunt doen; het verschil in programmeerstijl tussen Imperatief Programmeren (IP) en Functioneel Programmeren (FP) wordt diverse keren behandeld – er is veel voorbeeldcode die laat zien hoe je recursief, en in ’t algemeen in FP-stijl, kunt programmeren. Ook conventies die in de community ontwikkeld zijn, komen aan bod.

Het boek is tevens beschikbaar als eBook – ik had vanaf afgelopen september een preprint tot mijn beschikking. Ik was verbaasd over de leesbaarheid ervan – zelfs op een gewone laptop; niets eens op een speciale eBook reader. Ook is alle voorbeeldcode te downloaden.

Er wordt vrij weinig gerefereerd naar andere talen dan Java. Sowieso vind ik het boek goed leesbaar voor Javanen, maar of dit ook geldt als je kennis meer ligt bij andere talen, vraag ik me af.

Als tipje van de sluier wat betreft de inhoud volgt hier een (korte?) opsomming van de taalaspecten die behandeld worden: traits, closures, case classes, type parameters inclusief variance & erasure, implicits, pattern matching & extractors, for expressions, operator overloading, interne & externe DSL’s, lazy evaluation, currying, 1ste-klasse & hogere-orde functies, typehiërarchie en bibliotheken (onder anderen collecties, XML, Actors, parser combinator, Swing, testen).

Hoofdstuk 28 vond ik een vreemde: hierin wordt namelijk stap voor stap uitgelegd hoe je netjes equals() & hashCode() kunt implementeren. Inderdaad belangrijk, maar helemaal niet Scala-specifiek. Er wordt dan ook veelvuldig wordt gerefereerd naar Joshua Bloch’s “Effective Java.”

Het hoofdstuk over integratie tussen Scala & Java viel me wat tegen – het is erg kort. Nu is het wel zo dat Scala & Java naadloos integreren, en er dus niet al te veel aandacht aan besteed hoeft te worden, maar iets meer had geen kwaad gekund.

Het afsluitende voorbeeld vond ik wel erg interessant. In minder dan 200 regels code worden erg veel taalaspecten gebruikt, en de volgende technieken worden gecombineerd tot een spreadsheetapplicatie: Interne & externe DSL (Swing & formules), termevaluatie en separation of concerns – MVC en Pub/Sub (op 2 niveaus).

“Programming in Scala” is niet bedoeld als referentie of handleiding; dit is duidelijk een leerboek, onder anderen vanwege de grotere & kleinere codevoorbeelden, die de tekst extra verhelderen. Mijn aanbeveling is om ‘t van voor tot achter te lezen, en niet hapsnap, anders zul je details missen. Al met al biedt het boek op een toegankelijke manier een complete behandeling van de taalaspecten van Scala, en kun je – tijdens het lezen al – zelf aan de gang met deze erg interessante taal.

Kleurindicatie: Groen (3 op schaal van 3)

Nu ik toch jullie aandacht heb wat betreft Scala: op dinsdag 9 juni geef ik een TechSessie over Scala. Primair bedoeld voor J-Tech’ers, maar natuurlijk zijn alle Ordina-medewerkers welkom. Binnenkort kun je een uitnodiging in de mail verwachten!

Hedzer Westra

Hedzer Westra




Hoe agile is architectuur?

Door: Eric Jan Malotaux, 20 March 2009

Sinds er software ontwikkeld wordt is één van de grootste uitdagingen daarbij hoe je ervoor zorgt dat je precies bouwt wat nodig is. Hoe houd je de afstand tussen klant en ontwikkelaar klein, terwijl er allerlei krachten werkzaam zijn die die afstand juist vergroten? Bijna iedere methode of programmeertaal belooft een oplossing voor dit probleem.

Neem COBOL, één van de oudste programmeertalen: de naam COBOL betekent COmmon Business Oriented Language.  Het idee was dat met COBOL business mensen zelf konden programmeren. Dat is nooit gelukt natuurlijk. COBOL wordt algemeen beschouwd als een moeilijke programmeertaal, en COBOL programmeurs, hoewel een uitstervend ras, blijven nodig om de enorme hoeveelheid COBOL programmatuur die nog altijd in gebruik is te onderhouden.

SQL, zelfde verhaal. In SQL vertel je de computer, of de database eigenlijk, wat je met de gegevens wilt, maar niet hoe. Inmiddels wordt SQL zelfs voor gemiddelde programmeurs als te moeilijk beschouwd, en zijn er Object-Relational Mappers om ze tegen de “complexiteit” van SQL te beschermen.

Volgende kandidaat: UML.  We maken diagrammen, plaatjes die gebruikers kunnen begrijpen of zelf maken, en een code-generator die de plaatjes vertaald naar programma’s, en de gebruiker is weer “in control”. Ook deze aanpak, hoewel vrij recent, is inmiddels weer uit de gratie. Zie mijn eerdere post “Wat is er nieuw aan Model-Driven Development?“. Het gebruik van DSL’s in plaats van UML helpt wel een beetje, omdat een DSL nu eenmaal eenvoudiger is. Maar de verwachting van sommigen, dat het domein specifieke karakter van een DSL betekent dat een domein expert ermee kan programmeren kunnen we op basis van de eerdere voorbeelden gerust als naïef beschouwen. Al is het maar omdat het domein van een DSL vrijwel nooit het domein van de gebruiker is, maar dat van de programmeur.

Goed, nieuwe programmeertalen of in het algemeen technische hulpmiddelen helpen dus blijkbaar niet om de kloof tussen gebruiker en programmeur te verkleinen. Laten we het helemaal anders aanpakken. We hebben architecten nodig die de gebruiker helpen om de processen van zijn organisatie in kaart te brengen, en de automatisering daar precies op te laten aansluiten. En we introduceren een Service Oriented Architecture (SOA), zodat alle applicaties makkelijk met elkaar kunnen communiceren via services, en een process engine waarmee we de processen heel direct kunnen ondersteunen door de services in de juiste volgorde aan te roepen. Alleen, SOA experts worden niet moe om te benadrukken dat een SOA niet makkelijk in te voeren is in een organisatie, dat de beoogde voordelen – snelle aanpasbaarheid van de automatisering aan de veranderende eisen van de business – pas na jaren behaald zullen worden. Tenminste, als de invoering op de juiste manier wordt gedaan, en er gezorgd is voor een goede inbedding in de organisatie.  Governance is hier het toverwoord.

Klinkt allemaal prachtig, maar ik geloof er geen woord van. Ten eerste, hoezo snelle aanpassing aan veranderende eisen, als je eerst jaren moet investeren?  Ten tweede, governance wekt bij mij de associatie van “programming by commitee”. Moet dat sneller gaan dan programmeren door één of twee programmeurs? Ten derde, nu zitten de architecten tussen de gebruiker en de ontwikkelaars, zodat de afstand juist groter geworden is. De goede niet te na gesproken natuurlijk, maar veel van deze architecten hebben weinig affiniteit met de praktische problemen waar programmeurs mee te maken hebben bij het implementeren van een SOA. Ik hoor architecten vrijwel altijd klagen dat de programmeurs zich niet aan hun richtinggevende kaders houden. Hoe zou dat toch komen? Even opvallend is dat die organisaties de er een aparte afdeling architecten op na houden meestal ook degene zijn waar het hele software ontwikkelproces vrijwel tot stilstand is gekomen.

Is er dan helemaal geen hoop? Jawel, die is er. Die projecten die radicaal agile werken, volgens eXtreme Programming, Scrum, Evo of hoe ze ook heten, met een on-site customer, behalen ook een radicaal hogere productiviteit, en bouwen wat de klant wil. Behalve dat de verhalen overtuigend klinken heb ik het ook zelf ervaren. Dat beviel zo goed, dat ik eigenlijk niet meer anders wil en misschien ook niet meer kan.

Ondanks de goede resultaten is er toch veel weerstand tegen agile methoden.  Eén veelgehoord bezwaar is, dat grote systemen niet zonder architectuur kunnen, en dat een agile werkwijze tot chaotische onbeheersbare systemen leidt. Het eerste is waar: architectuur is nodig. Het tweede is niet waar: agile leidt niet noodzakelijk tot onbeheersbare chaos. Maar agile is geen vervanging voor vakmanschap. Alleen de manier waarop de architectuur tot stand komt is helemaal anders. Architectuur is een bijprodukt van software ontwikkeling. Het ontstaat tegelijk met de software zelf, en niet vooraf.  Alleen dan is er hoop dat de architectuur als een maatpak bij de applicatie past.

Systemen zijn tegenwoordig zo ingewikkeld, dat ze niet zonder architectuur kunnen. Diezelfde complexiteit is er ook de oorzaak van, dat die architectuur niet meer helemaal vooraf bedacht kan worden. Wordt dat wel geprobeerd, dan leidt dat tot starre systemen die moeilijk veranderd kunnen worden, precies wat diezelfde architectuur probeert te vermijden. Immers, het hoeft niet meer veranderd te worden, er is toch van tevoren over nagedacht? Kortom architectuur moet, maar wel via een agile proces.




IBM wil Sun overnemen?

Door: Stephan Oudmaijer, 18 March 2009

Het is nog geen 1 april, maar toen ik vanmorgen het onderstaande bericht las moest ik toch echt even denken aan een 1 april grap. In hoeverre dit waar is?

IBM onderhandelt met Sun Microsystems over een overname. Big Blue zou 6,5 miljard dollar voor Sun op tafel willen leggen en met de overname zijn positie op de internet-, software- en telecommunicatiemarkt willen versterken.

De twee Amerikaanse bedrijven zouden deze week al tot een overeenkomst kunnen komen, meldt The Wall Street Journal. De krant weet echter ook te melden dat er nog niets is beslist en dat de onderhandelingen ook zonder succes afgebroken kunnen worden. Sun heeft moeite om winst te maken en zou al meerdere bedrijven over een acquisitie gepolst hebben, maar tot nu toe zonder succes: onder andere HP zou Sun al de deur hebben gewezen. Voor IBM zou het de grootste overname in zijn geschiedenis zijn. Vorig jaar betaalde het computerbedrijf 5 miljard dollar om het in business intelligence gespecialiseerde Cognos in te lijven.

Met Sun in de gelederen zou IBM zijn omzet voor bijna een derde uit hardware halen, waar het zich de afgelopen jaren juist meer op software en diensten richtte. Verder hebben de multinationals een nogal verschillende bedrijfscultuur: het in 1982 opgerichte Sun richt zich vooral op innovatie, terwijl het uit 1911 stammende International Business Machines zich met name op de vraag in de markt oriënteert. Aan de andere kant zijn er de nodige overeenkomsten: de band met Microsoft en Intel is bij beide bedrijven niet sterk en zowel IBM als Sun leunen zwaar op Linux en Java.

Bron: http://tweakers.net/nieuws/59083/ibm-wil-sun-microsystems-overnemen.html




Spelen met Java Bluetooth

Door: Hedzer Westra, 21 February 2009

Bluetooth logo

De Bluetooth JSR-82 en de API daarbij zijn al enkele jaren oud (v1.1: 2002), maar voor mij was het een nieuwe. Hiermee kun je vanuit Java met bluetooth apparaten communiceren. Het leek me wel leuk om, al forenzend in de trein een eBook te lezen en tegelijkertijd te zien wie er allemaal elke dag met me meereist. Deze zelfde exercitie is natuurlijk ook uitstekend in de file of op vaste locaties uit te voeren…

Inmiddels hebben heel veel apparaten een bluetooth (‘bt’) module: GPS ontvangers, WiiMotes, smartphones, billboards, verkeerslichten, you name it. Elk ingeschakeld apparaat adverteert zijn nummer en meestal een (door de fabrikant of eigenaar ingestelde) naam. De leukste tot nu toe vond ik “smartföhn”, maar voornamelijk zie je de naam van de eigenaar, of het merk & type van het apparaat verschijnen. O, en laat ik vooral ‘Dennis Ordina’ niet ongenoemd laten! Welke collega met Nokia telefoon met bt adres 001A165A1686 zat op 4 februari om kwart voor zes in de intercity van Amsterdam Bijlmer naar Utrecht CS? :-) Als laatste vermelding: één telefoon had als naam het 06-nummer. Lijkt me niet handig, behalve als je wilt dat Jan en alleman je belt…

De naam Bluetooth komt overigens van de 10e-Eeuwse koning van Denemarken en Noorwegen: Harald Blåtand (niet te verwarren met Blauwbaard!). Het logo is afgeleid van de runentekens van zijn initialen.
De laatste bluetoothversie (uit 2007) is 2.1+EDR (3Mbps), en er wordt gewerkt aan een high speed variant die moderne WiFi-snelheden haalt. De radius is afhankelijk van de ‘class’ 100, 10 of 1 meter.

Begrippen

Eerst vuur ik enkele begrippen op je af uit de ‘bt’ wereld, waarna wat codevoorbeelden langskomen.

Protocol bluetooth is opgebouwd als OSI network stack van protocollen, waarvan de interessantste L2CAP (Logical Link Control and Adaptation Protocol), RFCOMM (Radio Frequency Communications) en OBEX (OBject EXchange) zijn. Het zijn op elkaar gestapelde transportprotocollen net zoals TCP en IP op elkaar gestapeld zijn. L2CAP is packet oriented en RFCOMM stream oriented. OBEX is session oriented.
Profiel interfacespecificatie; ruwweg een netwerkprotocol op applicatieniveau. Er zijn er zo’n 25 gedefinieerd; voorbeelden zijn FTP (file transfer), HID (muis/keyboard), OPP (vCards), BIP (plaatjes) en PAN (piconet). JSR-82 omvat alleen de basisprofielen GAP, SPP, SDAP, GOEP en de daarbij horende protocollen SDP (GAP+SDAP), OBEX (GOEP), RFCOMM (SPP) en L2CAP. Andere profielen moet je zelf uitprogrammeren!
Bt adres vergelijkbaar aan een Ethernet MAC-adres. Bestaat uit 12 hex digits, waarvan de eerste 6 verdeeld zijn onder de fabrikanten. Aan het adres kun je dus al zien of het bijvoorbeeld een Nokia of Motorola apparaat betreft!
Master net zoals er bij TCP/IP-verbindingen servers (daemons) zich registeren op een bekende poort en clients hiernaar connecten, is bt ook client/server georiënteerd; de server heet ‘master’ en registreert (publiceert) services. Dit vind je terug in bt UUIDs en URLs.
UUID uniek nummer om een service (gedefinieerd in een profiel) te identificeren, vergelijkbaar aan een server IP port number. In 3 lengtes: 4, 8 of 32 hex digits. Er bestaat een simpele conversie om 4/8-digit UUID’s naar volledige lengte te converteren: concateneren met het vaste nummer 00001000800000805F9B34FB. Enkele voorbeeldwaarden: OBEX File Transfer = 0×1106, Human Interface Device Profile (WiiMote!) = 0×1124.
BCC Bluetooth Control Centre; een GUI om je device, services & security te configureren, en te zoeken naar & pairen met andere devices. Meegeleverd met je bt driver.
URLs je maakt connecties met behulp van URLs in het bekende formaat. Server URLs bevatten altijd “localhost”, de service UUID en eventueel parameters zoals een naam. Client URLs bevatten het remote bt adres, het kanaal- of PSM [Protocol Service Multiplexer] nummer – vergelijkbaar met een client IP port number; is niet hetzelfde als een service UUID – en eventueel (security) parameters. Enkele voorbeelden:
o OBEX/GOEP
Server btgoep://localhost:ed495afe28ed11da94d900e08161165f
Client btgoep://00A3920B2C22:12
o RFCOMM/SPP
Server btspp://localhost:;name=Sample SPP Server
Client btspp://0050CD00321B:3;authenticate={true|false}; authorize={true|false};encrypt={true|false}
o L2CAP
Client btl2cap://0050CD00321B:1003; ReceiveMTU=512;TransmitMTU=512
Piconet mininetwerk van maximaal 8 bt devices – meer verbindingen ondersteunt bluetooth niet. Een netwerk van meerdere aan elkaar gekoppelde piconets heet een scatternet.
Service class elk bt device kan met zijn service class aangeven welke service types hij ondersteunt (bijv. positioning, networking of audio) en van welk (sub)type hij is (bijv. Computer/Laptop of Peripheral/Joystick).
Discovery scannen naar devices en/of services. Na discovery levert JSR-82 je URLs zodat je die niet zelf hoeft op te bouwen. Een bt device kan altijd (‘global’/’general’) discoverable zijn (GIAC), een beperkte tijd (‘limited’ – LIAC) of helemaal niet. Dit poor-mans beveiligingsmechanisme is bekend van WiFi routers. Ook daar is de fabrieksinstelling meestal niet de veiligste… Discovery is niet erg snel; een complete sweep van devices & hun services duurt afhankelijk van het aantal devices in bereik één tot meerdere minuten, dit onder andere omdat er geen parallelle service discoveries kunnen draaien.
Service record bij discovery van een service ontvang je een lijst van attributen met onder anderen een leesbare naam en kanaal (RFCOMM&OBEX)- of PSM (L2CAP) nummer. Helaas vullen niet alle bt devices dit service record exact volgens de specs.
Pairing pas nadat apparaten aan elkaar bekend zijn gemaakt middels een PIN-code (meestal 0000…) kan communicatie gestart worden. Helaas voor mijn tagger kan dit alleen via de BCC; de JSR-82 API voorziet er niet in om een PIN-code door te geven. Bij pairing wordt overigens ook een gedeelde 128b sleutel afgesproken, die daarna gebruikt wordt als autorisatie en/of encryptie aangezet worden. Dat laatste kan dan wel weer vanuit Java. Discovery is overigens wel mogelijk zonder te pairen; mijn tagger kan van elk device dat in bereik is en in bluetooth discovery mode staat (hetgeen bijna elke telefoon is, vanuit de winkel) de volgende attributen uitvragen: bt adres, naam, service class, services inclusief naam, UUID en URL. Als een pairing wel bestaat (in JSR-82 termen: het device is ‘trusted’), is het mogelijk om een connectie op te bouwen, bijv. simpelweg om de pingtijd te meten.

Codevoorbeelden

De betrokken Java packages zijn: javax.bluetooth, javax.obex en javax.microedition.io.
Wat betreft dat laatste package: JSR-82 heeft veel raakvlakken met J2ME (termen in het verlengde hiervan: MIDP, CLDC en CDC), wat logisch is omdat bluetooth in 1998 door Nokia bedacht is als draadloze communicatie van mobieltjes naar andere apparaten. Mocht je iets met J2ME & bt willen doen (laat me je resultaten weten!): telefoons kunnen zelf ook JSR-82 implementeren, maar niet alle telefoons met bt & Java doen dat! Zie de bluecove Wiki voor een lijst.

De API is vrij klein. De belangrijkste klassen zijn DiscoveryAgent, LocalDevice en RemoteDevice.

Twee problemen die ik ben tegengekomen met deze API:
1. Een afgrijselijke klasse is DataElement. Dit is een wrapper voor diverse soorten datatypes. Je zult er helaas mee moeten leven.
2. Als je alleen het bt adres van een device weet, dan moet je eerst discoveren. Je kunt namelijk niet op basis van dit adres een RemoteDevice (laten) instantiëren. Maar als je een URL kent kun je wel meteen connecten! Vreemd…

Nu volgen enkele zeer kleine & korte codevoorbeelden – check voor enkele compleet werkende applicaties de Eclipse workspace op de Ordina Wiki. (Helaas zijn de syntax highlighting & tabs verloren gegaan bij kopiëren vanuit Word naar WordPress…)

// setup: get local device & discovery agent
LocalDevice localDevice = LocalDevice.getLocalDevice();
DiscoveryAgent discoveryAgent = localDevice.getDiscoveryAgent();

// start global device inquiry
MyDiscoveryListener discoveryListener = new MyDiscoveryListener();
boolean limited = false;
boolean started = discoveryAgent.startInquiry(
limited ? DiscoveryAgent.LIAC : DiscoveryAgent.GIAC,
discoveryListener);

// retrieve name of first remote device in list
RemoteDevice remoteDevice = discoveryListener.getDiscoveredDevices().get(0).getRemoteDevice();
String deviceName = remoteDevice.getFriendlyName(true);

// search for services using RFCOMM on the first remote device
UUID[] uuids = new UUID[]{new UUID(BluetoothConstants.PROTOCOL_RFCOMM)};
int transId = discoveryAgent.searchServices(null, uuids, remoteDevice,
discoveryListener);

// retrieve a connection URL using the first service record
ServiceRecord record = discoveryListener.getServiceRecords().get(transId)[0];
String url = record.getConnectionURL(ServiceRecord.NOAUTHENTICATE_NOENCRYPT, false);

// open L2CAP, RFCOMM & OBEX connections
L2CAPConnection l2capConnection = (L2CAPConnection) Connector.open(url);

StreamConnection rfcommConnection = (StreamConnection) Connector.open(url);

ClientSession obexConnection = (ClientSession) Connector.open(url);
HeaderSet hsConnectReply = obexConnection.connect(null);
if (hsConnectReply.getResponseCode() != ResponseCodes.OBEX_HTTP_OK) {
// 196 = not found, 204 = precon failed, 160 = ok
LOG.error(“expected OBEX_HTTP_OK but got ” + hsConnectReply.getResponseCode());
}

Hoe service registratie werkt (dit is: opzetten van een server connectie die wacht op clients) kun je terugvinden in de Eclipse workspace.

OBEX – OBject EXchange

OBEX is ‘geleend’ van de IrDa (infrarood) wereld, vandaar dat de API een eigen package javax.obex heeft. Binnen bt werkt OBEX bovenop RFCOMM, maar OBEX ondersteunt ook IrDa en TCP/IP als transportlaag.

Ondersteunde diensten zijn o.a. FTP (phone2PC), Object Push (phone2phone – zogezegd gebruikt bij toothing, Sync, basic imaging en basic printing.

Het protocol doet denken aan HTTP. Herkenbare concepten zijn:
• Headers 12 gedefinieerde parameters, o.a. name, type en length
• Sessions op basis van connectie ID
• Content types text/vcard, x-obex/folder-listing, etc.
• Commands CONNECT, PUT, GET, SETPATH, ABORT, CREATE-EMPTY, PUT-DELETE en DISCONNECT
• Error codes OBEX_HTTP_OK, OBEX_HTTP_NOT_FOUND, etc.

Voorbeelden van uit te wisselen data zijn: vCard, vCalendar, vMessage, vNotes en platte bestanden.

De belangrijkste 4 klassen/interfaces en hun supertypes zijn:
• ClientSession > Connection
• HeaderSet
• Operation > ContentConnection > StreamConnection > OutputConnection & InputConnection > Connection
• SessionNotifier > Connection

JSR-82 implementaties & bt stacks

Bluecove is momenteel de enige actief onderhouden, bruikbare en gratis JSR-82 implementatie, maar werkt gelukkig redelijk goed. Bluecove heeft wel een bluetooth stack nodig. Voor Windows wordt widcomm aangeraden en BlueSoleil ten zeerste afgeraden – dit kan ik beamen! De bluetooth stack wordt meegeleverd met je chipset, dus kiezen kun je niet. Gelukkig bevat mijn Ordina laptop (HP Compaq 6910p) een widcomm ingebouwd. Wel eerst even een service pack van 100MB installeren! Voordat ik dat deed werd de widcomm niet herkend en ben ik met een USB bt stikkie van cygnet aan het klooien geweest. Helaas zat daar BlueSoleil bij en dat ging niet erg lekker.

Op Linux kun je gebruik maken van de BlueZ stack. Ik heb ‘m niet geprobeerd – laat me je ervaringen weten!

Een mogelijk client programma is Nokia PC Suite, die bijvoorbeeld. een remote file browser biedt. Helaas installeert Nokia zoveel dingen achter je rug om (koppelt onder andere de JAR extensie aan een Nokia application installer!) dat ik deze afraad.

Overigens werkt ook de combinatie widcomm & bluecove niet vlekkeloos. Enkele keren heb ik een JVM crash gehad, een vastlopende BT stack (een volledige herstart helpt, maar soms is killen van BTStackServer.exe voldoende), een BCC die mijn connecties afpakte (alleen een unpair/pair-actie verhelpt dit), et cetera. Als je de documentatie van bluecove mag geloven, ligt dit eerder aan de slechte staat van bluetooth stacks, danwel aan een mismatch tussen stacks en JSR-82, dan aan bluecove zelf. Toch krijg ik een beetje een déjà-vu met JMF en Java Serial: ook dit zijn Java extensies waarvoor eigenlijk nooit een goede (reference) implementatie is gekomen, en door Sun een beetje aan hun lot lijken te zijn overgelaten.

Documentatie

Er bestaat een bluetooth SIG die alle specs publiceert; onder andere die van alle profielen. Helaas moet je voor de meest informatie lid zijn, en dat kunnen alleen betalende bedrijven of universiteiten. Ik heb ze gecontacteerd voor een simpele lijst met standaard UUID nummers, en kreeg pas na lang aandringen antwoord – natuurlijk pas nadat ik mijn code af had. De online documentatie & tutorials die ik wél gevonden heb is helaas vaak slecht, oud, weinig diepgaand en lastig te vinden – ik heb hier en daar door open source code moeten snuffelen voor ontbrekende informatie (zoals voornoemde UUID nummers).

Voor mijn source code, verwijzingen naar boeken, meer technische informatie, een lijst van geregistreerde UUIDs, attributen en service classes, en extra URLs verwijs ik je naar de Ordina Wiki pagina die ik hiervoor opgezet heb.

Mocht je zelf ook aan de gang gaan met Java bluetooth, dan hoor ik graag van je terug wat je resultaten zijn. Codebijdragen zijn natuurlijk welkom op de Wiki!

Hedzer Westra

Hedzer Westra




Domain Driven Design in de Referentie Architectuur.

Door: Pieter van Boxtel, 19 February 2009

In de huidige versie van de Referentie Architectuur hebben we verklaard aanhanger te zijn van Domain Driven Design. We hebben domein objecten gedefinieerd, maar wat doen we nu eigenlijk met het gedachtengoed van Evans? Een van de doelen voor de volgende versie is te kijken of we de patterns van DDD een plekje kunnen geven. Hieronder een poging daartoe, waarbij ik niet al te veel beschrijving of uitleg van de patterns geef. Voor een goede uitleg van de patterns is een niet te overtreffen bron, en dat is het boek van Evans.

Evans beschijft eigenlijk twee soorten patterns. De eerste soort geeft een onderscheid in typen objecten en methoden. Deze patterns zijn concreet terug te zien in een domein model. Dit zijn de patterns waar we echt iets mee kunnen in de referentie architectuur. De tweede soort zijn eerder proces patterns. Deze beschrijven wat abstractere doelen en wegen naar deze doelen. Deze patterns zijn moeilijk concreet te maken in een referentie architectuur en ze komen hier verder niet meer aan bod.

Kern van een DDD domein model zijn Entities (89) en Value Objects (97). Dit zijn de klassieke OO objecten met een toestand en gedrag. Entities zijn objecten met een “identiteit”. Ze zijn niet uitwisselbaar. Ze kunnen gedurende hun levensduur veranderen, maar ze blijven uniek. Een persoon object is in de regel een Entity. Een persoon wordt ouder, zijn uiterlijk verandert, allerlei attributen wijzigen, maar een persoon blijft dezelfde identiteit. Value Objects daarentegen zijn wel uitwisselbaar. In een klantencontactsysteem is een adres niets meer dan een verzameling attributen. Een adres object kan hergebruikt worden, maar dat hoeft niet. Het maakt niet uit als in het systeem twee adres objecten geïnstantieerd zijn met hetzelfde adres. En als een persoon en zijn adres uit memory verdwijnen, dan is het wanneer de persoon opnieuw opgevraagd wordt niet belangrijk dat hetzelfde adres object teruggevonden wordt. (Voor een kadastraal systeem gaat deze redenatie uiteraard niet op…)

Onderscheid tussen Entities en Value Objects is waardevol bij het ontwerp van een applicatie. We kunnen andere ontwerpregels op deze typen objecten loslaten. Zo is het een goed idee om Value Objects immutable te maken. Wanneer een attribuut dient te wijzigen vervangen we het object gewoon door een nieuwe instantie. Fowler definieerde het onderscheid tussen Entities en Value Objects al in Patterns of Enterprise Application Architecture. Hij lijkt Value Objects echter te suggereren voor algemene, herbruikbare zaken, zoals Money. Evans gebruikt het onderscheid structureler door elk “klassiek” domein object in een van beide hokjes te duwen. Bijvoorbeeld in een facturatie systeem kunnen we facturen modelleren als Entities en factuurregels als Value Objects.

Ook geeft Evans enkele richtlijnen voor het opstellen van Entities en Value Objects:

  • Gebruik Intention-Revealing Interfaces (246), waarbij namen van klassen en methoden hun effect en doel beschrijven.
  • Gebruik Side-Effect-Free Functions (250), factor deze uit in Value Objects en maak er Closed Operations (268) van.
  • Maak daarentegen van Entity methodes die de state wijzigen commands die geen domein klassen teruggeven. Gebruik Assertions (255) om post-condities en invarianten van deze methodes te controleren.

Services (104) zijn objecten met enkel gedrag. Ze bevatten methoden die geen logische plek hebben in een Entity of Value Object. De naam ‘Service’ is enigszins verwarrend aangezien de term ’service’ in de Referentie Architectuur en andere architecturen in een andere context gebruikt wordt. Een betere naam is wellicht ‘Domain Service’.

Entities en Value Objects zijn de objecten in het domein model die gepersisteerd worden. Factories (136) en Repositories (147) zijn de domein objecten die voor persistentie verantwoordelijk zijn. Factories creëren domein objecten en Repositories bieden zoek-ingangen. Een Factory is in feite geen afzonderlijk type object. Een Factory wordt gerealiseerd door middel van een Factory Method (GoF) op een Entity of op een al dan niet speciaal voor het doel gecreëerde Service. Door vanuit de Factory Method te delegeren naar een ‘add’ methode op een Repository bewerkstelligen we dat database logica in één type domeinobject gecentreerd wordt.

De eenheid voor persistentie is een Aggregate (125). Dit is verzameling van een of meerdere entities en value objects, waarbij één entity, de root, als aanspreekpunt fungeert. Alle niet-root objecten in de aggregate staan uitsluitend ter dienste van de root en objecten buiten de aggregate hebben uitsluitend relaties naar de aggregate root.

Verder kunnen domeinobjecten gegroepeerd worden in Modules (109), om zodoende structuur te creëren in het domeinmodel. Modules of Packages zijn standaard concepten in OO programmeertalen en modelleertechnieken.

Een Specification (224) tenslotte is een eenvoudig Value Object dat een (of meerdere) business rule controleert voor een ander object. Specifications zijn gebaseerd op predicatenlogica waardoor ze als logische condities zijn te combineren tot complexere business rules. Een Specification kan drie doelen hebben:

  1. Validatie van een business rule op een object. Een toepassing hiervan is de manier waarop Mod4J met business rules in de domein DSL omgaat.
  2. Een selectie criterium specificeren om een object uit een selectie te selecteren. Een toepassing hiervan is gebruik van een Specification als parameter voor een Repository.
  3. Bouw van een nieuw object specificeren.

Onderstaand plaatje toont bovenstaande patterns en hun relaties:

De hierboven genoemde patterns kunnen we zonder al te grote gevolgen in de referentie architectuur opnemen ter vervanging van / uitbreiding op de huidige typen business componenten. De vertaling gaat dan als volgt:

  • De huidige Referentie Architectuur kent Business Processen, welke vergelijkbaar lijken met Domain Services. Business Processen zijn echter geen onderdeel van het domein model, ze worden niet aangeroepen door domein objecten. Verder stelt de Referentie Architectuur dat elke aanroep van een domein object via een business process gaat. In feite hebben we met deze Business Processen een extra “laagje” gecreëerd dat redundant is, aangezien erboven zich een verplichte servicelaag bevindt. Niets let ons om dat laagje te schrappen en domain services alleen te definieren als ze een toegevoegde waarde hebben.
  • De domein objecten zoals we ze nu kennen kunnen we onderverdelen in Entities en Value Objects.
  • Aggregates worden nu wel genoemd in de implementation view als eenheid van persistentie, maar ze worden niet expliciet onderkend als modelleereenheid in de logische view.
  • Specifications zijn nieuw ten opzichte van de referentie architectuur, hoewel Mod4J ze wel al toepast voor business rules.
  • Repositories zitten nu in een afzonderlijke laag, de datalaag, en heten Data Access Logic component. Echter, zoals ik in een vorige blog betoogde is dat niet terecht en horen ze in de domeinlaag thuis.
  • Volgens diezelfde blog zijn de Service Agents en Data Service Agents zoals we ze nu kennen dezelfde dingen en kunnen we ze onderbrengen in een (nieuwe) laag, de Integratielaag.

Mijn conclusie is dat we door toepassing van de DDD patterns de referentie architectuur consistenter en begrijpelijker kunnen maken. In het ontwerp van een applicatie komt meer structuur, terwijl het resultaat, de implementatie, nagenoeg niet wijzigt ten opzichte van de huidige referentie architectuur. Bijkomend voordeel van toepassing van DDD is dat we voor de educatie van de architectuur kunnen verwijzen naar het boek “Domain Driven Design” van Evans.




Flat file parsing met Spring Batch

Door: Richard Kettelerij, 7 November 2008

Legacy systemen gebruiken vaak flat files voor gegevens uitwisseling. Bij integratie met dergelijk systemen moeten deze files worden geparst. In zo’n geval kan je natuurlijk zelf met de Java Scanner of StingTokenizer aan de slag gaan maar het is waarschijnlijk verstandiger om een bestaand framework te gebruiken. Spring Batch biedt hiervoor een elegante oplossing.

Mocht je overigens meer willen weten over Spring Batch en batch processing in het algemeen? Schrijf je dan in voor Special Meeting op 18 november a.s.

Bestandsdefinitie
Als voorbeeld gebruiken we een fixed-width file afkomstig uit een legacy systeem van een fictieve online videotheek. Zoals gebruikelijk bij deze vorm van gegevensuitwisseling bestaat het bestand uit verschillende soorten records: Een header record met metadata als een bedrijfsnaam en batchnummer, een footer record met een controlegetal en uiteraard een aantal records met de daadwerkelijke informatie; in dit geval film titels.

H OrdinaVideoStore.nl 12
M Shrek II
M Lord of War
M Godfather, The
M Kungfu Panda
F 0000000000000000006

Tokenizing
Om bovenstaand bestand te kunnen parsen dient allereerst onderscheid te worden gemaakt tussen de verschillende soorten records. Aangezien dit uit het eerste karakter van elk record kan worden afgeleid gebruiken we de PrefixMatchingCompositeLineTokenizer.

<bean id="movieFileLayout"
class="org.springframework.batch.item.file.transform.PrefixMatchingCompositeLineTokenizer">
	<property name="tokenizers">
		<map>
			<entry key="H" value-ref="movieHeaderRecordLayout" />
			<entry key="M" value-ref="movieRecordLayout" />
			<entry key="F" value-ref="movieFooterRecordLayout" />
		</map>
	</property>
</bean>
 
<bean id="movieHeaderRecordLayout"
	class="org.springframework.batch.item.file.transform.FixedLengthTokenizer">
	<property name="names" value="recordtype, videostore, batchid" />
	<property name="columns" value="1,5-25,28-30" />
</bean>

Deze tokenizer geeft records op basis van het type door aan een nieuwe LineTokenizer. Zoals je in bovenstande configuratie kunt zien mapped deze tokenizer elke fixed-width kolom naar een bijbehorende kolomnaam. Hier zie je duidelijk de kracht van de configuratie mogelijkheden in Spring. Je geeft gewoon in de application context de ranges van gerelateerde kolommen op en Spring Batch doet de rest. Om deze magic mogelijk te maken heeft Spring wel wat hulp nodig in de vorm van een CustomEditorConfigurer. Deze vertaald de range definities (5-3, etc) naar betekenisvolle Range objecten.

<bean id="customEditorConfigurer"
	class="org.springframework.beans.factory.config.CustomEditorConfigurer">
	<property name="customEditors">
	  <map>
	    <entry key="org.springframework.batch.item.file.transform.Range[]">
	      <bean class="org.springframework.batch.item.file.transform.RangeArrayPropertyEditor" />
	    </entry>
	  </map>
	</property>
</bean>

Mapping naar domein objecten
Vervolgens is het de bedoeling om de kolom/veld definities naar domein objecten te vertalen. Hiervoor heeft Spring Batch de FieldSetMapper interface geïntroduceerd. Hoewel we hiermee zelf de mapping van velden naar domein objecten kunnen verzorgen is het mogelijk om dit aan Spring Batch over te laten middels een FieldSetMapper gebaseerd op Spring’s BeanWrapper. Er moet echter ook onderscheid worden gemaakt tussen de verschillende record soorten. Hiervoor is – in tegenstelling tot de prefix-enabled tokenizer – geen standaard fieldset mapper aanwezig. Daarom schijven we zelf een eenvoudige mapper:

public class PrefixAwareMovieFieldSetMapper implements FieldSetMapper {
	private FieldSetMapper headerFieldSetMapper;
	private FieldSetMapper movieFieldSetMapper;
	private FieldSetMapper footerFieldSetMapper;
 
	public Object mapLine(FieldSet fieldSet) {
		final String recordType = fieldSet.readString("recordtype");
		if (recordType.equals("H")) {
			return headerFieldSetMapper.mapLine(fieldSet);
		}
		else if (recordType.equals("M")) {
			return movieFieldSetMapper.mapLine(fieldSet);
		}
		else if (recordType.equals("F")) {
			return footerFieldSetMapper.mapLine(fieldSet);
		}
		throw new IllegalStateException("onbekend record type");
	}
	// setters
}

Wanneer we deze FieldSetMapper configureren is de mapping van tokens naar domein objecten compleet.

<bean id="movieFileFieldSetMapper"
	class="nl.ordina.batch.PrefixAwareMovieFieldSetMapper">
	<property name="headerFieldSetMapper" ref="movieHeaderFieldSetMapper" />
	<property name="movieFieldSetMapper" ref="movieFieldSetMapper" />
	<property name="footerFieldSetMapper" ref="movieFooterFieldSetMapper" />
</bean>
 
<bean id="movieHeaderFieldSetMapper" 
   class="org.springframework.batch.item.file.mapping.BeanWrapperFieldSetMapper">
	<property name="prototypeBeanName" value="headerRecord" />
</bean>
 
<bean id="headerRecord" class="nl.ordina.batch.model.MovieHeaderRecord"
scope="prototype" />

Parsen
Nu we hebben gedefinieerd welke karakters naar welke velden mappen, en welke velden naar welk domein object mapped wordt het tijd om bestanden te parsen. Hiervoor gebruiken we een FlatFileItemReader die we injecteren met de eerder gecreërde tokenizer en fieldset mapper. Geconfigureerd binnen een batch job ziet dit er als volgt uit. Wanneer deze job wordt uitgevoerd ontvangt de “DummyWriter” voor elke record in het bronbestand een overeenkomstig domein object.

<bean id="videotheekJob" parent="simpleJob">
  <property name="steps">
    <list>
      <bean id="printRecordStep" parent="simpleStep">
	<property name="itemReader">
	   <bean class="org.springframework.batch.item.file.FlatFileItemReader">
	     <property name="resource" ref="file:///videotheek/films.txt" />
	     <property name="lineTokenizer" ref="movieFileLayout" />
	     <property name="fieldSetMapper" ref="movieFileFieldSetMapper" />
	   </bean>
	</property>
	<property name="itemWriter" ref="dummyWriter" />
      </bean>
    </list>
  </property>
</bean>

Zoals je wellicht opvalt wijst de FlatFileItemReader naar een hardcoded filepath. Momenteel biedt Spring Batch nog geen mogelijkheid om dit voor meerdere bestanden configurabel te maken. Dit heb ik inmiddels gemeld via een JIRA ticket en een oplossing bijgevoegd in de vorm van een DynamicMultiResourceItemReader.

Tot slot, Spring Batch biedt m.i. behoorlijke ondersteuning om diverse soorten bestanden te parsen. Dit is met name handig in applicaties die reeds gebruik maken van het Spring Framework. Maar Spring Batch bevat méér en is zeker het overwegen waard buiten pure Spring applicaties.




Java 6 undocumented change: @Override

Door: Jan-Kees van Andel, 15 October 2008

Het valt me op projecten al een tijdje op dat collega’s compilatiefouten krijgen op @Override. Deze fouten kreeg ik zelf nooit. Gisteren tijdens de JSF cursus gebeurde het weer. Weer twee mensen die tegen deze fout aan liepen. Bij de rest van de groep ging het goed, maar bij deze twee niet, ondanks dat ze dezelfde stappen doorliepen als de rest.

In de code kwamen een stuk of 20 compile errors naar voren, allemaal gerelateerd aan @Override. De melding was:

The method [METHODNAME] of type [CLASSNAME] must override a superclass method

Het probleem is een aanpassing die in Java 6 is gemaakt. In Java 5 mag deze annotation alleen op een method staan die een method uit een klasse override. Of de method in de superclass abstract is en of de superclass zelf abstract is, maakt niet uit. Wat wel uitmaakt in Java 5, is dat een method die een interface method implementeert, niet met @Override geannoteerd mag zijn.

Dit mag dus niet in Java 5.

interface MyInterface {
    void doSomething();
}
 
class MyImplementation implements MyInterface {
    // Error in Java 5: The method doSomething() of type MyImplementation must override a superclass method
    @Override
    void doSomething() {}
}

Het vervelende was dat Eclipse die annotaties neer had gezet omdat mijn Compiler Compliance Level op 6 stond en ik een Java 6 compiler gebruikte, maar niet iedere cursist gebruikte Java 6.

Leuk detail: We hebben het hier over een (per ongeluk) niet gedocumenteerde feature van Java 6. Zie Peter Ahé’s weblog.
http://blogs.sun.com/ahe/entry/override
http://blogs.sun.com/ahe/entry/override_snafu




Dojo Toolkit 3 – UI in Dojo

Door: jeroen weelink, 9 September 2008

Andere posts:

  1. Dojo Toolkit 1 – Uitbreidbare HTML
  2. Dojo Toolkit 2 – Themes
  3. Dojo Toolkit 3 – UI in Dojo

Dojo Toolkit is groot. Om dit overzichtelijk en snel te houden, maakt Dojo gebruik van een modulair systeem. JavaScript ondersteunt modulariteit niet, dus is het noodzakelijk om een bootstrap te gebruiken:

...
    <head>
        <script type="text/javascript" src="http://o.aolcdn.com/dojo/1.0.0/dojo/dojo.xd.js" djConfig="parseOnLoad:true, isDebug:true"></script>

        <script type="text/javascript">
            // Import statements voor de gebruikte modules
        </script>
    </head>
...

dojo.js is de bootstrap. Het levert ook enkele core modules. Deze kan gedownload worden en meegedeployed met de applicatie of, zoals hier, worden geladen vanaf AOL’s Content Delivery Network (CDN). De script tag is uitgebreid met djConfig (zie ook Dojo Toolkit 1). parseOnLoad geeft aan of de HTML-achtige declaratie van widgets in pagina’s automatisch moeten worden omgezet naar echte Dojo Widgets. isDebug geeft aan of de applicatie in debug modus draait. In Internet Explorer wordt automatisch een FireBug console geladen.
Themes (Dojo Toolkit 2) is de enige manier om de widgets te stylen. Dojo levert standaard een paar themes bij. De meest gebruikte theme is Tundra.

    <style type="text/css">
        @import "http://o.aolcdn.com/dojo/1.0.0/dijit/themes/tundra/tundra.css";
        @import "http://o.aolcdn.com/dojo/1.0.0/dojo/resources/dojo.css"
    </style>
    ...
</head>
<body class="tundra">

Door theming gaan de formulierelementen er anders uitzien. Er wordt (in ieder geval bij de door Dojo meegeleverde widgets) aandacht besteed aan accessibility. Widgets kunnen met JavaScript worden aangemaakt, maar ook met behulp van HTML. Dit laatste wordt alleen omgezet naar een echte widget als parseOnLoad op true staat in de bootstrap.

    <button id="btnHelloWorld" dojoType="dijit.form.Button">Klik hier</button>

Het widget systeem van Dojo heet Dijit. Om de button te kunnen renderen, moet dit wel geimporteerd worden. In de head sectie:

        <script type="text/javascript">
            // Import statements voor de gebruikte modules
            dojo.require('dijit.form.Button');
        </script>

De knop wordt tijdens het laden van de pagina omgezet naar een dojo widget, gestyled met het tundra theme (normaal en mouseover):

Het registreren van een handler kan met javascript (dojo.byId is hetzelfde als ‘$’ in prototype of jQuery):

    dojo.byId('btnHelloWorld').connect('click', function() {
        alert('Hallo Wereld!');
    });

of in HTML:

    <button id="btnHelloWorld" dojoType="dijit.form.Button">
        Hello World
        <script type="dojo/method" event="onClick">
            alert('Hallo Wereld!');
        </script>
    </button>

De onClick event handler wordt overridden. Het type van dit script blok is dojo/method. De ongeschreven regel maakt dit mogelijk. Browsers snappen het type dojo/method niet en negeren het.

Dit is de standaard popup. Dijit heeft ook een eigen popup. Mooier en accessible:

    <script type="text/javascript">
        // Import statements voor de gebruikte modules
        dojo.require('dijit.form.Button');
        dojo.require("dijit.Dialog");
        dojo.require("dijit.ProgressBar");
        dojo.require("dijit.form.Slider");
    </script>

    ...

    <button id="btnHelloWorld" dojoType="dijit.form.Button">
        Hello World
        <script type="dojo/method" event="onClick">
            dijit.byId('dlgHelloWorld').show();
        </script>
    </button>

    <div id="dlgHelloWorld" dojoType="dijit.Dialog" title="Hallo Wereld">
        <div dojoType="dijit.ProgressBar" style="width:300px" id="downloadProgress" indeterminate="true"></div>
        <div id="horizontalSlider" dojoType="dijit.form.HorizontalSlider" value="25" minimum="0" maximum="1000" handleSrc="http://o.aolcdn.com/dojo/1.0.0/dijit/themes/tundra/images/preciseSliderThumb.png"></div>
    </div>

Hier wordt dijit.byId gebruikt. Met dijit.byId wordt de widget teruggegeven, dojo.byId levert de DOM node op. Wat meer voorbeelden staan op de DijitThemeTester. Dit zijn niet alle widgets die standaard bij Dijit wordt meegeleverd.




Dojo Toolkit 2 – Themes

Door: jeroen weelink, 8 September 2008

Voorgaande posts:

  1. Dojo Toolkit 1 – Uitbreidbare HTML

Een webpagina bestaat uit 4 delen:

  • Structuur (= HTML tags)
  • Content (= Dynamisch)
  • Opmaak (= CSS)
  • Gedrag (=JavaScript)

Met CSS wordt niet de content opgemaakt, maar de structuur van het HTML document. Voor goed en makkelijk gebruik van CSS en JavaScript is het van belang de structuur goed en duidelijk op te zetten. Een menu is misschien makkelijker om vorm te geven met een tabel, maar een menu is eigenlijk een opsomming van menuitems en een menuitem kan weer een submenu bevatten:

<html>
    <head>
        <title>Dojo Toolkit 2 - Voorbeeld menu</title>

        <style type="text/css">
            body {
                margin: 0px;
                padding: 0px;
                font-family: Arial;
                font-size: 12px;
            }
        </style>

        <link rel="stylesheet" type="text/css" href="themes.css" />
    </head>

    <body class="normal">
        <div id="menu">
            <ul>
                <li>
                    <a href="home.html">Home</a>
                </li>
                <li>
                    <a href="#">Themes</a>
                    <ul>
                        <li>
                            <a href="#" onclick="window.document.body.className='normal';">Normal</a>
                        </li>
                        <li>
                            <a href="#" onclick="window.document.body.className='pulldown';">Pulldown</a>
                        </li>
                    </ul>
                </li>
            </ul>
        </div>
    </body>
</html>

CSS is zo uitgebreid en krachtig dat er met deze structuur allerlei manieren zijn om het menu op het
scherm weer te geven. Als de vormgeving van het menu moet worden aangepast, is het nu niet nodig om de HTML aan te passen. Het is namelijk geen aanpassing aan de structuur.

Hier zijn twee themes gedefinieerd: pulldown en normal. De class van de body geeft de huidige theme aan. Door het aan de body vast te maken, geldt de theme voor de hele pagina. Het is ook mogelijk om de class aan een ander element toe te voegen, zodat alleen dat element de theme toegepast krijgt.

/* Het menu in het pulldown theme */
.pulldown #menu ul {
    padding: 0px;
    margin: 0px;
        background-color: #000000;
}

.pulldown #menu li {
    display: inline;
}

.pulldown #menu ul ul {
      visibility: hidden;
      margin-top: 5px;
}

.pulldown #menu li:hover ul {
      visibility: visible;
}

.pulldown #menu a {
        color: #FFFFFF;
    padding: 3px 5px;
    text-decoration: none;
        font-weight: bolder;
}

/* Het menu in normal theme */
.normal #menu {
        margin: 10px;
        float: left;
        border: 2px solid #000000;
        border-bottom: none;
}

.normal #menu ul {
        padding: 0px;
        margin: 0px;
        list-style: none;
}

.normal #menu a {
        text-decoration: none;
        color: #999999;
        display: block;
        width: 150px;
        height: 20px;
}

.normal #menu li {
        border-bottom: 2px solid #000000;
}

.normal #menu ul ul {
        padding-left: 20px;
        list-style: none;
}

.normal #menu ul ul li {
        border-bottom: none;
}

.normal a:hover, .normal li:hover a, .normal ul ul li:hover a {
        font-weight: bolder;
}

.normal li:hover ul a {
        font-weight: normal;
}

.normal ul ul li {
        border-top: 1px solid #CCCCCC;
}

Alle applicaties dat hun menu in de bovenstaande structuur zet, kan worden geskind met deze CSS.

Het skinnen van een applicatie kan dus alleen maar als er afspraken zijn gemaakt over de structuur van de HTML. De ontwikkeling van Dojo is professioneel, waardoor deze afspraken vast komen te liggen en waarbij de widgets zich aan dienen te houden. Dankzij themes zien Dojo applicaties er goed en consistent uit.




Rich web applicaties met Spring Web MVC

Door: Jethro Bakker, 5 September 2008

In de spring cursus van Ordina wordt het Spring Web MVC framework behandeld. Tijdens de cursus wordt ook gekeken naar de integratie met ajax technologie.  In 2007 is bijvoorbeeld het DWR (Direct Web Remoting) framework behandeld. Met de komst van Spring Webflow 2.0 is het DWR onderdeel komen te vervallen en behandelen we nu Spring Javascript. Het is een relatief onbekende library, die wat mij betreft meer aandacht mag krijgen.

Wat is Spring Javascript?

Je kunt Spring Javascript zien als een abstractie laag bovenop bestaande widget technologie en ajax remoting. Momenteel is er alleen nog ondersteuning voor de Dojo Toolkit maar op termijn zal dit verder uitgebreid worden. Het zal dan een generieke API zijn waarmee je andere javascript frameworks kunt gebruiken.  Spring Javascript biedt je verder een resource servlet, deze servlet handelt het CSS, JS verkeer af wat je nodig hebt voor rich widgets. Een Dojo javascript file laad je bijvoorbeeld als volgt in:

<script type=”text/javascript” src=”<c:url value=”/resources/dojo/dojo.js” />”> </script>

De servlet moet je natuurlijk registreren in de web.xml en mapt op url pattern /resources/*. De Spring Javascript JAR module bevat alle javascript en stylesheets resources die je nodig hebt voor het Dojo framework. Naast de genoemde zaken bevat Spring Javascript de volgende classes:

  • AjaxTilesView, is een Tiles view implementatie dat delen van een pagina kan renderen voor ajax requests.
  • AjaxUrlBasedViewResolver, een UrlBasedViewResolver met een specifieke implementatie voor redirect views.
  • SpringJavascriptAjaxHandler, een handler klasse die gebruikt wordt door de AjaxTilesView om ajax requests goed te kunnen afhandelen.

Voorbeeld

We starten met het registreren van twee beans, de tiles configurer en de view resolver.

<bean id="tilesConfigurer" class="org.springframework.web.servlet.view.tiles2.TilesConfigurer">
  <property name="definitions">
    <list>
	<value>/WEB-INF/defs/general.xml</value>
    </list>
  </property>
</bean>

<bean id="tilesViewResolver" class="org.springframework.js.ajax.AjaxUrlBasedViewResolver">
  <property name="viewClass" value="org.springframework.webflow.mvc.view.FlowAjaxTilesView"/>
</bean>

De ajax support in Spring Javascript werkt nauw samen met Apache Tiles. Met Apache Tiles kun je de webpagina opdelen in logische stukken. Met behulp van Spring Javascript kun je een los deel vervangen. Bijvoorbeeld alleen de body. Een normale link moet je decoreren met een stuk javascript:

<a id="newEntry" href="entry/edit.html">Nieuwe entry</a>
<script type="text/javascript">
Spring.addDecoration(new Spring.AjaxEventDecoration({
  elementId: "newEntry",
  event: "onclick",
  popup: false,
  params: {fragments: "body"}
}));

Deze link zal nu ajax gebruiken en het onderdeel ‘body’ van de pagina vervangen door nieuwe content. Je hebt ook de mogelijkheid om de link in een pop-up te openen. Naast deze ondersteuning voor ajax remoting is het ook mogelijk om widgets te gebruiken. Dat kan als volgt:

<form:input id="subjectString" path="subject" />
<script type="text/javascript">
Spring.addDecoration(new Spring.ElementDecoration( {
  elementId :"subjectString",
  widgetType :"dijit.form.ValidationTextBox",
  widgetAttrs : {
    promptMessage :"Fill in a subject for this blog entry"
  }
}));
</script>

Zoals je kunt zien wordt de Spring Javascript library aangeroepen. Deze library zal intern de Dojo toolkit gebruiken. Spring Javascript is dus een abstractie laag bovenop de bestaande widget technologie. Op dit moment biedt dat nog niet zoveel voordeel maar op het moment dat er meerdere widget technlogieen ondersteund worden kun je op een uniforme manier de widget technologie gebruiken.

Ik ben benieuwd wat jullie er van vinden.

In een volgende post zal ik ingaan op Spring Faces, deze library maakt ook onderdeel uit van de Spring Webflow distributie.