Wicket adapts to your persistence needs, from conventional to unusual The best persistence technology to bundle with a Web framework might just be none at all. In this final installment in his series on Web development with Wicket, Nathan Hamblen demonstrates how Wicket’s independence from any one persistence tool leaves your Web app with lots of options. See what happens when you persist application data in four different combinations of Spring, Hibernate, ActiveObjects, and Databinder.According to the Wicket vision statement, Wicket was designed with the intentionally narrow focus of “enabling component-oriented, programmatic manipulation of markup.” Of course, Wicket must account for requirements outside of that domain, such as data persistence, but it does so indirectly and flexibly, without incorporating any one solution. Wicket thus avoids two bugaboos common to other Web application frameworks: unchecked growth and unnecessary dependency.Dependency here should be understood not only in its literal programming sense (a linked library), but metaphorically: a Web framework that ties its fortunes to a data persistence framework elevates its risk of an early decline. Today, Wicket is considered a fairly new, and thereby risky, option for Web development. If the project were to commit to a persistence framework, it would need to choose an established one to reassure users. But in the inevitable cycle of software growth, maturity, and decline, a safe choice early on would later leave Wicket with an outdated persistence technology. Decoupling from persistence eliminates that risk. This series has been an overview of the benefits of of using Wicket for software development. I started with the machinations of software state in a stateless Web, then showed you how to leverage stateful components by aggressively reusing code and markup. This final installment will introduce you to practical approaches to data persistence with Wicket. Because there are so many ways to store data, we’ll look at several permutations of an application. As the application evolves, you’ll observe Wicket’s interface with a progression of persistence technologies, from the familiar to the less so.Example 1: Spring and HibernateYou might be a Java programmer if seeing the words Spring and Hibernate together does not conjure images of a groggy bear emerging from a woodland cave. (And you might be a biologist if you point out that bears do not actually, metabolically, hibernate.) To most Java developers, a Spring-managed Hibernate session is an established persistence strategy. It’s the first strategy you’ll explore for building a data-driven Wicket application.As most readers will have experience with the Spring and Hibernate side of things, this tutorial only covers the potential surprises. Firstly, for this application example you’ll use Spring 2.5 and Hibernate Annotations. Doing so will reduce the bulk of XML configuration through classpath scanning and Java annotations. Secondly, the application will be self-contained rather than depending on a servlet container (see “Life outside the IDE” for a primer on how that works). While these departures make the application look different, they have no effect on the technique used to bring data to Wicket from Spring and Hibernate. You could use the same methods discussed here to integrate Wicket with an existing application using, for example, Spring 1.2, Hibernate Core, and a Tomcat JNDI data source. Scrambled tadaData integrity is of primary concern in software persistence, but the twist to the example application is that it will garble information on purpose — just not permanently. Scramble is a word guessing game, in which a word appears on screen with its character order randomized. Players must enter the correct spelling to win points and progress to the next word. To exercise data persistence a bit more heavily, in this game each word has an assigned point value. An administration page allows for entering and updating the words and points.You can download the sample code for this article now. The first Scramble example is called scramble-spring; each example is stored in a directory that builds and runs independently. This example maps the data in a class using JPA-standard annotations, shown in Listing 1.Listing 1. Word class with JPA annotations@Entity public class Word implements Serializable { @Id @GeneratedValue private Integer id; @Column(nullable=false) private String value; @Column(nullable=false) private Integer points; // getters, setters... You’ll see in a moment why the class has implemented Serializable. To process this annotated class and also create a table for it, the applicationContext.xml file for Spring contains the directives shown in Listing 2. Listing 2. Session factory definition in applicationContext.xml<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"> <property name="annotatedClasses"> <list> <value>example.data.Word</value> </list> </property> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect">org.hibernate.dialect.HSQLDialect</prop> <prop key="hibernate.hbm2ddl.auto">create</prop> </props> </property> </bean> We’ll kick off this Web application with a server class like those in previous examples, called ScrambleServer. The web.xml file shown in Listing 3 now has two filters — one for Wicket and one for Spring to open a Hibernate session for each request — as well as a listener for context loads so that Spring can process applicationContext.xml.Listing 3. web.xml with filters and context loader listener<web-app ... > <filter> <filter-name>opensessioninview</filter-name> <filter-class> org.springframework.orm.hibernate3.support.OpenSessionInViewFilter </filter-class> </filter> <filter> <filter-name>WicketFilter</filter-name> <filter-class>org.apache.wicket.protocol.http.WicketFilter</filter-class> <init-param> <param-name>applicationClassName</param-name> <param-value>example.ScrambleApp</param-value> </init-param> </filter> <filter-mapping> <filter-name>opensessioninview</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <filter-mapping> <filter-name>WicketFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <listener> <listener-class> org.springframework.web.context.ContextLoaderListener </listener-class> </listener> </web-app> Just so you’re clear on this configuration, here’s a potential sequence of events as the application executes:The JVM starts with example.ScrambleServer as the main class.ScrambleServer configures and launches the embedded Jetty server.Spring’s loader listener fires.Spring finds applicationContext.xml, then configures Hibernate Annotations with the mapped class.A request comes in.Spring’s filter opens a thread-bound Hibernate session.Wicket’s filter processes the request as a Page or other resource. Administrative skills neededAt this point, you’re back in Wicket world, inside a Spring universe that knows that a user request is active. To get going on the administration screen, you need to make the page template shown in Listing 4 and rendered in Figure 1. Listing 4. Administer.html page template<html> <head> <title>Scramble Administration</title> </head> <body> <h2>Scramble Administration</h2> <form wicket:id="form"> Word <input wicket:id="value"/> Points <input wicket:id="points"/> <input type="submit" value="Save" /> <input type="submit" wicket:id="cancel" value="Cancel" /> </form> <div wicket:id="feedback" /> <div wicket:id="words-cell"> <table class="legacyTable"> <tr><th>word</th><th>points</th></tr> <tr wicket:id="words"> <td><a href="#" wicket:id="link"><span wicket:id="value">super</span></a></td> <td wicket:id="points">5</td> </tr> </table> <wicket:link>Play Game</wicket:link> </div> </body> </html> Figure 1. Administer.html previewListing 4 is less fancy than the examples from the last article in this series, which emphasized layout reuse. Here, you have one form for entering data, with an unbound Save button that triggers the default form submit action; a Cancel button; a slot for feedback messages below the form inputs; a table for listing the known words; an autolink to the game playing page; and a cell for hiding the table and link (if there are no known words). Listing 5 shows the code that drives the form’s behavior.Listing 5. EditForm for Scramble administrationpublic class Administer extends WebPage { ... private EditForm form; public Administer() { add(form = new EditForm("form")); ... } public class EditForm extends Form { public EditForm(String id) { super(id, new CompoundPropertyModel(new Word())); add(new RequiredTextField("value", String.class)); add(new RequiredTextField("points", Integer.class)); add(new Button("cancel") { @Override public void onSubmit() { EditForm.this.setModel(new CompoundPropertyModel(new Word())); } }.setDefaultFormProcessing(false)); } @Override protected void onSubmit() { dictionaryService.updateWord((Word) getModelObject()); setModel(new CompoundPropertyModel(new Word())); } } } In Listing 5, you can see why the entity in Listing 1 implemented Serializable: it’s going into a CompoundPropertyModel. Like Model, this model class requires that its referenced object be storable, because the model does live between requests and may need to travel across a cluster of application servers. In truth, that Word instance has no valuable information to be serialized; it’s brand new, and no possible scenario leads to it having data to be serialized. Knowing that, you could do things differently, but the easiest thing to do is mark it as serializable.The Cancel button resets the state of the form. It needs to turn off default form processing, because that would pass through validation; the user should be able to cancel even if a required value or point field is empty. Now, for the real deal: onSubmit(). The updateWord() method must be saving the current word object, but what is dictionaryService and where is it initialized? Listing 6. applicationContext.xml setting scannable packages and transactional annotations<context:component-scan base-package="example.dao" /> <context:component-scan base-package="example.service" /> ... <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory"/> </bean> <tx:annotation-driven /> Listing 7. DictionaryServicepublic interface DictionaryService { void updateWord(Word word); } Listing 8. DictionaryServiceImpl@Service @Transactional public class DictionaryServiceImpl implements DictionaryService { private DictionaryDao dictionaryDao; public void updateWord(Word word) { dictionaryDao.updateWord(word); } @Autowired public void setDictionaryDao(DictionaryDao dictionaryDao) { this.dictionaryDao = dictionaryDao; } } Listing 9. Administer page referencing Spring beanspublic class Administer extends WebPage { @SpringBean private DictionaryDao dictionaryDao; @SpringBean private DictionaryService dictionaryService; ... } Listings 6 through 8 use the latest in Spring brevity to define a transactional service. How that works and what it means are not really the subject of this article, but it does allow changes to the relevant object to be persisted by Hibernate. There’s also a data access object (DAO) referred to there, the contents of which are not very interesting. Listing 9 reveals the means by which Spring is brought into Wicket (or one way of doing it). The @SpringBean annotation flags a component field for injection; no name is required if there is only one bean known to Spring matching the required type. For this annotation to have any effect, you need to add the component instantiation listener shown in Listing 10.Listing 10. Making ScrambleApp aware of the SpringBean annotationpublic class ScrambleApp extends WebApplication { @Override protected void init() { addComponentInstantiationListener(new SpringComponentInjector(this)); } ... } With that configuration in place, it’s trivial to access any Spring bean from any Wicket component. The next step is to render the words known to the application. To achieve this, the sample app uses a ListView similar to the one used to render the list of calculators in the previous article in this series. That list was unchanging, but for this page the list may change from one request to the next. Fortunately, Wicket’s IModel offers a solution. When you give a component an IModel instance, you’re not giving it a reference the object it refers to; you’re giving it an object to produce the object it refers to. And the IModel interface expects to be notified when a request ends so that it can dereference the object if it wants to. Listing 11 shows how this can be leveraged for the word list.Listing 11. Word list model populated using a Spring beanIModel wordsModel = new LoadableDetachableModel() { @Override protected Object load() { return dictionaryDao.getWords(); } }; Listing 11 uses one of the many base IModel implementations, this one optimized for objects that need to be loaded only once per request cycle. The first time its object is requested, it loads and retains a reference. Near the end of the cycle the model is detached and that reference is discarded. In wordsModel, the anonymous subclass uses dictionaryDao (an instance variable of the page that happens to be a Spring bean) to load its list of words. Listing 12 shows this model being used for two components. Listing 12. Adding components for the word list and linksadd(new WebMarkupContainer("words-cell", wordsModel) { @Override public boolean isVisible() { return !((List)getModelObject()).isEmpty(); } }.add(new PropertyListView("words", wordsModel) { @Override protected void populateItem(final ListItem item) { item.add(new Link("link") { public void onClick() { form.setModel(new CompoundPropertyModel(item.getModel())); } @Override public boolean isEnabled() { return !item.getModelObject().equals(form.getModelObject()); } }.add(new Label("value"))); item.add(new Label("points")); } })); words-cell is a block that is used to hide the table header and link to the next page when there are no words. (For their markup, these components are still part of the page template in Listing 4.) Note that you have to cast the model object to a List to know if it’s empty; in Wicket 1.4, which is in development, the need for such casting will be reduced through the use of Java generic types. Tagging along to that call (add(...) always returns this in Wicket), the code adds a PropertyListView to the cell. This subclass of ListView simply wraps the item models in a CompoundPropertyModel so that the names of each subcomponent will define the properties of the Word it refers to.Each ListItem component has a Link that updates the form’s model to that item, a label for that Link that’s derived from the value property, and the points property, which goes in the following column. The link is disabled if the current item has already been selected for the form. Once selected, the item can be updated in the form or the edit cancelled. This list and the form detailed earlier work together to provide functionality for adding, listing, and editing words stored in a database. Figure 2 shows this completed administration page in action.Figure 2. The Administer screen, with a word selected for editingPlaytime!The user has entered a number of words with relative point values. The user has avoided words that are anagrams of each other. The user deserves some playtime! As outlined earlier, the application should select a word at random — finally, some interesting work for the DAO! This works as shown in Listing 13. Listing 13. Selecting a random word in DictionaryDaoImplpublic Word getRandomWord() { return (Word) getHibernateTemplate().execute(new HibernateCallback() { public Object doInHibernate(Session session) throws HibernateException, SQLException { Integer count = (Integer) session.createCriteria(Word.class) .setProjection(Projections.count("id")) .uniqueResult(); Random rand = new Random(System.currentTimeMillis()); return session.createCriteria(Word.class) .setFirstResult((int) (rand.nextFloat() * count)) .setMaxResults(1) .uniqueResult(); } }); } The method used in Listing 13 to select a random word first gets a count of the known words, then selects a random number rand from 0 to count-1, and finally uses a combination of setFirstResult() and setMaxResults() to select and return the randth word. But that’s not the only pseudorandom thing needed around here: the word itself needs to be jumbled up. Listing 14 takes care of that.Listing 14. String randomization functions in the Word classpublic String scrambled() { return scramble(value, new Random(System.currentTimeMillis())); } private static String scramble(String str, Random rand) { if (str.length() == 1) return str; int idx = (int) (rand.nextFloat() * str.length()); return scramble(exclude(str, idx), rand) + str.charAt(idx); } private static String exclude(String str, int idx) { return idx == str.length() - 1 ? str.substring(0, idx) : str.substring(0, idx) + str.substring(idx+1); } Listing 14 shows several methods on Word. The scrambled() method returns a scrambled version of the value property using a recursive scramble() function and an exclude() utility function. These methods aren’t laudably efficient, but for the relatively short words found in human languages, they will do the job.Rules of the gameNow it’s time to plan exactly how the game-playing page will work. When the page renders for the first time, the application will need to select a word at random and scramble its characters. On the subsequent request, the app must remember two things: the Word instance that was selected, and the generated scrambled spelling. Because the Word object does not retain scrambled spellings, the two items will need to be stored separately. When the user guesses the word correctly, the points for that word are added to the tally and a new word is selected and scrambled. If the user is wrong, the game deducts one point from the tally and presents the same scrambled word for another guess. To keep things simple, this game has no ending: words can be repeated, and the score will continue to accumulate until the player leaves the page.I’m thinking of a word …To store the current word, the application uses another LoadableDetachableModel.Listing 15. The Play page with its detachable modelpublic class Play extends WebPage { @SpringBean private DictionaryDao dictionaryDao; ... class WordModel extends LoadableDetachableModel { private Integer id; public WordModel() { } public WordModel(Word word) { id = word.getId(); } @Override protected Object load() { if (id == null) { Word word = dictionaryDao.getRandomWord(); id = word.getId(); return word; } else return dictionaryDao.getWord(id); } protected void reset() { id = null; detach(); } @Override public Word getObject() { return (Word) super.getObject(); } } } Listing 15 shows how the page makes use of an inner subclass of LoadableDetachableModel. The WordModel class knows two states for loading itself: its id field is either null or not null. When first constructed, the model will load itself with a random word and retain the identifier so that, on the next request, the same word can be reloaded. reset() offers a way to clear this identifier so a new random word can be loaded, and getObject() is overridden to return a typed instance of the model’s object. You should be aware of a couple of things with this model. Firstly, it uses a Spring bean and is dependent on its containing class to provide it. As written, the model could not be a static or top-level class. Secondly, it contains logic that is specific to the game. It’s not just a detachable model for Word instances; it is a model that knows that it should supply a random word when not bound to a specific word. This model is explicitly bound to this page and would be difficult to reuse elsewhere.One technique for reusing models depending on Spring beans is to define them in a base class containing the annotated bean so that the model inner class can be used by any subclass. Another is to define an abstract class that calls itself to get the bean in an abstract method, so that it can easily be made concrete with an anonymous subclass. This points to the final technique, which is to simply use the loadable model and AbstractReadOnlyModel base classes liberally wherever you need a model that uses a Spring bean. This is fairly bulky in terms of braces and line breaks, but on the whole it’s a straightforward and tidy way to leverage Spring beans in Wicket applications.Listing 16. Play page’s fields, constructor, and form definitionprivate WordModel model; protected String scrambled; protected int score = 0; public Play() { setModel(model = new WordModel()); scrambled = model.getObject().scrambled(); add(new PlayForm("form")); add(new FeedbackPanel("feedback")); } protected class PlayForm extends Form { private TextField attempt; public PlayForm(String id) { super(id, new CompoundPropertyModel(Play.this)); add(new Label("scrambled")); add(attempt = new TextField("attempt", new Model())); add(new Label("score")); } @Override protected void onSubmit() { Word word = model.getObject(); if (word.getValue().equalsIgnoreCase((String)attempt.getModelObject())) { score += word.getPoints(); model.reset(); scrambled = model.getObject().scrambled(); attempt.setModelObject(null); info(getString("right", new WordModel(word))); } else { score -= 1; info(getString("wrong")); } } } Listing 16 shows that the current word’s scrambled permutation and the current score can be held as simple objects. They’re small enough, and aren’t stored anywhere else to be reloaded from. Note that the form is using the Play instance itself for its compound property model object, so that the scrambled and score labels are automatically filled by the corresponding fields. In onSubmit(), the submitted word is compared to the correct spelling, the score is adjusted, and an informational message is displayed for the user. The getString() method can take a model as a parameter to fill in named fields or properties. For that purpose, you need to construct a new model using the current word, as the old one has already been reset to load a new random word. Listing 17 shows the contents of the properties file for this page, and Figure 3 shows what the game looks like in action. Listing 17. Play.properties, containing user messagesright=Very good, you get ${points} points! wrong=Sorry, try again. Figure 3. A game in progressThat’s it for this application; it now has all the functionality that it needed to implement. Spring integrates with Wicket fairly transparently. If the loadable models seem like extra work, keep in mind that Wicket is not operating like a traditional single-request Web framework, in which you simply load objects, do something to them, use them to render the page, and discard. Wicket is instead simulating an environment that exists across requests, and the IModel interface is an essential part of it. Because of the model and the work put into custom detachable models, Wicket applications can refer to wrapped objects whether they were first located in the current request or one hundred requests ago, while the object identifier is the only thing that’s retained in memory. It’s an architectural give and take.Alternative paths to persistenceThe method presented thus far is a good one, and it hews fairly closely to conventional practices. Now you’ll take a look at less conventional ways to access and eventually update data. The point isn’t to advocate one strategy over another, but to bring out the advantages and disadvantages of each, and to understand the approaches even if they don’t fit every project.The remaining three examples all use the Databinder toolkit, a product of this author’s off-hour, free-software labors. While the choice to use Databinder for the remaining examples certainly isn’t impartial, it is also true that the landscape is sparse when it comes to bare-bones bridging libraries for Wicket persistence. The following discussion is intended to demonstrate a more direct approach to persistence, not so much the toolkit itself. Indeed, the Databinder toolkit, with its basis in easy and simple choices over conventional ones, would be easy enough to clone. But enough chatter: let’s take a look at some code! Example 2: Spring, Hibernate, and DatabinderThe next example, scramble-databinder-spring, also uses the Spring framework, but links to models and components of the Databinder toolkit. Its annotated Word class is exactly the same as the one in the first example, but its DAO classes and interfaces have had their getWord() and getWords() methods extracted. Those methods could have been left alone, but to bring the differences into relief, these examples eliminate idle code and show each application as if it were developed independently.The reason the two query methods are unnecessary is evident in Listing 18, where the Administer class’s default constructor adds a query model.Listing 18. Administer page’s query modelpublic Administer() { add(form = new EditForm("form")); HibernateListModel wordsModel = new HibernateListModel("from Word order by value"); The HibernateListModel is an implementation of Wicket’s IModel interface that wraps lists returned from Hibernate queries. It can work with HQL query parameters or Hibernate’s Criteria API; this query with no parameters is its simplest manifestation. But how is it able to access the Spring-managed Hibernate session without going through a Spring-managed DAO? It simply asks the Hibernate session factory for the current session — that is, the one that Spring opened at the beginning of the request. (The session factory itself is obtained via Databinder’s HibernateApplication interface, which ScrambleApp implements.) There’s no funny business: Spring tolerates this operation because the transaction is read-only. Databinder is free to fill its query models and Spring is still the gatekeeper for commits. Everyone is happy! Query reuse can be accomplished with subclasses or factories, but one-off queries that perform specific jobs are not discouraged in this arrangement. Using Hibernate directly avoids the chore of repeatedly expanding query interfaces and implementations in DAO as needs expand (for one entity type after another); this should be familiar to anyone who has worked in that standard arrangement.Listing 19. Adding a ModelSourceLink component}.add(new PropertyListView("words", wordsModel) { @Override protected void populateItem(final ListItem item) { item.add(new ModelSourceLink("link", form, item.getModel()) .add(new Label("value"))); item.add(new Label("points")); } })); Listing 19 moves beyond a Databinder model to a custom component. Inside a PropertyListView (which is otherwise unchanged from the previous example) is a ModelSourceLink component. It takes another component as its target, to which it assigns its own model object when clicked. The same task was performed by an anonymous Link subclass in the last example’s Listing 12; but with this component, there is no need to override isEnabled() and onClick().Listing 20. EditForm backed by a HibernateObjectModelpublic class EditForm extends Form { HibernateObjectModel model = new HibernateObjectModel(Word.class); The only other structural change in the Administer page is the use of a HibernateObjectModel, shown in Listing 20. This page can be backed by a query like the list model in Listing 18, but is usually bound by an identifier and always refers to zero or one entities. With this model, it is possible to swap out or nullify its object at any time, which is just how the ModelSourceLink works. Compare this with the previous example, where the model itself — the IModel subclass — was swapped. That technique is equally valid, but the flexibility of the HibernateObjectModel is useful in many situations and necessary in a few (for the model backing a DropDown component, for example).Lastly in Administer, the update operation in onSubmit() happens exactly as before, calling into a transaction service to make the changes to the object permanent. Listing 21. Play page’s constructor using HibernateObjectModelpublic Play() { setModel(new HibernateObjectModel(dictionaryDao.getRandomWord())); The Play page is much shorter in this variation, as the HibernateObjectModel in Listing 21 eliminates the need for a WordModel subclass. A random word is put into it on construction or after a successful guess; Databinder takes care of the loading and detaching.Example 3: Databinder with HibernateWhereas the last example still depended upon Spring for Hibernate session and transaction management, this one uses Databinder for that purpose. (These functions are in separate library modules, to avoid memory waste and namespace pollution.) The web.xml file for this version, therefore, specifies only the Wicket filter to handle incoming requests.Databinder is intentionally unambitious in its transaction management: it initiates and exposes the programmatic transactions intrinsic to Hibernate. A Hibernate session is opened only when required (because, indeed, some requests do not require the database) and only a single transaction is ever opened. It is the client application’s responsibility to commit that transaction; if uncommitted, it will be rolled back at the end of the request cycle.This full-bore configuration of Databinder is activated by linking to the databinder-app-hib module and extending DataApplication, as this version of ScrambleApp does. The ScrambleServer class isn’t needed here, as DataServer from the databinder-app module does the same thing.To demonstrate how different this arrangement may look, this scramble-databinder-hib example has none of the DAOs or services of the previous examples, nor the applicationContext.xml they rode in on. The model classes loaded entities and lists of entities directly, while the main purpose of DictionaryService was to imply a transactional operation. In this version of Administer, the transaction is committed explicitly, though it may not be immediately obvious where.Listing 22. EditForm extending DataFormpublic class EditForm extends DataForm { HibernateObjectModel model = new HibernateObjectModel(Word.class); public EditForm(String id) { ... add(new Button("cancel") { @Override public void onSubmit() { getPersistentObjectModel().unbind(); EditForm.this.modelChanged(); } }.setDefaultFormProcessing(false)); } @Override protected void onSubmit() { super.onSubmit(); getPersistentObjectModel().unbind(); } The DataForm class that is extended in Listing 22 is intended exclusively for single entities wrapped in a HibernateObjectModel. In its initial condition or after calling unbind, that model returns a newly constructed Word. The instance is retained in memory between requests, likely serialized, until it is stored to the database (if that ever actually happens). The DataForm class itself extends DataFormBase, and the most important thing to know about both of these classes is that they commit transactions in onSubmit(). That means that the transient object will be saved, or the existing entity stored, in the call to super.onSubmit().It is also possible to obtain the current Hibernate session and transaction and commit it directly, but these form classes handle common scenarios and serve as a reminder that destructive operations should be initiated by submitting a form (rather than following a link) whenever possible.Attentive readers may be wondering at this point whatever happened to the getRandomWord() function from the DictionaryDAO that is no longer. It could have gone into the Play page, or it could have gone into a new class. In this app, it has found a home in the Word class itself, which already had a few static utility functions. Word is otherwise unchanged (it includes the same old JPA annotations), but now Play is able to ask it to pull a random word from a given Hibernate session, as implied in Listing 23.Listing 23. The reset() method of in Playprotected void reset() { setModel(new HibernateObjectModel(Word.getRandom(Databinder.getHibernateSession()))); } Example 4: Databinder with ActiveObjectsHaving violated the bulk of presiding Hibernate mores (by, oddly enough, approaching its originally intended workflow), perhaps the only way I can further scandalize the reader is to present the same application with an ORM alternative that is comparatively embryonic: ActiveObjects, which at the time of this writing has reached the ripe version number of 0.8.2.This final example, scramable-databinder-ao, also uses Databinder, linking to a different set of modules. The models and components provided are similar to those for Hibernate, but adopted for the strengths of the underlying persistence technology. Some, like the DataApplication base class, have the same names, but they reside in different packages and — so long as you don’t put more than one set of persistence modules on the classpath — will not confound IDE autocompletion.Listing 24. Administer page’s constructor and query modelpublic Administer() { add(form = new EditForm("form")); IModel wordsModel = new EntityListModel(Word.class, Query.select().order("value")); The EntityListModel in Listing 24 is analogous to the HibernateListModel in Listing 18, with this one using ActiveObject’s query API rather than HQL. Otherwise, the page is nearly identical to its scramble-databinder-hib incarnation, as is the Play page. The biggest difference between the two applications is in the entity specification. As Listing 25 shows, the ActiveObjects entity is defined by an interface rather than a class definition.Listing 25. Word as an extension of the Entity interfacepublic interface Word extends Entity { String getValue(); void setValue(String value); Integer getPoints(); void setPoints(Integer points); public class Service { ... public static Word getRandom(EntityManager mgr) { try { Integer count = mgr.count(Word.class); if (count == 0) return null; Random rand = new Random(System.currentTimeMillis()); Query q = Query.select(); q.setOffset((int) (rand.nextFloat() * count)); q.setLimit(1); return mgr.find(Word.class,q)[0]; } catch (SQLException e) { throw new RuntimeException(e); } } } } ActiveObjects takes care of implementing the get and set operations. The inner Service class in Listing 25 is one way to stash code relating to the entity, including a random word selector adapted for ActiveObjects.As this application does little querying, there isn’t much else to see that is different from the previous Hibernate-based example. (Databinder’s aim is to have different underlying persistence technologies work alike at the client application level, except where there is a competitive difference to exploit.) If you want a complete picture of ActiveObjects and how it compares to other object-relational mappers, start digging into scramble-databinder-ao and, ideally, expanding on it.Committing the transactionAll this should be plenty to get you up and running with a data-driven Wicket application in one of the four directions detailed in these examples. You could of course also go in an entirely different direction, whatever suits your coding style and application requirements — there are, as these four examples are intended to show, many different ways to get from here to there.So ends this series on Wicket programming, where I’ve covered stateful versus stateless programming, illustrated the easy and effective reuse provided by templated components, and finally surveyed data persistence strategies. Wicket is constantly evolving — Web frameworks hardly have a choice — and there will always be something new to learn. But if you can work through the code presented in these tutorials, you’ll be well on your way to swimming confidently in that current.Nathan Hamblen is a career software programmer who codes primarily in Java. In his spare, time he works on the Databinder toolkit for Wicket and writes Coderspiel, a programming Weblog. Open SourceSoftware DevelopmentWeb DevelopmentJavaLibraries and FrameworksData ManagementTechnology Industry