JavaFX: Using Patterns & Clean Code
We are seeing quite a number of exciting JavaFX demos around, demonstrating the pretty features of the language and the capability of easily integrating cool graphics. But, as a software designer, I can't prevent myself from seeing that in most examples we see bloated code - no good separation of concerns and poor applications of the MVC pattern. This is reasonable, as JavaFX was a new language and people needed first to be taught about the syntax and features; but now that - I presume - many of us have been introduced with the new language, it's high time we started worrying about good practices, as well as writing self-commenting code. Let's remember that good practices and good design are always more important than the language! So, let's introduce a very simple project - a Contact List whose specifications are: We have a list of "contacts", where each item is name, last name, email, phone, etc... The UI shows a list of contacts, that can be filtered by a text field; if you enter a value in it, only the contacts whose name starts with the entered text are shown. Selections are applied as you type. Selecting an item in the list of contacts, the details are shown in a form, where you can edit them. At any selection change, the form is animated (a rotation and a blur effect). You can get the code from: svn co -r 37 https://kenai.com/svn/javafxstuff~svn/trunk/ContactList/src/ContactList The model Let's first have a quick look at the model classes. First a simple value object representing a piece of data: package it.tidalwave.javafxstuff.contactlist.model; public class Contact { public var id: String; public var firstName: String; public var lastName: String; public var phone: String; public var email: String; public var photo: String; override function toString() { return "\{id: {id}, value: {firstName} {lastName}, phone: {phone}, email: {email}" } } Then a small service which provides a bunch of data: package it.tidalwave.javafxstuff.contactlist.model; public abstract class ContactRegistry { public abstract function items() : Contact[]; } In the demo code, you'll find a mock implementation with some wired values; in a real case this could be a Business Delegate encapsulating code for retrieving data remotely. So far, so good - it's pretty normal to keep these things separated from the UI. The Controllers We're not going to see a classic Controller here; actually, we're slightly departing from the "pure" MVC. The code I'm showing you is more a "Presentation Model", a pattern described by Martin Fowler as: The essence of a Presentation Model is of a fully self-contained class that represents all the data and behavior of the UI window, but without any of the controls used to render that UI on the screen. A view then simply projects the state of the presentation model onto the glass. This class is basically an hybrid between a classic model and a controller. It is also a façade between the view and the domain model. package it.tidalwave.javafxstuff.contactlist.model; import it.tidalwave.javafxstuff.contactlist.model.ContactRegistry; import it.tidalwave.javafxstuff.contactlist.model.ContactRegistryMock; public class PresentationModel { public var searchText : String; public var selectedIndex : Integer; // The Business Delegate def contactRegistry = ContactRegistryMock{} as ContactRegistry; def allContacts = bind contactRegistry.items(); // The contacts filtered according the contents of the search field public-read def contacts = bind allContacts[contact | "{contact.firstName} {contact.lastName}".startsWith(searchText)]; // The selected contact; the code also triggers a notification at each change public-read def selectedContact = bind contacts[selectedIndex] on replace previousContact { onSelectedContactChange(); }; // Notifies a change in the current Contact selection public-init var onSelectedContactChange = function() { } } Note the extreme compactness brought by functional programming. There's almost no imperative programming as everything is achieved by properly using the binding feature. The only imperative part is the 'onSelectedContactChange' function, which is just a listener to notify selection changes to some external code - it will be used only for triggering the animation. BTW, I'd like to remove it from here, but I wasn't able to. Maybe it's a JavaFX thing that I've not understood yet, but I'm keeping it for another post. Now, everything about the animation goes encapsulated in a specific class, which only exposes two properties controlling the animation: the effect and the rotation angle. A single play() function is provided to start the animation. package it.tidalwave.javafxstuff.contactlist.view; import javafx.animation.Interpolator; import javafx.animation.Timeline; import javafx.scene.effect.GaussianBlur; public class AnimationController { public-read var rotation = 0; public-read def effect = GaussianBlur{} def timeline = Timeline { repeatCount: 1 keyFrames: [ at(0s) { effect.radius => 20; rotation => 45 } at(300ms) { effect.radius => 0 tween Interpolator.EASEBOTH; rotation => 0 tween Interpolator.EASEBOTH } ] } public function play() { timeline.playFromStart(); } } The Views Now, a UI component. The way we design it largely depends on the process, as a graphic designer could be involved. In any case, I think that the whole UI should not be implemented in a single, bloated class; rather relevant pieces should be split apart. For instance, a CustomNode can model the "form" that renders the contact details (in the code below I've omitted all the attributes related to rendering): package it.tidalwave.javafxstuff.contactlist.view; import javafx.scene.CustomNode; import javafx.scene.Group; import javafx.scene.layout.HBox; import javafx.scene.layout.VBox; import javafx.scene.Node; import javafx.ext.swing.SwingLabel; import javafx.ext.swing.SwingTextField; import it.tidalwave.javafxstuff.contactlist.model.Contact; public class ContactView extends CustomNode { public var contact : Contact; public override function create() : Node { return Group { content: [ VBox { content: [ SwingLabel { text: bind "{contact.firstName} {contact.lastName}" } HBox { content: [ SwingLabel { text: "First name: " } SwingTextField { text: bind contact.firstName } ] } HBox { content: [ SwingLabel { text: "Last name: " } SwingTextField { text: bind contact.lastName } ] } HBox { content: [ SwingLabel { text: "Email: " } SwingTextField { text: bind contact.email } ] } HBox { content: [ SwingLabel { text: "Phone: " } SwingTextField { text: bind contact.phone } ] } ] } ] }; } } As you can see, we have only layout and data binding here, the only things a view should do. Putting all together Now the last piece of code, the Main, which builds up the application (again, I've omitted all attributes only related to rendering): package it.tidalwave.javafxstuff.contactlist.view; import javafx.scene.layout.HBox; import javafx.scene.layout.VBox; import javafx.scene.Scene; import javafx.stage.Stage; import javafx.ext.swing.SwingLabel; import javafx.ext.swing.SwingList; import javafx.ext.swing.SwingListItem; import javafx.ext.swing.SwingTextField; import it.tidalwave.javafxstuff.contactlist.controller.PresentationModel; Stage { def animationController = AnimationController{}; def presentationModel = PresentationModel { onSelectedContactChange : function() { animationController.play(); } }; scene: Scene { content: VBox { content: [ HBox { content: SwingLabel { text: "Contact List" } } HBox { content: [ SwingLabel { text: "Search: " } SwingTextField { text: bind presentationModel.searchText with inverse } ] } HBox { content: [ SwingList { items: bind for (contact in presentationModel.contacts) { SwingListItem { text:"{contact.firstName} {contact.lastName}" } } selectedIndex: bind presentationModel.selectedIndex with inverse } ContactView { contact: bind presentationModel.selectedContact effect: bind animationController.effect rotate: bind animationController.rotation } ] } ] } } } As in the previous code snippets, I think the listing can be easily read and understood. Basically, we are glueing all the pieces together and binding the relevant models. In the end, each class in this small project does a simple, cohese thing: representing data, encapsulating the presentation logic, controlling the animation, rendering the views. Dependencies are reduced to the minimum and they have the correct direction: views depend on the models (and not the opposite) and the AnimationController; the AnimationController is independent. You could replace the view components without affecting the rest of the classes, as well as removing or adding other animations by properly using different AnimationControllers. This good separation of roles and responsibilities is the good way to apply OO. There is a detail which is worth discussing. Note the two bind ... with inverse. They implement the so-called "bidirectional binding" where not only a change in the model (e.g. PresentationModel.selectedIndex) is reflected to attributes in the UI (e.g. SwingList.selectedIndex), but also the opposite happens. Indeed, the reverse binding is more important in our example, because it implements the controller responsibility (it captures user's gestures from the view and changes the model); the direct binding from the PresentationModel to SwingList, instead, is useless, as in our case the PresentationModel is never the originator of a change. So, why not using a simple, direct binding in PresentationModel towards SwingList? Such as: public class PresentationModel { var list : SwingList; public def selectedIndex = bind list.selectedIndex; ... } Because this would introduce a dependency from the model/controller to the view, which is plain wrong. Here, bind ... with inverse not only works as a shortcut for writing less code (that is, explicitly declaring a binding and its inverse), but it's also an essential feature for a better design. As far as I know - but I could be wrong - for example in ActionScript (Adobe Flex language) there's no bidirectional binding (you need to put binding keywords at both ends of the association), thus introducing unneeded or circular dependencies. I believe this is true at least at code level (as far as I understand, there are different ways to do binding in ActionScript).
May 12, 2009
·
45,200 Views
Comments
Jul 27, 2013 · James Sugrue
Releases are not something done on a whim. They are carefully planned and orchestrated actions, preceded by countless rules and followed by more rules.Sure. This doesn't mean that they shouldn't be automated as much as possible. This doesn't mean that at a certain point one might have performed all the homework and approved a release, and then the decision of making a release could just turn into pressing a button (e.g. launch a job in Hudson which in turn runs Maven). The Maven release plugin might support or not this automated process, but this is another matter. Small projects, such as libraries, that have adequate test coverage can be released as frequently as one wants, for instance.
Releasing software is a process, not a single command on the command line.What kind of logics does infer that "a process" cannot be automated, partially or totally? Manual processes are error-prone and the last thing that I'd like to see is a release failed for a trivial manual error (I've seen a lot).Then you wrote some Maven facts that are very incorrect.
Even Maven’s most fierce supporters agree on this. The Maven release plugin just tries to do too much stuff at once: build your software, tag it, build it again, deploy it, build the site (triggering yet another build in the process) and deploy the site. And whilst doing that, running the tests x times. Most of the time, you’re making candidate releases, so building the complete documentation is a complete waste of time.False. The release maven plugin can be customized in very flexible ways. You can disable running tests, generating the javadoc, or the source jars, and the site, and eventually design profiles to have variants on these choices. Have you ever read about the preparationGoals, goals, completionGoals properties of the plugin? To give concrete examples: I don't need the Maven generated site, so site generation is always disabled for me. I also disabled tests, because before releasing I run tests separately. The core of the release cycle can just be: check that everything is compilable, tag and prepare the next version, and then run a forked Maven that checks out from the tag and performs the build.
The release plugin is just a combination of the versions, scm, deploy and site plugin that seriously violates the single responsibility principle.Apart from the fact that this comment on internal software quality need not to have to do with usability (there are famous counter-examples), your statement is erroneous... Composing things does not violate the SRP. The important thing is that the single components have a single responsibility, and in this is true with the mentioned plugins. If your sentence was true, we should only have software apps that do a single, simple thing.
The release plugin is one of the reasons Maven has gotten a bad reputation with some people.Maven could have a bad reputation with some people because they legitimately don't like the way it works or because people just don't read the f***ing manual, and then blog incorrect things. :-)I set up a number of industrial products where releases are managed with the release-plugin and in most cases no problems. Yes, we do Releases Candidates too. In a case where the customer is not totally satisfied with the release plugin, he is not really satisfied with the way dependencies are managed (e.g. because you have a dependency graph among subprojects with many levels and there are "ripples" when dependencies are updated. I verified that some people have similar problems with different tools, such as Gradle, so it has more to do with the process, the project structure, the dependency management, and not the release plugin.
Jul 27, 2013 · James Sugrue
Lieven, you started right, but ended wrong... :-) Overall, you're right: nobody should feel forced to use the release maven plugin if it doesn't fit the release process he wants. In fact, first you define a release process, then you use/adapt the best tool to run it. We agree. I don't have remarks about the release process you describe - I woulnd't use it as is, but in this area there is room for variants, above all it depends on the context (a single developer, a small agile team, a medium sized team or a large team of course would choose different processes).
But:
Releases are not something done on a whim. They are carefully planned and orchestrated actions, preceded by countless rules and followed by more rules.
Sure. This doesn't mean that they shouldn't be automated as much as possible. This doesn't mean that at a certain point one might have performed all the homework and approved a release, and then the decision of making a release could just turn into pressing a button (e.g. launch a job in Hudson which in turn runs Maven). The Maven release plugin might support or not this automated process, but this is another matter. Small projects, such as libraries, that have adequate test coverage can be released as frequently as one wants, for instance.
Releasing software is a process, not a single command on the command line.
What kind of logics does infer that "a process" cannot be automated, partially or totally? Manual processes are error-prone and the last thing that I'd like to see is a release failed for a trivial manual error (I've seen a lot).
Then you wrote some Maven facts that are very incorrect.
Even Maven’s most fierce supporters agree on this. The Maven release plugin just tries to do too much stuff at once: build your software, tag it, build it again, deploy it, build the site (triggering yet another build in the process) and deploy the site. And whilst doing that, running the tests x times. Most of the time, you’re making candidate releases, so building the complete documentation is a complete waste of time.
False. The release maven plugin can be customized in very flexible ways. You can disable running tests, generating the javadoc, or the source jars, and the site, and eventually design profiles to have variants on these choices. Have you ever read about the preparationGoals, goals, completionGoals properties of the plugin? To give concrete examples: I don't need the Maven generated site, so site generation is always disabled for me. I also disabled tests, because before releasing I run tests separately. The core of the release cycle can just be: check that everything is compilable, tag and prepare the next version, and then run a forked Maven that checks out from the tag and performs the build.
The release plugin is just a combination of the versions, scm, deploy and site plugin that seriously violates the single responsibility principle.
Apart from the fact that this comment on internal software quality need not to have to do with usability (there are famous counter-examples: many say that Wordpress and JIRA are poorly designed, still they work well and are very popular), your statement is erroneous... Anyway composing stuff, as you correctly say, does not violate the SRP. The important thing is that the single components have a single responsibility, and in this is true with the mentioned plugins. If your sentence was true, we should only have software apps that do a single, simple thing.
The release plugin is one of the reasons Maven has gotten a bad reputation with some people.
Maven could have a bad reputation with some people because they legitimately don't like the way it works or because people just don't read the f***ing manual, and then blog incorrect things. :-)
I set up a number of industrial products where releases are managed with the release-plugin and in most cases no problems. Yes, we do Releases Candidates too. In a case where the customer is not totally satisfied with the release plugin, he is not really satisfied with the way dependencies are managed (e.g. because you have a dependency graph among subprojects with many levels and there are "ripples" when dependencies are updated. I verified that some people have similar problems with different tools, such as Gradle, so it has more to do with the process, the project structure, the dependency management, and not the release plugin.
Jul 27, 2013 · James Sugrue
Lieven, you started right, but ended wrong... :-) Overall, you're right: nobody should feel forced to use the release maven plugin if it doesn't fit the release process he wants. In fact, first you define a release process, then you use/adapt the best tool to run it. We agree. I don't have remarks about the release process you describe - I woulnd't use it as is, but in this area there is room for variants, above all it depends on the context (a single developer, a small agile team, a medium sized team or a large team of course would choose different processes).
But:
Releases are not something done on a whim. They are carefully planned and orchestrated actions, preceded by countless rules and followed by more rules.
Sure. This doesn't mean that they shouldn't be automated as much as possible. This doesn't mean that at a certain point one might have performed all the homework and approved a release, and then the decision of making a release could just turn into pressing a button (e.g. launch a job in Hudson which in turn runs Maven). The Maven release plugin might support or not this automated process, but this is another matter. Small projects, such as libraries, that have adequate test coverage can be released as frequently as one wants, for instance.
Releasing software is a process, not a single command on the command line.
What kind of logics does infer that "a process" cannot be automated, partially or totally? Manual processes are error-prone and the last thing that I'd like to see is a release failed for a trivial manual error (I've seen a lot).
Then you wrote some Maven facts that are very incorrect.
Even Maven’s most fierce supporters agree on this. The Maven release plugin just tries to do too much stuff at once: build your software, tag it, build it again, deploy it, build the site (triggering yet another build in the process) and deploy the site. And whilst doing that, running the tests x times. Most of the time, you’re making candidate releases, so building the complete documentation is a complete waste of time.
False. The release maven plugin can be customized in very flexible ways. You can disable running tests, generating the javadoc, or the source jars, and the site, and eventually design profiles to have variants on these choices. Have you ever read about the preparationGoals, goals, completionGoals properties of the plugin? To give concrete examples: I don't need the Maven generated site, so site generation is always disabled for me. I also disabled tests, because before releasing I run tests separately. The core of the release cycle can just be: check that everything is compilable, tag and prepare the next version, and then run a forked Maven that checks out from the tag and performs the build.
The release plugin is just a combination of the versions, scm, deploy and site plugin that seriously violates the single responsibility principle.
Apart from the fact that this comment on internal software quality need not to have to do with usability (there are famous counter-examples: many say that Wordpress and JIRA are poorly designed, still they work well and are very popular), your statement is erroneous... Anyway composing stuff, as you correctly say, does not violate the SRP. The important thing is that the single components have a single responsibility, and in this is true with the mentioned plugins. If your sentence was true, we should only have software apps that do a single, simple thing.
The release plugin is one of the reasons Maven has gotten a bad reputation with some people.
Maven could have a bad reputation with some people because they legitimately don't like the way it works or because people just don't read the f***ing manual, and then blog incorrect things. :-)
I set up a number of industrial products where releases are managed with the release-plugin and in most cases no problems. Yes, we do Releases Candidates too. In a case where the customer is not totally satisfied with the release plugin, he is not really satisfied with the way dependencies are managed (e.g. because you have a dependency graph among subprojects with many levels and there are "ripples" when dependencies are updated. I verified that some people have similar problems with different tools, such as Gradle, so it has more to do with the process, the project structure, the dependency management, and not the release plugin.
Apr 11, 2012 · James Sugrue
Given that we're commenting regex maps, I've been using another home-made since a few time. It works for my specific projects that needs it, but I never validated it against the Map contract. I'd like to get some feedback just while you're still hot about the topic ;-). It is not optimized with pattern compilation, but it does super.put() and has a shortcut for gets whose arg is not a regexp (which in my use cases happens 80% of the time). My impression is that designing an implementation that is optimized for a lot of generic cases *and* it complies with Map contract is a hard task.
Mar 24, 2012 · James Sugrue
In any case CLASS retention has nothing to do with the fact that you don't need the jar at runtime. Even RUNTIME retention doesn't require the jar; if it's missing, it's just as those annotations weren't there. See http://stackoverflow.com/questions/3567413/why-doesnt-a-missing-annotation-cause-a-classnotfoundexception-at-runtime
Nov 07, 2011 · James Sugrue
I could be wrong, but I don't think that in order to activate @PostConstruct you need Spring MVC, thus the dependencies you mentioned on Spring Web and Servlet. AFAIK,<mvc:annotation-driven> isn't the only way to go, as <context:annotation-config> is enough, and only requires depending on Spring Context.
Oct 14, 2011 · James Sugrue
Before saying that I mostly disagree, I think it's necessary to make a preamble. "Evil" and "good" are often misused in our world. I think they are good for a brief title or for telling things with some humour, but "appropriate" and "unappropriate" are better terms. In other words, there's no black and white, but a scale of greys. There's no "true OOP" in practice, you can do things in many ways, paying some costs and getting benefits. The important thing is that you are aware of your choice, I mean, you are aware of what you are going to pay and what are you going to get, and you are consistent.
The basic point is not related to the danger of exposing the internal state. It's to depend on a public thing. For instance, if I have a Person with firstName, lastName and age properties, and I use them by means of getters, my whole application potentially depends on these three properties. If any of these properties change (let me say it disappears), you have broken code potentially everywhere. Of course, it's unlikely that a firstName, lastName disappears from a Person. So in this very example, one might assume that the risks of going with getter / setters are low. Let's just think of a more complex domain where properties are more likely to change.
In this case, the risks might be higher. What I'd do is not to expose those properties as public, but as package friends. If I have to render Person e.g. on a web page, I'd write a PersonRenderer which has a method render(Person, WebPage) [with WebPage I mean any infrastructure related to a give web technology to render something] which does the job. Should I send an email to that person, I'd use a similar friend class PersonEmailer, etc. With this approach, I know that the dependencies on the structure of Person are well known in advance and I can predict what impact will have any change in the structure of Person (of course, I can say the impact is very small).
Is it better or not? Sure, it's more complex, because I have more classes (even though they are very small and simple). I've written and Android application using this approach and, once you've understood it, it's not that difficult. But I agree, it's not necessarily always the best solution. See my preamble.
For what concerns DTO in DDD, there's a way to fix the anemic object thing which make it also possible to work without getter/setters: DCI. Google for DCI and read the Artima's article for quickly learning on it. In short, your entities get decomposed in an anemic object (what would be he DTO, called Datum) and a number of active classes (Roles) doing operations on it. Roles are not services, since there's an instance of Role per each Datum. Without getter/setters the Datum basically has no methods. I'd have person.getRenderer().renderTo(renderable) for rendering it, or person.getEmailer().sendEmailTo(recipient) in a simple fashion. If I am concerned about decoupling dependencies, I can have a dynamic approach as person.getRole(Renderer).renderTo(renderable) [or a better syntax that I prefer, person.as(Renderer).renderTo(renderable)], and roles can be dynamically injected in a number of ways.To deal with frameworks that absolutely want getters/setters as JPA, I can have person.as(Persistable).persist(), where the specific implementation of Persistable would copy the internal state of Person into a JPAPersonBean and do the job trasparently. You get that I have another advantage here, that I can replace the persistence mechanism as I want.
This is very powerful, very extensible, very robust. It costs a bit more than a plain design with getters/setters. In a way, I think it's a very appropriate way to use OOP, since the Single Responsibility Principle is respected to a very fine grain. In some cases, though, it can cost too much for the purpose.
Oct 06, 2011 · James Sugrue
Sep 09, 2011 · Ladislav Gažo
Jun 22, 2011 · Farrukh Najmi
Nov 12, 2010 · James Sugrue
Actually we don't know if this comes out of a listening to the community. It could be that Oracle acted on its own, and possibly the Apple public news of "deprecation" were a part of a negotiating strategy (that could have been started much earlier than we know). In fact, we don't know the detail of the deal.
For what concerns the sanity of our teeth, the solution is obvious: we of course start commenting about news just after five minutes, but we don't get too worried about consequences for some time, not thinking that the lack of an immediate communication from any corporate means a complete lack of strategy / interest / whatever.
Of course, these are good news and the closing of a very old problem in the community. This demontrates that having a strong steward is better than having a weak steward... at least for some things. Of course, we pay the strenght of Oracle in other ways (see Apache etc...).
Sep 20, 2010 · Tim Boudreau
Agreed - we're discussing what happens in the minority of cases. Re: javadoc, is not an option. javadoc is needed and good for readers and understanding what's going on; for pure code readability, javadoc/comments must be the last chance.
Sep 20, 2010 · Tim Boudreau
Sep 15, 2010 · Luigi Viggiano
Sep 15, 2010 · Luigi Viggiano
Sep 15, 2010 · Luigi Viggiano
Sep 15, 2010 · Luigi Viggiano
Sep 15, 2010 · Luigi Viggiano
Sep 15, 2010 · Luigi Viggiano
Sep 15, 2010 · Luigi Viggiano
Sep 15, 2010 · Luigi Viggiano
Sep 15, 2010 · Luigi Viggiano
Sep 15, 2010 · Luigi Viggiano
Aug 20, 2010 · James Sugrue
Jun 07, 2009 · Fabrizio Giudici
I've posted here a screencast of the application running with about 1.000 elements. The screencast is neither cut nor accelerated, you can see the real speed on a MacBook Pro.
For what concerns my original demo, the only problem I see on JavaFX 1.2 is some parts of the layout screwed up.
Jun 04, 2009 · Fabrizio Giudici
Jun 02, 2009 · Fabrizio Giudici
Krzysztof, no, I didn't see problems with that handful of names. BTW, I have another application where a similar trick is used and it works with about 1.000 items, with only some slightly noticeable delay in some cases. Of course, with such a big number of items you probably have to do some smarter filtering rather than using subsequences.
May 15, 2009 · Fabrizio Giudici
May 13, 2009 · Fabrizio Giudici
The fact that you do things in JavaFX "better" than Java is subjective, at this time, and related to a number of things. For me, I don't see compelling reasons for turning my Java desktop stuff into JavaFX _now_. If I had some compelling graphics requirements, at the point to throw a graphic designer into the team, JavaFX would make the difference. I expect the two different perspectives to get closer and closer in the next years.
Objectively, JavaFX is more coincise and binding is the key trick. Try to write the same example I'm talking of in Java. Of course, the same functional binding could be introduced in Java (thinking of it...) thus even Java programs could be much shorter. But with Java binding can't be as natural as is with JavaFX.
May 13, 2009 · Fabrizio Giudici
May 12, 2009 · Fabrizio Giudici
It's one of the things I'll try in future. For now, the only thing I've done is to run javap on a compiled JavaFX value object, and - as expected - I saw it's very different from a regular JavaBean. Basically every attribute its an independent object, I presume with its own get()/set() and binding support. But there are also lots of other stuff that I don't understand at a glance.
Feb 09, 2009 · Geertjan Wielenga
May 06, 2008 · Geertjan Wielenga
Feb 06, 2008 · Geertjan Wielenga
--Fabrizio Giudici