Create a Blog with JBoss Seam, Hibernate JPA and JSF then Deploy it to Tomcat in the Cloud – Part IV
In this part (4) of the tutorial we will correct the bugs inherent in version 2.2 of Seam-gen and we will add some code to spice up our blog CMS.
First of all, our PostEdit.seam page is not working at all as it is. We shall fix this:
Open PostEdit.xhtml from the WebContent folder and find the <rich:tabPanel switchType=”ajax”> block. This is what’s causing the problem, because it has more than one tab – one to have the user select a category from a grid on another page, and the second one for selecting a user, since these two entites have @ManyToOne relationships to the post entity, and Seam-gen can’t handle generating more than one joined object selection user interface item in this version.
I don’t want an external grid for selection of a category anyway, so we will delete the entire <rich:tabPanel> block on this page, and instead make the category selectable from a pop-up menu using a typical JSF selectOneMenu UI component.
After you delete the <rich:tabPanel> go towards the beginning of the page and locate the code block starting with <s:decorate id=”titleField” template=”layout/edit.xhtml”>.
Within that block replace <h:inputTextarea id=”title” cols=”80″ rows=”2″ required=”true” value=”#{postHome.instance.title}”/> with <h:inputText id=”title” required=”true” value=”#{postHome.instance.title}”/>
Next, add the following code block below the closing tag (</s:decorate>) for titleField:
<s:decorate id="categoryField" template="layout/edit.xhtml"> <ui:define name="label">Post Category</ui:define> <h:selectOneMenu id="category" required="true" value="#{postHome.instance.title}"> <s:selectItems value="#{categoryList.resultList}" var="cat" label="#{cat.name}" noSelectionLabel="Please select..." /> <s:convertEntity /> </h:selectOneMenu> </s:decorate>
Now find the following after the closing tag of richPanel (</rich:panel) :
<h:commandButton id="save" value="Save" action="#{postHome.persist}" disabled="#{!postHome.wired}" rendered="#{!postHome.managed}"/>
Replace #{!postHome.wired} with “false”
so that disabled=”false”.
Now open Post.xhtml and put the following between title and content:
<s:decorate id="category" template="layout/display.xhtml"> <ui:define name="label">Post Category</ui:define> <h:outputText value="#{postHome.instance.category.name}"/> </s:decorate>
We also want to display category and user names instead of IDs in the post list. So open PostList.xhtml and find the following (should be at line 69 or somewhere near):
<ui:param name="propertyLabel" value="User id"/>
Remove ” id” from the value then three lines below, replace #{_post.user.id} with #{_post.user.name}
Now let’s make the authenticator authenticate real users from the database. Open Authenticator.java (in net.ozar.blog.session package). After line 16 (@In Credentials credentials) add the following:
@In(required = false) @Out(required = false, scope = SESSION) private User user; @In private EntityManager entityManager; @In private FacesMessages facesMessages;
You may want to
import net.ozar.blog.entity.User; import static org.jboss.seam.ScopeType.SESSION; import org.jboss.seam.annotations.Out;
(JBoss Tools can fail to auto-guess where to import ScopeType.SESSION.)
Here we are using a Seam-specific technique called “bijection” a term invented by makers of Seam. What bijection is basically injecting the User component using dependency injection, and also ‘outject’ing it, so that it is made available to both the method handling the event and the subsequent view.
Delete or comment the following and replace it with the code snippet below the following:
//write your authentication logic here, //return true if the authentication was //successful, false otherwise if ("admin".equals(credentials.getUsername())) { identity.addRole("admin"); return true; } return false;
The final version of the Authenticator.java should be like the following:
package net.ozar.blog.session; import java.util.List; import javax.persistence.EntityManager; import net.ozar.blog.entity.User; import static org.jboss.seam.ScopeType.SESSION; import org.jboss.seam.annotations.In; import org.jboss.seam.annotations.Logger; import org.jboss.seam.annotations.Name; import org.jboss.seam.annotations.Out; import org.jboss.seam.log.Log; import org.jboss.seam.security.Credentials; import org.jboss.seam.security.Identity; @Name("authenticator") public class Authenticator { @Logger private Log log; @In Identity identity; @In Credentials credentials; @In(required = false) @Out(required = false, scope = SESSION) private User user; @In private EntityManager entityManager; @In private FacesMessages facesMessages; @SuppressWarnings("unchecked") public boolean authenticate() { log.info("authenticating {0}", credentials.getUsername()); List<User> adaylar = entityManager.createQuery("select u from User u where u.login=#{identity.username} and u.password =#{identity.password}").getResultList(); if (adaylar== null || adaylar.size()==0) { String msj="No user by that name or password can be found"; log.error(msj); facesMessages.add(msj); return false; } else { user = (User) adaylar.get(0); if (user.getLevel()>1 ) identity.addRole("admin"); return true; } } }
I will be updating this post shortly demonstrating further optimization to the application and finally deploying it to a server in the cloud. Stay tuned!
6 Comments
Hey, this is probably the best free Seam tutorial ever. Keep up the great work!
why, thank you. 🙂
I fully agree.Very good.
Any solution for the duplicate Id for a component selectParent error caused by seam-gen 2.2? While I admit it’s better to select related objects via the h:selectOneMenu, but there are cases where I need multiple tabs in the rich:tabPanel to manage different related collection objects.
Hi, I’m trying to access http://localhost:8080/test/home.seam or http://localhost:8080/test/login.seam, but I only get the error HTTP Status 503 – Concurrent call to conversation.
What can I do to resolve this problem?