[RESOLVIDO] Open Session in View com erro de session close

Olá pessoal. Sou iniciante em Java EE e estou tentando implementar o padrão “Open Session in View” - OSV, porem depois de logado no sistema, qualquer operação que tento fazer da mensagem que a sessão esta fechada, o que será que estou fazendo de errado. Utilizo o Spring Security para controle de acesso, mais Hibernate, JSF e Primefaces.

Segue meu hibernate.cfg.xml

[code]

<?xml version="1.0" encoding="UTF-8"?> org.postgresql.Driver org.hibernate.dialect.PostgreSQLDialect java:/comp/env/jdbc/protocolo thread 1 50 300 50 3000 org.hibernate.cache.NoCacheProvider update true true DEBUG [/code]

Meu WEB.XML

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
	id="WebApp_ID" version="3.0">
	
	<display-name>Protocolo</display-name>
	<!-- Spring security -->
	
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>
			/WEB-INF/applicationContext.xml
			/WEB-INF/applicationContext-security.xml
		</param-value>
	</context-param>
	
	<resource-ref>
		<description>DataSource protocolo</description>
		<res-ref-name>jdbc/protocolo</res-ref-name>
		<res-type>javax.sql.DataSource</res-type>
		<res-auth>Container</res-auth>
	</resource-ref>
	
	<resource-ref>
		<description>Mail Session</description>
		<res-ref-name>mail/Session</res-ref-name>
		<res-type>javax.mail.Session</res-type>
		<res-auth>Container</res-auth>
	</resource-ref>
	
	<filter>
		<filter-name>springSecurityFilterChain</filter-name>
		<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
	</filter>
	<filter-mapping>
		<filter-name>springSecurityFilterChain</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>
	
	<filter>
		<filter-name>conexaoFilter</filter-name>
		<filter-class>apresentacao.filter.ConexaoHibernateFilter</filter-class>
	</filter>
	<filter-mapping>
		<filter-name>conexaoFilter</filter-name>
		<url-pattern>/*</url-pattern>		
	</filter-mapping>	
	
	
	<!-- Java server faces -->
	
	<context-param>
		<description>State saving method: 'client' or 'server' (=default). See JSF Specification 2.5.2</description>
		<param-name>javax.faces.STATE_SAVING_METHOD</param-name>
		<param-value>server</param-value>
	</context-param>
	
	
	<!-- Faces servlet -->
	<servlet>
		<servlet-name>Faces Servlet</servlet-name>
		<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
		<load-on-startup>120</load-on-startup>
	</servlet>
	<servlet-mapping>
		<servlet-name>Faces Servlet</servlet-name>
		<url-pattern>/faces/*</url-pattern>
	</servlet-mapping>	
		
	<welcome-file-list>
		<welcome-file>faces/publico/login.xhtml</welcome-file>
	</welcome-file-list>
	
	<session-config>
        <session-timeout>
            30
        </session-timeout>
    </session-config>
    
    <error-page>
    	<exception-type>
       		 javax.servlet.ServletException
    	</exception-type>
   		<location> 
        	/publico/login.xhtml 
    	</location>
	</error-page>
	
	<filter>
		<filter-name>PrimeFaces FileUpload Filter</filter-name>
		<filter-class>org.primefaces.webapp.filter.FileUploadFilter</filter-class>
	</filter>
	<filter-mapping>
		<filter-name>PrimeFaces FileUpload Filter</filter-name>
		<servlet-name>Faces Servlet</servlet-name>
	</filter-mapping>
	<context-param>
		<param-name>primefaces.THEME</param-name>
		<param-value>hot-sneaks</param-value>
	</context-param>
	
	<context-param>
		<param-name>javax.servlet.jsp.jstl.fmt.localizationContext</param-name>
		<param-value>resources.application</param-value>
	</context-param>
	<listener>
		<listener-class>com.sun.faces.config.ConfigureListener</listener-class>
	</listener>
	
</web-app>

Minha classe Filter

[code]
public class ConexaoHibernateFilter implements Filter {

private SessionFactory sf;

public void doFilter(ServletRequest request,
                     ServletResponse response,
                     FilterChain chain)
        throws IOException, ServletException { 
    try {           
        sf.getCurrentSession().beginTransaction(); 
        // Call the next filter (continue request processing)
        chain.doFilter(request, response); 
        // Commit and cleanup           
        sf.getCurrentSession().getTransaction().commit(); 
    } catch (StaleObjectStateException staleEx) {  
    	staleEx.printStackTrace();
        throw staleEx;
    } catch (Throwable ex) {
        // Rollback only
        ex.printStackTrace();
        try {
            if (sf.getCurrentSession().getTransaction().isActive()) {
                sf.getCurrentSession().getTransaction().rollback();
            }
        } catch (Throwable rbEx) {
           rbEx.printStackTrace();
        } 
        // Let others handle it... maybe another interceptor for exceptions?
        throw new ServletException(ex);
    }
}

public void init(FilterConfig filterConfig) throws ServletException {
    sf = HibernateUtil.getSessionFactory();
}

public void destroy() {}

}[/code]

Minha Classe DAOFactory

public class DAOFactory {

	public static UsuarioDAO criarUsuarioDAO() {
		UsuarioDAOImpl usuarioDAO = new UsuarioDAOImpl();
		usuarioDAO.setSession(HibernateUtil.getSessionFactory().getCurrentSession());
		return usuarioDAO;
	}

Minha Classe HibernateUtil

[code]

public class HibernateUtil {

private static final SessionFactory sessionFactory = buildSessionFactory();

private static SessionFactory buildSessionFactory() {
    try {
        // Create the SessionFactory from hibernate.cfg.xml
        return new Configuration().configure().buildSessionFactory();
    }
    catch (Throwable ex) {
        // Make sure you log the exception, as it might be swallowed
        System.err.println("Initial SessionFactory creation failed." + ex);
        throw new ExceptionInInitializerError(ex);
    }
}

public static SessionFactory getSessionFactory() {
    return sessionFactory;
}

}[/code]

Classe UsuarioDAOImpl

[code]
public class UsuarioDAOImpl implements UsuarioDAO {

private Session	session;

public void setSession(Session session) {
	this.session = session;
}


@Override
public void salvar(Usuario usuario) {
	this.session.saveOrUpdate(usuario);
	
}

@Override
public void excluir(Usuario usuario) {
	this.session.delete(usuario);
	
}

@Override
public Usuario carregar(Integer conta) {
	return (Usuario) this.session.get(Usuario.class, conta);
}

@SuppressWarnings("unchecked")
@Override
public List<Usuario> listar() {
	Criteria criteria = this.session.createCriteria(Usuario.class);
	return criteria.list();
}

public Usuario buscarPorLogin(String login){	
	System.out.println(login);
	if(this.session==null)
		System.out.println("tava vazio");
	Criteria criteria = this.session.createCriteria(Usuario.class);
	criteria.add(Restrictions.eq("login", login));
	Usuario us = new Usuario();
	us = (Usuario) criteria.uniqueResult();
	System.out.println(us.getNome() +"  -   "+ us.getSenha());
	return 	us;	
}

}[/code]

Mensagem de erro

Caused by: org.hibernate.SessionException: Session is closed!

Onde dá esse erro de session close ?
Após a transação ?

Esse erro acontece sempre nos DAOImpl quando vai executar qualquer metodo que utiliza a session, depois de eu já estar logado no sistema. Interessante porque quando faz o login, eu consulto os dados do usuario no banco tudo sem problema, depois disso qualquer, processo que eu solicite da essa mensagem, neste caso foi aqui:

public List<Usuario> listar() {
		Criteria criteria = this.session.createCriteria(Usuario.class);
		return criteria.list();
	}

Pra que reinventar a roda fazendo filtro pra controlar a Session do Hibernate você já ta usando Spring não tah…
pois eh ele já tem um filtro que faz isso é só dar uma pesquisada.
http://www.guj.com.br/java/233706-opensessioninview-do-spring-resolvido
http://blog.smartkey.co.uk/2010/03/open-session-in-view-pattern-spring-jpa/
http://static.springsource.org/spring/docs/2.5.x/api/org/springframework/orm/hibernate3/support/OpenSessionInViewFilter.html
Outra forma seria usando o controle transacional do Spring.

[quote=jweibe]Pra que reinventar a roda fazendo filtro pra controlar a Session do Hibernate você já ta usando Spring não tah…
pois eh ele já tem um filtro que faz isso é só dar uma pesquisada.
http://www.guj.com.br/java/233706-opensessioninview-do-spring-resolvido
http://blog.smartkey.co.uk/2010/03/open-session-in-view-pattern-spring-jpa/
http://static.springsource.org/spring/docs/2.5.x/api/org/springframework/orm/hibernate3/support/OpenSessionInViewFilter.html
Outra forma seria usando o controle transacional do Spring.[/quote]
Isso nao significa reinventar a roda, significa ter mais controle, é um trabalho que é feito uma vez só para infra, ninguem é obrigado a usar spring pra gerenciar essas coisas triviais.

Acho que você não entendeu minha colocação… primeiro eu não disse que o cara eh obrigado a usar Spring para fazer tal gerenciamento, mais observando o web.xml que ele postou
pode-se observar que ele já esta usando Spring, uma vez que o Spring já tem este recurso acho que não tem justificativa criar um Filtro para fazer a mesma coisa, salve exceção se ele
deseja fazer algo mais neste filtro.

Acho que você não entendeu minha colocação… primeiro eu não disse que o cara eh obrigado a usar Spring para fazer tal gerenciamento, mais observando o web.xml que ele postou
pode-se observar que ele já esta usando Spring, uma vez que o Spring já tem este recurso acho que não tem justificativa criar um Filtro para fazer a mesma coisa, salve exceção se ele
deseja fazer algo mais neste filtro.[/quote]
Entendi. Mas nao sao frameworks separados?

[quote=reisah]Olá pessoal. Sou iniciante em Java EE e estou tentando implementar o padrão “Open Session in View” - OSV, porem depois de logado no sistema, qualquer operação que tento fazer da mensagem que a sessão esta fechada, o que será que estou fazendo de errado. Utilizo o Spring Security para controle de acesso, mais Hibernate, JSF e Primefaces.

Segue meu hibernate.cfg.xml

[code]

<?xml version="1.0" encoding="UTF-8"?> org.postgresql.Driver org.hibernate.dialect.PostgreSQLDialect java:/comp/env/jdbc/protocolo thread 1 50 300 50 3000 org.hibernate.cache.NoCacheProvider update true true DEBUG [/code]

Meu WEB.XML

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
	id="WebApp_ID" version="3.0">
	
	<display-name>Protocolo</display-name>
	<!-- Spring security -->
	
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>
			/WEB-INF/applicationContext.xml
			/WEB-INF/applicationContext-security.xml
		</param-value>
	</context-param>
	
	<resource-ref>
		<description>DataSource protocolo</description>
		<res-ref-name>jdbc/protocolo</res-ref-name>
		<res-type>javax.sql.DataSource</res-type>
		<res-auth>Container</res-auth>
	</resource-ref>
	
	<resource-ref>
		<description>Mail Session</description>
		<res-ref-name>mail/Session</res-ref-name>
		<res-type>javax.mail.Session</res-type>
		<res-auth>Container</res-auth>
	</resource-ref>
	
	<filter>
		<filter-name>springSecurityFilterChain</filter-name>
		<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
	</filter>
	<filter-mapping>
		<filter-name>springSecurityFilterChain</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>
	
	<filter>
		<filter-name>conexaoFilter</filter-name>
		<filter-class>apresentacao.filter.ConexaoHibernateFilter</filter-class>
	</filter>
	<filter-mapping>
		<filter-name>conexaoFilter</filter-name>
		<url-pattern>/*</url-pattern>		
	</filter-mapping>	
	
	
	<!-- Java server faces -->
	
	<context-param>
		<description>State saving method: 'client' or 'server' (=default). See JSF Specification 2.5.2</description>
		<param-name>javax.faces.STATE_SAVING_METHOD</param-name>
		<param-value>server</param-value>
	</context-param>
	
	
	<!-- Faces servlet -->
	<servlet>
		<servlet-name>Faces Servlet</servlet-name>
		<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
		<load-on-startup>120</load-on-startup>
	</servlet>
	<servlet-mapping>
		<servlet-name>Faces Servlet</servlet-name>
		<url-pattern>/faces/*</url-pattern>
	</servlet-mapping>	
		
	<welcome-file-list>
		<welcome-file>faces/publico/login.xhtml</welcome-file>
	</welcome-file-list>
	
	<session-config>
        <session-timeout>
            30
        </session-timeout>
    </session-config>
    
    <error-page>
    	<exception-type>
       		 javax.servlet.ServletException
    	</exception-type>
   		<location> 
        	/publico/login.xhtml 
    	</location>
	</error-page>
	
	<filter>
		<filter-name>PrimeFaces FileUpload Filter</filter-name>
		<filter-class>org.primefaces.webapp.filter.FileUploadFilter</filter-class>
	</filter>
	<filter-mapping>
		<filter-name>PrimeFaces FileUpload Filter</filter-name>
		<servlet-name>Faces Servlet</servlet-name>
	</filter-mapping>
	<context-param>
		<param-name>primefaces.THEME</param-name>
		<param-value>hot-sneaks</param-value>
	</context-param>
	
	<context-param>
		<param-name>javax.servlet.jsp.jstl.fmt.localizationContext</param-name>
		<param-value>resources.application</param-value>
	</context-param>
	<listener>
		<listener-class>com.sun.faces.config.ConfigureListener</listener-class>
	</listener>
	
</web-app>

Minha classe Filter

[code]
public class ConexaoHibernateFilter implements Filter {

private SessionFactory sf;

public void doFilter(ServletRequest request,
                     ServletResponse response,
                     FilterChain chain)
        throws IOException, ServletException { 
    try {           
        sf.getCurrentSession().beginTransaction(); 
        // Call the next filter (continue request processing)
        chain.doFilter(request, response); 
        // Commit and cleanup           
        sf.getCurrentSession().getTransaction().commit(); 
    } catch (StaleObjectStateException staleEx) {  
    	staleEx.printStackTrace();
        throw staleEx;
    } catch (Throwable ex) {
        // Rollback only
        ex.printStackTrace();
        try {
            if (sf.getCurrentSession().getTransaction().isActive()) {
                sf.getCurrentSession().getTransaction().rollback();
            }
        } catch (Throwable rbEx) {
           rbEx.printStackTrace();
        } 
        // Let others handle it... maybe another interceptor for exceptions?
        throw new ServletException(ex);
    }
}

public void init(FilterConfig filterConfig) throws ServletException {
    sf = HibernateUtil.getSessionFactory();
}

public void destroy() {}

}[/code]

Minha Classe DAOFactory

public class DAOFactory {

	public static UsuarioDAO criarUsuarioDAO() {
		UsuarioDAOImpl usuarioDAO = new UsuarioDAOImpl();
		usuarioDAO.setSession(HibernateUtil.getSessionFactory().getCurrentSession());
		return usuarioDAO;
	}

Minha Classe HibernateUtil

[code]

public class HibernateUtil {

private static final SessionFactory sessionFactory = buildSessionFactory();

private static SessionFactory buildSessionFactory() {
    try {
        // Create the SessionFactory from hibernate.cfg.xml
        return new Configuration().configure().buildSessionFactory();
    }
    catch (Throwable ex) {
        // Make sure you log the exception, as it might be swallowed
        System.err.println("Initial SessionFactory creation failed." + ex);
        throw new ExceptionInInitializerError(ex);
    }
}

public static SessionFactory getSessionFactory() {
    return sessionFactory;
}

}[/code]

Classe UsuarioDAOImpl

[code]
public class UsuarioDAOImpl implements UsuarioDAO {

private Session	session;

public void setSession(Session session) {
	this.session = session;
}


@Override
public void salvar(Usuario usuario) {
	this.session.saveOrUpdate(usuario);
	
}

@Override
public void excluir(Usuario usuario) {
	this.session.delete(usuario);
	
}

@Override
public Usuario carregar(Integer conta) {
	return (Usuario) this.session.get(Usuario.class, conta);
}

@SuppressWarnings("unchecked")
@Override
public List<Usuario> listar() {
	Criteria criteria = this.session.createCriteria(Usuario.class);
	return criteria.list();
}

public Usuario buscarPorLogin(String login){	
	System.out.println(login);
	if(this.session==null)
		System.out.println("tava vazio");
	Criteria criteria = this.session.createCriteria(Usuario.class);
	criteria.add(Restrictions.eq("login", login));
	Usuario us = new Usuario();
	us = (Usuario) criteria.uniqueResult();
	System.out.println(us.getNome() +"  -   "+ us.getSenha());
	return 	us;	
}

}[/code]

Mensagem de erro

Caused by: org.hibernate.SessionException: Session is closed![/quote]
Onde voce está chamando o close da session do hibernate? É ai que voce deve colocar o breakpoint, provavelmente está num momento cedo.

Aqui tem um exemplo bem abrangente pra servir de referencia: https://community.jboss.org/wiki/OpenSessionInView

Javaflex, na verdade eu já estou utilizando esta referencia da jboss community, inclusive o hibernateFilter é de lá e não tem o session.close(). Na verdade esta aplicação precisa entrar em produção o mais breve possível, então gostaria de resolver o problema da forma como esta usando a classe filter e depois eu vou pesquisar e quem sabe muda-la para Spring, como o jweibe falou.

O Filter que voce postou nao está tratando o Close da session entao nao sei onde voce está fechando a conexao. O da referencia que passei está chamando o Close, e no momento certo para o desejado. Entao pelo que apresentou nao está controlando o Close somente da mesma forma que o exemplo chama, pode estar em algum lugar ou fechando indiretamente por alguem. Sobre Spring pra controlar conexao nao posso ajudar pois nao uso.

Cara uso esse padrão, mais controlo a abertura e o fechamento usando um PhaseListener, na fase 1 recupero uma sessão do hibernate e jogo como um atributo na minha sessão e na fase 6 fecho essa sessão do hibernate e tiro da minha sessão http, fica a dica.

Pessoal, obrigado pela ajuda até aqui, consegui fazer os commit através do filter, porem minhas transações ainda estão no banco postgres como IDLE, a cada transação nova, cria mais uma query no banco com este estado até que a aplicação chega no limite e para ficando inacessível. Segue meu filter como esta agora, sei que ele é chamado a cada transação e é feito o commit, então agora não sei porque estas query ficam neste estado no banco.

@Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException { try { this.sf.getCurrentSession().beginTransaction(); chain.doFilter(servletRequest, servletResponse); this.sf.getCurrentSession().getTransaction().commit(); this.sf.getCurrentSession().close(); } catch (Throwable ex) { try { if (this.sf.getCurrentSession().getTransaction().isActive()) { this.sf.getCurrentSession().getTransaction().rollback(); } } catch (Throwable t) { t.printStackTrace(); } throw new ServletException(ex); } }