Pages

Wednesday, May 27, 2009

seamy photo gallery, resting easier (part 4)

On my previous post I made a restful photo gallery that has a nice little feature where upon a restful request like 'http://.../mygallery/photo/photo/yoda' served the image named 'yoda' to the user. In order to achive that what I did was first I edited the pages.xml so that it could extract the name (id) part from the request url:
<page view-id="/photo/photo.xhtml" login-required="true">
<rewrite pattern="/photo/photo/{fotoId}" />
<param name="fotoId" value="{fotoId}" />
</page>
Here the name is extracted into el context as 'fotoId'. Second thing is that I created the photo.xhtml mentioned above:
<f:view>
<s:graphicImage id="imaj" value="#{photoService.getFoto(fotoId)}"
style="border: 1px solid black;" lt="image could not be found">
</s:graphicImage>
</f:view>
I used a 's:graphicImage' component which serves the photo using a little service bean using our 'fotoId' parameter. For completeness here is the service bean:
@Name("photoService")
@Scope(ScopeType.APPLICATION)
public class PhotoService {
public byte[] getFoto(String fotoId) {
Photo p = getPhoto(fotoId);
if (p == null) {
return null;
}
return p.getData();
}
...
What bugged me on this method was that although I just wanted the serve the image here I was actually serving a html page which linked to the image. 
After looking around I learned that what I wanted, came with the seam & resteasy integration. RESTEasy (jaxrs) comes with annotations where you can use to serve the result of methods & beans directly. Seam package comes with the required jars  (dont go downloading for a resteasy package from jboss.org) for integrating it. You just put them in your classpath. So inorder to serve my 'photoService.getFoto' I can use the @Get, @Path and other annotations :
@Name("photoService")
@Scope(ScopeType.APPLICATION)
@Path("/foto")
public class PhotoService {

@GET
@Path("/{fotoId}")
@ProduceMime("image/jpeg")

public byte[] getFoto(@PathParam("fotoId")
String fotoId) {
...
Rest access is by default configured under '.../seam/resource/rest/'. So by using the path and get annotions I can access the 'photoService.getFoto' method with the '.../seam/resource/rest/foto/yoda' request. ProduceMime annotation tells that we are serving an jpeg image and the PathParam annotation is used so that we can get the 'yoda' out of the request and used it as a parameter to our method.
Now are we done ? No, because we need to secure it!. We dont want Vader to see the comprimising images of the Yoda (hehe) so we need to secure it with the restrict annotation :
@GET
@Path("/{fotoId}")
@ProduceMime("image/jpeg")
@Restrict("#{s:hasRole('user') || s:hasRole('admin')}")
public byte[] getFoto(@PathParam("fotoId")
String fotoId) ...
Now what happens when someone not logged in tries to acces the yoda is we will see a NotLoggedInException on the stacktrace. Of course we need to handle that and give the user the option to log in. Seam has a 'web:authentication-filter' component that supports the http basic or digest authentication which I configured like this on components.xml:
<web:authentication-filter url-pattern="/seam/resource/rest/*"
auth-type="basic" />
Now the yoda is safe I guess and I am sure there will be different authentication types supported in the future. I got few that could be implemented like the oauth which I belive is used by twitter and such.

No comments:

Post a Comment