Dúvida TransactionInterceptor

pessoal

fiz um interceptor para controlar minhas transações com o banco de dados e analisando as atividades dela percebi que ela abre várias transações para executar um comando salvar

lista de ações

interception
interception
inicia a transacao
comita transação
interception
interception
inicia a transacao
comita transação
interception
interception
inicia a transacao
Hibernate: 
    insert 
    into
        Estado
        (nome, uf) 
    values
        (?, ?)
comita transação
interception
interception
inicia a transacao
comita transação

classe TransactionInterceptor

[code]
package smcv.infra;

import org.hibernate.Session;
import org.hibernate.Transaction;
import br.com.caelum.vraptor.Intercepts;
import br.com.caelum.vraptor.core.InterceptorStack;
import br.com.caelum.vraptor.interceptor.Interceptor;
import br.com.caelum.vraptor.resource.ResourceMethod;

@Intercepts
public class TransactionInterceptor implements Interceptor {
private final Session session;

public TransactionInterceptor(Session session) {
	this.session = session;
}

public void intercept(InterceptorStack stack, ResourceMethod method,
		Object instance) {
	Transaction transaction = null;
	try {
		System.out.println("inicia a transacao");
		transaction = session.beginTransaction();
		stack.next(method, instance);
		transaction.commit();
		System.out.println("comita transação");
	} finally {
		if (transaction != null && transaction.isActive()) {
			transaction.rollback();
			System.out.println("cancela transação");
		}
	}
}

public boolean accepts(ResourceMethod method) {
	System.out.println("interception");
	return !method.containsAnnotation(HibernateTransaction.class); 
}

}[/code]

gostaria de saber se isso é normal e porque acontece, alguém sabe explicar?

aproveitando apartir dessa classe interceptor, como eu poderia gravar logs de ações no banco de dados?

obrigado

t+

Sempre que você tiver uma dúvida sobre vraptor, poste sempre no subfórum específico: Índice dos Fóruns » Frameworks e Bibliotecas brasileiros. Além disso lembre-se de sempre dizer a versão que você usa. Só notei que você está usando vraptor por causa dos pacotes br.com.caelum.vraptor.

Conforme já conversamos em outro tópico com o vraptor você não precisa trabalhar com transações manualmente. Creio pelo seu relato de abrir várias transações é por que você abre transação manual e o vraptor também abre outra transação. Isso só dá para saber vendo como você configurou no web.xml. Se por acaso você configurou o componente para controle do Hibernate do vraptor e tenta usar esse manual certamente vai dar um comportamento estranho.

Eu gosto das coisas mais automatizadas, então já que o vraptor possui (via Spring) um controle automatico não apenas de transação mas de controle da hibernate session porque vocẽ não a usa? A grande vantagem é poder trabalhar de forma transparente. Isso é bom por que você deixa tudo a cargo do vraptor, não precisando dar manutenção em mais uma classe em seu sistema. Além do mais as classes do vraptor são exaustivamente testadas, garantindo o bom funcionamento.

Mas se você quer fazer o controle manual, o que nada lhe impede, desabilite os componentes de controle de session-factory que estão no seu web.xml e use apenas o seu componente.

Além do mais, olhando seu componente, o método accepts está retornando true quando você não tiver a anotação HibernateTransaction. Isso significa que sempre que você não tiver a anotação no método ele executa a transação. Não seria o contrário?

Outra coisa… finnaly SEMPRE é executado, ou seja, você faz commit e depois um rollback logo abaixo?

Abraços

garcia obrigado pelas dicas mas

a unica transação manual que eu abri é a do interceptor

try {
			//System.out.println("inicia a transacao");
			transaction = session.beginTransaction();
			stack.next(method, instance);
			transaction.commit();
			//System.out.println("comita transação");
		}

olha o meu dao

package smcv.dao;

import java.util.List;

import org.hibernate.Session;

import br.com.caelum.vraptor.ioc.Component;

import smcv.infra.HibernateTransaction;
import smcv.modelo.area.Estado;

@Component
public class DAO<T> {

	private Session session;

	public DAO(Session session) {
	
		this.session = session;
	}
	
	@HibernateTransaction
	public void adiciona(T reg) {
		this.session.save(reg);
		
	}

	public void remove(T reg) {
		this.remove(reg);
	}
}

e no meu xml não tem nada configurado

<?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_2_5.xsd"
	id="WebApp_ID" version="2.5">
	<display-name>Sistema de Mapeamento e Controle de Vetores</display-name>
	<welcome-file-list>
		<welcome-file>index.html</welcome-file>
		<welcome-file>index.htm</welcome-file>
		<welcome-file>index.jsp</welcome-file>
		<welcome-file>default.html</welcome-file>
		<welcome-file>default.htm</welcome-file>
		<welcome-file>default.jsp</welcome-file>
	</welcome-file-list>
	
	<!-- configura o controlador do VRaptor -->
	<filter>
		<filter-name>vraptor</filter-name>
		<filter-class>br.com.caelum.vraptor.VRaptor</filter-class>
	</filter>
	
	<filter-mapping>
		<filter-name>vraptor</filter-name>
		<url-pattern>/*</url-pattern>
		<dispatcher>FORWARD</dispatcher>
		<dispatcher>REQUEST</dispatcher>
	</filter-mapping>
	
	<jsp-config>
		<jsp-property-group>
			<description>Mapeamento</description>
			<display-name>Mapeamento de Vetores</display-name>
			<url-pattern>*.jsp</url-pattern>
			<include-prelude>/header.jspf</include-prelude>
			<include-coda>/footer.jspf</include-coda>
		</jsp-property-group>
	</jsp-config>
</web-app>

como eu posso fazer isso no meu projeto conforme as classes que eu te passei?

Eu estou completamente confuso, o que eu quero é fazer com que meu sistema execute ações no banco sem ter que ficar abrindo transações manuais e que de alguma forma eu possa gravar logs no banco para fazer auditoria, estou lendo bastante artigos e vários tópicos nos forum e to ficando cada vez mais confuso.

obs: estou utilizando o vraptor 3.1.0

vlw

Oi cvinicios.

Primeira coisa a fazer é remover as suas classes que cuidam de transação, creio que sejam elas: TransactionInterceptor, HibernateTransaction, HibernateHelper e CriadorDeSessoes. Ou seja, remova tudo que você tem de classes que fazem a tarefa de cuidar do Hibernate manualmente.

Agora apenas adicione as tags no seu web.xml. Isso vai dizer para o vraptor cuidar das transações e também de iniciar o hibernate.

<context-param> <param-name>br.com.caelum.vraptor.provider</param-name> <param-value>br.com.caelum.vraptor.util.hibernate.HibernateCustomProvider</param-value> </context-param>

Feito isso você só precisa colocar a sua Session no construtor das classes que você quer trabalhar com o Hibernate. Assim toda vez que a classe for chamada o Vraptor verá que tem um objeto session lá e irá não apenas inicializar a sessão como fará o devido controle transacional. Muito simples e prático.

Aproveitando o DAO que você postou aqui, ela ficaria conforme abaixo. Note que você apenas declara sua session na classe e no construtor. Assim toda vez que você chamar essa classe o Vraptor vai injetar a session aí para você e fará o controle de transação com os devidos commits e rollbacks. Lembrando que o padrão é sempre commit, porém caso alguma filha de RuntimeException for lançada será feito um rollback, seguindo o padrão J2EE.

[code]@Component
public class DAO {

private Session session;

public DAO(Session session) {
	this.session = session;
}

public void adiciona(T reg) {
	session.save(reg);
}

public void remove(T reg) {
	session.remove(reg);
}

}[/code]

Vocẽ quer fazer um interceptor para auditar as alterações no banco de dados (insert, update e delete) ou você quer apenas gravar a URL de acesso?

Abraços

Hmm, adora notei que você usa generics em dua DAO. Não sei como o Vraptor trabalha com isso, mas o Lucas ou o Paulo Silveira podem te ajudar melhor quanto a isso. Se você procurar no subfórum de frameworks brasileiros há uma extensa thread sobre isso.

Mas creio que para você usar em seu controller basta fazer algo assim:

[code]@Resource
public class UserController {
private DAO userDAO;

public UserController(DAO<User> userDAO) {
    this.userDAO = userDAO;
}

}[/code]

garcia vlw pela ajuda mesmo

eu quero um interceptor para auditar todos os métodos insert, delete e update.

t+

eu coloco dessa forma o código no xml? pq tá dando erro ou tem algum jar especifico para ele?

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
		"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
		"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>
        <property name="hibernate.connection.driver_class">net.sourceforge.jtds.jdbc.Driver</property>
        <property name="hibernate.connection.password">042507</property>
        <property name="hibernate.connection.url">jdbc:jtds:sqlserver://127.0.0.1/SMCV</property>
        <property name="hibernate.connection.username">adm</property>
        <property name="hibernate.dialect">org.hibernate.dialect.SQLServerDialect</property>
        
		<property name="hibernate.hbm2ddl.auto">update</property>
		
        <property name="hibernate.show_sql">true</property>
        <property name="hibernate.format_sql">true</property>
        
        <mapping class="smcv.modelo.area.Estado"/>     
		
		<context-param>
    	<param-name>br.com.caelum.vraptor.provider</param-name>
    	<param-value>br.com.caelum.vraptor.util.hibernate.HibernateCustomProvider</param-value>
		</context-param> 

    </session-factory> 
</hibernate-configuration>

Sobre a dúvida das transações, você conseguiu fazer funcionar direitinho? Me reporte tuas dúvidas e/ou problemas que você possa ter tido. Além do mais se você não entendeu alguma coisa avise-me.

Sobre auditoria, aconselho você a usar o Envers, que faz essa auditoria detalhada. Há um artigo muito bom na Javamagazine de uns 2 meses atrás se não me engano. Ele faz a aditoria completa e transparente de tudo que mudou no projeto, bastando você anotar as classes com @Audit (se não me engano).

Na verdão 3.5 do Hibernate o envers vem já no core. Nas versões anteriores você precisa baixar separado. Tenho usado em um projeto grande que tenho e tem me atendido muito bem. Uma pequena que só funcione com Hibernate, e não com qualquer implementação de JPA.

Abraços

Isso você tem que colocar no WEB.XML (minusculo)

garcia, muito obrigado pelas ajudas, agora ta funcionando certinho como você me disse só falta a parte de auditoria, vc sabe mais algum lugar inde posso achar um tutoria legal sobre Envers além da revista javamagazzine?

obrigado

http://www.jboss.org/envers
http://www.jboss.org/files/envers/docs/index.html
http://blogs.dextra.com.br/palavra-do-arquiteto/2009/auditoria-em-banco-de-dados-com-hibernate-envers/

http://www.google.com.br/search?q=envers