Posts tonen met het label JAVA. Alle posts tonen
Posts tonen met het label JAVA. Alle posts tonen

dinsdag 6 oktober 2009

Einde aan boilerplate met Project Lombok

Weer een getter en setter schrijven, weer die equals en hashCode updaten omdat er weer een field bij is gekomen. Gelukkig heb je die twee generiek gemaakt via reflectie. Maar wat word daardoor die HashSet toch traag, toch maar weer handmatig implementeren. En oeps, een tikfout die toch wel valid Java blijkt te zijn is erin geslopen! En oh ja, ook nog toString aanpassen…

Toch vreemd dat zoiets als een getter, setter, toString, equals en hashCode toch weer zoveel problemen geven, vooral omdat IDE’s deze toch al weer een tijdje voor je kunnen genereren. Maar deze zul je toch ook nog moeten onderhouden (al was het alleen maar regenereren van deze methodes). Je zou toch haast zeggen dat dit werk is voor een computer? Daarnaast blijf je constant tegen die methodes aankijken in de source, en dat geeft, en brengt, extra mentale belasting die eigenlijk helemaal niet nodig is in de meeste gevallen.

Er zijn over de jaren een aantal oplossingen bedacht voor dit probleem, een ervan is equals, hashCode en toString via reflectie. Dit werkt, helaas werkt het ook traag. Dit komt omdat de JVM (HotSpot) deze niet goed kan inlinen omdat het in feite type-less code is. En reflectie kan ook geen getters en setters maken die je in je code kan gebruiken (of in Swing).

Daarnaast zijn er door de jaren heen een aantal JSR Proposals geweest om een property keyword te krijgen, zodat getters en setters automatisch gegenereerd worden.
Bijvoorbeeld:

class Point {
public property int x;
public property int y;
}

om het volgende te genereren:
class Point {
private int x;
private int y;

public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
}

Maar de meest recente versie van deze proposal, in Project Coin, heeft de selectie niet gemaakt (voor Project Coin). Daarnaast lost dit ook niet direct het equals, hashCode en toString probleem op (uiteraard wel met de reflectie oplossing).

Het is in feite interessant om te zien dat, bijvoorbeeld, Scala dit soort dingen wel doet, in de vorm van case classes, bijvoorbeeld de Point klasse hierboven:
case class Point(var x:Int, var y:Int)

Dit genereert constructor, getters, setters, toString, equals, hashCode en Scala specifieke features, zoals Pattern Matching.

Maar er is licht aan het einde van de tunnel.

In Java5 zijn er, samen met Generics, Annotations toegevoegd. Hiermee kan je klassen, methoden, fields en parameters annoteren met metadata. En samen hiermee is er ook "APT" of "Annotation Processing Tool" uitgebracht. Dit is een losse tool, zoals javac, dat met een set processors een selectie klassen doorloopt en deze aanpast. Het is voornamelijk een source processing tool, waarbij acties getriggerd worden op annotaties.

Het is dus mogelijk om een annotatie te schrijven die een getter en setter van een veld genereert, of een toString, etc, etc. Het mooie is ook dat zodra dit is gebeurd je de nieuwe methode direct kan zien, en gebruiken, in een IDE, de meeste IDEs gebruiken class files om te zien of een methode (of zelfs class) bestaat.
Maar het schrijven van een AnnotationProcessor is lastig, en dit is een losse stap, en je kan het dus vergeten, en dan kan je leuke situaties krijgen, bijvoorbeeld dat getters en setters niet bestaan terwijl je deze op andere plekken wel verwacht.

Gelukkig is het in Java6 nu mogelijk om direct, bij het aanroepen van javac, annotations te processen. En daarom is er nu Project Lombok.

Lombok komt met een aantal standaard annotations om boilerplate te verwijderen.
Je voegt het gewoon toe aan je classpath (tijdens het compilen) en de annotation processors erin gaan aan het werk. Een lijstje met de annotations die meegeleverd worden zijn:
  • @Getter en @Setter
  • @ToString
  • @EqualsAndHashCode
  • @Data
  • @Cleanup
  • @Synchronized
  • @SneakyThrows
Alle annotations zijn te configureren.
De eerste drie (punten, vier annotations) spreken voor.
@Data combineerd de eerste 3 punten.
@Cleanup kan je gebruiken op variabelen in methodes zodat deze try { } finally { } blocken genereerd en een methode aanroept (default is close, maar kan ook "myOwnCleanupMethod" zijn).
@Synchronized is een method level annotation en word gebruikt om een algemeen synchronized pattern te gebruiken die beter locked op een field i.p.v. een (static) field. Het is ook mogelijk om meerdere, andere, locks te definieren (beter gezegd, specifieke velden te gebruiken).
Als laatste is er @SneakyThrows, dit word gebruikt om een methode bepaalde checked exceptions te laten throwen, zonder dat deze in de method descriptor hoeven te staan (de throws keyword). Een voorbeeld is UnsupportedEncodingException, zeg nou zelf, wat is de kans dat UTF-8 niet bestaat in jouw JDK? Wat dit doet is je methode wrappen in een try { } catch() {} block, en de ongewenste exception catchen, en deze dan te throwen met een unchecked exception.
Enkel voor de @SneakyThrows hoeft de lombok.jar runtime beschikbaar te zijn (omdat het een utility methode aanroept die de echte sneaky-throw doet).

Mijn vorige voorbeeld klasse kan met Lombok gereduceerd worden tot:
@EqualsAndHashCode @ToString
class Point {
@Setter @Getter private int x;
@Setter @Getter private int y;
}

Of nog korter:
@Data
class Point {
private int x;
private int y;
}
En dat is veel beter! Nog mooier is dat je het niet kan vergeten, als je de lombok.jar vergeet tijdens het compilen dan kan de compiler de verschillende annotaties niet vinden, en kan het compilen niet werken.

Om af te sluiten raad ik het je aan om de screen-cast te bekijken die op de Project Lombok website staat, en het gewoon uit te proberen. Eindelijk einde aan boilerplate code!

vrijdag 26 juni 2009

Frontcontrollers


Tijdens het volgen van een SCWCD (Sun Certified Web Component Developer) training kom je de coolste dingen tegen om een webapplicatie te ontwerpen en implementeren. Er wordt voortdurend op gehamerd dat je elk component in een webapplicatie (POJO, EJB, Servlet, JSP e.d.) moet gebruiken waar het voor dient, en ze niet misbruikt door bijvoorbeeld logica in een JSP te gaan stoppen omdat dat ook wel werkt. Neen! Men doet er verstandig aan de verschillende lagen van een applicatie te scheiden, het voornaamste voorbeeld hiervan is het MVC (Model-View-Controller) model. De details hiervan laat ik even achterwegen (Wikipedia is your friend) maar kort gezegd krijg je door dit model te implementeren een applicatie waarin de bussiness logic, het ophalen van data uit de bussiness logic en het tonen daarvan van elkaar gescheiden zijn.

Bovenstaande kan gerealiseerd worden door in bijvoorbeeld een servlet de bussiness logic (via EJB o.i.d.) aan te spreken en het resultaat te delegeren naar JSP's die gevuld worden met deze data. Echter is dit model op deze manier ook niet perfect. In een website met omvangrijke grootte kan het schrijven van dergelijke code redundant en onoverzichtelijk worden. Je voelt het misschien al aankomen, maar inderdaad, ze hebben ook hier iets op gevonden. Een techniek (eigenlijk een design-pattern) met een vrij algemene naam "frontcontroller". Frontcontrollers zijn kleine frameworkjes die je kunt gebruiken om de code die je in je controllerlaag gebruikt om de bussiness logic aan te spreken evenals de code die je gebruikt om de view-laag aan te spreken in herbruikbare objecten te stoppen. Op die manier hoef je code om requests af te handelen niet steeds opnieuw te schrijven voor elke servlet die je in je applicatie gebruikt. Dit leidt al gauw tot meer overzicht in de code die makkelijker onderhoudbaar is. Een belangrijke kenmerk van een frontcontroller is dat het een centraal punt vormt in een applicatie voor het ontvangen van requests en het delegeren daarvan.

Een keerpunt van een dergelijke techniek is dat je al je logica zult moeten implementeren in de frontcontroller, wat tot heel wat configuratie en omslachtigheid kan leiden. Bijvoorbeeld het delegeren van een bepaald request naar een bepaalde servlet kun je dan niet even snel met een RequestDispatcher doen, maar je zult een object moeten schrijven dat de configuratie en logica voor die delegatie bevat. Op die manier is het gebruik van een frontcontroller aan de ene kant een zegen en aan de andere kant een vloek. Zoals een bekende voetballer ooit zei (ja, Kruijff): elk noadeel heb een foordeel!

Een bekende Java implementatie van een frontcontroller is Jakarta Struts, wat niet bij iedereen geliefd is. Dit geldt echter ook voor Spring, wat minder bekend is maar ook gebruikt wordt in de webwereld om je controller en view netjes neer te zetten. Spring heeft echter ook roots in de modellaag, eigenlijk een frontcontroller++ :P. Beide technieken implementeren het frontcontroller pattern op hun eigen manier, en je wilt ermee werken of niet. Mij persoonlijk lijkt het gebruik van Struts wel interessant, en misschien zelfs wel nuttig. Echter denk ik niet dat je het moet gebruiken in websites van kleine omvang omdat je dan waarschijnlijk niet het potentieel eruit haalt.

vrijdag 12 juni 2009

Van ontwikkelomgeving naar test- en productieomgeving

Een van de dingen waar een applicatieontwikkelaar mee te maken krijgt, is het configureren van de software voor verschillende omgevingen. De applicatie wordt ontwikkeld op een ontwikkelomgeving, gaat daarna in het algemeen naar een omgeving waar de klant een en ander kan bekijken en testen, en wordt vervolgens op een productieomgeving geplaatst, al dan niet na een aantal aanpassingen. Deze omgevingen hebben hun eigen instellingen nodig. Bij het uitrollen van een nieuwe versie van de applicatie naar een omgeving moet de omgeving de juiste instellingen krijgen en/of houden. Er zijn veel manieren om dit mogelijk te maken, een van de eenvoudigste is via files in verschillende bestandsformaten. Er worden dan verschillende files gemaakt met per omgeving de specifieke configuratie. Vaak is er een file met standaard instellingen, die overschreven kan worden om specifieke eigenschappen aan te passen. Deze files moeten op een goede manier worden beheerd en uitgerold. Er zijn veel verschillende frameworks en tools om dit te realiseren. Een ervan is de Commons Configuration van het Apache Commons project, te vinden op de Apache website. Hiermee kan configuratie worden ingelezen vanuit bijvoorbeeld properties files, XML files, Windows INI files, System properties, etc. Eigenschappen kunnen meerdere waardes hebben indien gewenst, en zijn bovendien van een bepaald type. De toegang tot de eigenschappen verloopt via de generieke Configuration interface.
ISAAC heeft inmiddels in verschillende projecten naar tevredenheid gebruik gemaakt van de XMLConfiguration van Apache Commons. Handmatige aanpassingen na het uitrollen van een applicatie zijn voor deze projecten niet meer nodig.

zondag 31 mei 2009

Graphical comparison of programming languages

How to compare the speed and code size of programming languages? What language is really slow but also very compact in writing? Are the Ruby religionists right? And is TCL-script really as annoyingly, depressingly bad at performance (and else) as some legacy systems (that we @ISAAC have to integrate with) seem to prove to us every day? I found a nice article with very interesting graphics the other day, via a posting at Slashdot. Note when you scroll directly to the graphs: there are several Java versions in the results.

The rest is shamelessly ripped from "The Square root of X divided by zero" blog, by Guillaume Marceau.

(orginally posted at: http://gmarceau.qc.ca/blog/2009/05/speed-size-and-dependability-of.html )

The speed, size and dependability of programming languages
The Computer Language Benchmarks Game is a collection of 1368 programs, consisting of 19 benchmark reimplemented across 72 programming languages. It is a fantastic resource if you are trying to compare programming languages quantitatively. Which, oddly, very few people seems to be interested in doing.

The Benchmark Game spends a lot of efforts justifying itself against claims that the benchmarks are always flawed and that the whole exercise is pointless. I don't think it is. In fact, I've found that The Game is remarkably effective at predicting which forum hosts programmers annoyed at the slowness of their language, and that's good enough for me.

I was happy to find that in addition to speed The Game also publishes a line-of-code metric for each benchmark programs in each language. Thanks to this The Game let us at explore a fascinating aspect of programming language design: the tension that exist between expressiveness and performance. It is this tension that gives the expression "higher-level programming language" a pejorative connotation. When you are coding this high, you might be writing beautiful code, but you are so far away from the hardware you can't possibly get good performance, right?If you drew the benchmark results on an XY chart you could name the four corners. The fast but verbose languages would cluster at the top left. Let's call them system languages. The elegantly concise but sluggish languages would cluster at the bottom right. Let's call them script languages. On the top right you would find the obsolete languages. That is, languages which have since been outclassed by newer languages, unless they offer some quirky attraction that is not captured by the data here. And finally, in the bottom left corner you would find probably nothing, since this is the space of the ideal language, the one which is at the same time fast and short and a joy to use.

Each pinkish dot in this chart comes from one language implementing one benchmark solution, so there are 1368 dots, minus a few missing implementations. Both axes show multipliers of worsening from best. That is, if a particular solution is not the best one, the axis show how many times worse it is when compared to the best. The barrier of dots on the left side means that it is common to have many solutions near the best performer (The best performer is usually one of a handful of C compilers.) On the right side and beyond it, there are a number of distant points which are clipped out of view by the edge. As it stands, the right edge represents 8-fold worse performance than the best solution.

The distribution of pink points is more uniform along the Y axis (verbosity) than along the X (slowness), suggesting that the world has not hit a wall in the progression of the expressiveness of programming languages the way it has with performance.

Like many scientific datasets, the data coming from The Computer Language Benchmark Game is rich in shapes, insight and stories. In order to retain as much of the shape as possible, it is critical to avoid calculating averages, as averages tend to smooth over the data and hide interesting sources of variation. The average function does to numbers what Gaussian blur does to pictures. Avoid it if you want to see the edges.

One such source of variation that attracted my curiosity was dependability: how well does the language performs across a variety of tasks, such as those composing the benchmark suite? A language might be concise most of the time, but if once a month a quirk of the language forces the code to be five times as large as what it ought to be, it's a problem.

In order to show dependability, and to avoid relying on averages and standard deviations, I drew star charts in the following manner. Take, for example, the Java benchmarks. Starting with the previous chart and its 1368 dots, I added a gray line from the XY position of each Java benchmark to the position of the overall average of all the Java programs.


The center of the star is Java's average performance, and the branches shoot out to the individual benchmarks. The resulting shape says something about Java. On the X axis (slowness), we see that the performance is impressive, often brushing near the "wall of best performance" of C on the left. But on a few occasions the performance breaks down and the star shoots to the right. On the Y axis (code size), the star spreads across the chart, twice brushing near the top. Also the center of the star is slightly above the centroid of the background cloud. In other words, Java is not a particularly concise language, and in fact it is sometime depressingly convoluted, but its performance is excellent except when it's not.

The next chart arranges the entire collection of the 72 programming languages available at The Computer Language Benchmark Game into a 8x9 grid. The chart is a so-called 'small multiples' design: each swatch in the grid has the same axes in the same scales as each other. It's the same setup as the one for Java that we just saw. The 1368 dots in the background are the same throughout. The intent is to make it easy to compare the shape of the star between languages (across the page), and against the general trend (in the background).

The swatch of the languages are grouped into columns according to their overall performance. Thus the fastest languages are in the first column on the left and the slowest are on the right. Within each column the swatches are sorted by average code size, with the best one at the bottom. In this way, the disposition of the grid mimics the axes within the swatches.


This chart is a treasure of narratives.

The languages in the first column all have tall thin pogo-stick stars. They show strikingly consistent performance, maxing out the CPU times after times. Their code sizes, on the other hand, are spread all over. The bottom left three languages, Cmucl, Regina and Stalin are outliers. These languages do not have enough benchmark implementations in the database to generate fully fleshed stars.

In the rightmost three columns we find many bushy stars, flat and wide. These are the scripting languages whose communities have not invested as much effort into building optimizing compilers for their language as they have spent tweaking its expressiveness. There are, however, a few spectacular exceptions. Lua, which has always been noted for its good performance among scripting languages, shows a beautiful round star in the swatch at (5, 2), counting from the bottom left. Even better, the star of Luajit (3, 1) seems to squeeze itself in the coveted bottom left corner, amongst academic Juggernauts such as Mlton (2, 1), Ocaml (3, 2), Gambit (4, 1), and Haskell (4, 2).

The shape of the Haskell star, specifically the way that it bends up, suggest to me that writing high-performance programs in Haskell is a bit of a black art, and that some of the benchmarks submissions could be improved if someone got around to it. It also suggests that the tweaks introduced to boost the performance occupy a lot of code space. (I hope someone from the Haskell community will be able to confirm whether this is the case)

I find the swatch for the language Clean at (1, 8) quite interesting, in light of the oddly shaped Haskell star. Clean is a lazy language just like Haskell. Its star looks like the result of smashing Haskell star against the left wall, as if a huge effort of optimization had paid off.

Psyco (4, 1) is a decent improvement on the standard Python (7, 1) evaluator but it is still rather bushy. On the plus side, both versions of Python can claim many of the smallest programs in the collection. Ruby (8, 1) might also compete for titles, but unfortunately its performance is so bad its star falls off the performance chart.

C# (3, 4) has the same shape as Java (3, 7), merely 1, 2, or three rows down, depending on how you count. The arrival of Scala (6, 7) in the Java world is a mixed blessing. While it fixes the worse convolutions (it has no top-of-the-square points) it also introduces terrible performance hiccups (the points which shoots out to the right.)

Is interesting to see Groovy (7, 5) right next to MzScheme (6, 5). Both languages have similarities in terms of the features that would impact the performance of the evaluator. You would expect Groovy to display better performance since it uses the Java virtual machine and all its optimizations, but the reverse is true.Finally, the top right corner is occupied by specialty languages, with their momentous stars which reach across the performance spectrum along both axes, from the very best to the very worst.

Does introducing functional features kill performance?
No, it does not. In the following chart, the ordering is the same as in the large chart. Languages which include functional features such as lambda, map, and tail call optimization are highlighted in green. C compilers, C++ and C-derivatives are in blue. The blues dominate the first column. The greens occupy the main diagonal, from the oddball corner to the "ideal" corner. Ultimately the first factor of performance is the maturity of the implementation.


Source code
The code to generate these charts runs in PLT Scheme (MzScheme) v4.1.5. You will need the data file from The Game's cvs repository.

dinsdag 31 maart 2009

Java Swing: past, present and future

Swing is de lightweight GUI toolkit voor Java, gebouwd op de AWT toolkit. Beide waren al beschikbaar in een van de eerste versies van de JDK's die door Sun werden uitgebracht. Tot op heden is de Swing toolkit niet helemaal meegeëvolueerd met de rest van de JDK. Het maakt bijvoorbeeld nog geen gebruik van generics en de Event Dispatch Thread (de core-thread van Swing waar alle GUI acties op uitgevoerd worden) is qua code nog steeds zoals deze destijds is opgezet. Dit betekent dat het geen gebruik maakt van de concurrency componenten die vandaag de dag met de JDK geleverd worden. Ook zijn de standaard componenten die bij Swing geleverd worden, zoals JTable, JCombobox, etc, behoorlijk kaal en moet je zelf vaak heel wat code schrijven om component op te maken qua functionaliteit en stijl.

Toch wordt in de tussentijd de toolkit wel bijgehouden. Er worden nog steeds bugs uit gehaald en de performance kan blijkbaar nog altijd beter. Tevens worden er verschillende libraries met generieke componenten in de JDK opgenomen die het programmeren in Swing vergemakkelijken. Dit zijn vaak hoger level componenten, ontwikkeld door Swing gebruikers, die een bepaalde functionaliteit bieden die je anders zelf zou moeten ontwikkelen of steeds overnieuw zou moeten schrijven. Op die manier is er voor Swing applicaties steeds minder boilerplate code nodig omdat je steeds meer componenten tot je beschikking hebt die je standaard kunt gebruiken. Denk hierbij aan de SwingWorker, het TimingFramework en JOGL. De laatste maakt zelfs 3D rendering in Swing applicaties mogelijk!

Swing is van nature een toolkit die basisfunctionaliteit voor grafische applicaties biedt, maar wat niet veel mensen beseffen is dat dit juiste de kracht van de toolkit is. Dat heeft ook Sun ingezien en daarom willen ze in de volgende versie van de JDK (ja ja, versie 7 alweer!) gewoon verder gaan met het optimaliseren van de Swing engine. Tevens wordt er hard aan gewerkt om Swing in steeds meer frameworks te integreren. JavaFX bijvoorbeeld zal Swing componenten kunnen gebruiken voor bepaalde functionaliteit in dergelijke applicaties. Het verder uitbreiden van toepasbare Swing componenten laat Sun lekker over aan iedereen die hier aan mee wil werken. Ze hebben zelfs een website opengezet (http://openjdk.java.net/) dat als het zenuwstelsel hiervoor moet dienen.

Ik ben benieuwd wat er van Swing in de toekomst gaat komen. De volgende JDK brengt geen wereldschokkende uitbreiding van de toolkit met zich mee, maar ik denk dat het juist aan de Swing communities is om de toepasbaarheid van Swing te vergroten. Nog steeds, na al die jaren dat Swing in ontwikkeling is, denk ik dat het voor veel ontwikkelaars een ondergewaardeerde toolkit is. Het potentieel van een robuuste, goed presterende applicatie met een mondwaterende gebruikersinterface behoort zeker tot de mogelijkheden maar de mogelijkheid hiervan is niet bij iedereen bekend. Natuurlijk is Swing niet de enige speler meer op de markt als het aankomt op een web- of desktopapplicatie met een mooie grafische interface. Toch is deze toolkit veruit de meest generieke, wat ook meteen zijn kracht en tegelijk zijn zwakte vormt.

vrijdag 20 maart 2009

Wellicht Java?

Recentelijk heb ik een weblog geschreven over een bepaalde "monad", namelijk de "Maybe Monad".
Maar toen ik er bijna klaar mee was kwam ik erachter dat ik ook nog een post moest schrijven voor deze ISAAC weblog. Het artikel is een beetje te groot, en wellicht te esoterisch, om zomaar te vertalen naar het Nederlands. Daarom geef ik hier een samenvatting.

Het volledige artikel is hier te lezen.

De Maybe Monad, in de simpelste van termen, gaat over de vraag, "Wat moet een functie teruggeven als de combinatie van parameters eigenlijk tot niks uitkomt?" Om een voorbeeld te noemen, delen door nul. De meeste talen die we tegenkomen in ons werk bij ISAAC geven, in dit geval, over het algemeen een "exception", of in geval van Javascript "NaN". In feite is een exception throwen precies wat er zou moeten gebeuren, omdat delen door nul nog helemaal niet is opgelost door de wiskunde. Maar een aantal talen naast Java leveren een antwoord op deze vraag met een mechanisme dat "lichter" is dan een exception. Om dit te doen word in vrijwel alle gevallen een variatie van de Maybe Monad gebruikt. In een aantal talen is dit enorm simpel uitgedrukt, bijvoorbeeld Haskell:

data Maybe = Some a
             Nothing


Of in Scala:

trait Option {}
sealed case class Some[A](val a:A) extends Option[A] {}
sealed case object None extends Option[Any] {}


Maar dat zijn Haskell en Scala, en niet Java. Gelukkig is het (bijna) net zo simpel als in deze talen. Net zo simpel als een Pair of (simpele) Tuple class die iedereen wel eens schrijft tijdens een project. De Scala versie hierboven is eigenlijk enorm vereenvoudigd (maar is, binnen Scala helemaal functioneel te gebruiken), het heeft extra methoden, bijvoorbeeld een "getOrElse", die voor Some a terug geeft, en voor None de parameter die je meegeeft. Daarnaast is Option "Iterable", dat wil zeggen, je kan het in een for-loop gebruiken. Deze dingen zijn zeker nodig in Java, omdat Java geen Pattern Matching heeft, zoals Haskell en Scala (Haskell leeft erop!). Daarnaast zijn constant instanceof checks in je code niet veel beter dan null checks.

In Java is de Maybe Monad niet veel moeilijker in het gebruik dan het bovenstaande (code is te vinden in de post hierboven):

public Maybe integerDivide(int value, int divisor);

Het grootste voordeel is dat je de mogelijkheid dat het "fout" kan gaan expliciet gemaakt word, i.p.v. een runtime exception (zoals ArithmaticException, bij het delen door 0). Je wilt die niet zomaar krijgen in een 24/7/365 systeem alleen omdat een informatieleverancier ergens (per ongelijk) een 0 plaatst. Maar om try/catch om iedere deel operatie te zetten is ook weer te vervelend, het zelfde met iedere keer if statements om een deel operatie. Nu kan je gewoon, simpel, getOrElse aanroepen. Ik moet toegeven, in Haskell en Scala heb je het mooie Pattern Matching mechanisme, waar dit allemaal elegant word opgelost. Hoewel dit in Java iets minder elegant is, is het nogaltijd eleganter dan exceptions of velen if statements.

Daarnaast beschrijf ik hoe je de Map interface kan uitbreiden zodat deze Some teruggeeft als de key daadwerkelijk bestaat, en None teruggeeft als deze niet bestaat. Heel handig als null een goede waarde is voor een value bij een Key. Je hoeft dan niet nog een keer de key op te zoeken. En dat gebeurd ook niet in de aangepaste get, omdat er alleen Some of None waardes erin staan zal het zo zijn dat als er null terugkomt (intern) het alleen kan betekenen dat de key niet bestaat, en dan kan None teruggegeven worden.

Als laatste gaat de post over wat het nou toch is met die null, waarom ergeren we er ons toch iedere keer aan, en blijven we er toch bij terugkomen? Een van de karakteristieken van null is dat je het aan iedere type kan toewijzen, dit lijkt heel vreemd, en dat is het in feite ook. Null is een zogenaamde "Bottom Type", en is een type (in een Type System) dat (impliciet) een subtype is van alle andere types in het Type System. In Java is, bijvoorbeeld, Object een bottom type, zelfs Object subclasses Object in Java. Maar, er zit een gotcha aan, null heeft geen type. En dat is (vind ik) nou jammer, het betekend gewoon dat er allerlei special cases in de JVM en de Type System van Java zitten, alleen maar om die null waarde zonder type. Maar waarom is null nou bedacht?

Die eer komt toe aan Sir Tony Hoare, in 1965, en hij noemt het zijn "Million Dollar Mistake". Het was toendertijd zo gedaan omdat het simpeler was om te maken. Ik zal zeker de eerste zijn om te zeggen dat luiheid over het algemeen een goede karakter eigenschap is voor een programmeur, maar nu, 44 jaar later, moet zelfs ik bekennen dat er gevallen zijn waar luiheid schade berokkend. Null references zijn er een van. Het is wellicht grappig om te weten dat C++ null pointers kan hebben, maar niet null references (het zou een compiler bug zijn als dat mogelijk was!). Maar de pijn lijkt een beetje verbeterd nu er Elvis operators (zoals ze deze noemen in Groovy) komen in Java7.

En toch, ik vrees dat we voor een lange tijd niet af zijn van "null". Gelukkig hebben we gezien dat er "betere" dingen zijn in het geval "geen waarde". Dus, als je je afvraagt "wat moet ik doen als ik eigenlijk niks kan teruggeven vanuit deze functie?" Dus geen exception (tenzij het echt "exceptioneel" is) en ook geen null, want dat is een waarde, maar geen "None" terug! Maak het expliciet, de wereld zal je er dankbaar voor zijn.

vrijdag 30 januari 2009

Afstudeerverslag: "Showcase Web 2.0"

Edwin Derks en Sjors Keuninkx (2007)

Er worden door en door nieuwe technieken ontwikkeld die problemen met bestaande webbrowsers op een eigen manier oplossen. Deze technieken, gedefinieerd onder de term “Rich Internet Application (RIA)” of “Web2.0”, bieden in het algemeen meer functionaliteit en grafische mogelijkheden dan standaard XHTML. Tijdens hun afstudeerstage in de eerste helft van 2007 hebben Edwin en Sjors deze voor ISAAC interessante technieken gebruikt voor het ontwerp en de bouw van een Web 2.0 showcase. Hierbij hebben ze onder andere gebruik gemaakt van technieken als het Flex 2 Framework, Hibernate en SQL Server 2005.

Download afstudeerverslag

Afstudeerverslag: "Java Business Rules in Action"

Roy Bouten (2007)

In de eerste helft van 2007 studeerde Roy Bouten in het kader van zijn HBO-opleiding Informatie af binnen ISAAC Software Solutions. Zijn opdracht betrof het vergelijken en analyseren van verschillende server-side scripting-technieken voor een Java Enterprise Edition-omgeving en het bouwen van een prototype van een JEE-omgeving waarin real-time modificeerbare business rules een rol spelen. Roy heeft hiertoe technieken als JBoss Rules, JBMP en JRuby vergeleken en op basis van JBoss Rules en Enterprise Java Beans (EJB3) een prototype applicatie ontwikkeld. Het domein van deze prototype applicatie was een applicatie voor de bepaling van loyaliteitspunten in een retail-omgeving, vergelijkbaar met een spaarprogramma als Airmiles. Echter, één en ander volledig dynamisch configureerbaar middels variabele business rules.

Afstudeerverslag: "Real-Time event notification & log statistics in an asynchronous server environment"

Maarten Daalder (2006)

De stageopdracht van Maarten Daalder (tweede helft 2006), als onderdeel van de HBO-opleiding Hogere Informatica, betrof het ontwerp van een systeem waarmee uit een Java Enterprise Environment, dynamisch te configureren events gepubliceerd kunnen worden, en log gegevens gevisualiseerd kunnen worden. De event-notificatie had hierbij als extra, specifieke eis de vraag om deze zonder gebruik te maken van een Java Runtime Environment, zichtbaar te maken in een Windows system-tray omgeving. Om aan deze eis te voldoen is gebruik gemaakt van een Win32 user interface.

dinsdag 9 december 2008

D(evoxx)-Day 2

Vandaag zijn weer diverse mensen van ISAAC naar Devoxx geweest voor het volgen van enkele leerzame presentaties.
Wij zijn onder andere aanwezig geweest bij "Flex Today and Tomorrow", "Seam in Action", "Creating performance test data with the benerator" en "JSF, Ajax, and Seam portlet development with the JBoss Portlet Bridge".

Vooral de "Flex Today and Tomorrow" en "Creating performance test data with the benerator" waren voor ons zeer geslaagde presentaties. Bij Flex kreten van vreugde over de nieuwe mogelijkheden van Gumbo (Flex 4). En bij de benerator presentatie verbazing over de mogelijkheden tot het genereren van test data voor onze applicaties.

Jammer genoeg was de lunch voor ons tijdens Devoxx niet zo geslaagd (de salade viel niet in goede aarde bij ons), en na enig zoeken vonden wij een tentje waar wel eten naar onze smaak aanwezig was. Vooral onze ISAAC carnivoor was zeer tevreden met de ontdekking.


Ook waren enkele fanboy activiteiten ons niet vreemd bij het zien van Chet Haase en Romain Guy (het boek op de foto is Filthy Rich Clients).


Al met al was het weer een zeer geslaagde dag op Devoxx voor ISAAC.

woensdag 18 juni 2008

Het is me in de (aard)bol geslagen


“In mathematics, you don't understand things, you get used to them.” von Neumann

En met dat in gedachte zal ik toch proberen om een verhelderend stuk te schrijven over dit favoriete vak van menig programmeur. Waar heb ik dat aan te danken, hoor ik je denken en ergens heb je gelijk. Waarom zou ik je lastig vallen met een onderwerp waar je vroeger al slecht in was en wat je sinds het behalen van je diploma waarschijnlijk achteraan in je hersenen hebt geduwd (nog achter die genante herinneringen van toen je veertien was en je je geluk waagde bij het mooiste meisje van de klas). Hiervoor verwijs ik je naar Google in Mountain View, Californië. Die bedachten enkele jaren geleden dat het grappig zou zijn om een virtuele aarde te maken met aaneengeregen foto’s. Google Earth is in een korte tijd uitgegroeid tot een begrip en steeds vaker word je geconfronteerd met opdrachten waarbij locatiegegevens en kaarten een rol spelen. Het is een kwestie van tijd voordat je oog in oog komt te staan met de opgave om de afstand tussen twee coördinaten te berekenen en erachter komt dat deze coördinaten (uitgedrukt in lengtegraden en breedtegraden) niet altijd even ver van elkaar af staan. Met alleen de stelling van Pythagoras, die je ooit uit je hoofd hebt geknald omdat je wiskunde docent je wist te vertellen dat je hiermee alles kon uitrekenen, kom je letterlijk en figuurlijk nergens. Wat jij nodig hebt is een stevige dosis haversinus.

De haversinus formule kun je gebruiken om de afstand tussen twee coördinaten te berekenen en wel op de volgende manier:


  • Je neemt de radius van de aarde (R), 6371 km

  • Je neemt het verschil tussen de twee breedtegraden (∆b = b1 – b2)

  • Je neemt het verschil tussen de twee lengtegraden (∆l = l1 – l2)

  • En dan gooi je die in de onderstaande formule:

    afstand = R * (2 * atan2(√(sin2(∆b/2) + cos (b1) * cos(b2) * sin2(∆l/2) ), √(1-a)))


Ho ho ho, even een stapje terug, wat was die laatste? Laat me het uitdrukken in Java code, dat begrijp je vast beter.


public double calculateDistance(double long1, double long2, double lat1, double lat2) {
Integer r = new Integer(6371);
Double deltaLong = Math.toRadians(long1 - long2);
Double deltaLat = Math.toRadians(lat1 - lat2);
Double x = Math.sin(deltaLat/2) * Math.sin(deltaLat/2) + Math.cos(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2)) * Math.sin(deltaLong/2) * Math.sin(deltaLong/2);
Double y = 2 * Math.atan2(Math.sqrt(x), Math.sqrt(1-x));
Double z = r * y;
return z;
}

Ok, laten we het er maar op houden dat je in wiskunde niks begrijpt, maar er aan went.

maandag 9 juni 2008

Een webservice in 5 minuten


EJB 3.0 en webservice annotations maken het mogelijk om webservices te maken, zonder alle details te kennen van WSDL of binding of wat dan ook. Sterker nog, je kunt in enkele minuten een webservice maken. Het enige dat je nodig hebt is een interface klasse, een implementatie klasse en een paar annotations. Laten we dit eens van dichtbij bekijken met het aloude “Hello World” voorbeeld. Maak een EJB 3.0 project en maak daarin allereerst de interface klasse.

package nl.isaac.ejb.service;

import java.rmi.Remote;

import javax.jws.WebService;
import javax.jws.soap.SOAPBinding;
import javax.jws.soap.SOAPBinding.Style;

@WebService
@SOAPBinding(style = Style.DOCUMENT)
public interface HelloWorld extends Remote {
String hello(String name);
}

Hierin zie je twee annotations staan. De eerste “@WebService” geeft simpelweg aan dat het om een webservice gaat. De tweede geeft aan welk soort SOAP binding je gebruikt, hierin heb je twee smaken “RPC” en “Document”. In het voorbeeld gebruik ik “Document”, maar in dit geval maakt het niet uit om hier “RPC” van te maken (Het verschil tussen document en RPC is grofweg gezegd dat RPC maar een enkel element als resultaat geeft en document een uitgebreid XML document terug kan geven). In de interface klasse staat verder alleen onze methode gedefinieerd. Let er wel op dat de interface jave.rmi.Remote extend. Nu kunnen we onze implementatie klasse maken.

package nl.isaac.ejb.service;

import javax.ejb.Stateless;
import javax.jws.WebService;

@Stateless
@WebService(endpointInterface = "nl.isaac.ejb.service.HelloWorld")
public class HelloWorldImpl {
public String hello(String name) {
return "Hello " + name;
}
}

Let erop dat, ondanks dat dit de implementatie klasse van een interface is, je deze niet implementeert met de code “implements HelloWorld”. Dit gebeurt in de annotation @WebService, die in deze methode zijn endpoint interface instelt. Deze verwijst naar de interface klasse die we zojuist gemaakt hebben. Onze methode wordt geïmplementeerd en voilá, een webservice is geboren. Deploy je project in JBoss en controleer voordat je een client maakt of je service draait door de WSDL file aan te roepen. Dit kun je doen door de URL van je project in IE in te voeren met daarachter “/HelloWorldImpl?wsdl”, dit zou je een XML document moeten tonen met alle details over de webservice.

woensdag 23 april 2008

JSR 303 bij ISAAC


De afgelopen twee dagen heb ik samen met Jan Willem JSR 303 (Bean Validation) besproken. Tijdens de gesprekken heeft hij zijn ervaringen met deze specificatie in wording uit de immer spreekwoordelijke doeken gedaan. Aangezien ik zelf de afgelopen maanden meer in de frontend hoek heb gezeten (flex, dojo) was het een voor mij zeer interessant gesprek. JSR 303 is een poging om het valideren van JavaBeans te standaardiseren en bouwt voort op de gebleken 'best practices' van XWork en Hibernate validator.

De kracht van Bean Validation is dat de programmeur declaratief controles kan definiëren die moeten worden uitgevoerd op de waarden van javabean properties. In plaats van dit soort controles te vangen in code, kan je deze logica met annotaties definiëren. Met behulp van een standaard validatie framework worden de annotaties uitgelezen en gebruikt om de bean te controleren. Dus in plaats van bijvoorbeeld de volgende code in bijvoorbeeld PersonFacade.java te moeten schrijven:


if (person.getEmailAddress() == null) {
throw new ValidationException("person.email.isNull");
} else if (person.getEmailAddress().length() > 100) {
throw new ValidationException("person.email.tooLong");
} else if (!isValidEmailAddress(person.getEmailAddress()) {
throw new ValidationException("person.email.notValid");
} else {
person.makePersistent();
}


kan het volgende worden geschreven in de EJB Person.java


@NotNull
@Length(max=100)
@EmailAddress
private String emailAddress;


en in PersonFacade.java vervolgens:


person.validate();
person.makePersistent();


Alle "heavy lifting" vindt plaats achter de schermen, hoeft maar eenmalig te worden geschreven en kan eenvoudig als een component worden gebruikt binnen verschillende projecten.

Ik heb in de interne ISAAC wiki een artikel geschreven waarin ik onze aanpak uit de doeken doe. Daarnaast staat daar wat voorbeeld code en enkele sequence diagrammen waarin uit wordt gelegd hoe het valideren precies in zijn werk gaat.

Mocht je verder willen lezen, hier zijn enkele intressante artikelen over JSR 303 op Gavin King's blog: 1, 2 en 3

donderdag 17 april 2008

Korte Eclipse tip

Een korte Eclipse tip voor iedereen die vind dat zijn Eclipse te traag is. Start Eclipse op met de volgende parameters:

-vmargs -Xmx1024m -XX:MaxPermSize?=128m

Op deze manier maak je een gig beschikbaar aan geheugen en 128Mb aan PermSize (voor het laden van Classes)

zondag 9 maart 2008

Binnenkort ondersteuning van Java op iPhone en iPod Touch


Normaal gesproken blijf ik weg van alles wat met Apple of iPod's te maken heeft, maar als Java programmeur kan ik niet anders dan hier een melding over maken. Sun is druk bezig met het maken van een virtual machine voor Apple's iPhone en iPod Touch. De virtual machine moet vergelijkbaar zijn met Java ME, maar Sun sluit niet uit dat laterna meer mogelijkheden worden toegevoegd.

Sun is begonnen aan de virtual machine dankzij het vrijgeven van de SDK van de iPhone en iPod Touch door Apple eerder deze maand.

vrijdag 1 februari 2008

More fun with iText

Laten we heel eerlijk zijn, iText is niet de meest elegante API. Het is praktisch onmogelijk om een echt mooie PDF te maken met iText zonder te belanden in het gesticht. Maar voor ieder probleem is een oplossing, zo ook voor iText en die oplossing is misschien simpeler dan je dacht. De oplossing is Graphics2D. Op deze pagina vind je meer informatie over hoe je een Graphic2D object direct om kunt zetten naar een PDF document. Hiermee omzeil je alle problemen met iText en kun je alles wat je hartje begeerd in een PDF zetten. Een tipje nog wel: het lijkt erop dat niet alle functionaliteiten van Graphics2D zomaar netjes overgenomen worden door iText (het zou ook eens niet), dit kun je omzeilen door alles eerst in een BufferedImage te schrijven en deze in iText te zetten.

woensdag 24 oktober 2007

Tutorial: Custom Taglib in JSP (Deel 3)


Welkom bij deel drie van de taglib tutorial. In dit deel nemen we een kijkje naar tags met een body.

Tot nu toe zijn alle tags in deze tutorial leeg geweest, dit is te herkennen aan het feit dat er maar één tag is die wordt afgesloten met een “/”. Kijken we echter naar HTML zijn de meeste tags niet leeg. Dit willen we met onze eigen taglib natuurlijk ook kunnen. De tag in dit deel van de tutorial gaat verder op de “Hello World” tags uit deel 1 en 2. Alleen printen we in dit deel de tekst “Hello World” in een stuk HTML code. De tag ziet er als volgt uit:

<tutorial:helloBody>
<p class=”cssClass” id=”helloWorld”>$_tekst</p>
</tutorial:helloBody>

Je ziet dat onze tag een begin-tag en een eind-tag, met daartussen HTML code. Ook is je misschien de tekst “$_tekst” gezien, op deze plaats wordt onze “Hello World” geplaatst. Aangezien dit gewoon via de replace() methode van String gaat had hier net zo goed iets anders kunnen staan, zolang we het maar netjes kunnen vervangen.

Om deze tag te kunnen verwerken zullen we hem eerst in onze taglib description moeten zetten. Dit gaat op dezelfde manier als onze allereerste tag, met een kleine wijziging.

<tag>
<name>helloBody</name>
<tag-class>nl.mysite.tags.HelloBodyTag</tag-class>
<body-content>JSP</body-content>
</tag>

In de bovenstaande code zie je de tag zoals deze wordt toegevoegd aan de taglib description. Zoals je ziet is deze inderdaad vrijwel identiek aan de code uit de eerste tutorial, echter waar eerder de waarde “empty” aan body-content werd meegegeven wordt nu de waarde “JSP” meegegeven. Dit betekend simpelweg dat de tag geen empty body heeft maar een body met daarin JSP code.

In onze tag handler zitten ook een aantal wijzigingen om de body van de tag te kunnen benaderen. Het eerste verschil is dat onze tag-handler geen subklasse is van javax.servlet.jsp.tagext.TagSupport maar van javax.servlet.jsp.tagext.BodyTagSupport. Ook hierin kun je dezelfde methoden overriden als normaal, maar je hebt er de methode getBodyContent() bij. Deze methode geeft een BodyContent object terug waarin de body staat.

In ons voorbeeld willen we de body ophalen een string (“$_tekst”) vervangen door “Hello World”. Dit doen we op de onderstaande manier:

BodyContent body = getBodyContent();
JspWriter out = body.getEnclosingWriter();
String data = body.getString();
data = data.replaceAll("\\$_tekst", "Hello World");
out.println(data);
body.clearBody();

In de eerste twee regels wordt de body en de JspWriter waarmee de body wordt geschreven opgehaald. De code in de body wordt in regel 3 in een string geplaats en in regel 4 gewijzigd. Daarna wordt de tekst geprint en de body wordt leeggemaakt.

zondag 21 oktober 2007

Java ME zal verdwijnen


Volgens guru en über-nerd James Gosling zal Java Micro Edition, de mobiele variant van Java langzaam maar zeker verdwijnen. Aangezien mobiele apparaten over steeds meer rekenkracht beschikken zal Java ME steeds meer met Java SE samensmelten. Zo bevat Java FX Mobile al bijna de volledige API van Java SE. "We're trying to converge everything to the Java SE specification. Cell phones and TV set-top boxes are growing up," Aldus Gosling "That convergence is going to take years."

Bron: CNet

zondag 14 oktober 2007

Effecten in swing


Tijdens mijn ziekte vorige week heb ik eens uitgeprobeerd hoever ik nou kan gaan in met Java Swing custom painting en geprobeerd om een effect na te bootsten wat ik ooit in assembler op school had geschreven. Dit effect bootst vuur na door middel van een vrij eenvoudig algoritme. Later meer hierover.

Om dit te bouwen heb ik een abstracte class gedefinieerd die de java.awt.Paint interface implementeert, zodat op eenvoudige wijze het scherm gevuld kan worden dmv setPaint op het Graphics object en een fillRect call.
Ik ga niet elke class bespreken hoe deze werkt, dit kun je me, als je het niet volgt, natuurlijk altijd vragen :).

De Effect class ziet er als volgt uit:





public abstract class Effect implements java.awt.Paint {

private final EffectListener listener;
protected DataBuffer db;
protected SampleModel model;

Timer effectTimer = new Timer(30, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
buildNextFrame();
listener.nextFrameReady();
}
} );

protected abstract void buildNextFrame();
protected abstract SampleModel createModel();
protected abstract DataBuffer createBuffer();

public DataBuffer getBuffer() {
if (this.db == null) {
this.db = createBuffer();
}
return this.db;
}

public SampleModel getModel() {
if (this.model == null) {
this.model = createModel();
}
return this.model;
}

public Effect(EffectListener l) {
if (l == null) throw new IllegalArgumentException("l == null");
this.listener = l;
this.effectTimer.start();
}

public interface EffectListener {
void nextFrameReady();
}

@Override
public abstract PaintContext createContext(ColorModel cm,
Rectangle deviceBounds,
Rectangle2D userBounds,
AffineTransform xform,
final RenderingHints hints);


@Override
public int getTransparency() {
return Transparency.OPAQUE;
}

}




Naast de definitie van het effect is er ook een Swingcomponent nodig dat dit effect laat zien, deze ziet er als volgt uit:




public class EffectPanel extends JPanel {

private Effect effect;

public EffectPanel() {
super.setOpaque(true);
}

@Override
protected void paintComponent(Graphics g) {
if (this.effect == null) return;
((Graphics2D) g).setPaint(this.effect);
g.fillRect(0, 0, getWidth(), getHeight());
}

public Effect getEffect() {
return this.effect;
}

public void setEffect(Effect effect) {
this.effect = effect;
}

}




Dit is alles wat we nodig hebben om een leuk effect op te kunnen bouwen in swing.
Het geheel is 100% compatible met swing en dit zou direct in elke applicatie geplugged kunnen worden door een bestaand JPanel te vervangen door het EffectPanel.
Aan het effectPanel kunnen gewoon op normale wijze andere Swingcomponenten worden toegevoegd layoutManagers geset worden etc.


Dit frameWork zou dus als volgt gebruikt kunnen worden, belangrijk is dat er aan het effect een listener wordt gekoppeld die het scherm opnieuw tekent als er een nieuw frame beschikbaar is. In dit geval heeft de effect-class een static methode die de "dirty region" bepaald.



public class EffectPanelTest {

public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
final EffectPanel p = new EffectPanel();
p.setEffect(new FireEffect(new Effect.EffectListener() {
@Override
public void nextFrameReady() {
p.repaint(FireEffect.getRepaintRectangle(p));
}
} ));
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setSize(340, 200);
f.setContentPane(p);
p.setLayout(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
c.anchor = c.NORTH;
p.add(new JButton("North button"), c);
c.anchor = c.SOUTH;
c.weighty = 1;
c.gridy = 2;
p.add(new JButton("South button"), c);
f.setVisible(true);
};
} );
}

}


Meer over het algoritme

Het originele algoritme werkte als volgt: vul de onderste 2 regels van de schermbuffer met willekeurige pixelswaarden tussen 0 en 255. Loop daarna de hele buffer af en tel de pixelwaarde onder, links van en rechts van op bij de huidige waarde van de pixel en deel dit door 4, trek er één af en plaats deze 1 boven de huidige positie terug in de buffer. Kopieer daarna de buffer naar het scherm en herhaal bovenstaande stappen.

Dit werkte toen goed omdat er gebruik werd gemaakt van 256 kleuren en een pallet aangepast op de kleuren. Dit zullen we dus moeten emuleren. Een ander verschil met toen is de resolutie van het scherm, nu op de pc waarop dit ontwikkeld is 1680x1050 toen 320x200. Dit verschil wordt nagebootst door een buffer met een vaste grootte te gebruiken en deze te schalen naar de benodigde grootte.




public class FireEffect extends Effect {

public FireEffect(EffectListener l) {
super(l);
initColors();
initBuffer();
}

Color colors[] = new Color[255];

public final static int height = 100;
public final static int width = 800;

Random r = new Random();

private void initBuffer() {
for (int x = 0; x < width; x++) {
for (int y = 0; y < height - 3; y++) {
getModel().setPixel(x, y, new int[] {0, 0, 0}, getBuffer());
}
}
}
/**
* initializeert het geemuleerde pallet
*/
private void initColors() {
for (int i = 0; i < 255; i++) {
int r = i - i / 16;
int g = i / 3;
int b = i / 8;
colors[i] = new Color(r, g, b);
}
}
int pixelBuffer[][] = new int[width][height];

@Override
protected SampleModel createModel() {
return new SinglePixelPackedSampleModel(DataBuffer.TYPE_INT, width, height, new int[] {0xFF0000, 0x00FF00, 0x0000FF});
}

@Override
protected DataBuffer createBuffer() {
return new DataBufferInt(width * height);
}

@Override
public PaintContext createContext(ColorModel cm, Rectangle deviceBounds,
final Rectangle2D userBounds, AffineTransform xform, final RenderingHints hints) {
PaintContext p = new PaintContext() {
@Override
public Raster getRaster(int x, int y, int w, int h) {
WritableRaster result = Raster.createWritableRaster(getModel(), getBuffer(), new Point(x, y));
for (int x1 = x; x1 < x + w; x1 ++) {
for (int y1 = y; y1 < y + h; y1 ++) {
// kopieer de waarden uit het geemuleerde pallet en schaal naar de grootte van userBounds
double userX = ((double) x1 / (double) userBounds.getBounds().width) * (double) width;
double userY = ((double) y1 / (double) userBounds.getBounds().height) * (double) (height - 3);
Color col = colors[pixelBuffer[(int) userX][(int) userY]];
result.setPixel(x1, y1 , new int[] {col.getRed(), col.getGreen(), col.getBlue()});
}
}
return result;
}
@Override
public void dispose() {
// doe hier niets, normaal vind hier cleanup plaats dit hoeft niet in deze demo
}
@Override
public ColorModel getColorModel() {
return new DirectColorModel(32, 0xFF0000, 0x00FF00, 0x0000FF);
}
} ;
return p;
}

@Override
public void buildNextFrame() {
for (int x = 1; x < width - 1; x++) {
for (int y = height - 2; y > height - 65 ; y--) {
int pixel1 = pixelBuffer[x - 1][y];
int pixel2 = pixelBuffer[x + 1][y];
int pixel3 = pixelBuffer[x][y];
int pixel4 = pixelBuffer[x][y - 1];
int newCol = (pixel1 + pixel2 + pixel3 + pixel4) / 4;
newCol = newCol < 2 ? 0 : newCol - 2;
Color c = colors[newCol];
pixelBuffer[x][y - 1] = newCol;
}
}
for (int x = 0; x < width; x+=4) {
for (int y = height - 3; y < height - 2; y++) {
int val = r.nextInt(255);
pixelBuffer[x][y] = val;
pixelBuffer[x + 1][y + 2] = val;
pixelBuffer[x + 2][y + 2] = val;
pixelBuffer[x + 3][y + 1] = val;
pixelBuffer[x + 2][y + 2] = val;
pixelBuffer[x + 1][y + 1] = val;
pixelBuffer[x + 2][y + 1] = val;
}
}

}

/**
* Geeft de dirty region terug zodat er niet te veel gerepaint wordt
* @param p
* @return
*/
public static Rectangle getRepaintRectangle(JComponent p) {
Rectangle repaint = new Rectangle();
double h = ((double) 65 / (double) FireEffect.height) * (double) p.getHeight();
repaint.y = p.getHeight() - (int) h;
repaint.x = 0;
repaint.height = (int) h;
repaint.width = p.getWidth();
return repaint;
}

}




Het belangrijkste in dit geval is natuurlijk niet de sourcecode, maak om het ding in het echt te zien.
Webstart demo:


donderdag 4 oktober 2007

Tutorial: Custom TagLib in JSP (Deel 2)


Het tweede deel van onze tutorial gaat over het maken van een custom tag met parameters. Wanneer je deel één van de tutorial hebt gemist en je afvraagt waar ik het over heb, klik dan hier om eerst het eerste deel te lezen voor je verder leest.

In het voorbeeld van deel één deden we niet meer dan de tekst “Hello World” afdrukken. Dit gaan we in dit deel uitbreiden met een parameter. Onze tag gaat er op de volgende manier uitzien:

<tutorial:helloworld name="Isaac Newton" />

En deze tag drukt de tekst “Hello [name]” af, in het bovenstaande voorbeeld wordt dus “Hello Isaac Newton” afgedrukt. Hiervoor moeten we de taglib description uitbreiden op de onderstaande manier.


<tag>
<name>helloworld</name>
<tag-class>nl.mysite.tags.HelloWorldTag</tag-class>
<body-content>empty</body-content>
<attribute>
<name>name</name>
<required>yes</required>
</attribute>
</tag>


De tag “attribute” wordt toegevoegd. Hieronder bevinden zich een aantal andere tags: “name” en “required”. Beide spreken voor zich, in “name” staat de naam van de parameter en in “required” staat of de parameter vereist is of niet. In dit laatste geval zal de tag handler een default waarde moeten bevatten. Daarnaast kunnen ook nog een tweetal tags voorkomen die we in dit voorbeeld niet nodig hebben: “rtexprvalue”, die aangeeft dat de return-type van expressies die de parameter doorgeven van een bepaald type moeten zijn of alles mag zijn (kan de waarden “true” of “false” bevatten) en de tag “type” wordt gebruikt om dit type aan te geven.

Na het aanpassen van onze taglib description kunnen we onze class file erbij pakken. Hieronder zie je dezelfde code als in de vorige tutorial, maar dan met de aanpassingen erin.


package nl.directa.tags;
import java.io.IOException;
import javax.servlet.jsp.tagext.TagSupport;

public class HelloWorldTag extends TagSupport {
private String name;

public int doEndTag() {
try {
pageContext.getOut().println("Hello "+name);
} catch (IOException ignored) { }
return EVAL_PAGE;
}

public void setName(String name) {
this.name = name;
}
}


Zo simpel is het! Je voegt een globale variabele toe en een set methode (let op de naamgeving volgens JavaBean conventies met de naam van de parameter erin verwerkt). In onze doEndTag methode gebruiken we de parameter om “Hello [name]” te printen.

Daarmee komen we aan het einde van het tweede deel in de custom taglib tutorial. In het volgende deel maken we een tag met een body, dat wordt lachen.