0
votes

I have a @ConversationScoped CDI Managed Bean in my JSF application, using Primefaces 5.2 running on Wildfly 8.2.1 . Implicit navigation is just working once in my application. First, i have my index.xhtml which has a button that calls my managed bean, CiudadManagedBean:

<!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"
      xmlns:ui="http://java.sun.com/jsf/facelets"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:p="http://primefaces.org/ui"> 

<ui:composition template="/plantilla/template.xhtml">

    <ui:define name="contenido">
    <h:form>
        <p:commandButton action="#{ciudadMB.cargarCiudades()}"
        value="Mostrar ciudades" />
    </h:form>
    </ui:define>
 </ui:composition>
</html>

Next, here is CiudadesManagedBean. As you can see, i start a conversation on @PostConstruct method and it loads a list when i call cargarCiudades from index.xhtml, and finally it loads ciudades/lista.xhtml:

package com.saplic.fut.beans;

import java.io.Serializable;
import java.util.List;

import javax.annotation.PostConstruct;
import javax.enterprise.context.Conversation;
import javax.enterprise.context.ConversationScoped;
import javax.inject.Inject;
import javax.inject.Named;

import com.saplic.fut.daos.CiudadDAO;
import com.saplic.fut.entity.Ciudad;

@Named(value="ciudadMB")
@ConversationScoped
public class CiudadManagedBean implements Serializable {

    private static final long serialVersionUID = 7339176875158769385L;

    private Ciudad instance;
    private List<Ciudad> cities;
    private Integer idCity;

    @Inject
    private CiudadDAO ciudadDAO;

    @Inject
    private Conversation conversation;

    @PostConstruct
    public void inicializarConversacion() {
        if(conversation.isTransient())
            conversation.begin();
    }

    public Ciudad getInstance() {
        return instance;
    }

    public String cargarCiudades() {
        setCities(ciudadDAO.cargarCiudades());
        return "ciudades/lista";
    }

    public String cargar() {
        Ciudad flt = new Ciudad();
        flt.setId(getIdCity());
        setInstance(ciudadDAO.cargarDetalle(flt));
        if(getInstance() == null)
            setInstance(new Ciudad());
        return "ciudades/detalle";
    }

    public String guardar() {
        ciudadDAO.guardar(getInstance());
        setCities(ciudadDAO.cargarCiudades());
        return "ciudades/lista";
    }

    public String actualizar() {
        ciudadDAO.actualizar(getInstance());
        setCities(ciudadDAO.cargarCiudades());
        return "ciudades/lista";
    }

    public String eliminar() {
        ciudadDAO.guardar(getInstance());
        setCities(ciudadDAO.cargarCiudades());
        return "ciudades/lista";
    }

    public void setInstance(Ciudad instance) {
        this.instance = instance;
    }

    public List<Ciudad> getCities() {
        return cities;
    }

    public void setCities(List<Ciudad> cities) {
        this.cities = cities;
    }

    public Integer getIdCity() {
        return idCity;
    }

    public void setIdCity(Integer idCity) {
        this.idCity = idCity;
    }

}

Finally, the xhtml where i call my method cargar(). I want to invoke that method and then load ciudades/detalle.xhtml because here's my form.

<!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"
      xmlns:ui="http://java.sun.com/jsf/facelets"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:p="http://primefaces.org/ui"> 

<ui:composition template="/plantilla/template.xhtml">

    <ui:define name="contenido">
    <h:form id="frm1">

        <p:dataTable id="tablita" resizableColumns="true" rowIndexVar="rowIdx"
        paginator="true" rows="10" paginatorPosition="bottom" value="#{ciudadMB.cities}"
        var="ciu" >
            <p:column headerText="Código pais">
                <p:outputLabel value="#{ciu.codigoPais}" />
            </p:column>
            <p:column headerText="Distrito">
                <p:outputLabel value="#{ciu.distrito}" />
            </p:column>
            <p:column headerText="Nombre">
                <p:outputLabel value="#{ciu.nombre}" />
            </p:column>
            <p:column headerText="Población">
                <p:outputLabel value="#{ciu.poblacion}" />
            </p:column>
            <p:column headerText="Accion">
                <p:commandLink action="#{ciudadMB.cargar()}" ajax="false" value="Ver" process="@form">
                    <f:setPropertyActionListener value="#{ciu.id}" target="#{ciudadMB.idCity}" />
                </p:commandLink>
            </p:column>
        </p:dataTable>
    </h:form>
    </ui:define>
 </ui:composition>
</html>

When i click on a link inside my datatable, it invokes ciudadMB.cargar() and executes the code inside it, but it ignores the return "ciudades/detalle" . So, implicit navigation works at first time (when i'm on index.xhtml and i click the buttons, it takes me to lista.xhtml) but when i click on a link to go to detalle.xhtml, it ignores it. It just refresh lista.xhtml. Also, I've tried with @SessionScoped and @RequestScoped (always using javax.enterprise.context annotations instead JSF annotations, and removing Conversation object and initialization).

With @SessionScoped it has the same behavior. Pagination works without problems but when i click on the commandLink inside datatable it invokes the action method but ignores the String return.

With @RequestScoped if i click the commandLink it refreshes the page but doesn't invoke the action method. If i put a dummy commandLink outside the datatable it invokes the action method but again, it ignores the String return.

Why Implicit Navigation is not working? Is some CDI issue? Regards.

EDIT: I also changed the annotations to import javax.faces.bean.ManagedBean; import javax.faces.bean.SessionScoped; to check if it was about CDI annotations, but it didn't work either, so it isn't a problem of CDI. Do i have to activate something in my configuration to make it work? This is a Eclipse Dynamic Web Project 3.1, JPA 2.1 and JSF 2.2 running on Wildfly 8.2.1 . Here is my web.xml configuration file:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
  <display-name>SistemaFutJsf</display-name>
  <welcome-file-list>
    <welcome-file>index.xhtml</welcome-file>
  </welcome-file-list>
  <servlet>
    <servlet-name>Faces Servlet</servlet-name>
    <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>Faces Servlet</servlet-name>
    <url-pattern>/</url-pattern>
    <url-pattern>*.xhtml</url-pattern>
  </servlet-mapping>
  <context-param>
    <param-name>primefaces.THEME</param-name>
    <param-value>cupertino</param-value>
  </context-param>
</web-app>

faces-config.xml:

<?xml version="1.0" encoding="UTF-8"?>
<faces-config
    xmlns="http://xmlns.jcp.org/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-facesconfig_2_2.xsd"
    version="2.2">

</faces-config>

And CDI beans.xml file:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://xmlns.jcp.org/xml/ns/javaee"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/beans_1_1.xsd"
       version="1.1" bean-discovery-mode="annotated">

</beans>
2
You're implying that it works fine with JSF managed bean. But you have nowhere explicitly confirmed this in your question. Please clarify. Also, your bean is actually session scoped instead of conversation scoped. This is confusing. - BalusC
Sorry, you're right. I changed to @ SessionScoped to check if it was a problem specific with @ ConversationScopes but it didn't work either. I will correct my question. - Oscar Calderon
OK, summarized, regardless of the bean management framework, and regardless of the bean scope, the action method is in any case properly invoked, but the returned string for navigation outcome is completely ignored, as in that it goes back to same page? - BalusC
Exactly, it goes to the same page. In the console output i don't get any output indicating that my String return is wrong or that the xhtml page (ciudades/detalle.xhtml) doesn't exist. I can see the refresh because i'm using ajax="false". EDIT: With CDI @RequestScoped, a commandLink inside the datatable doesn't invoke the action method, but outside it, it does - Oscar Calderon
Here is a link to download the source code infotomb.com/mx2i6.rar (right now it has JSF annotations instead CDI ones) - Oscar Calderon

2 Answers

2
votes

You are using relative navigation. Try with

return "detalle";

instead of

return "ciudades/detalle";

Or use absolute navigation instead:

return "/ciudades/detalle";

0
votes

Finally, i tried something: I haven't set JSF parameter "PROJECT_STAGE" in my web.xml file, so i set it in development mode:

<context-param>
        <param-name>javax.faces.PROJECT_STAGE</param-name>
        <param-value>Development</param-value>
</context-param>

After that, i've tried again and i got this error:

09:58:58,487 WARNING [javax.enterprise.resource.webcontainer.jsf.application] (default task-21) JSF1064: Unable to find or serve resource, /ciudades/ciudades/detalle.xhtml.

The problem is that i was using a relative path. The first time, moving from index.xhtml to ciudades/lista.xhtml, it worked without problem because i was in the root path (http:localhost:8094/SistemaFutJsf), but after that, when i was trying to go to ciudades/detalle.xhtml, the application context was this (http:localhost:8094/SistemaFutJsf/ciudades) and because of that it couldn't find /ciudades/ciudades/detalle.xhtml.

So, the solution was to add a slash (/) to make the paths absolute, like this:

public String cargarCiudades() {
        setCities(ciudadDAO.cargarCiudades());
        return "/ciudades/lista";
    }

    public String cargar() {
        Ciudad flt = new Ciudad();
        flt.setId(getIdCity());
        setInstance(ciudadDAO.cargarDetalle(flt));
        if(getInstance() == null)
            setInstance(new Ciudad());
        return "/ciudades/detalle";
    }