Monday, June 14, 2010

Bookmarkable URLs with JSF2



Parameters are now defined in the page itself so a request like:

http://localhost:8080/contactInfo.jsf?contactId=manu%40ffff.se

would have its parameters defined as

<f:metadata>
        <f:viewParam name="contactId" value="#{contactController.email}"/>
    </f:metadata>

If the parameter value isn't specified in the request then the value will be null, so make sure the property receiving the parameter value isn't a primitive (i.e. it must be nullable).

You will also need an action to load data into the view. Any component can have pre-render events attached to it. For example, a form:

<h:form id="contactInfoForm">
            <f:event type="preRenderComponent" listener="#{contactController.loadContact}"/>

All you need to do is declare the parameters to be bound and the action on the page/view you wish to make bookmarkable.

Sunday, June 6, 2010

JSF2 on Google App Engine

I updated my JSF2 on Google GAE demo (a simple address book). I added more Primefaces stuff, authentication (using Google accounts), integration with Google Maps, persistence with Objectify, and a some servlets to be able to upload and serve images using the image service (the upload component in Primefaces does not yet work on GAE). There's a blobstore service that makes image uploads much easier but it's only available when billing is enabled on your appengine account.

The next step could be to add conversation support for this (using WELD). 

The code is here: https://github.com/manuel-palacio/JSF2-Primefaces-GAE-Sample-Project

The application also demonstrates how to use @Controller and @Inject together with Spring.

Some thoughts

I started prototyping with Twig but I didn't find it intuitive enough. I switched to Objectify and things started working right away :)

Objectify does not provide "managed" relationships in the way that JDO or JPA does. This means that you have to write more code in order to manage them (you have to explicitly load the relationships unless you are using GWT?)

When you create relationships to other entities in your system, the type of the entity relationship should be Key.



@Entity
public class Contact {

    @Id
    String email;

    String name;

    Key<ContactImage> contactImage;

if (imageId != null) {
            contact.setContactImage(new Key<ContactImage>(ContactImage.class, imageId));

        }


This is a simple one to one relationship. If I wanted the contact to have a list of images I'd write:

class Contact{
    @Id Long id;
    String name;
}

class ContactImage{
    @Id Long id;
    Key<Contact> contact;
    String caption;
    String blobStoreKey;

} 

And query like:

Query<ContactImage> query = createQuery(ContactImage.class).filter("contact", contactKey);
List<ContactImage> fetched = ofy.prepare(query).asList(); 

In GAE, this is more efficient than defining a collection of ContactImage in the Contact itself although it may look counter-intuitive.