Camino 1.1: My Mac OS X Web Browser of Choice

Since I got my Mac Book Pro last November, I have been extremely disappointed with the stability of FireFox on Intel Macs. The PPC version is quite stable and gives Safari a run for the money. On Intel however, it feels like an alpha-quality product. I have been using Safari, which gets the job done, but I had really missed some of the great features that FireFox provided:

  • HTML Editing capabilities (the WordPress HTML editor works in FireFox, not Safari)
  • Built-in spell checker
  • Site-level pop-up blocking
  • Cool extensions like FireBug

For one reason or another, I decided to take another look at Camino. Camino was started by Mike Pinkerton and it is built on Mozilla’s Gecko, which is also what powers FireFox. The big difference between Camino and FireFox is that Camino was designed to be a Mac-only browser that uses the Cocoa framework for its UI rather than XUL. What you end up with a browser that has a lot of the niceties of Safari, with most of the capabilities of FireFox. Some things you don’t get is FireFox extensions & themes, but I can live with that. As far as stability goes, I’m using one of the nightly builds and haven’t had a crash yet.

Camino 1.1: My Mac OS X Web Browser of Choice

JBoss Seam to the rescue!

One area that had annoyed me about RESTEasy is dealing with JAXB annotated Entity Beans that get returned from a Stateless Session Bean. Once the SLSB returns the entity, the transaction is committed but the object graph that will be needed for the XML representation may not be fully initialized, thus resulting in a LazyInitializationException from Hibernate. Since the JAXB marshaling code lives on the web tier, this is generally a problem when using Hibernate + an SLSB.

RESTEasy invokes an SLSB via the EJBResourceInvoker. As a work around, I had been starting a UserTransaction around the invoke() method. While this works, it’s not an ideal situation. Thankfully JBoss Seam offers an much more elegant solution to this issue. To get around this, it’s simply a matter of doing the following:

  • Set up the SeamListener & SeamServletFilter in your web.xml
  • Name a persistence context to Seam’s components.xml
  • In your SLSB, inject the persistence context using @In rather than @PersistenceContext

And just like that, Seam handles all of the Hibernate magic and RESTEasy works with no additional code. In fact, I have removed the UserTransaction code block in the EJBResourceInvoker as a result. A special thanks to Gavin King for answering my questions on the JBoss forums to help get this working right.

JBoss Seam to the rescue!

Automagically RESTful Entity Beans

So far, I have gotten some very useful feedback for RESTEasy. One excellent set of questions came from the rest-discuss group on Yahoo!:

How do you map different parts of the namespace to the same component? What, for instance, do GETs to the following resources result in:

  http://localhost/resteasy/contacts/12345/something
  http://localhost/resteasy/contacts/12345?myparam=whatever

The short answer is that you could map the URI to the following Java method:

@HttpMethod(GET)
public Something getSomethingFromContact(URIParam("contactId") Long id);

This would return just the “something” attribute for the contact 12345.

While this approach works just fine, it could become cumbersome if the Contact contians additional members which represent complex entities. The Contact class already contains multiple entities:

  • a collection of Addresses
  • a collection of EmailAddresses
  • a collection of PhoneNumbers
  • a Company if the Contact is a Person instance and the Person is employed

This list could easily expand depending on what your needs are. But you can see that this would add a lot of extra code to your service.

I started thinking there there might be a better way to this without the need to even write a service class. In the service examples I have been working on are effectively DAOs that return Java objects. The code is so generic and repetative accross most services, that it might be possible to just expose the entity as a service.

To achive this, I have started playing around with the idea of a @RestfulEntity annotatation. At this point, it is just a thought an no code has been written yet, but I thought it would be a good idea to share what I’m thinking. When RESTEasy processes this annotation, it will create a DAO-style service that will accept GET,POST,PUT, and DELETE. An Entity Bean could be annoated as follows:

@Entity
@RestfulEntity(baseURI="/contacts",
               entityURI="/contacts/{contactId}",
               readOnly=false, 
               persistenceStrategy=PersistenceStrategy.JAXB_HIBERNATE,
               excludeSearchProperties={"id","isActive"},
               ignoreCase=true)
@MediaTypes(
      types={
          @MediaType("application/xml"),
          @MediaType("application/contact+xml")
       })
public class Contact implements Auditable {

    @Id
    @Column(name = "contact_id", nullable = false)
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @XmlAttribute
    @URIParam("contactId")
    private Long id;
    
    private String firstName;
    
    private String lastName;
    
    private boolean isActive;

    @XmlElementWrapper(name="addresses")
    @XmlElement(name="address",required = true, nillable = true)
    @OneToMany(cascade = CascadeType.ALL, mappedBy = "contact")
    private Set
addresses = new HashSet
(); [...]

The annotation requires URI values:

  1. baseURI: the base resources that contains all entities of this type
  2. entityURI: the URI that represents a specific entity

In this example, the entityURI is used to handle all updates, deletes, and retrieval by ID operations. The baseURI determines where all contacts are stored. You can create a new resource by issuing a PUT with the entity data to the following URI:

http://localhost/contacts

A 201 response is issued by the server and the Location of the new entity is returned. The URI in the Location header will be one that matches the entityURI.

You can also perform search operations using a GET or a POST opertation and adding the approiate query parameters to the URI:

http://localhost/contacts?firstName=ry&lastName=mcd

By default, you can search for a contact using the property names. You can exclude specific properties by adding them to the excludeSearchProperties value. The idea is very silimar to Hibernates “query by example” Criteria query.

Since since the Contact contains a collection of Addresses, you can access an address independently of the Contact:

@RestfulEntity(baseURI="/contacts/{contactId}/addresses",
               entityURI="/contacts/{contactId}/addresses/{addressId}",
               readOnly=false, 
               persistenceStrategy=PersistenceStrategy.HIBERNATE)
               
public class Address implements Auditable {

    @Id
    @Column(name = "contact_id", nullable = false)
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @XmlAttribute
    @URIParam("addressId")
    private Long id;
    
    @ManyToOne
    @JoinColumn(name = "contact_id")
    @URIParam("contactId")
    @XmlTransient
    private Contact contact;
    
    [...]

The persistenceStrategy would be used to determine how the data is persisted and retrieved. Currently, I am thinking about the following types of options:

  • FILE: Uses the file system to persist objects.
  • JPA: uses dynamic queries to return the necessary portions of an object graph
  • HIBERNATE: Similar to JPA, but leverages the Hibernate Criteria API.

Lastly, the @MediaTypes annotation determines the mime types that are applicable for this type entity.

This is just in the idea phase at the the moment and it’s not a finished idea. It’s still half-baked and I’m sure I forgot something along the way. But if you have any suggestions on the idea, please feel free to post a comment.

Automagically RESTful Entity Beans