Como utilizar OpenSessionInViewFilter

Olá,
estou utilizando os seguintes frameworks em um projeto web:

  • Spring 1.2.6
  • Hibernate 3.1
  • JSF 1.1
  • TomCat 5.5
  • Java 5

Eu tentei configurar o filtro OpenSessionInViewFilter para acessar meus TOs em meus Managed Beans (JSF) utilizando lazy-load, mas eu devo ter cometido algum equivoco, pois quando tento acessar, vejo o famoso erro:

org.hibernate.LazyInitializationException: could not initialize proxy - the owning Session was closed

Acredito que eu devo ter cometido algum engano na configuração do filtro. Vejam como eu configurei meus arquivos xml:

<?xml version="1.0"?>
<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
 <display-name>PauliWeb</display-name>

 <context-param>
  <param-name>javax.faces.STATE_SAVING_METHOD</param-name>
  <param-value>server</param-value>
 </context-param>

  <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/classes/boContext.xml,/WEB-INF/classes/daoContext.xml,/WEB-INF/classes/dataSource.xml,/WEB-INF/classes/hibernateProperties.xml,/WEB-INF/classes/servicesContext.xml,/WEB-INF/classes/transactionContext.xml</param-value>
  </context-param>
 
 <filter>
  <display-name>Ajax4jsf Filter</display-name>
  <filter-name>ajax4jsf</filter-name>
  <filter-class>org.ajax4jsf.Filter</filter-class>
 </filter>
 <filter-mapping>
  <filter-name>ajax4jsf</filter-name>
  <servlet-name>Faces Servlet</servlet-name>
  <dispatcher>REQUEST</dispatcher>
  <dispatcher>FORWARD</dispatcher>
  <dispatcher>INCLUDE</dispatcher>
 </filter-mapping>
 <listener>
  <listener-class>com.sun.faces.config.ConfigureListener</listener-class>
 </listener>
 
  <filter>
	  <filter-name>sessionFilter</filter-name>
	  <filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
  </filter>
	        
  <filter-mapping>
	  <filter-name>sessionFilter</filter-name>
	  <url-pattern>*.jsf</url-pattern>
  </filter-mapping>
  <filter-mapping>
	  <filter-name>sessionFilter</filter-name>
	  <url-pattern>*.jsp</url-pattern>
  </filter-mapping>
  <listener>
      <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>	
  
 <!-- Faces Servlet -->
 <servlet>
  <servlet-name>Faces Servlet</servlet-name>
  <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
  <load-on-startup>1</load-on-startup>
 </servlet>
 
	<!--  usado pelo inputFileUpload (MyFaces JSF Component) -->
	<filter>
	    <filter-name>ExtensionsFilter</filter-name>
	    <filter-class>
	        org.apache.myfaces.component.html.util.ExtensionsFilter
	    </filter-class>
	    <init-param>
	        <param-name>uploadMaxFileSize</param-name>
	        <param-value>10m</param-value>
	    </init-param>
	    <init-param>
	        <param-name>uploadThresholdSize</param-name>
	        <param-value>500k</param-value>
	    </init-param>
	</filter>
	
	<filter-mapping>
	    <filter-name>ExtensionsFilter</filter-name>
	    <servlet-name>Faces Servlet</servlet-name>
	</filter-mapping> 
 
 
 <!-- Faces Servlet Mapping -->
 <servlet-mapping>
  <servlet-name>Faces Servlet</servlet-name>
  <url-pattern>*.jsf</url-pattern>
 </servlet-mapping>

 <login-config>
  <auth-method>BASIC</auth-method>
 </login-config>
</web-app>

Acredito que nao preciso incluir todos os meus arquivos XML, visto que eles sao apenas mapeamentos de meus beans. Vou dar prioridade para o s relacionados a persistencia:

hibernateProperties.xml (fragmento)

	<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
	
		<property name="dataSource">
			<ref bean="dataSource" />
		</property>

		<property name="mappingResources">
			<list>
			 ...
                         </list>
		</property>

		<property name="hibernateProperties">
			<ref local="hibernateProperties"/>
		</property>
	</bean>

       ...

    <!-- This is the base definition for all Hibernate based DAOs -->
    <bean id="hibernateDaoSupport" 
          class="org.springframework.orm.hibernate3.support.HibernateDaoSupport"
          abstract="true">
        <property name="sessionFactory">
            <ref bean="sessionFactory"/>
        </property>
    </bean>

daoContext.xml (fragmento)

	<bean id="productDAO" class="br.com.nonono.dao.impl.ProductDAOHibernateImpl"
		parent="hibernateDaoSupport">
		<property name="sessionFactory">
			<ref bean="sessionFactory" />
		</property>
	</bean>

transactionContext.xml

	<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager" >
		<property name="sessionFactory">
			<ref bean="sessionFactory" />
		</property>	
	</bean>

    <!-- This is the base transaction proxy factory bean, all transactional managers 
         use this bean definition. -->
    <bean id="txProxyTemplate" abstract="true"
        class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
        <property name="transactionManager">
            <ref bean="transactionManager"/>
        </property>
        <property name="transactionAttributes">
            <props>
                <prop key="save*">PROPAGATION_REQUIRED</prop>
                <prop key="store*">PROPAGATION_REQUIRED</prop>
                <prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>
                <prop key="read*">PROPAGATION_REQUIRED,readOnly</prop>
                <prop key="load*">PROPAGATION_REQUIRED,readOnly</prop>
                <prop key="find*">PROPAGATION_REQUIRED,readOnly</prop>                
                <prop key="*">PROPAGATION_REQUIRED</prop>
            </props>
        </property>

        <property name="preInterceptors">
            <list>

            </list>
        </property>

        <property name="postInterceptors">
            <list>

            </list>
        </property>
    </bean>

enfim, serviceContext.xml (fragmento)

    <bean id="pauliWebServices" parent="txProxyTemplate">
    	<property name="proxyInterfaces">
    		<value>br.com.nonono.services.PauliWebServices</value>
    	</property>
        <property name="target">
           <bean class="br.com.nonono.services.impl.PauliWebServicesImpl">
			  <property name="productBO">
			   <ref bean="productBO"/>
			  </property>
           </bean>
        </property>
    </bean> 

Meus DAOs todos herdam de HibernateDaoSupport e utilizam getHibernateTemplate().

Acredito que eu deva ter feito alguma configuracao errada no Filtro. Quando eu executo o codigo abaixo no meu Managed bean, ocorre o erro:

		Product prod = services.findProductById(87);
		
		prod.getImage();

O log da aplicacao eh:

75500 [http-8080-Processor24] DEBUG org.springframework.orm.hibernate3.HibernateTransactionManager  - Closing Hibernate Session [org.hibernate.impl.SessionImpl@103c520] after transaction
75500 [http-8080-Processor24] DEBUG org.springframework.orm.hibernate3.SessionFactoryUtils  - Closing Hibernate Session
75500 [http-8080-Processor24] DEBUG org.hibernate.impl.SessionImpl  - closing session
75500 [http-8080-Processor24] DEBUG org.hibernate.jdbc.ConnectionManager  - performing cleanup
75500 [http-8080-Processor24] DEBUG org.hibernate.jdbc.ConnectionManager  - closing JDBC connection [ (open PreparedStatements: 0, globally: 0) (open ResultSets: 0, globally: 0)]
75515 [http-8080-Processor24] DEBUG org.hibernate.jdbc.JDBCContext  - after transaction completion
75515 [http-8080-Processor24] DEBUG org.hibernate.jdbc.ConnectionManager  - transaction completed on session with on_close connection release mode; be sure to close the session to release JDBC resources!
75515 [http-8080-Processor24] DEBUG org.hibernate.impl.SessionImpl  - after transaction completion
78031 [http-8080-Processor24] ERROR org.hibernate.LazyInitializationException  - could not initialize proxy - the owning Session was closed
org.hibernate.LazyInitializationException: could not initialize proxy - the owning Session was closed
	at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:56)
	at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:98)
	at org.hibernate.proxy.CGLIBLazyInitializer.intercept(CGLIBLazyInitializer.java:158)
	at br.com.nonono.to.Image$$EnhancerByCGLIB$$bd4cc5a7_2.getImage(<generated>)
	at br.com.nonono.jsf.visualizarproduto.VisualizarProduto.doComprar(VisualizarProduto.java:37)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
	at java.lang.reflect.Method.invoke(Unknown Source)
	at com.sun.faces.el.MethodBindingImpl.invoke(MethodBindingImpl.java:126)
	at com.sun.faces.application.ActionListenerImpl.processAction(ActionListenerImpl.java:72)
	at javax.faces.component.UICommand.broadcast(UICommand.java:312)
	at org.ajax4jsf.framework.ajax.AjaxViewRoot.processEvents(AjaxViewRoot.java:281)
	at org.ajax4jsf.framework.ajax.AjaxViewRoot.broadcastEvents(AjaxViewRoot.java:257)
	at org.ajax4jsf.framework.ajax.AjaxViewRoot.processApplication(AjaxViewRoot.java:412)
	at com.sun.faces.lifecycle.InvokeApplicationPhase.execute(InvokeApplicationPhase.java:75)
	at com.sun.faces.lifecycle.LifecycleImpl.phase(LifecycleImpl.java:200)
	at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:90)
	at javax.faces.webapp.FacesServlet.service(FacesServlet.java:197)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:252)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:173)
	at org.apache.myfaces.webapp.filter.ExtensionsFilter.doFilter(ExtensionsFilter.java:144)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:202)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:173)
	at org.ajax4jsf.framework.ajax.xmlfilter.BaseXMLFilter.doXmlFilter(BaseXMLFilter.java:65)
	at org.ajax4jsf.framework.ajax.xmlfilter.BaseFilter.doFilter(BaseFilter.java:226)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:202)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:173)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:71)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:202)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:173)
	at org.springframework.orm.hibernate3.support.OpenSessionInViewFilter.doFilterInternal(OpenSessionInViewFilter.java:174)
	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:202)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:173)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:213)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:178)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:126)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:105)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:107)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:148)
	at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:869)
	at org.apache.coyote.http11.Http11BaseProtocol$Http11ConnectionHandler.processConnection(Http11BaseProtocol.java:664)
	at org.apache.tomcat.util.net.PoolTcpEndpoint.processSocket(PoolTcpEndpoint.java:527)
	at org.apache.tomcat.util.net.LeaderFollowerWorkerThread.runIt(LeaderFollowerWorkerThread.java:80)
	at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:684)
	at java.lang.Thread.run(Unknown Source)

Percebi que quando eu carrego a pagina, aparece no log a mensagem:

org.springframework.orm.hibernate3.support.OpenSessionInViewFilter  - Opening single Hibernate Session in OpenSessionInViewFilter

e, quando a pagina é carregada, aparece tbm:

org.springframework.orm.hibernate3.support.OpenSessionInViewFilter  - Closing single Hibernate Session in OpenSessionInViewFilter

Porem, quando eu clico no <h:commandButtom> para que ele invoque a action do meu managed bean (veja log acima), o filtro aparentemente nao é invocado.

O que será que está errado na minha configuracao? Alguem consegue ver onde eu me equivoquei?

Agradeco qquer ajuda.

  • informacoes:

Retirei os outros filtros que existiam - Ajax4jsf e ExtensionsFilter (myFaces) e o erro continua ocorrendo.

Perceba que o log informa que o transactionManager fecha a conexao assim que o services finaliza sua execucao:

DEBUG org.springframework.orm.hibernate3.HibernateTransactionManager  - Closing Hibernate Session [org.hibernate.impl.SessionImpl@a33ce2] after transaction
DEBUG org.springframework.orm.hibernate3.SessionFactoryUtils  - Closing Hibernate Session
DEBUG org.hibernate.impl.SessionImpl  - closing session

Será que é por isso que no managed bean o erro ocorre? Por estarem na mesma requisicao, a conexao nao deveria continuar aberta e ser fechada pelo filtro apenas no final da mesma?

Já pesquisei bastante na web, e encontrei outros desenvolvedores com problemas por existirem 2 contextos com sessoes e sessionFactories diferentes… mas isso ocorria no Struts, e eu estou usando JSF.

Tenho certeza que estou cometendo algum equívoco, mas nao sei onde :frowning:

Obrigado

achei um pouco estranho o teu mapeamento do spring. O erro pode estar aí.

Não há necessidade de mapear o hibernateDaoSpuport.
Faça teu DAO extender a HibernateDaoSupport e injete o sessionFactory.

<bean id="productDAO" class="br.com.nonono.dao.impl.ProductDAOHibernateImpl">
 	<property name="sessionFactory">
 		<ref bean="sessionFactory" />
 	</property>
</bean>

tua classe DAO

public class ProductDAOHibernateImpl extends HibernateDaoSupport{
}

Talvez o erro não esteja aí, porém é uma forma mais correta e elegante de se mapear os DAO’s.

T+

Ola Marcelo, obrigado pelo seu comentário.

Originalmente meu mapeamento estava conforme sua indicacao, mas como o erro ocorria realizei essa alteracao, seguindo um artigo que achei no ArcMind.

http://www.thearcmind.com/confluence/display/SpribernateSF/Configuring+Hibernate%2C+Spring%2C+OpenInSessionViewFilter+and+MyFaces+JSF?showComments=true#comments

Realizei a modificacao sugerida por voce, mas o erro continua ocorrendo.

Onde será que estou errando? :frowning:

engraçado… segundo o log que vc mostrou, a requisição passou pelo filtro.

Não conheço o jsf, me explique pq você aplicou o filtro nas páginas jsp tb?
Esse .jsf seria o mesmo que o .do do struts?
Se for aplique o filtro somente nele, retire o filtro das jsp.

Hey amigo, tive um problema similar com esse filtro, quando usava o template do Spring e o método merge().

Altere primeiramente o código para o modo anterior, estendendo a classe HibernateDAOSupport e usando o template.

Deixei um código nessa thread - http://www.guj.com.br/posts/list/41629.java , onde alterei uma configuração do OpenSession, e no meu caso funcionou.

Tenta, se der certo, poste pra eu saber :slight_smile:

Oi Marcelo, obrigado novamente pela sua ajuda!

Eu apliquei o filtro erroneamente nas paginas jsp. :oops: Realmente a necessidade existe apenas em aplicá-lo para paginas jsf.

Respondendo sua pergunta: Sim, o .jsf eh para o JSF o mesmo que o .do é para o Struts.

E sobre o log, eu percebi que quando entro na pagina jsf pela url, o filtro é aplicado. Mas, quando clico no botao que dispara a action JSF, o filtro aparentemente nao eh aplicado, pois nao aparece no log a informacao de que ele abriu uma sessao.

Alterei o web.xml, deixando apenas o filtro para paginas jsf, mas o erro persiste :frowning:

Onde será que está o erro? Já pesquisei bastante na web, mas nao encontrei nada diferente daquilo que estou usando.

Obrigado pela ajuda

Ola Kenobi, obrigado pelo seu comentario.

Eu tinha visto a thread que vc mencionou, mas como o meu problema ocorre em uma simples consulta (assim como o da thread citada), acreditei que sua solucao nao se aplicava.

Vou realizar as alteracoes por ti descritas, e postarei se obtive sucesso ou nao… tomara que funcione :slight_smile:

Valeu pessoal, a ajuda de voces está sendo muito bem vinda.

Obrigado

engraçado…

como vc está chamando a action por um botão? vc está usando AJAX? é para dar o post em um form?

Kenobi,
tentei utilizar a implementacao que vc sugeriu mas ela nao funcionou tambem :frowning:

Nao sei se eu fiz corretamente. Vejam como ficou meu arquivo web.xml:

<?xml version="1.0"?>
<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
 <display-name>PauliWeb</display-name>

 <context-param>
  <param-name>javax.faces.STATE_SAVING_METHOD</param-name>
  <param-value>server</param-value>
 </context-param>

  <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/classes/boContext.xml,/WEB-INF/classes/daoContext.xml,/WEB-INF/classes/dataSource.xml,/WEB-INF/classes/hibernateProperties.xml,/WEB-INF/classes/servicesContext.xml,/WEB-INF/classes/transactionContext.xml</param-value>
  </context-param>
 
 
 	<filter>
 		<filter-name>AutoFlushOpenSessionInViewFilter</filter-name>
 		<filter-class>br.com.nonono.spring.hibernate.support.AutoFlushOpenSessionInViewFilter</filter-class>
 		<init-param>
 			<param-name>singleSession</param-name>
 			<param-value>true</param-value>
 		</init-param>
 	</filter>
 	<filter-mapping>
 		<filter-name>AutoFlushOpenSessionInViewFilter</filter-name>
 		<servlet-name>springapp</servlet-name>
 	</filter-mapping> 
	  <filter-mapping>
		  <filter-name>AutoFlushOpenSessionInViewFilter</filter-name>
		  <url-pattern>*.jsf</url-pattern>
	  </filter-mapping>   
	  
  <listener>
      <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>	  
 <!-- Faces Servlet -->
 <servlet>
  <servlet-name>Faces Servlet</servlet-name>
  <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
  <load-on-startup>1</load-on-startup>
 </servlet>
 
 <!-- Faces Servlet Mapping -->
 <servlet-mapping>
  <servlet-name>Faces Servlet</servlet-name>
  <url-pattern>*.jsf</url-pattern>
 </servlet-mapping>

 <login-config>
  <auth-method>BASIC</auth-method>
 </login-config>
</web-app>

e o codigo do filter:

public class AutoFlushOpenSessionInViewFilter extends OpenSessionInViewFilter {

 	/**
 	 * Busca uma Session do Hibernate e aplica flush mode para auto.
 	 * @param sessionFactory a SessionFactory
 	 * @return the Session para utilizar
 	 * @throws DataAccessResourceFailureException se sessão não for criada
 	 * @see org.springframework.orm.hibernate3.SessionFactoryUtils#getSession(SessionFactory, boolean)
 	 * @see org.hibernate.FlushMode#AUTO
 	 */
 	protected Session getSession(SessionFactory sessionFactory) throws DataAccessResourceFailureException {
 		Session session = SessionFactoryUtils.getSession(sessionFactory, true);
 		session.setFlushMode(FlushMode.AUTO);
 		return session;
 	}

}

Depurando, percebi que o metodo AutoFlushOpenSessionInViewFilter.getSession eh invocado corretamente no inicio do request, mas a sessão continua sendo fechada antes da requisicao acabar. Ou seja, quando eu executo o seguinte codigo no meu Managed Bean, a sessao acaba:

Product prod = services.findProductById(87);

//aqui a sessao está sendo finalizada (org.hibernate.impl.SessionImpl  - closing session)
		
//na linha abaixo, ocorre o famoso LazyInitializationException		
prod.getImage();

Estou ficando aflito… onde será que estou errando?

Obrigado

Marcelo,
estou utilizando um <h:commandButton>, que é um componente JSF. Este componente realiza o submit da pagina.

Minha pagina jsf está assim:

<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<meta http-equiv="Pragma" content="no-cache">
</head>
<body>

<f:view>
	<h:form>
	
		<h:commandButton action="#{visualizarProduto.doComprar}" value="comprar" />
	
	</h:form>
</f:view>			

</body>
</html>		

E meu managed bean está assim:

public class VisualizarProduto extends ManagedBeanBase {

	PauliWebServices services = (PauliWebServices) ApplicationContextUtility.getBean("pauliWebServices");
	public String doComprar() {
		
		Product prod = services.findProductById(87);
		
		prod.getImage();
		
		return null;
	}
}

A configuracao desse managed bean no faces-config.xml foi feita assim:

 <managed-bean>
  <managed-bean-name>visualizarProduto</managed-bean-name>
  <managed-bean-class>br.com.nonono.jsf.visualizarproduto.VisualizarProduto</managed-bean-class>
  <managed-bean-scope>request</managed-bean-scope>
 </managed-bean>

Acredito que esteja tudo correto com as configuracoes acima exibidas.

Como dito no post anterior, o log está informando que a sessao está sendo finalizada assim que o services finalizada sua execucao… o que é estranho para mim, pois tinha entendido que o filtro OpenSessionInViewFilter deveria manter a conexao aberta até o final da requisicao.

Acredito que eu esteja errando em algum ponto, mas nao sei em qual…

Amigos, alguma sugestao?

Obrigado a todos pela ajuda