[jbossseam-issues] [JBoss JIRA] Updated: (JBSEAM-3368) conversation id evaluated to null (natural conversations)
Pete Muir (JIRA)
jira-events at lists.jboss.org
Tue Sep 2 12:32:40 EDT 2008
[ https://jira.jboss.org/jira/browse/JBSEAM-3368?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]
Pete Muir updated JBSEAM-3368:
------------------------------
Fix Version/s: 2.1.0.CR1
Priority: Critical (was: Blocker)
> 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
> Priority: Critical
> Fix For: 2.1.0.CR1
>
>
> 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>
>      
> <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