Conversation example with faces-config navigation doesn't work
infinity2heaven Feb 12, 2011 5:22 AMI have an example app extending seam-javaee-booking app (shipped with seam-3beta1)
Here's my flow (page - action):
- members.xhtml (members listing) - select member (@Begin)
- program-registration.xhtml - selectProgram
- program-registration-select-program.xhtml - register
- program-registration-confirm.xhtml - confirm (@End)
step 1 is fine, selectedMember gets set
But in Step 2, when selectProgram is called from jsf actionMethod, the page doesn't navigate to next page as per faces-config file, instead it stays same with cid=1 on request param.
Conversation Stateful Bean
@Stateful @ConversationScoped @Named( "programRegistration" ) public class MemberProgramRegistration implements Serializable { private static final long serialVersionUID = 985615785945128136L; @Inject private Logger log; @PersistenceContext( type = PersistenceContextType.EXTENDED ) private EntityManager em; @Inject @Confirmed private Event< ProgramRegistration > programRegisteredEvent; private Member selectedMember; private Program selectedProgram; private ProgramRegistration registration; private boolean registrationValid; @Inject Conversation conversation; // @Begin # I've used this from Seam 3 instead of conversation.begin but still get the same error public void selectMember( final String _id ) { conversation.begin(); Long id = Long.valueOf( _id ); // get a fresh reference that's managed by the extended persistence context selectedMember = em.find( Member.class, id ); if ( selectedMember != null ) { log.info( "Member selected:" + selectedMember ); } } public void selectProgram() { selectedProgram = loadDefaultProgram(); } public void register() { if ( selectedProgram != null ) { log.info( "selectedProgram selected:" + selectedProgram ); } registration = new ProgramRegistration( selectedMember, selectedProgram, new Date(), 1 ); selectedMember = null; } @End public void confirm() { em.persist( registration ); conversation.end(); } @Produces @ConversationScoped @Named public ProgramRegistration getRegistration() { return registration; } @Produces @Named public Member getSelectedMember() { return registration.getMember() != null ? registration.getMember() : selectedMember; } @Produces @Named public Program getSelectedProgram() { return registration != null ? registration.getProgram() : selectedProgram; } private Program loadDefaultProgram() { return em.find( Program.class, 1L ); } @Produces @Named @SessionScoped public List< Program > getPrograms() { return em.createNamedQuery( "Program.findAll", Program.class ).getResultList(); } }
jsf
<ui:define name="content"> <h:messages /> <h3> Regitration </h3> <h1> Member </h1> <h:form> <h:panelGroup layout="block"> <h:panelGrid columns="1"> <b>first name:</b> <h:outputText value="#{selectedMember.firstName}" required="true" /> <b>last name:</b> <h:outputText value="#{selectedMember.lastName}" required="true" /> <b>dob:</b> <h:outputText value="#{selectedMember.lastName}" required="true" /> <b>email:</b> <h:outputText value="#{selectedMember.email}" required="true" /> <b>phone number:</b> <h:outputText value="#{selectedMember.phone}" /> <b>notes:</b> <h:outputText value="#{selectedMember.notes}" /> </h:panelGrid> </h:panelGroup> <h:commandButton action="#{programRegistration.selectProgram}" value="Register a program" /> #{' '} <h:commandButton id="cancel" action="#{programRegistration.cancel}" value="Return to Search" immediate="true" /> </h:form> </ui:define>
faces-config.xml
<?xml version="1.0" encoding="UTF-8"?> <!-- This file is not required if you don't need any extra configuration. --> <faces-config version="2.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_2_0.xsd"> <!-- Navigation rules --> <navigation-rule> <from-view-id>*</from-view-id> <navigation-case> <from-action>#{authenticator.login}</from-action> <if>#{true}</if> <to-view-id>/pages/home.xhtml</to-view-id> <redirect /> </navigation-case> <navigation-case> <from-action>#{authenticator.logout}</from-action> <to-view-id>/pages/auth/login.xhtml</to-view-id> <redirect /> </navigation-case> <navigation-case> <from-action>#{programRegistration.cancel}</from-action> <to-view-id>/pages/home.xhtml</to-view-id> <redirect /> </navigation-case> </navigation-rule> <navigation-rule> <from-view-id>/pages/secure/program-registration.xhtml</from-view-id> <navigation-case> <from-action>#{programRegistration.selectProgram}</from-action> <to-view-id>/pages/secure/program-registration-select-program.xhtml</to-view-id> <redirect /> </navigation-case> </navigation-rule> <navigation-rule> <from-view-id>/pages/secure/program-registration-select-program.xhtml</from-view-id> <navigation-case> <from-action>#{programRegistration.register}</from-action> <to-view-id>/pages/secure/program-registration-confirm.xhtml</to-view-id> <redirect /> </navigation-case> </navigation-rule> <navigation-rule> <from-view-id>/pages/secure/program-registration-confirm.xhtml</from-view-id> <navigation-case> <from-action>#{programRegistration.confirm}</from-action> <to-view-id>/pages/secure/members.xhtml</to-view-id> <redirect /> </navigation-case> </navigation-rule> </faces-config>
Replacing Weld's Conversation interface with Seam's @Begin and @End along with ConversationBoundaryInterceptor results in no change. Removing the navigation elements from faces-config and simply returning the page identifiers in action methods gives another error:
java.lang.IllegalStateException: Context is already active at org.jboss.weld.context.AbstractConversationContext.activate(AbstractConversationContext.java:301) at org.jboss.weld.jsf.WeldPhaseListener.activateConversations(WeldPhaseListener.java:110)
I've spent 3 days trying to figure out but in vain. Seam 3's hotel booking example is BROKEN (conversation doesn't work either) and there's no end to end example anywhere. Any help, appreciated.