Sunday, May 29, 2011

Playing with Wicket 1.5

This weekend I played with the new wicket 1.5 and saw some improvements that I'd like to share. These improvements are about page mounting and page parameter translation, it turns out that we don't choose anymore how parameters will be passed to the page when we mount the page but just simply mount the page and then you can read parameters in a new way.

Mounting a Page.
To mount a page we just need to (as always) call the mount method on our application class, but we can note that the wicket folks have removed (not even deprecated) the mount methods that take IRequestTargetUrlCodingStrategy as a parameter and instead created a simple mountPage method.

Here is an example of how pages will be mounted from now on:
   @Override  
protected void init() {
super.init();
mountPage("/home", HomePage.class);
}

Reading the Parameters.
Some of you may ask, if the URL coding strategies have been removed, now how can we read the page parameters?
The answer is simple! From the PageParameters object we get on the page constructor, this class has been rebuilt and moved into another package and no longer extends ValueMap, this change is HUGE and it will impact lots of my code for sure, but anyway, I think this change is for good since now I can query lots of things to read the parameters and something really ugly is now removed from our lives: We now can read indexed parameters with numbers and not with string-numbers. We also have the chance to read the parameters converted as different types in a much more elegant way.

Here is an example of how parameters can be read:
 public class HomePage extends WebPage {  
private static final long serialVersionUID = 1L;

public HomePage(PageParameters params) {

//build a list of the page parameters:
ArrayList<String> stringList = new ArrayList<String>();

int indexed = params.getIndexedCount();

//go through the indexed page parameters
for (int i = 0; i < indexed; i++) {
stringList.add(i + ": " + params.get(i).toString());
}

//go through the named page parameters
for (String key : params.getNamedKeys()) {
stringList.add(key + ": " + params.get(key).toString());
}
...
}
}

Servlet 3 Integration.
Wicket 1.5 wont have integration with servlet 3 but I've managed to use servlet3-style configuration for the wicket filter, the way it's done is less than ugly and I hope they add servlet 3 support in the future at least in the form of a separate project.

Here's how I did it:
 package com.juancavallotti.wicket15;  

import javax.servlet.annotation.WebInitParam;
import javax.servlet.annotation.WebFilter;
import org.apache.wicket.protocol.http.WicketFilter;

/**
* This is a dummy subclass of filter to allow servlet 3.0 style config.
* @author juancavallotti
*/
@WebFilter(urlPatterns = "/*", initParams = {
@WebInitParam(name = "applicationClassName",
value = "com.juancavallotti.wicket15.DemoWicketApplication"),
@WebInitParam(name = "filterMappingUrlPattern",
value = "/*")
})
public class MyWicketFilter extends WicketFilter {
}



Wednesday, May 18, 2011

Setting up maven to use local JAR Libraries

Since the very first time I've started using maven (and as a previous ANT user) I wondered how I could achieve the only thing that ANT does great: Add manually my own libraries.

The answer is easy: install them into the local repository. But that's not so easy! If someone new joined the project, he would have to install the artifact also in his local repository and this is an extra step anyone could easily forget!

Another thing you could do is install nexus in some tomcat, and after a little bit of configuration install the jar and add the server url as a repository on my project, but... Isn't that a little bit of overkill for one or two JARS?

All the previous analysis already contains the solution: we need to do both: Add a repository, but the repository should be local... to the project and manually install the files there (and probably check them in into a repository).

And here is how you do It: First of all you need to know that you can add a file:// url as the url of the repository, so we can add something like this:
   <repositories> 
<repository>
<id>project</id>
<name>Project Maven Repository</name>
<layout>default</layout>
<url>file://${project.basedir}/lib/</url>
</repository>
</repositories>
And we take advantage of the variable referencing the project's directory: project.basedir.

So now we only need to copy artifacts installed manually from our local repository to our project repository (or better install them directly into the project repository). And that's it your project build will still be flawless and you won't have to worry about putting nexus to work or remind your new co-workers to install the artifact.

Sunday, May 15, 2011

Wicket 1.4 URL Character Encoding Problems

While developing web apps using wicket I've faced a problem with character encoding on URLs, for example, if you are using default settings and deploying your application into Tomcat, you'll be able to reproduce the issue quite simply:
  • Create a page that prints somewhere a parameter read from the url (on standard query string url coding strategy).
  • Call the page directly from the browser using some special char on the parameter value.
  • Check that the special char has been decoded wrongly and you're scratching your head ;) on how to solve this out.
So my first thought was "this for sure is a wicket issue!" but soon learned the problem is much deeper than that. It turns out that most browsers don't tell to the server the encoding in which they're making the request so it's up to the server to guess this.

Modern browsers can send (and they actually do) make the requests in UTF-8 but most of the containers assume (because it's what you can read in the HTTP protocol RFC) that the encoding is by default ISO-8859-1. From the HTTP protocol definition:
The "charset" parameter is used with some media types to define the character set (section 3.4) of the data. When no explicit charset parameter is provided by the sender, media subtypes of the "text" type are defined to have a default charset value of "ISO-8859-1" when received via HTTP.
Ok, now, wicket has a lot of things you can set up on the web application, one of all is the request cycle character encoding, and it defaults to UTF-8, so this leads us to the first solution to our problem.

The first solution: Change the request cycle character encoding.

This can be done in a very simple way, with just a line of code:
 getRequestCycleSettings().setResponseRequestEncoding("ISO-8859-1");
By doing this, you tell wicket to treat requests and responses as they were in ISO-8859-1 and special characters on the URL get url-encoded and everything works just fine. I have though some suspicions that some strings with special characters get broken but I really can't confirm that (because it could be they get broken for some other reason).

Now, I don't know you but I really don't feel comfortable with having my request and response on ISO-8859-1, specially because I like UTF-8. So since the problem is that the container assumes the requests are in ISO-8859-1 why not tell the container to assume the requests will be by default on UTF-8?

The second solution: Let the container assume the requests are in UTF-8.

To make this solution work we'll need to have access to the production server's configuration, and it's quite easy: tomcat's http connector has a property called URIEncoding, we just need to set that up and all set:
 <Connector port="8080" protocol="HTTP/1.1"  
connectionTimeout="20000"
redirectPort="8443" URIEncoding="UTF-8" />
This solution is quite pretty and works like a charm as well, and you can stick with your beloved UTF-8 charset.

I have a third solution but isn't pretty.

The third solution: Write your own QueryStringURLCodingStrategy

This solution is what I've fell down when I first met the issue because I thought it was a wicket issue and was exactly that: subclassing QueryStringURLCodingStrategy and write my own implementation of the decode parameters method and decode the parameters yourself!. At the time it worked, but now I can see it just have a lot of side problems so I think you want to stay away from this solution.

Other solutions that didn't work for me.

While trying to solve this problem I also tried other solutions without luck: some tried writing a servlet filter to set the encoding of the request to UTF-8 including the filters provided by the spring framework and apache tomcat. I also wrote my own implementation of a filter to change the encoding with no luck (the problem didn't go away). But also I think it's worth a try.

Friday, May 13, 2011

Using JAX-B to parse XML files without DTD or XSD

XML parsing is one common task for any developer, specially in Java. For any beginner looking how to do this it's very easy to find on internet lots of articles showing how to parse XML using a DOM parser or worse, a SAX parser!

Both DOM and SAX parsers are very powerful and general tools but even to parse simple things you need to write tons of code. For simple XML parsing (and writing) Java has the JAX-B API. JAX-B stands for Java Architecture for Xml Binding.

Even though there are tons of JAX-B tutorials on the internet, most of them start by building a XSD file and generating with the IDE, a maven plugin, (or another tool), the matching object model for the XML structure, and automatically get the binding of the classes by adding some Java annotations.

There are some situations where we don't want to do this:
  • We don't have the DTD or XSD available.
  • The DTD or XSD is outdated.
  • We really don't want to write a DTD or XSD for a simple domain-specific file that we won't re-use!
Using JAX-B is pretty straightforward but it has some concepts and terms we need to know first:
  • Marshalling: Is the process of converting a Java object into an XML representation.
  • Unmarshalling: Is the process of converting an XML file into a Java object.
For that matter, Java provides us with two interfaces and one factory class:
  • Marshaller
  • Unmarshaller
  • JAXBContext
And also it provides a huge set of annotations to allow us to bind a data model with an XML representation. So let's get started!

The following snippet show's the XML file we will be parsing:

<?xml version="1.0" encoding="UTF-8"?>
<movie-backup-index>
    <file-info lastBackup='2011-04-02' totalMovies='4'/>
    <media-list>
        <disc label="disc1">
            <movie>The Hulk</movie>
            <movie>Thor</movie>
        </disc>
        <disc label="disc1">
            <movie>Iron Man</movie>
            <movie>Captain America</movie>
        </disc>
    </media-list>
</movie-backup-index>

So the first thing we need is a class that will contain this structure, let's call it MovieIndex, and we'll add a few annotations to it. Since we want to work with JavaBeans we'll tell JAX-B to use the getters and setters of the class:
@XmlRootElement(name="movie-backup-index")
@XmlAccessorType(XmlAccessType.PROPERTY)
public class MovieIndex implements Serializable {

}

Now we have our first step, next we need to model the file information tag. We can do several things like adding an internal class or creating a new public class (or other ways of defining a class) but since this is a potential API ;) I'll create another public class: MovieIndex Info, and will add some annotations to it:

@XmlRootElement(name="file-info")
@XmlAccessorType(XmlAccessType.PROPERTY)
public class MovieIndexInformation implements Serializable {
    private Date lastBackup;
    private Integer totalMovies;
    public void setLastBackup(Date lastBackup) {
        this.lastBackup = lastBackup;
    }
    public void setTotalMovies(Integer totalMovies) {
        this.totalMovies = totalMovies;
    }
    @XmlAttribute
    public Date getLastBackup() {
        return lastBackup;
    }
    @XmlAttribute
    public Integer getTotalMovies() {
        return totalMovies;
    }
}


With the XmlAttribute we instruct JAX-B to read the data as an attribute instead of a child element. Now we need to create a model for our backup media and add some annotations:

@XmlRootElement(name="disc")
@XmlAccessorType(XmlAccessType.PROPERTY)
public class Media implements Serializable {
    private String label;
    private List<String> movies;
    @XmlAttribute
    public String getLabel() {
        return label;
    }
    @XmlElement(name="movie")
    public List<String> getMovies() {
        return movies;
    }
    public void setLabel(String label) {
        this.label = label;
    }
    public void setMovies(List<String> movies) {
        this.movies = movies;
    }
}


Ok, now we have all we need so we can add all the remaining elements to our MovieIndex class:

@XmlRootElement(name="movie-backup-index")
@XmlAccessorType(XmlAccessType.PROPERTY)
public class MovieIndex implements Serializable {
    private MovieIndexInformation fileInfo;
    private List<Media> media;
    
    @XmlElement(name="file-info")
    public MovieIndexInformation getFileInfo() {
        return fileInfo;
    }
    
    @XmlElement(name="disc")
    @XmlElementWrapper(name="media-list")
    public List<Media> getMedia() {
        return media;
    }
    public void setFileInfo(MovieIndexInformation fileInfo) {
        this.fileInfo = fileInfo;
    }
    public void setMedia(List<Media> media) {
        this.media = media;
    }
}

We've used the XmlElementWrapper annotation because we have an extra element that wraps our list of discs, so to avoid creating a new type with only a list, we have this annotation.

So we're ready to parse!! In order to quickly test, I've added the toString methods on the model objects, (I won't show it here because it's Netbeans-generated.

So now we need to add the boilerplate code to bootstrap the JAXBContext and to un-marshall our file:

public class JAXBDemoParse {
    /**
    * In this Main method we will be parsing an XML file into a Java Object using
    * the JAXB library included in the JDK.
    * @param args
    */
    public static void main(String[] args) throws Exception {
        //bootstrap the context.
        JAXBContext context = JAXBContext.newInstance(MovieIndex.class);
        //create an unmarshaller.
        Unmarshaller unmarshaller = context.createUnmarshaller();
        //parse the xml file!
        InputStream is = JAXBDemoParse.class.getResourceAsStream("demoXML.xml");
        MovieIndex index = (MovieIndex) unmarshaller.unmarshal(is);
        System.out.println(index);
    }
}

So finally!! We ended up loading all the data from the XML file into the object in only 3 lines of code!! and some annotations. Here is the program output, please notice how the dates on the xml attribute got parsed the right way, JAXB handled all the data conversion.

 MovieIndex{
  fileInfo=MovieIndexInformation{
      lastBackup=Sat Apr 02 00:00:00 GMT-03:00 2011,
      totalMovies=4},
  media=[
      Media{
          label=disc1,
          movies=[The Hulk, Thor]},
      Media{
          label=disc1,
          movies=[Iron Man, Captain America]
      }]
}

I've added some enters and tabs to the output so it can be better read by humans.

So that's all for now. One final note, if you would like to marshall the object to an XML file you ask the JAXBContext for a marshaller and just call the method with the object and an output stream.

Saturday, May 7, 2011

Creating Custom Ajax Behavior on Wicket 1.4

Today we're creating a calendar picker behavior to add to some wicket components. Sample code for this post can be downloaded here.

In order to run the sample code you need a servlet 3 container like Apache Tomcat 7, lets get started.

Wicket Application Configuration.

Since servlet 3, the web.xml file isn't needed anymore. So how we configure the wicket filter? we could create a web.xml file and define it there but since we want to do things in the new way, we can define a subclass of the wicket filter and add the annotation defined on servlet 3 spec.

 @WebFilter(urlPatterns = "/*", initParams=@WebInitParam(name="applicationClassName", value="com.juancavallotti.wicketcustomcomponents.DemoApplication"))
public class CustomWicketFilter extends WicketFilter {
}

Wicket Application and Home Page.

The wicket application and home page are pretty standard so I will not put them here, you can take a look at them directly on the sample code package.

JQuery and JQueryUI.

For this example we've used JQueryUI. As you should know, you can add resources on the java packages, so that's what we did, there are some more elegant ways to do this, specially if you're building your own component library, but for this example we've added the files from the JQueryUI bundle on the classpath and within our home page we loaded the necessary resources:
 add(new StyleSheetReference("jqueryuitheme", HomePage.class, "jquery-ui-1.8.12.custom.css"));
add(new JavaScriptReference("jqueryjs", HomePage.class, "jquery-1.5.1.min.js"));
add(new JavaScriptReference("jqueryuijs", HomePage.class, "jquery-ui-1.8.12.custom.min.js"));
We have previously copied those files into /src/main/resources/{path to package} and wicket resource system will take care to set the right url for us on the html file.

At this point we have what we need to start creating a fun ajax behavior to enable text fields or panels to have a date picker.

Coding a custom AJAX Behavior

The common way to bootstrap JQueryUI components (and generally most of JQuery components) is to call a method with the name of the component on an HTML element with some id, like the following:
 $(document).ready(function() {
$("#${componentId}").datepicker(${options});
});
So we'll start with that, and save it into a file called calendarTemplate.js on the resources package in which we'll create our custom behavior, in my case: /src/main/resources/com/juancavallotti/components.

Now we create one class called JqueryUIDatePickerBehavior, that class will extend AbstractDefaultAjaxBehavior, and it looks like the following:
 package com.juancavallotti.components;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import org.apache.wicket.Component;
import org.apache.wicket.ajax.AbstractDefaultAjaxBehavior;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.model.Model;
import org.apache.wicket.util.template.TextTemplateHeaderContributor;
/**
*
* @author juancavallotti
*/
public class JqueryUIDatePickerBehavior extends AbstractDefaultAjaxBehavior {
private JqueryUIDatePickerSettings settings;
public JqueryUIDatePickerBehavior() {
}
public JqueryUIDatePickerBehavior(JqueryUIDatePickerSettings settings) {
this.settings = settings;
}
@Override
public void onConfigure(Component component) {
component.setOutputMarkupId(true);
String id = component.getMarkupId(true);
Map<String, Object> params = new HashMap<String, Object>();
params.put("componentId", id);
params.put("options", buildSettings());
component.add(TextTemplateHeaderContributor.forJavaScript(JqueryUIDatePickerBehavior.class, "calendarTemplate.js", new Model((Serializable) params)));
}
@Override
protected void respond(AjaxRequestTarget target) {
}
private String buildSettings() {
if (settings == null) {
return "";
}
return settings.toString();
}
}
We override the onConfigure method and instruct the target component for this behavior to output the markup id, then we get that id and populate a HashMap with it (and some configuration that we'll soon explain). Then we call TextTemplateHeaderContributor class and we load our javascript template. The resulting code will be placed on the header section of the page with it's parameters replaced from the values on the hash map.

Finally, we know that the DatePicker component has a lot of options (you can check them out on the documentation page), so It's a good idea to be able to set those options within java code, so we create a class named JqueryUIDatePickerSettings and add some of those options. Please note that this is only example code intended to give you some understanding of how this works, a production implementation should be far more robust than this one.
 public class JqueryUIDatePickerSettings {
private String altField;
private String buttonText;
private String dateFormat;
public JqueryUIDatePickerSettings setTargetComponent(Component component) {
String markupId = component.getMarkupId(true);
altField = "#" + markupId;
return this;
}
public String getButtonText() {
return buttonText;
}
public JqueryUIDatePickerSettings setButtonText(String buttonText) {
this.buttonText = buttonText;
return this;
}
public String getDateFormat() {
return dateFormat;
}
public JqueryUIDatePickerSettings setDateFormat(String strDateFormat) {
this.dateFormat = strDateFormat;
return this;
}
@Override
public String toString() {
return "{"
+ "altField: '" + altField + "',"
+ "buttonText: '" + buttonText + "' , showOn: 'button',"
+ "dateFormat: '"+dateFormat + "'"
+ "}";
}
}
So now we have all the puzzle pieces in place but one: How we add the date picker behavior to some component? Very easy!

Let's take a look at our full home page code and HTML:
 public class HomePage extends WebPage {

private TextField<Date> date;

public HomePage() {

//BOOTSTRAP THE SETTINGS AND A TARGET COMPONENT
date = new TextField("datePickerTarget");
date.setOutputMarkupId(true);
JqueryUIDatePickerSettings settings = new JqueryUIDatePickerSettings();
settings.setTargetComponent(date).setButtonText("Pick Date!").setDateFormat("dd/mm/y");


add(new StyleSheetReference("jqueryuitheme", HomePage.class, "jquery-ui-1.8.12.custom.css"));
add(new JavaScriptReference("jqueryjs", HomePage.class, "jquery-1.5.1.min.js"));
add(new JavaScriptReference("jqueryuijs", HomePage.class, "jquery-ui-1.8.12.custom.min.js"));

//EXAMPLE USE OF THE BEHAVIOR
add(new TextField("miDatePicker").add(new JqueryUIDatePickerBehavior(settings)));
add(new WebMarkupContainer("inlineCalendar").add(new JqueryUIDatePickerBehavior()));
add(date);
}
}
And this is the HTML
   <body>
<h1>jCavallotti JQuery UI custom Components</h1>
<div wicket:id="inlineCalendar"></div>
<div><input type="text" wicket:id="miDatePicker" /></div>
<div><input type="text" wicket:id="datePickerTarget" /></div>
</body>
So we can finally see how things are working:


Conclusion
Building a component library in wicket is really easy and powerful, but we should not forget that there's already a lot of stuff out there ready for us to just use it, specially on wicket stuff maven repository. Nevertheless if what we find doesn't fit our needs we can still build a powerful component library.