[jbossseam-issues] [JBoss JIRA] Commented: (JBSEAM-3368) conversation id evaluated to null (natural conversations)

Arron Ferguson (JIRA) jira-events at lists.jboss.org
Tue Sep 30 15:45:20 EDT 2008


    [ https://jira.jboss.org/jira/browse/JBSEAM-3368?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=12431851#action_12431851 ] 

Arron Ferguson commented on JBSEAM-3368:
----------------------------------------

>There is a lot of noise in the provided code, specifically:

I've taken out as much noise is as possible.

> 1. The pages.xml contains navigation rules based on #{identity.loggedIn},
> yet there is no way to authenticate.

Remove all three cases of this showing up, yes, thanks.

> 2. The view extensions are inconsistent - some are .html and some are .xhtml. Perhaps
> uploading the test case files as a zipped attachment would provide a more accurate
> test case? (without the jar files)

A typo. I was new to JIRA and didn't realize you can do that. Yes, I have uploaded a gzip attached (minus the JAR files of course).

> 3. The use case seems excessively complex just to reproduce a single issue - are 
> register2, register3, etc really needed?

No, you don't need them. If you run the example without them you still see the same behavior. I've left them in there because together all of these pages offer the following with regards to natural conversations:
- beginning a conversation
- ending a conversation
- joining a conversation
- going forwards in a conversation (navigation wise)
- going backwards in a conversation (navigation wise)
- canceling (ending) a conversation
- restricting access to a page based on the requirement of needing a natural conversation

Specifically:
- index.xhtml clears any existing conversations
- register.xhtml starts a natural conversation
- register1.xhtml offers two choices: cancel existing natural conversation and continue (forward) or join existing conversation
- register2.xhtml offers only one choice: continue or join existing conversation
- register3.xhtml offers two choices: continue (forward) with existing conversation and go back one page in the existing conversation
- register4.xhtml ends a natural conversation

This example is useful because it demonstrates all of the possible interactions (at least that I could think of) that one can have with natural conversations which could be useful for further debugging and trouble shooting. But as I mentioned above, feel free to remove register pages 2 - 4 from the example and simply type the URL register1.xhtml and you will see the exact same behavior.

> 4. Conversation propagation seems to be declared both in pages.xml and in the view,
> for example the following navigation rule in the <page> entry for register.xhtml:
...
> You need to use one or the other, not both.

Thanks, I didn't know that. I've removed it from the uploaded gzip.

> conversation id evaluated to null (natural conversations)
> ---------------------------------------------------------
>
>                 Key: JBSEAM-3368
>                 URL: https://jira.jboss.org/jira/browse/JBSEAM-3368
>             Project: Seam
>          Issue Type: Bug
>          Components: Core
>    Affects Versions: 2.0.3.CR1
>         Environment: Linux Ubuntu 7.10, Intel Pentium 4, 3GHz, 1 GB RAM, Tomcat 6.0.16
>            Reporter: Arron Ferguson
>            Assignee: Shane Bryzak
>            Priority: Critical
>             Fix For: 2.1.0.GA
>
>         Attachments: conversation-src.tar.gz
>
>
> If the user attempts to go to a page that is restricted based on what is in the pages.xml file, two things go wrong: 1) an exception is thrown (java.lang.IllegalStateException: conversation id evaluated to null: [name of natural conversation]), 2) the user can still view the page that is supposed to be restricted (i.e., using the restrict element in the pages.xml file).
> Setup Instructions:
> 1.) Set up Tomcat 6.x
> 2.) Create web app project structure
> 3.) Use the following for your pages.xml file (copy/paste):
> <?xml version="1.0" encoding="UTF-8"?>
> <pages xmlns="http://jboss.com/products/seam/pages"
>        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
>        xsi:schemaLocation="http://jboss.com/products/seam/pages http://jboss.com/products/seam/pages-2.0.xsd"
>        http-port="8080" https-port="8443"
>        no-conversation-view-id="/index.xhtml"
>                  login-view-id="/index.xhtml">
>   <conversation name="regmem"
>     parameter-name="memberID"
>     parameter-value="#{memberreg.tempKey}"/>
>   <page view-id="*" scheme="http" />
>   <page view-id="/register.xhtml">
>     <description>Register Member: #{memberreg}</description>
>     <navigation from-action="#{memberreg.start}">
>       <begin-conversation join="true" conversation="regmem"/>
>       <redirect view-id="/register1.xhtml"/>
>     </navigation>
>     <navigation>
>       <rule if="#{identity.loggedIn}">
>         <redirect view-id="/memberadmin.xhtml"/>
>       </rule>
>       <rule if="#{memberreg.acceptedInformation}">
>         <redirect view-id="/register3.xhtml"/>
>       </rule>
>       <rule if="#{memberreg.agree}">
>         <redirect view-id="/register2.xhtml"/>
>       </rule>
>       <rule if="#{memberreg.started}">
>         <redirect view-id="/register1.xhtml"/>
>       </rule>
>     </navigation>
>   </page>
>   <page view-id="/register1.xhtml" conversation-required="true"
>     conversation="regmem">
>     <description>Register Member: #{memberreg}</description>
>     <restrict>#{memberreg.started}</restrict>
>     <navigation from-action="#{memberreg.agreeToLicense}">
>       <redirect view-id="/register2.xhtml"/>
>     </navigation>
>     <navigation from-action="#{memberreg.cancel}">
>       <end-conversation/>
>       <redirect view-id="/index.xhtml"/>
>     </navigation>
>     <navigation>
>       <rule if="#{identity.loggedIn}">
>         <redirect view-id="/memberadmin.xhtml"/>
>       </rule>
>       <rule if="#{memberreg.acceptedInformation}">
>         <redirect view-id="/register3.xhtml"/>
>       </rule>
>       <rule if="#{memberreg.agree}">
>         <redirect view-id="/register2.xhtml"/>
>       </rule>
>     </navigation>
>   </page>
>   <page view-id="/register2.xhtml" conversation-required="true"
>     conversation="regmem">
>     <description>Register Member: #{memberreg}</description>
>     <restrict>#{memberreg.agree}</restrict>
>     <navigation from-action="#{memberreg.next}">
>       <rule if="#{memberreg.readyToConfirm}">
>         <redirect view-id="/register3.xhtml"/>
>       </rule>
>       <rule if="#{not memberreg.readyToConfirm}">
>         <redirect view-id="/register2.xhtml"/>
>       </rule>
>     </navigation>
>     <navigation>
>       <rule if="#{identity.loggedIn}">
>         <redirect view-id="/memberadmin.xhtml"/>
>       </rule>
>       <rule if="#{memberreg.acceptedInformation}">
>         <redirect view-id="/register3.xhtml"/>
>       </rule>
>     </navigation>
>   </page>
>   <page view-id="/register3.xhtml" conversation-required="true"
>     conversation="regmem">
>     <description>Register Member: #{memberreg}</description>
>     <restrict>#{memberreg.readyToConfirm}</restrict>
>     <navigation from-action="#{memberreg.acceptInformation}">
>       <redirect view-id="/register4.xhtml"/>
>     </navigation>
>     <navigation from-action="#{memberreg.editInformation}">
>       <redirect view-id="/register2.xhtml"/>
>     </navigation>
>     <navigation>
>       <rule if="#{identity.loggedIn}">
>         <redirect view-id="/memberadmin.xhtml"/>
>       </rule>
>     </navigation>
>   </page>
>   <page view-id="/register4.xhtml" conversation-required="true"
>     conversation="regmem">
>     <description>Register Member: #{memberreg}</description>
>     <restrict>#{memberreg.acceptedInformation}</restrict>
>     <navigation from-action="#{memberreg.end}">
>       <end-conversation before-redirect="false"/>
>       <redirect view-id="/index.xhtml"/>
>     </navigation>
>   </page>
>   <!-- START EXCEPTIONS -->
>   <exception class="org.jboss.seam.security.NotLoggedInException" log="false">
>     <redirect view-id="/index.xhtml">
>       <message severity="warn">Your session ended or expired.</message>
>     </redirect>
>   </exception>
>   <exception class="org.jboss.seam.security.AuthorizationException" log="false">
>     <end-conversation/>
>     <redirect view-id="/index.xhtml">
>       <message severity="warn">You are not authorized.</message>
>     </redirect>
>   </exception>
>   <!-- END EXCEPTIONS -->
> </pages>
> 4.) Create two Java classes (registration bean and POJO):
> Registration Bean:
> package com.test;
> import javax.ejb.Remove;
> import javax.persistence.Column;
> import javax.persistence.NoResultException;
> import java.io.Serializable;
> import java.util.Date;
> import javax.persistence.EntityManager;
> import org.jboss.seam.annotations.In;
> import org.jboss.seam.annotations.End;
> import org.jboss.seam.annotations.Destroy;
> import org.jboss.seam.annotations.Name;
> import org.jboss.seam.annotations.Out;
> import org.jboss.seam.annotations.Scope;
> import org.jboss.seam.faces.FacesMessages;
> import org.jboss.seam.faces.Renderer;
> import static org.jboss.seam.ScopeType.CONVERSATION;
> @Scope(CONVERSATION)
> @Name("memberreg")
> public class MemberRegistrationAction implements Serializable
> {
>     private static long tempKey = 0;
>     @Out(required = false) @In(required = false)
>     private Member newMember;
>     @In(create = true)
>     private Renderer renderer;
>     private boolean started = false;
>     private boolean agree = false;
>     private boolean acceptedInformation = false;
>     private boolean readyToConfirm = false;
>     private boolean stillNeedsToEdit = false;
>     private String confirm = "";
>     public String getConfirm() { return confirm; }
>     public void setConfirm(String confirm) { this.confirm = confirm; }
>     public long getTempKey() { return tempKey; }
>     public void setTempKey(long tempKey) { this.tempKey = tempKey; }
>     public Member getNewMember() { return newMember; }
>     /////////////////////////////////////////////
>     // CONVERSATION METHODS
>     /////////////////////////////////////////////
>     public void start()
>     {
>         newMember = new Member();
>         if(tempKey >= Long.MAX_VALUE)
>         {
>             tempKey = 0;
>         }
>         tempKey++;
>         started = true;
>     }
>     public void agreeToLicense() { agree = true; }
>     public void cancel()
>     {
>       started = false;
>       agree = false;
>       acceptedInformation = false;
>       readyToConfirm = false;
>       stillNeedsToEdit = false;
>     }
>     public void next() { readyToConfirm = this.verify(); }
>     private boolean verify() {
>         return true; // test purposes, always true
>     }
>     public void acceptInformation()
>     {
>         acceptedInformation = true;
>         stillNeedsToEdit = false;
>         this.complete();
>     }
>     public void editInformation()
>     {
>         stillNeedsToEdit = true;
>         acceptedInformation = false;
>     }
>     private void complete() {
>         ; // write to JPA/Hibernate
>     }
>     public void end() {
>         ; // something, something, something, dark side
>     }
>     /////////////////////////////////////////////
>     public boolean isStarted() { return started; }
>     public boolean isAgree() { return agree; }
>     public boolean isAcceptedInformation() { return acceptedInformation; }
>     public boolean isReadyToConfirm() { return readyToConfirm; }
>     public boolean isStillNeedsToEdit() { return stillNeedsToEdit; }
>     public void destroy()
>     {
>       started = false;
>       agree = false;
>       acceptedInformation = false;
>       readyToConfirm = false;
>       stillNeedsToEdit = false;
>     }
> }
> POJO:
> package com.test;
> import java.io.Serializable;
> import javax.persistence.Column;
> import javax.persistence.Entity;
> import javax.persistence.GeneratedValue;
> import javax.persistence.Id;
> import javax.persistence.Table;
> import org.hibernate.validator.Length;
> import org.hibernate.validator.NotEmpty;
> import org.hibernate.validator.NotNull;
> import org.jboss.seam.annotations.Name;
> @Entity @Name("member") @Table(name="member")
> public class Member implements Serializable {
>     @Id
>     @GeneratedValue
>     @Column(name = "id")
>     private long id = -1;
>     @NotNull
>     @Length(min=2, max=20, message="Must be between 2 and 20 chars long")
>     @Column(name = "lastname")
>     private String lastName;
>     @NotNull
>     @Length(min=2, max=20, message="Must be between 2 and 20 chars long")
>     @Column(name = "firstname")
>     private String firstName;
>     public long getId() { return id; }
>     public void setId(long id) { this.id = id; }
>     public String getLastName() { return lastName; }
>     public void setLastName(String lastName) { this.lastName = lastName; }
>     public String getFirstName() { return firstName; }
>     public void setFirstName(String firstName) { this.firstName = firstName; }
>    @Override
>    public String toString()  { return firstName + " " + lastName; }
> }
> 5.) Create XHTML files (template, index, register1 - register4):
> ///////////////////////////////////
> template.xhtml:
> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
>           "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
> <html xmlns="http://www.w3.org/1999/xhtml" lang="en"
>       xmlns:ui="http://java.sun.com/jsf/facelets"
>       xmlns:h="http://java.sun.com/jsf/html"
>       xmlns:f="http://java.sun.com/jsf/core" >
>   <head>
>     <title>something.com</title>
>   </head>
>   <body>
>     <div>
>       <h:messages globalOnly="true"/><br/><br/>
>       <ui:insert name="maincontent">
>       </ui:insert>
>     </div>
>   </body>
> </html>
> ///////////////////////////////////
> index.html:
> <html xmlns="http://www.w3.org/1999/xhtml"
>       xmlns:ui="http://java.sun.com/jsf/facelets"
>       xmlns:s="http://jboss.com/products/seam/taglib">
>     <!-- <ui:composition template="./template.xhtml"> -->
>   <ui:composition template="./template.xhtml">
>     <ui:define name="maincontent">
>       <s:link view="/register.html" value="click here to register" propagation="none"/>
>     </ui:define>
>   </ui:composition>
> </html>
> ///////////////////////////////////
> register.html
> <html xmlns="http://www.w3.org/1999/xhtml"
>       xmlns:ui="http://java.sun.com/jsf/facelets"
>       xmlns:h="http://java.sun.com/jsf/html"
>       xmlns:s="http://jboss.com/products/seam/taglib">
>   <ui:composition template="./template.xhtml">
>     <ui:define name="maincontent">
>         <p>Click to start natural conversation:</p>
>         <h:form id="testform">
>           <h:outputText value="Click: "/>
>           <h:commandButton value="Register" action="#{memberreg.start}">
>             <s:conversationName value="regmem"/>
>             <s:conversationPropagation type="join"/>
>           </h:commandButton>
>         </h:form>
>     </ui:define>
>   </ui:composition>
> </html>
> ///////////////////////////////////
> register1.xhtml
> <html xmlns="http://www.w3.org/1999/xhtml"
>       xmlns:ui="http://java.sun.com/jsf/facelets"
>       xmlns:h="http://java.sun.com/jsf/html"
>       xmlns:s="http://jboss.com/products/seam/taglib" >
>     <ui:composition template="./template.xhtml">
>       <ui:define name="maincontent">
>         <h:form id="agreeform">
>           <h:commandButton id="agreebut1" value="Agree"
>             action="#{memberreg.agreeToLicense}">
>             <s:conversationName value="regmem"/>
>             <s:conversationPropagation type="join"/>
>           </h:commandButton>
>           <br/><p>Click cancel to kill the natural conversation early</p>
>           <h:commandButton id="disagreebut1" value="Disagree"
>             action="#{memberreg.cancel}">
>             <s:conversationName value="regmem"/>
>             <s:conversationPropagation type="end"/>
>           </h:commandButton>
>         </h:form>
>       </ui:define>
>     </ui:composition>
> </html>
> ///////////////////////////////////
> register2.xhtml
> <html xmlns="http://www.w3.org/1999/xhtml"
>       xmlns:ui="http://java.sun.com/jsf/facelets"
>       xmlns:h="http://java.sun.com/jsf/html"
>       xmlns:s="http://jboss.com/products/seam/taglib" >
>   <ui:composition template="./template.xhtml">
>      <ui:define name="maincontent">
>      <h:form id="formfields">
>         <p>Content inserted for testing purposes when this button clicked:</p>
>         <h:commandButton id="next" value="Next" action="#{memberreg.next}">
>           <s:conversationName value="regmem"/>
>           <s:conversationPropagation type="join"/>
>         </h:commandButton>
>       </h:form>
>     </ui:define>
>   </ui:composition>
> </html>
> ///////////////////////////////////
> register3.xhtml
> <html xmlns="http://www.w3.org/1999/xhtml"
>       xmlns:ui="http://java.sun.com/jsf/facelets"
>       xmlns:h="http://java.sun.com/jsf/html"
>       xmlns:rich="http://richfaces.org/rich"
>       xmlns:s="http://jboss.com/products/seam/taglib" >
>   <ui:composition template="./template.xhtml">
>     <ui:define name="maincontent">
>       <h:form id="formfields" rendered="#{not identity.loggedIn}">
>         <h:commandButton id="editinfo" value="Edit Information"
>           action="#{memberreg.editInformation}">
>           <s:conversationName value="regmem"/>
>           <s:conversationPropagation type="join"/>
>         </h:commandButton>
>         &#160;&#160;&#160;&#160;&#160;
>         <h:commandButton id="confirmreg" value="Confirm Registration"
>           action="#{memberreg.acceptInformation}">
>           <s:conversationName value="regmem"/>
>           <s:conversationPropagation type="join"/>
>         </h:commandButton> 
>       </h:form>
>     </ui:define>
>   </ui:composition>
> </html>
> ///////////////////////////////////
> register4.xhtml
> <html xmlns="http://www.w3.org/1999/xhtml"
>       xmlns:ui="http://java.sun.com/jsf/facelets"
>       xmlns:s="http://jboss.com/products/seam/taglib" >
>   <ui:composition template="./template.xhtml">
>     <ui:define name="maincontent">
>       <p>Click back to finish natural conversation.</p>
>       <s:link value="Back to home." action="#{memberreg.end}"
>         propagation="end"/>
>     </ui:define>
>   </ui:composition>
> </html>
> 6.) Use the following JARs for your web app (for running inside of Tomcat 6):
> activation.jar
> antlr.jar
> asm.jar
> cglib.jar
> commons-beanutils.jar
> commons-codec-1.3.jar
> commons-collections.jar
> commons-digester.jar
> commons-lang.jar
> commons-logging.jar
> DA.jar
> dom4j.jar
> ejb-api.jar
> filelist.txt
> hibernate-annotations.jar
> hibernate-commons-annotations.jar
> hibernate-entitymanager.jar
> hibernate.jar
> hibernate-search.jar
> hibernate-validator.jar
> javassist.jar
> jboss-archive-browsing.jar
> jboss-el.jar
> jboss-seam-debug.jar
> jboss-seam-ioc.jar
> jboss-seam.jar
> jboss-seam-mail.jar
> jboss-seam-ui.jar
> jsf-api.jar
> jsf-facelets.jar
> jsf-impl.jar
> jstl.jar
> jta.jar
> lucene-core.jar
> mail.jar
> persistence-api.jar
> richfaces-api.jar
> richfaces-impl.jar
> richfaces-ui.jar
> spring.jar
> urlrewrite-3.1.0.jar
> 7.) (Optional) Set up facelets but you may also want to make the default extension html:
>   <servlet-mapping>
>     <servlet-name>Faces Servlet</servlet-name>
>     <url-pattern>*.html</url-pattern>
>   </servlet-mapping>
> Steps to reproduce bug:
> 1.) Start web app inside of Tomcat 6
> 2.) using your browser's URL text field, type in the name of a register1.html, register2.html, or register3.html. At this point your web app will generate an exception stack which will be caused by:
> java.lang.IllegalStateException: conversation id evaluated to null:
> The conversation is evaluated to null. Since conversations are a layer on top of sessions, the same behavior is expected which is a faces message purporting of no conversation existing and a redirect to the URL specified in the pages.xml attribute no-conversation-view-id="/index.xhtml" (so in this case index.xhtml page). It should not allow the user to see the page and generate exceptions.

-- 
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

        



More information about the seam-issues mailing list