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

12 respostas
R

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

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
                                         "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
 <session-factory >
  <property name="hibernate.connection.driver_class">org.postgresql.Driver</property>
  <property name="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</property>
  <property name="connection.datasource">java:/comp/env/jdbc/protocolo</property>
  <property name="current_session_context_class">thread</property>
  <property name="c3p0.min_size">1</property>
  <property name="c3p0.max_size">50</property>
  <property name="c3p0.timeout">300</property>
  <property name="c3p0.max_statements">50</property>
  <property name="c3p0.idle_test_period">3000</property> 
  <property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>
  <property name="hibernate.hbm2ddl.auto">update</property>
  <property name="show_sql">true</property>
  <property name="format_sql">true</property>
  <property name="log4j.logger.org.hibernate.type">DEBUG</property>
  <mapping class="dominio.Usuario"/>
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

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() {}

}

Minha Classe DAOFactory

public class DAOFactory {

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

Minha Classe HibernateUtil

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;
    }

}

Classe UsuarioDAOImpl

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;	
	}

	
}

Mensagem de erro

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

12 Respostas

L

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

R

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();
	}
J

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.

J

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.

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.

J

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.

J

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.
Entendi. Mas nao sao frameworks separados?

J
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

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
                                         "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
 <session-factory >
  <property name="hibernate.connection.driver_class">org.postgresql.Driver</property>
  <property name="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</property>
  <property name="connection.datasource">java:/comp/env/jdbc/protocolo</property>
  <property name="current_session_context_class">thread</property>
  <property name="c3p0.min_size">1</property>
  <property name="c3p0.max_size">50</property>
  <property name="c3p0.timeout">300</property>
  <property name="c3p0.max_statements">50</property>
  <property name="c3p0.idle_test_period">3000</property> 
  <property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>
  <property name="hibernate.hbm2ddl.auto">update</property>
  <property name="show_sql">true</property>
  <property name="format_sql">true</property>
  <property name="log4j.logger.org.hibernate.type">DEBUG</property>
  <mapping class="dominio.Usuario"/>
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

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() {}

}

Minha Classe DAOFactory

public class DAOFactory {

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

Minha Classe HibernateUtil

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;
    }

}

Classe UsuarioDAOImpl

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;	
	}

	
}

Mensagem de erro

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


Onde voce está chamando o close da session do hibernate? É ai que voce deve colocar o breakpoint, provavelmente está num momento cedo.

J

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

R

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.

J

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.

S

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.

R

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); } }

Criado 15 de março de 2013
Ultima resposta 18 de mar. de 2013
Respostas 12
Participantes 5