The release is as early as the version implies, but here it is. Swit 0.9.0 is a small library providing various stuff for Wicket: a button generation engine, with a bunch of skins; a border generator for html/css, and a layout manager for liquid [1-3]-column layouts.
The fun part implementing it was the button generator, not unlike the various one available around the web, except that here it's primarily meant to be used in java apps to dynamically generate some graphics stuff that are seriously boring to draw manually with the gimp or photoshop.

Swit Homepage: http://swit.kornr.net
Hey, I hope Quentin Tarantino won't steal my title and make a movie out of it! Anyway, the Wicket's implementation of Ajax is so good that I just stopped using anything else to make my web client communicate with my server. There's this one thing however, that prevents the fine scaling of Wicket sites, that's namely memory consumption. Wicket by itself does not consume that much memory though, but if you want to use the sweet Ajax components, you're stuck with stateful pages. And using stateful pages + lots of visitors usually implies memory issues: it's not just your own data contained in the WebSession object that is stored in memory, but also the current page hosting the ajax components, and the n last pages visited. If your pages are big, the session are big, that's the point.
Add to that a specific need to make the session last longer than usual, to allow users to stop using the site, then going back after a long period of time, and still have their session available, and you'd rapidly be waiting your users with fear.
So, to conciliate long sessions, limited-memory servers, and stateful wicket, the best possible solution, besides asking your users not to tell their friends, is to apply a Jdbc Jutsu to the session management of your servlet container. At least, that's how I solve my issue.
Tomcat provides a JDBCStore for its PersistentManager class (which is responsible for managing the sessions): this java jutsu just saved my server's memory from going out of control. Unlike the default org.apache.catalina.session.StandardManager that stores everything in your precious heap memory, the PersistentManager provides a lot of flexibility regarding the session storage. For instance, a typical configuration would keep the sessions in-memory, but passivate them into a database after a few minutes of inactivity (instead of consuming all this good memory for idle or disconnected users until their session expires).
The Tomcat documentation lacks a few examples, so here's mine: I wanted unlimited sessions, and passivate idle sessions in the JDBC database after 120 seconds of inactivity (lines to customize are yellow).
<Host ...... <Context path="/MYPATH" docBase="MY-APPLICATION.WAR"> <Manager className="org.apache.catalina.session.PersistentManager" saveOnRestart="true" maxIdleSwap="120" minIdleSwap="-1" maxActiveSessions="-1" maxIdleBackup="-1"> <Store className="org.apache.catalina.session.JDBCStore" driverName="com.mysql.jdbc.Driver" connectionURL="jdbc:mysql://localhost/MYAPP" connectionName="DATABASE-USERNAME" connectionPassword="DATABASE-PASSWORD" sessionTable="tomcat_sessions" sessionIdCol="session_id" sessionValidCol="valid_session" sessionMaxInactiveCol="max_inactive" sessionLastAccessedCol="last_access" sessionAppCol="app_name" sessionDataCol="session_data" checkInterval="60" /> </Manager> </Context> </Host>
Then in the database and schema specified in the configuration above, just add the following table:
(from the Tomcat Manual at http://tomcat.apache.org/tomcat-6.0-doc/config/manager.html):
create table tomcat_sessions ( session_id varchar(100) not null primary key, valid_session char(1) not null, max_inactive int not null, last_access bigint not null, app_name varchar(255), session_data mediumblob, KEY kapp_name(app_name) );
Well, that's it, no more wicket-related memory issues.
Update after Thyzz comment (see below)
Wicket can actually use either its original HttpSessionStore (that stores everything in the servlet http session), or its new SecondLevelCacheSessionStore that stores the PageMap on disk. Here is below some metrics I made that compare the memory usage with and without the tomcat's JDBCStore:
To get those metrics, I used a web application that makes a moderate memory usage, and changed it so that the SessionStore can be either the HttpSessionStore or the SecondLevelCacheSessionStore. Additionnally, I added a new byte[1024*500] allocation into the session object, so that the memory consumption be artificially higher (for the purpose of testing in this specific configuration, applications with a really low memory footprint of their session behave totally differently, and are unlikely to have any memory-related issue). Then I ran a script on another computer that would make a loop over an http request for the frontpage (and all the resources of that page).
As a result, both HttpSessionStore and SecondLevelCacheSessionStore end up with an OutOfMemoryException. The memory usage is slightly better when using the SecondLevelCacheSessionStore, but I did not test the http latency; a real benchmark would require to compare both memory and speed, but at least the figures shows that the memory issue is prevented.
Imagine you're developping a web site that manages subdomains for your users, in such a way that all your users automatically get a http://user1.example.com or http://user2.example.com subdomain.
In order to keep the normal session available on all the subdomains, one just needs to make the session cookie associated to the smallest common domain, in this exemple, the example.com domain, so that www.example.com share the same cookie with all the other http://[whatever].example.com subdomains. Piece of cake: cookie.setDomain("example.com"), right? Almost. Just, not in a servlet container. Because, you can't.
It's amazing, but in a servlet container, you just can't tell which domain the JSESSIONID cookie is associated to. Unfortunately, Tomcat provides no container-specific way to modify this behaviour.
So, here's a simple patch that fixes the issue. It's not suited for all purpose, it just removes any www prefix that appears in the hostname, and use it as cookie domain. If there's no www prefix, the normal behaviour applies.
In apache-tomcat-6.0.18-src/java/org/apache/catalina/connector/Request.java, find the configureSessionCookie() method, and replace it with this one:
/**
* Configures the given JSESSIONID cookie.
*
* @param cookie The JSESSIONID cookie to be configured
*/
protected void configureSessionCookie(Cookie cookie) {
cookie.setMaxAge(-1);
String contextPath = null;
if (!connector.getEmptySessionPath() && (getContext() != null)) {
contextPath = getContext().getEncodedPath();
}
if ((contextPath != null) && (contextPath.length() > 0)) {
cookie.setPath(contextPath);
} else {
cookie.setPath("/");
}
if (isSecure()) {
cookie.setSecure(true);
}
// CHANGES BELOW
String domain = this.getServerName();
if (domain != null)
{
if (domain.toLowerCase().startsWith("www."))
domain = domain.substring(4);
cookie.setDomain(domain);
}
}
Now compile (with a JDK 1.5... as of Tomcat 6.0.18 you can't compile it with JDK1.6 because of a DBCP issue), and use this distribution. Or just grab the catalina.jar.
Not that I'm much into Windows development, but I've personnally always preferred using the Microsoft CHM format rather than plain HTML. It's compact, it's fast to open, and pretty fast to search for a specific class or method.
I took some time this morning to generate the Wicket javadocs WITHOUT the examples packages (I can't see why they are included in the default javadocs, it's just annoying to have them mixed with the Wicket API), and the corresponding CHM file using the jd2chm javadocs-to-chm converter. This program works amazingly well.
For those interested, I generated two flavours of the wicket-javadocs:
The linksource option provides a link between a method and its java source code, which makes it a breeze to check what the code does under the water (and that's utterly useful when the documentation of some method is not available).
Other adjustments I've made to the javadocs:
A quick post just to share a country list model I did a few days ago. It's no big deal, but I think it's worth sharing to avoid my fellow wicketeers the trouble to do it.
So, it's a standard Wicket Model that uses a standard ISO-3166-1 (2-char long) code to store the country name. The idea is to keep simplicity in my domain object, so the country property is just a String that stores the ISO3166 code. As it's not easily possible to use this ISO3166 code directly in a Wicket DropDownChoice (I want to display a localized country full name, but store the ISO-3166 short code), I had to create a Country object, which is internally used. Note however that the CountryList class provides an adaptor that converts this internally-used Country object into the property string of my domain POJO, so it's transparent.

The country list is localized, and comes from the ISO files I found at http://www.iso.org/iso/country_codes/iso_3166_code_lists.htm. Unfortunately, the ISO organization only provides english and french locales from the country name, so if you want more, you'll have to translate them yourselves and add the resource file to the jar.
Actually, using it is pretty straightforward, so I'll just show how to use it in an example.
The HTML is, as expected, the standard:
<select wicket:id="country"> <option value="US">United States</option> <option value="FR">France</option> </select>
The java code instanciates a country list, and uses it as a model for the DropDownChoice element (although it can be used with any component that uses an IModel<List> ).
CountryList countrylist = new CountryList(); // (1)
DropDownChoice country = new DropDownChoice("country",
countrylist.getAdaptor(new PropertyModel(this.obj, "country")), // (2)
countrylist, // (3)
countrylist.getRenderer()); // (4)
form.add(country);
in (1), we instantiate the CountryList class using the default constructor, which uses the Wicket Session locale. It is also possible to pass a Locale object to the constructor.
in (2), we use the adaptor provided by the CountryList class: this is a very basic IModel<Country> that takes a IModel<String> as its own model to set and get the correct Country element. This allows our POJO to just use a String property, instead of dealing with an annoying Country object.
in (3), this is actually the list of countries itself
in (4), this is the ChoiceRenderer that displays the full country names, instead of the short code.
Recent comments