Pages

Wednesday, April 15, 2009

little restfull photo gallery example, with seam, which seams fine

I have decided it was time to check out the seam framework since many of my friends gave it a thumbs up. Starting with the blog example that comes with the package I have built a little restfull image gallery. Which looked liked this;
I started with a simple Photo domain object which has name as the id, and the data byte array as the photo file:
@Entity
@Name("newPhoto")
@Scope(ScopeType.SESSION)
public class Photo {
@Id
String name;
byte[] data;
...
}
Whats seamy here is the @Name and the @Scope annotations. @Name annotation declares named beans of the type. In this case I created one to use to hold the user submitted information. @Scope annotation declares the scope of the bean in this case I will use one bean for every session.
Then the action methods to persist and retrieve the photos:
@Name("pholog")
public class PhotoService {
@In
private EntityManager entityManager;
public List<Photo> getFrontPagePhotos() {
...
public byte[] getFoto(String fotoId) {
...
public void createNewPhoto(Photo p) {
if (p.getData() != null) {
try {
entityManager.persist(p);
}
catch (PersistenceException pe) {
FacesMessages.instance().add("Data exists!");
}
}
else {
FacesMessages.instance().add("File is required!");
}
}
}
The @In annotation injects other beans to our new bean. On the createNewPhoto method I do some validations and add validation errors if needed which I suppose a declarative syntax might exist that I don't know about.
On the view side seams comes with some extra tags that standard JSF does not have like the, fileUpload tag, or a better integrated graphicImage compenent. Nevertheless I had to add the richfaces package since I didn't like the way the standard datatable looks and behaves.
My form to upload a Photo:
    <h:form enctype="multipart/form-data">
<span class="errors"><h:messages /></span>
<h:panelGrid columns="2">
<h:outputLabel value="Name" for="txt_name" />
<h:inputText id="txt_name" value="#{newPhoto.name}" required="true"
requiredMessage="Name is required!" />
<h:outputLabel value="File" for="flu_dosya" />
<s:fileUpload id="flu_dosya" data="#{newPhoto.data}" />
</h:panelGrid>
<h:commandButton action="#{pholog.createNewPhoto(newPhoto)}"
value="Create" />
</h:form>
Tricky thing about the fileUpload was that you have to mark your form as "multipart/form-data" otherwise nothing gets uploaded. I am not sure if this is just a seam thing or a JSF spec thing. Another important feature here is #{pholog.createNewPhoto(newPhoto)} el expression which glues the domain and the action beans we have declared. I used to do something similiar using ognl expressions now it comes out of the box. 
Part that displays the gallery:
    <rich:dataGrid value="#{pholog.frontPagePhotos}" var="foto" columns="3"
elements="9">
<h:column>
<s:div>
<s:link id="lnk_foto" view="/photo/photo.xhtml" propagation="none">
<f:param name="fotoId" value="#{foto.name}" />
<s:graphicImage id="imaj" value="#{foto.data}"
style="border: 1px solid black;" lt="image could not be found">
<s:transformImageSize width="100" maintainRatio="true" />
</s:graphicImage>
</s:link>
</s:div>
I used the rich:dataGrid component which gives me nice 3x9 grid to display my images. seams graphicImage component converts the photo byte [] to a resource link which is served. In order it to work you have to add the Seam Resource Servlet to your web.xml;
    <servlet>
<servlet-name>Seam Resource Servlet</servlet-name>
<servlet-class>
org.jboss.seam.servlet.SeamResourceServlet
</servlet-class>
</servlet>

<servlet-mapping>
<servlet-name>Seam Resource Servlet</servlet-name>
<url-pattern>/seam/resource/*</url-pattern>
</servlet-mapping>
The s:link component links the thumbnail to photo.xml page where the image will be displayed with a restful url. My photo.xhtml is simply like;
<f:view>
<s:graphicImage id="imaj" value="#{pholog.getFoto(fotoId)}"
style="border: 1px solid black;" lt="image could not be found">
</s:graphicImage>
</f:view>
It has a graphicImage component with no transformations and gets the foto with the fotoId parameter. In order this to work and have urls like /examplegallery/photo/photo/yoda to display the image with the name yoda you have to make one last configuration in the pages.xml file;
    <page view-id="/photo/photo.xhtml">
<rewrite pattern="/photo/photo/{fotoId}" />
<param name="fotoId" value="{fotoId}" />
</page>
Here we are creating meaningful urls that could be bookmarked. In this case its like the page, photo, whit the foto name (photo id). And our page used the id (name) to retrieve and serve the image.
And for the last, things that I am curious about seam;
  • pages.xml file had to be seperate files since one file could easily go up to thounds of lines in a real project which won't be manageable. Or there might be a way that dumps the use of that xml file.
  • I am not entirely sure what the component.xml file does...
  • There could be a easier and better way to handle validations and display JSF exception that includes handling hibernate exceptions, validations.
  • Got to check out the seams conversation and navigation features.
  • Do a example with the bijection feature.
Those are my first impressions about seam I have added most of the code I added to the blog example here. So rest of the configuration is there.

No comments:

Post a Comment