Problema com cache de objeto serializado - Aplicação VRaptor?

Lucas, é isso mesmo, objetos (beans) com escopo de sessão não conseguem relacionar-se apenas de forma “tardia” por falta de sessão, não só na view (jsp) mas do lado do servidor também, quando requisitados.
Tem idéia de como posso fazer com que estes objetos continuem usando anotações em seus relacionamentos?

você pode fazer duas coisas: ou iniciar as coleções lazy do objeto na hora de colocá-lo no UsuarioScoped, ou a cada requisição recarregar o objeto no UsuarioScoped.

Olá Lucas, a infra para o sistema quanto a sessões ficou assim:

Me desfiz da SSessionS que tinha dois S’s como significado StaticSession’s e movi o método current para a SessionS.

Esta útima, recebe por injeção duas factorys (mysql, oracle), cria conexões e entrega conexões de duas formas:

  • Estática. Agora está nela o método “current” que captura a corrente instancia de SessionS. (usada em DAO’s e Schedules)

  • Injetada. Via construtor, distribuindo a conexão entre os métodos da classe. Geralmente Dao’s.

A resaponsabilidade da gestão das sessões ficará por conta do VRaptor mantendo presente o método (fecharTudo()) com a anotação @PostConstruct.

SessionS:

@Component  
public class SessionS{  
	
    private Session mysqlSession;
    private Session oracleSession;
    
    public SessionS(MysqlSessionFactory mysqlSessionFactory, OracleSessionFactory oracleSessionFactory) {
    	
         this.mysqlSession = mysqlSessionFactory.getInstance().openSession();
         
         this.oracleSession = oracleSessionFactory.getInstance().openSession();
         
    }
    
    public Session mysqlSession() {  
        return mysqlSession;
    }  
      
    public Session oracleSession() {
        return oracleSession;
    }  
    
	public static SessionS current() {
	    return  (SessionS) VRaptorRequestHolder.currentRequest().getRequest().getAttribute("sessionS");
	}

    @PreDestroy
    public void closeSessionS() {
        mysqlSession.close();
        oracleSession.close();
    }
    
}

Exemplos de chamadas:



// DAO's

@Component
public class SiteActionDAO {

	private final SessionS sessionS;
	private final SiteControllerDAO siteControllerDAO;

	public SiteActionDAO(SessionS sessionS, SiteControllerDAO siteControllerDAO) {
		this.sessionS = sessionS;
		this.siteControllerDAO = siteControllerDAO;
	}

// ....

}

// em beans

@Table(name="EMPRESAS_DIVISOES", schema="NBS")
@Entity
@IdClass(DivisaoPK.class)
public class Divisao implements Serializable{

//...

	@SuppressWarnings("unchecked")
	public Collection<DivisaoEpico> getDivisaoEpico() {
		
		return SessionS.current().mysqlSession().createCriteria(DivisaoEpico.class)
		  .add(Restrictions.eq("cod_empresa", this.cod_empresa))
		  .add(Restrictions.eq("cod_empresa_departamento", this.cod_empresa_departamento))
		  .list();
		
	}

// ....

}

Para re-vincular/entregar/devolver aos objetos de escopo de sessão abertas conexões criei um interceptor.


/**
 * @author davi.feo
 * VIDE: http://www.guj.com.br/java/255618-problema-com-cache-de-objeto-serializado---aplicacao-vraptor-/2
 * Atualiza objetos persistentes pertencentes a objetos @SessionScoped
 */
@Intercepts
@RequestScoped
public class AdmScope implements Interceptor{

	public AdmScope(SessionS sessionS, UsuarioScoped usuarioScoped) {
		
		if(usuarioScoped != null && usuarioScoped.getUsuarioEpico() != null){

			usuarioScoped.setUsuarioEpico( (UsuarioEpico)SessionS.current().mysqlSession().load(UsuarioEpico.class, usuarioScoped.getUsuarioEpico().getId()) );
			
		}
		
	}

	public boolean accepts(ResourceMethod method) {
		return true;
	}

	public void intercept(InterceptorStack stack, ResourceMethod method, Object resourceInstance) throws InterceptionException {
		stack.next(method, resourceInstance);
	}

}

Ficou um último problema. Tenho Jobs com o Quartz que não conseguem capturar uma instancia aberta de:

SessionS current()

Tem como, caso não haja uma sessão aberta para captura pelo VRaptorRequestHolder, instanciar uma nova e, mais importante, entrega-la a administração de sessões do VRaptor?

Abraços,
Jsign

Olá Lucas,

Fiz uma alteração na classe SessionS criando uma instancia, caso nulo VRaptorRequestHolder.currentRequest().
Ficou desta forma:

@Component  
public class SessionS{  
	
    private Session mysqlSession;
    private Session oracleSession;
    
    public SessionS(MysqlSessionFactory mysqlSessionFactory, OracleSessionFactory oracleSessionFactory) {
    	
         this.mysqlSession = mysqlSessionFactory.getInstance().openSession();
         
         this.oracleSession = oracleSessionFactory.getInstance().openSession();
         
    }
    
    public Session mysqlSession() {  
        return mysqlSession;
    }  
      
    public Session oracleSession() {
        return oracleSession;
    }  
    
	public static SessionS current() {
		
		SessionS sessionS = null;
		
		if( VRaptorRequestHolder.currentRequest() != null && VRaptorRequestHolder.currentRequest().getRequest() != null ) {
			
			sessionS = (SessionS) VRaptorRequestHolder.currentRequest().getRequest().getAttribute("sessionS");
			
		}else if(sessionS == null){
			
			sessionS = new SessionS(new MysqlSessionFactory(), new OracleSessionFactory());
			
		}
		
		return sessionS;
		
	}

    @PreDestroy
    public void closeSessionS() {
        mysqlSession.close();
        oracleSession.close();
    }
    
}

Começou a criar instancias em demasia/descontrolada:
Exception:

Exception in thread "com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread-#2" java.lang.OutOfMemoryError: Java heap space
[19/18/2011 02:18]  INFO [Timer-15] (BasicResourcePool.java:1392) - A checked-out resource is overdue, and will be destroyed: com.mchange.v2.c3p0.impl.NewPooledConnection@79d50b

	Managed Threads: 3
	Active Threads: 0
	Active Tasks: 
	Pending Tasks: 
		com.mchange.v2.resourcepool.BasicResourcePool$1DestroyResourceTask@f70e48
		com.mchange.v2.resourcepool.BasicResourcePool$1DestroyResourceTask@1cabd5e
		com.mchange.v2.resourcepool.BasicResourcePool$1DestroyResourceTask@a80a61
		com.mchange.v2.resourcepool.BasicResourcePool$AcquireTask@925547
		com.mchange.v2.resourcepool.BasicResourcePool$AcquireTask@11ce20e
Pool thread stack traces:
	Thread[com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread-#1,5,]
	Thread[com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread-#2,5,]
	Thread[com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread-#0,5,]


[19/18/2011 02:18]  WARN [Timer-8] (ThreadPoolAsynchronousRunner.java:608) - com.mchange.v2.async.ThreadPoolAsynchronousRunner$DeadlockDetector@ba4930 -- APPARENT DEADLOCK!!! Creating emergency threads for unassigned pending tasks!
Exception in thread "Timer-8" java.lang.OutOfMemoryError: Java heap space
[19/18/2011 02:18]  WARN [Timer-6] (ThreadPoolAsynchronousRunner.java:608) - com.mchange.v2.async.ThreadPoolAsynchronousRunner$DeadlockDetector@1206de4 -- APPARENT DEADLOCK!!! Creating emergency threads for unassigned pending tasks!
Exception in thread "Task-Thread-for-com.mchange.v2.async.ThreadPerTaskAsynchronousRunner@11edb54" java.lang.OutOfMemoryError: Java heap space[19/18/2011 02:18]  WARN [Timer-15] (ThreadPoolAsynchronousRunner.java:608) - com.mchange.v2.async.ThreadPoolAsynchronousRunner$DeadlockDetector@5a0eee -- APPARENT DEADLOCK!!! Creating emergency threads for unassigned pending tasks!
[19/18/2011 02:18]  INFO [com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread-#2] (BasicResourcePool.java:1831) - An exception occurred while acquiring a poolable resource. Will retry.
java.sql.SQLException: java.lang.OutOfMemoryError: Java heap space
	at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1073)
	at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:987)
	at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:982)
	at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:927)
	at com.mysql.jdbc.Util.handleNewInstance(Util.java:431)
	at com.mysql.jdbc.ConnectionImpl.getInstance(ConnectionImpl.java:378)
	at com.mysql.jdbc.NonRegisteringDriver.connect(NonRegisteringDriver.java:305)
	at com.mchange.v2.c3p0.DriverManagerDataSource.getConnection(DriverManagerDataSource.java:134)
	at com.mchange.v2.c3p0.WrapperConnectionPoolDataSource.getPooledConnection(WrapperConnectionPoolDataSource.java:182)
	at com.mchange.v2.c3p0.WrapperConnectionPoolDataSource.getPooledConnection(WrapperConnectionPoolDataSource.java:171)
	at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool$1PooledConnectionResourcePoolManager.acquireResource(C3P0PooledConnectionPool.java:137)
	at com.mchange.v2.resourcepool.BasicResourcePool.doAcquire(BasicResourcePool.java:1014)
	at com.mchange.v2.resourcepool.BasicResourcePool.access$800(BasicResourcePool.java:32)
	at com.mchange.v2.resourcepool.BasicResourcePool$AcquireTask.run(BasicResourcePool.java:1810)
	at com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread.run(ThreadPoolAsynchronousRunner.java:547)
[19/18/2011 02:18]  WARN [Timer-6] (ThreadPoolAsynchronousRunner.java:624) - com.mchange.v2.async.ThreadPoolAsynchronousRunner$DeadlockDetector@1206de4 -- APPARENT DEADLOCK!!! Complete Status: 
	Managed Threads: 3
	Active Threads: 0
	Active Tasks: 
	Pending Tasks: 
		com.mchange.v2.resourcepool.BasicResourcePool$AsyncTestIdleResourceTask@1a41cc1
		com.mchange.v2.resourcepool.BasicResourcePool$AsyncTestIdleResourceTask@15bdd63
Pool thread stack traces:
	Thread[com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread-#1,5,]
	Thread[com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread-#0,5,]
	Thread[com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread-#2,5,]



[19/18/2011 02:18]  WARN [Timer-15] (ThreadPoolAsynchronousRunner.java:624) - com.mchange.v2.async.ThreadPoolAsynchronousRunner$DeadlockDetector@5a0eee -- APPARENT DEADLOCK!!! Complete Status: 
	Managed Threads: 3
	Active Threads: 1
	Active Tasks: 
		com.mchange.v2.resourcepool.BasicResourcePool$AcquireTask@878c6f (com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread-#1)
	Pending Tasks: 
		com.mchange.v2.resourcepool.BasicResourcePool$AsyncTestIdleResourceTask@114f7ca
Pool thread stack traces:
	Thread[com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread-#0,5,]
	Thread[com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread-#1,5,main]
		com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread.run(ThreadPoolAsynchronousRunner.java:560)
	Thread[com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread-#2,5,]

bom, qdo isso estiver sendo acessado via job do quartz não existe request, é normal dar isso…

não sei se o heap space é por isso…

em todo caso, não faça assim…

o cara que inicia o quartz, faça-o receber as sessionFactories e abra uma session por execução do job… e controle isso dentro do próprio job, tanto a abertura qto o fechamento da sessão

Ok Lucas,
Pensei que fosse possível de outra forma recuperar uma sessão ativa que não por “request”.
Mas com diz o ditado: “quer moleza senta no pudim”.
Vou fazer o controle individual (por job).
Tive problema com a minha interceptor de atualização dos objetos de escopo quando em uma requisição “Ajax”.

AdmScope

@Intercepts
@RequestScoped
public class AdmScope implements Interceptor{

	public AdmScope(SessionS sessionS, UsuarioScoped usuarioScoped) {
		
		if(usuarioScoped != null && usuarioScoped.getUsuarioEpico() != null && SessionS.current() != null && SessionS.current().mysqlSession() != null){
			
                        // entra aqui sempre mesmo quando AJAX mas lança erro 

			usuarioScoped.setUsuarioEpico( (UsuarioEpico)SessionS.current().mysqlSession().load(UsuarioEpico.class, usuarioScoped.getUsuarioEpico().getId()) );
			
		}
		
	}

	public boolean accepts(ResourceMethod method) {
		return true;
	}

	public void intercept(InterceptorStack stack, ResourceMethod method, Object resourceInstance) throws InterceptionException {
		stack.next(method, resourceInstance);
	}

}

Javascript


function buscarHorario(){
	
	if(min("data",1) && min("idSala",1)){

		$("#dataS").html("<img src='"+ePath+"/images/infra/loading.gif' />");
		
		$.ajax({
		  type: "POST",
		  async: false,
		  data: "data=" + $("#data").val() + "&idSala=" + $("#idSala").val(),
		  url: ePath+'/reuniao/horarios-por-data',
		  dataType:"html",
		  success: function(dado) {
			  
			  $("#dataS").html(dado);
			  
		  },
		  beforeSend: function() {
			  
			  $("#dataS").html("<img src='"+ePath+"/images/infra/loading.gif' />");
			  
		  },
		  error:function (xhr, ajaxOptions, thrownError){
			  
			  $("#dataS").html("xhr.status :: " + xhr.status + ". ajaxOptions :: " + ajaxOptions + " thrownError :: " + thrownError);
		  
		  }
		});
		
	}else{
		
		$("#dataS").html("<div class='r'>Selecione uma sala e uma data e clique em 'Buscar data'</div>");
		
	}
	
}

O erro ocorre antes da action da lógica @Post ‘/reuniao/horarios-por-data’.
Sabe o que pode estar ocorrendo já que a Session e o Usuário estão carregados?
E porque isso só quando com ajax!

...
if(usuarioScoped != null && usuarioScoped.getUsuarioEpico() != null && SessionS.current() != null && SessionS.current().mysqlSession() != null){
...

Abraços,
Jsign.

Desculpe não mandei a Exception.

[19/51/2011 03:51] ERROR [http-bio-8080-exec-10] (LazyInitializationException.java:42) - could not initialize proxy - no Session
org.hibernate.LazyInitializationException: could not initialize proxy - no Session
	at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:167)
	at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:215)
	at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:190)
	at br.com.brabus.epico.model.acesso.UsuarioEpico_$$_javassist_25.getId(UsuarioEpico_$$_javassist_25.java)
	at br.com.brabus.epico.interceptor.AdmScope.<init>(AdmScope.java:29)
	at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
	at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
	at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
	at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:126)
	...

qual erro?

troque o load por get… o load retorna um proxy lazy, daí ele só é inicializado depois… o get já busca o usuário do banco

Certíssimo, aprendi mais uma.
Muito obrigado Lucas.
Problemas resolvidos.

[TRANSFERIDO]

http://www.guj.com.br/java/255793-handle-de-instrucao-nao-foi-executado—hibernate–vraptor#1331514

Certíssimo, aprendi mais uma.
Muito obrigado Lucas.
Fica o feedback: Muito legal trabalhar com o VRaptor e aprender um pouco mais do framework.

Gostaria de saber se há a possibilidade de trabalhar livre de sessão (SessionLess) com o VRaptor e como seria?
No mais considero resolvido o problema.

Problemas resolvidos.

[TRANSFERIDO]
http://www.guj.com.br/java/255793-handle-de-instrucao-nao-foi-executado—hibernate–vraptor#1331514
Valeu Lucas

jsign, isso já é outro tipo de erro, posta em outro tópico por favor?