[
https://jira.jboss.org/jira/browse/JBSEAM-3368?page=com.atlassian.jira.pl...
]
Arron Ferguson reopened JBSEAM-3368:
------------------------------------
Dudes ...
This is not fixed (nor is the other related bug I filed). I tried with
Jboss-seam-2.1.0.SP1. The following errors happen:
1) Target Unreachable, identifier 'memberreg' resolved to null
If I cancel the conversation at page 1(register1.html), hit the browser back button (back
to index.html), then try to continue on with the natural conversation, the above error
comes up. This should simply take me back to the index page and inform me that the natural
conversation is finished.
This error also pops up if the user does the following:
a) starts a natural conversation (register1)
b) tries to jump ahead to a page without access (register4) ... Seam states that "The
conversation ended, timed out or was processing another request" But if the user goes
back to the page that they were originally at before they tried jumping ahead (register1),
"resolved to null" comes up again.
2) conversation id evaluated to null: regmem
If I'm at page 4 (register4.html) and I type: register2.html (i.e., without the
natural conversation id appended at the end like this:
http://localhost:8080/test/register1.html?memberID=2), I get the following evaluated to
null error
The only jar file that I didn't get from the most recent JBoss Seam download was the
jboss-archive-browsing.jar file which is not included. I had to grab from the JBoss site.
I'm still using Tomcat 6.0.16.
3) Going back to a previous page doesn't redirect based on the rules in the pages.xml
file
None of the rules seem to be honored in the pages.xml file If the user is at
register3.html and then types:
http://localhost:8080/test/register2.html?memberID=2 (with the correct conversation ID)
The user can go to a previous page the but the redirect rules in the pages.xml file for
the register2.html page specify:
<navigation from-action="#{memberreg.next}">
<rule if="#{memberreg.readyToConfirm}">
<redirect view-id="/register3.xhtml"/>
</rule>
This is not being honored.
Summary:
These errors still exist for non-JBoss (i.e., Tomcat 6.x). The posted sample application
that I sent to this forum is, as Shane mentioned, more than what is required for a simple
test. However, it is incredibly useful for running ALL of the use cases that come up for
dealing with users and natural conversations. I STRONGLY urge the Seam crew to have
another look at this test file and try all possible use cases on this. Let me know if you
have any questions.
Regards,
Arron
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>
     
<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