<render> elements in pages.xml need to fallthrough like in case statements.
---------------------------------------------------------------------------
Key: JBSEAM-3935
URL:
https://jira.jboss.org/jira/browse/JBSEAM-3935
Project: Seam
Issue Type: Feature Request
Reporter: Dan Hinojosa
I found a situation where having a Renderer object injected into a bean is not at all
ideal. Case in point, resetting a password. In example 1, when I call renderer.render,
the user object has not be outjected yet. Therefore if I have information in
/email/password.xhtml referring to #{user.password} the email will send either nothing or
the old password. In example 2, I can get around it with a kludge which is updating the
user object injected and then do the render. This is inelegant. The best option I
believe is to do the rendering outside of the method, so I propose doing something like in
example 3.
Example 1:
@Name("registrationBean")
@Scope(ScopeType.CONVERSATION)
public class RegistrationBean implements Serializable {
@In
private EntityManager entityManager;
@In @Out
private User user;
@In
private Renderer renderer;
@In //Ostermiller random password utility
private RandPass randPass;
@Transactional
public void resetPassword() {
Query query = entityManager.createQuery("SELECT u from User u where
UPPER(u.email) = UPPER(:email)");
query.setParameter("email", user.getEmail());
user = (User) query.getSingleResult();
String newPassword = randPass.getPass(8);
user.setPassword(newPassword);
entityManager.flush();
renderer.render("/email/password.xhtml"); //Oh oh, nothing has been
updated!!!
}
}
Example 2:
@Name("registrationBean")
@Scope(ScopeType.CONVERSATION)
public class RegistrationBean implements Serializable {
@In
private EntityManager entityManager;
@In @Out
private User user;
@In
private Renderer renderer;
@In //Ostermiller random password utility
private RandPass randPass;
@Transactional
public void resetPassword() {
Query query = entityManager.createQuery("SELECT u from User u where
UPPER(u.email) = UPPER(:email)");
query.setParameter("email", user.getEmail());
User dbUser = (User) query.getSingleResult();
String newPassword = randPass.getPass(8);
dbUser.setPassword(newPassword);
user.setFirstName(dbUser.getFirstName()); //kludge
user.setLastName(dbUser.getLastName()); //kludge
user.setPassword(newPassword); //kludge
entityManager.flush();
renderer.render("/email/password.xhtml");
}
}
Example 3 (My proposition) :
@Name("registrationBean")
@Scope(ScopeType.CONVERSATION)
public class RegistrationBean implements Serializable {
@In
private EntityManager entityManager;
@In @Out
private User user;
@In //Ostermiller random password utility
private RandPass randPass;
@Transactional
public void resetPassword() {
Query query = entityManager.createQuery("SELECT u from User u where
UPPER(u.email) = UPPER(:email)");
query.setParameter("email", user.getEmail());
user = (User) query.getSingleResult();
user.setPassword(randPass.getPass(8));
entityManager.flush();
//NOTICE I TOOK OUT renderer.render("/email/password.xhtml")
}
}
Why did I take out renderer.render from the code? Because in pages.xml then we can make
use of the render element to do the emailing,
.....
<page view-id="/registration/register.xhtml">
<begin-conversation join="true"/>
<navigation from-action="#{registrationBean.resetPassword}">
<render view-id="/email/password.xhtml"/> <!--Send one
or more emails -->
<render view-id="/registration/register.xhtml"/> <!--I
want to stay on the same page, or I could redirect, etc. -->
<end-conversation/>
</navigation>
</page>
....
If you try it out now currently, this works except that it doesn't follow through.
What Seam does currently is that it renders /email/password.xhtml and stops. What I am
proposing that <render> elements follow through until the last render or redirect
element.
The advantages are highly numerous, one is as developers we would no longer need to be
concerned about including renderer calls in our unit and non-page integration tests. We
uncouple the view (emails, and pages) from the controller -- huge win. Another bigger
advantage is that we can treat emails around a method as an AOP, we can easily add, remove
emails based on the outcome of methods without us having to fidget with our code and have
to test and retest our code. See example 4.
Example 4 (My proposition) :
@Name("registrationBean")
@Scope(ScopeType.CONVERSATION)
public class RegistrationBean implements Serializable {
@In
private EntityManager entityManager;
@In @Out
private User user;
@In //Ostermiller random password utility
private RandPass randPass;
@Transactional
public String resetPassword() {
Query query = entityManager.createQuery("SELECT u from User u where
UPPER(u.email) = UPPER(:email)");
query.setParameter("email", user.getEmail());
try {
user = (User) query.getSingleResult();
user.setPassword(randPass.getPass(8));
entityManager.flush();
return "success"
} catch (NoResultException nre) {
return "noresult"
}
}
}
.....
<page view-id="/registration/register.xhtml">
<begin-conversation join="true"/>
<navigation from-action="#{registrationBean.resetPassword}">
<rule if-outcome="success">
<render view-id="/email/password.xhtml"/> <!--Send
one or more emails -->
<redirect view-id="/index.xhtml"/>
<end-conversation/>
</rule>
</navigation>
</page>
....
--
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators:
https://jira.jboss.org/jira/secure/Administrators.jspa
-
For more information on JIRA, see:
http://www.atlassian.com/software/jira