Problemas com JSF 2.0 (<h:selectOneMenu> e <f:ajax>)

Olá pessoal,

Meu problema é com JSF. Tenho um h:selectOneMenu de Especialidades e um h:selectOneMenu de Medicos. Quando seleciono uma especialidade o h:selectOneMenu de Médicos é populado com os Médicos daquela especialidade. Isto está funcionando e estou fazendo com Ajax. O problema é que quando eu faço o submit deste formuláro ocorre um erro como se os dados do médico não tivessem setados no meu objeto Consulta (que possue estes dois atributos e alguns mais).

Pelo que eu entendi este problema é por causa do Ajax. Faço uma requisão ajax para trazer os médicos e outra requisição Ajax para salvar a Consulta no banco, mas não sei por que estou tento esse problema. Já estudei o ciclo de vida da requisão JSF mas não encontrei a resposta. É como se meu componente médico não estivesse sendo setado.

O Tomcat me retorna o warning abaixo.
[color=red]01/10/2011 01:07:29 org.apache.tomcat.util.http.Parameters processParameters
INFO: Parameters: Invalid chunk ‘=10’ ignored.[/color]

Minha Página

<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:f="http://java.sun.com/jsf/core"
	xmlns:p="http://primefaces.prime.com.tr/ui">


<p:panel header="Consulta" id="panel">
	<h:panelGrid columns="3">

		<h:outputLabel value="Convênio: " for="consulta-convenio" />
		<h:selectOneMenu id="consulta-convenio"
			value="#{consultaBean.consulta.convenio}">
			<f:converter converterId="entityConverter" />
			<f:selectItem itemLabel="Selecione..." itemValue="" />
			<f:selectItems value="#{convenioBean.listaConvenios}" var="conv"
				itemLabel="#{conv.nome}" itemValue="#{conv}" />
		</h:selectOneMenu>
		<p:message for="consulta-convenio" />


		<h:outputLabel value="Especialidade: " for="consulta-especialidade" />
		<h:selectOneMenu id="consulta-especialidade"
			value="#{medicoBean.especialidadeId}">
			<f:ajax event="change" render="consulta-medico"
				listener="#{medicoBean.listenerMedicosByEspecialidade}" />
			<f:selectItem itemLabel="Selecione..." itemValue="" />
			<f:selectItems value="#{especialidadeBean.listaEspecialidades}"
				var="esp" itemLabel="#{esp.descricao}" itemValue="#{esp.id}" />
		</h:selectOneMenu>
		<p:message for="consulta-especialidade" />


		<h:outputLabel value="Médico: " for="consulta-medico" />
		<h:selectOneMenu id="consulta-medico"
			value="#{consultaBean.consulta.medico}">
			<f:converter converterId="entityConverter" />
			<f:selectItem itemLabel="Selecione..." itemValue="" />
			<f:selectItems value="#{medicoBean.listaMedicosByEspecialidade}"
				var="med" itemLabel="#{med.nome}" itemValue="#{med}" />
		</h:selectOneMenu>
		<p:message for="consulta-medico" />


		<h:outputLabel value="Paciênte: " for="consulta-paciente" />
		<h:selectOneMenu id="consulta-paciente" required="true"
			value="#{consultaBean.consulta.paciente}">
			<f:converter converterId="entityConverter" />
			<f:selectItem itemLabel="Selecione..." itemValue="" />
			<f:selectItems value="#{pacienteBean.listaPacientes}" var="pac"
				itemLabel="#{pac.nome}" itemValue="#{pac}" />
		</h:selectOneMenu>
		<p:message for="consulta-paciente" />

		<h:outputText value="Data da Consulta: " for="consulta-data" />
		<p:inputMask id="consulta-data" required="true"
			value="#{consultaBean.consulta.data}" mask="99/99/9999">
			<f:convertDateTime timeZone="America/Sao_Paulo" pattern="dd/MM/yyyy" />
		</p:inputMask>
		<p:message for="consulta-data" />


		<h:commandButton value="Salvar">
			<f:ajax event="click" execute="@form"
				listener="#{consultaBean.salvar}" render="@form" />
		</h:commandButton>

	</h:panelGrid>
</p:panel>

Meu ManagedBean

@ManagedBean
public class ConsultaBean {

	@ManagedProperty(value = "#{entityManager}")
	private EntityManager entityManager;
	private Consulta consulta = new Consulta();

	private List<Consulta> listaConsultas;

	
	public EntityManager getEntityManager() {
		return entityManager;
	}

	public void setEntityManager(EntityManager entityManager) {
		this.entityManager = entityManager;
	}


	public Consulta getConsulta() {
		return consulta;
	}

	public void setConsulta(Consulta consulta) {
		this.consulta = consulta;
	}

	public List<Consulta> getListaConsultas() {
		if (listaConsultas == null) {
			listaConsultas = ServiceFactory.getInstance().getConsultaService().findAll(entityManager);
		}
		return listaConsultas;
	}



	
	public void salvar() {
		
		ServiceFactory.getInstance().getConsultaService().insert(entityManager, consulta);
		consulta = new Consulta();
		listaConsultas = null;
	}

	public void remover(Consulta consulta) {
		ServiceFactory.getInstance().getConsultaService()
				.delete(entityManager, consulta);
		listaConsultas = null;
	}

}

Obs. Estou passando o objeto direto do meu h:selectOneMenu para minha Entity, mas o problema não é esse. Se eu coloco um h:selectOneMenu com todos os médicos e mando salvar no banco ele salva tudo corretamente. O problema é justamente com essas requisições Ajax =/

Desde já agradeço,
Adilson

amigo axo q o problema é outro pois WARNING não aborta a execução do programa só te alerta q algo naum está certo mas continua sem problemas, coloca seu stacktrace completo aki…

Fala Iuxu, correto não aborta a execução mesmo.
Na verdade a única mensagem que eu recebo do Tomcat é a que eu postei acima. E a mensagem de erro do JSF é “value is not valid”.
O formulário não grava nada no banco pois os campos são not null.

Até onde eu entendi as requisições Ajax do meu form estão conflitando. Alguém sabe como tratar isso???
Aparentemente o ajax do meu botão submit está limpando a busca feita pelo meu selectOneMenu via ajax também.

Alguém???

mas pq vc colocou td not null? no BD tb é assim? pq se de um jeito dá certo (selecionando td) e de outro naum dah tah explicado o problema…outra seu managedbean tem qual escopo? olha se falei besteira é pq “ainda” naum implementei injeção de dependêncis, ok?

Então, vou tentar explicar melhor. No momento que eu seleciono a especialidade o tomcat lança o warning

[color=red]01/10/2011 14:45:17 org.apache.tomcat.util.http.Parameters processParameters
INFO: Parameters: Invalid chunk ‘=10’ ignored.
01/10/2011 14:45:17 org.apache.tomcat.util.http.Parameters processParameters
INFO: Parameters: Invalid chunk ‘=10’ ignored.[/color]

mas tudo continua funcionando “perfeitamente”. Esse warning eu sei que acontece quando o JSF não consegue converter o valor para o tipo esperado. Por isso voltei meu sistema para que o managed bean recebesse o ID e não o objeto do selectOneMenu. Deixei tudo o mais simples possível mas o erro persiste.

Quando eu clico em salvar é lançado um erro no ciclo de vida do meu JSF que nem chega a chamar meu método salvar. Quando eu não seleciono a especialidade e clico em salvar o meu método é chamado e funciona normalmente. Então o problema está justamente no meu selectOneMenu de Especialidade, ele não está retornando algo válido. Já dei uma lida em artigos sobre f:ajax mas até agora não consegui descobrir qual é o problema.

Página

		<h:outputLabel value="Especialidade: " for="consulta-especialidade" />
		<h:selectOneMenu id="consulta-especialidade"
			value="#{consultaBean.especialidadeId}">
			<f:ajax event="change"  render="consulta-medico" listener="#{consultaBean.listenerMedicosByEspecialidade}" />						
			<f:selectItem itemLabel="Selecione..." itemValue="" />
			<f:selectItems value="#{especialidadeBean.listaEspecialidades}"
				var="esp" itemLabel="#{esp.descricao}" itemValue="#{esp.id}" />
		</h:selectOneMenu>
		<p:message for="consulta-especialidade" />


		<h:outputLabel value="Médico: " for="consulta-medico" />
		<h:selectOneMenu id="consulta-medico" value="#{consultaBean.medicoId}">

			<f:selectItem itemLabel="Selecione..." itemValue="" />
			<f:selectItems value="#{consultaBean.listaMedicosByEspecialidade}"
				var="medByEsp" itemLabel="#{medByEsp.nome}" itemValue="#{medByEsp.id}" />				 
		</h:selectOneMenu>
		<p:message for="consulta-medico" />

   <h:commandButton value="Salvar">
			<f:ajax event="click" execute="consulta-convenio consulta-medico consulta-paciente consulta-data"
				listener="#{consultaBean.salvar}" render="@form" />
		</h:commandButton>

ManagedBean ConsultaBean

public void listenerMedicosByEspecialidade(AjaxBehaviorEvent event) {	
		listaMedicosByEspecialidade = ServiceFactory.getInstance().getMedicoService().findByEspecialidade(entityManager, especialidadeId);
	}

	public List<Medico> getListaMedicosByEspecialidade() {
		return listaMedicosByEspecialidade;
	}

	public void setListaMedicosByEspecialidade(
			List<Medico> listaMedicosByEspecialidade) {
		this.listaMedicosByEspecialidade = listaMedicosByEspecialidade;
	}
	public Integer getMedicoId() {
		return medicoId;
	}

	public void setMedicoId(Integer medicoId) {	
		this.medicoId = medicoId;
	}

Meus managedBeans são todos de scope Request.
Não sei se me fiz entender melhor…

olha terá q indo fazer testes até chegar ao resultado, meus selectOneMenu faço assim:

<p:fieldset legend="Turma" style="font-size:15px;"> <h:selectOneMenu value="#{turmaAlunoBean.tur_codigo}" id="selecaoTurma" disabled="#{not empty turmaAlunoBean.tur_codigo}" required="true" requiredMessage="Campo [Turma] obrigatório"> <f:selectItems value="#{entradaTurmasAlunosBBean.turmas}" /> </h:selectOneMenu> </p:fieldset>
e no MB

public List<SelectItem> getTurmasAlunos() { TurmaAlunoDAO turmaAlunoDAO = new TurmaAlunoDAO(FacesContextUtil.getRequestSession()); List<Turma_Aluno> turmas = turmaAlunoDAO.getTurmas(); List<SelectItem> selectTurma = new ArrayList<SelectItem>(); selectTurma.add(new SelectItem(null, "Selecione uma turma..")); for (Turma_Aluno turma : turmas) { selectTurma.add(new SelectItem(turma.getTurma().getCodigo().toString(), turma.getTurma().getDescricao())); } return selectTurma; }

veja a montagem do select…primeiro a DESCRIÇÃO e o segundo item o CÓDIGO, daí qdo seleciono o q quero ele me retorna a CÓDIGO q vai gravar no BD…otra coisa o select é tipado como objeto SELECTITEM naum objeto MÉDICO pode ser q o problema esteja ali, pode ser testa ae pra gente ver…

Depois de muito tempo consegui descobrir qual é o meu problema.

Meu managedBean tem escopo de request. Logo quando eu faço a requisição ajax para filtar os médicos o container reconstroi meu managedBean novamente e eu perco tudo o que havia.
Uma solução para isso era apenas mudar o escopo para session, tudo bem. Mas tenho um problema nisso.
Toda a arquitetura do sistema está utilizando o EntityManager que faz todo o controle de requisição com o BD. O escopo dele é de request (e deve ser) quando eu mudo o escopo do ManagedBean para session eu tenho o seguinte erro

[color=red]javax.servlet.ServletException: Não foi possível criar o bean gerenciado consultaBean. Os seguintes problemas foram encontrados:
- O escopo do objeto referido pela expressão #{entityManager}, request, é menor do que o escopo do bean gerenciado referido (consultaBean) de session
javax.faces.webapp.FacesServlet.service(FacesServlet.java:321)
com.prontuario.filter.JPAFilter.doFilter(JPAFilter.java:28)[/color]

Alguém sabe como resolver esse tipo de problema?

Filter que é acionado em todas as requsições com BD

package com.prontuario.filter;

import java.io.IOException;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

public class JPAFilter implements Filter {

	private EntityManagerFactory factory;

	@Override
	public void doFilter(ServletRequest request, ServletResponse response,
			FilterChain chain) throws IOException, ServletException {

		EntityManager entityManager = this.factory.createEntityManager();
		request.setAttribute("entityManager", entityManager);

		entityManager.getTransaction().begin();

		chain.doFilter(request, response);

		try {
			entityManager.getTransaction().commit();
		} catch (Exception e) {
			entityManager.getTransaction().rollback();
			throw new ServletException(e);
		} finally {
			entityManager.close();
		}
	}

	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
		this.factory = Persistence.createEntityManagerFactory("prontuario");
	}

	@Override
	public void destroy() {
		this.factory.close();
	}

}

ManagedBean

    @ManagedBean  
    public class ConsultaBean {  
      
        @ManagedProperty(value = "#{entityManager}")  
        private EntityManager entityManager;  
        private Consulta consulta = new Consulta();  
      
        private List<Consulta> listaConsultas;  
      
          
        public EntityManager getEntityManager() {  
            return entityManager;  
        }  
      
        public void setEntityManager(EntityManager entityManager) {  
            this.entityManager = entityManager;  
        }  
      
      
        public Consulta getConsulta() {  
            return consulta;  
        }  
      
        public void setConsulta(Consulta consulta) {  
            this.consulta = consulta;  
        }  
      
        public List<Consulta> getListaConsultas() {  
            if (listaConsultas == null) {  
                listaConsultas = ServiceFactory.getInstance().getConsultaService().findAll(entityManager);  
            }  
            return listaConsultas;  
        }  
      
      
      
          
        public void salvar() {  
              
            ServiceFactory.getInstance().getConsultaService().insert(entityManager, consulta);  
            consulta = new Consulta();  
            listaConsultas = null;  
        }  
      
        public void remover(Consulta consulta) {  
            ServiceFactory.getInstance().getConsultaService()  
                    .delete(entityManager, consulta);  
            listaConsultas = null;  
        }  
      
    }  

Ninguém nunca teve esse problema ???