-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 6 posts ] 
Author Message
 Post subject: How to get interceptor from Jboss hibernate-service.xml?
PostPosted: Tue May 31, 2005 3:37 pm 
Newbie

Joined: Wed Feb 16, 2005 10:46 am
Posts: 13
Location: Lake Worth, FL
I am having difficulty getting an interceptor session. How do I do this?

If I define the following in my hibernate-service.xml file :

Code:
       <attribute name="SessionFactoryInterceptor">com.adcware.rcs.util.AuditLogInterceptor</attribute>


How do I get the interceptor from my session facade method such that I can set the hibernate session on the interceptor?

My session bean method is:

Code:
   public Branch createBranch(Branch branch, String microMarketId)
      throws HibernateException {
      Session hsession = _sessionFactory.getCurrentSession();
       MicroMarket microMarket = (MicroMarket) hsession.load(MicroMarket.class, microMarketId);
       branch.assignToMicroMarket(microMarket);
       hsession.save(branch);
       return branch;
   }   



Is the writing of the audit log records done in the same managed session as above or in a separate one that I have to open, begin tx, commit tx and close by myself?

Any help is greatly appreciated.

Many thanks in advance,
Joe


Top
 Profile  
 
 Post subject:
PostPosted: Tue May 31, 2005 5:15 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 3:00 pm
Posts: 1816
Location: Austin, TX
Currently there is no way. A SessionFactory-scoped interceptor is meant to be stateless. A session ref would certainly constitute state.

Inside an interceptor it is not good practice to use the same session anyway. The typcial approach is to open a new session on the same underlying JDBC connection. Just do something like:

Code:
Session currentSession = sf.getCurrentSession();
Session localSession = sf.openSession( currentSession.connection(), MY_NOOP_INTERCEPTOR );


Note the application of a different session-scoped interceptor for the new session...


Top
 Profile  
 
 Post subject:
PostPosted: Tue May 31, 2005 8:05 pm 
Newbie

Joined: Wed Feb 16, 2005 10:46 am
Posts: 13
Location: Lake Worth, FL
Thanks Steve. Try as I might I can't get the audit logging interceptor to work.

Here is the interceptor code ...
Code:
package com.adcware.rcs.util;

import java.io.Serializable;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

import org.hibernate.CallbackException;
import org.hibernate.EntityMode;
import org.hibernate.HibernateException;
import org.hibernate.Interceptor;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.type.Type;

import com.adcware.rcs.model.AuditLogRecord;
import com.adcware.rcs.model.Auditable;

public class AuditLogInterceptor implements Interceptor {
   
   private Session _session;
   private String  _userId;
   
   private Set _inserts = new HashSet();
   private Set _updates = new HashSet();
   
   public void setSession(Session s) { _session = s; }
   public void setUserId(String uid) { _userId = uid; }

   public boolean onLoad(Object arg0, Serializable arg1, Object[] arg2, String[] arg3, Type[] arg4) throws CallbackException {
      return false;
   }

   public boolean onFlushDirty(
         Object entity,
         Serializable id,
         Object[] currentState,
         Object[] previousState,
         String[] propertyNames,
         Type[] types
         ) throws CallbackException {
      if (entity instanceof Auditable) {
         _updates.add(entity);
      }
      return false;
   }

   public boolean onSave(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) throws CallbackException {
      if (entity instanceof Auditable) {
         _inserts.add(entity);
      }
      return false;
   }

   public void onDelete(Object arg0, Serializable arg1, Object[] arg2, String[] arg3, Type[] arg4) throws CallbackException {
   }

   public void preFlush(Iterator iter) throws CallbackException {
   }

   public void postFlush(Iterator iter) throws CallbackException {
      System.out.println("postFlush:  session is "+_session);
      System.out.println("postFlush:  userId is "+_userId);      
      if (_session != null) {
         System.out.println("postFlush:  session is "+_session);
         System.out.println("postFlush:  userId is "+_userId);            
         try {
            for (Iterator it = _inserts.iterator(); it.hasNext(); ) {
               Auditable entity = (Auditable) it.next();
               //AuditLog.logEvent("create", entity, _userId, _session.connection());
               try {
                  AuditLogRecord record =
                     new AuditLogRecord("create",
                                    entity.getId(),
                                    entity.getClass(),
                                    _userId );
                  System.out.println("..... entity class name "+entity.getClass().getName());
                  System.out.println("..... entity id "+entity.getId());                  
                  _session.save(record);
                  _session.flush();
   
               } catch (Exception ex) {
                  throw new CallbackException(ex);
               } finally {
                  try {
                     _session.close();
                  } catch (HibernateException ex) {
                     throw new CallbackException(ex);
                  }
               }
            }
            for (Iterator it = _updates.iterator(); it.hasNext(); ) {
               Auditable entity = (Auditable) it.next();
               //AuditLog.logEvent("update", entity, _userId, _session.connection());
            }         
         } catch (HibernateException ex) {
            throw new CallbackException(ex);
         } finally {
            _inserts.clear();
            _updates.clear();
         }
      }
   }

   public Boolean isTransient(Object arg0) {
      return null;
   }

   public int[] findDirty(Object arg0, Serializable arg1, Object[] arg2, Object[] arg3, String[] arg4, Type[] arg5) {
      return null;
   }

   public Object instantiate(String arg0, EntityMode arg1, Serializable arg2) throws CallbackException {
      return null;
   }

   public String getEntityName(Object arg0) throws CallbackException {
      return null;
   }

   public Object getEntity(String arg0, Serializable arg1) throws CallbackException {
      return null;
   }

   public void afterTransactionBegin(Transaction arg0) {
   }

   public void beforeTransactionCompletion(Transaction arg0) {
   }

   public void afterTransactionCompletion(Transaction arg0) {
   }

}


And here is the session bean method which would enable it ...

Code:
   public Referral createReferralForCustomer(Customer cust, ProductCategory prod,
         Account orgAcct, Account asnAcct, ReferralSource source, String comment)
      throws HibernateException, Exception {

      Session hsession = _sessionFactory.getCurrentSession();
      
      // enable audit logging ...      
      AuditLogInterceptor interceptor = new AuditLogInterceptor();
   
      Session localSession = _sessionFactory.openSession( hsession.connection(), interceptor );       
      interceptor.setSession(localSession);
      interceptor.setUserId(_ctx.getCallerPrincipal().getName());      
         
   
      
       Referral ref = new Referral();
      
            //
            //  ref.set* omitted ...
            //
   
      
       hsession.save(ref);
       return ref;
   }



Here is what is displayed in the console log ...

Code:
19:52:44,299 INFO  [STDOUT] postFlush:  session is null
19:52:44,299 INFO  [STDOUT] postFlush:  userId is null
19:52:44,729 INFO  [STDOUT] postFlush:  session is null
19:52:44,729 INFO  [STDOUT] postFlush:  userId is null
19:52:44,860 INFO  [STDOUT] postFlush:  session is null
19:52:44,860 INFO  [STDOUT] postFlush:  userId is null
19:52:44,980 INFO  [STDOUT] postFlush:  session is null
19:52:44,980 INFO  [STDOUT] postFlush:  userId is null
19:52:45,080 INFO  [STDOUT] postFlush:  session is null
19:52:45,080 INFO  [STDOUT] postFlush:  userId is null
19:52:45,170 INFO  [STDOUT] postFlush:  session is null
19:52:45,170 INFO  [STDOUT] postFlush:  userId is null
19:52:45,370 INFO  [STDOUT] postFlush:  session is null
19:52:45,370 INFO  [STDOUT] postFlush:  userId is null
19:52:45,490 INFO  [STDOUT] postFlush:  session is null
19:52:45,490 INFO  [STDOUT] postFlush:  userId is null
19:52:45,751 INFO  [STDOUT] postFlush:  session is null
19:52:45,751 INFO  [STDOUT] postFlush:  userId is null
19:52:45,881 INFO  [STDOUT] postFlush:  session is null
19:52:45,881 INFO  [STDOUT] postFlush:  userId is null
19:52:46,542 INFO  [STDOUT] postFlush:  session is null
19:52:46,542 INFO  [STDOUT] postFlush:  userId is null
19:52:46,852 INFO  [STDOUT] postFlush:  session is null
19:52:46,852 INFO  [STDOUT] postFlush:  userId is null
19:52:47,103 INFO  [STDOUT] postFlush:  session is null
19:52:47,103 INFO  [STDOUT] postFlush:  userId is null
19:52:47,423 INFO  [STDOUT] postFlush:  session is null
19:52:47,423 INFO  [STDOUT] postFlush:  userId is null
19:52:47,583 INFO  [STDOUT] postFlush:  session is null
19:52:47,583 INFO  [STDOUT] postFlush:  userId is null
19:52:47,704 INFO  [STDOUT] postFlush:  session is null
19:52:47,704 INFO  [STDOUT] postFlush:  userId is null
19:52:48,034 INFO  [STDOUT] postFlush:  session is null
19:52:48,034 INFO  [STDOUT] postFlush:  userId is null


I don't know why the session and userid are always null. If I remove the the SessionFactoryInterceptor from the hibernate-service.xml then I get no postFlush callbacks at all.

I am using hibernate 3.0.5 and Jboss 4.0.2. The classes for AuditLogRecord are as defined in the book "Hibernate in Action".

Many thanks for your prompt reply and help.

Joe


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jun 01, 2005 12:30 am 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 3:00 pm
Posts: 1816
Location: Austin, TX
Well basically you attempt to perform the save against a session to which the interceptor is not attached. You attach the interceptor to the 'localSession' instance, then perform the save against the 'hsession' instance.

I am assuming that AuditLogInterceptor also gets attached to the SessionFactory; is that correct? If so, you need to make that thing stateless by removing the 'session' and 'userId' inst-vars (sorry my fingers refuse to type underscore prefixes :). Then, the interceptor itself should look up these values when it needs them as stack (aka method-local) variables.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jun 01, 2005 12:20 pm 
Newbie

Joined: Wed Feb 16, 2005 10:46 am
Posts: 13
Location: Lake Worth, FL
Do I use localSession for all hibernate actions then? (In my session bean method)

>> Then, the interceptor itself should look up these values when it needs them as stack (aka method-local) variables.

How do I do this in the interceptor?

Also, If I am using JBoss for all transaction management, do I then need to close the session and transaction?

I have been trying to follow the example in the book "Hibernate in Action" but I am still confused as to exactly what to do to make this work.

Thanks and I apologize for my ignorance.

Joe


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jun 01, 2005 4:48 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 3:00 pm
Posts: 1816
Location: Austin, TX
Well lots has changed since the 1st edition of the book. I don't think the jboss integration was even done at that point.

If you want to do it the way its done in the book, you'll not be able to use getCurrentSession() and you will not be able to use a SessionFactory-scoped interceptor.

If you want to use the getCurrentSession() functionality, then here's what you need:

1) As mentioned before, you need to remove those inst-vars from your interceptor to make it SessionFactory-scoped. A SessionFactory-scoped interceptor needs to be stateless in terms of state specific to a given session (which all your inst-vars are).
2) You need to change the logic inside the interceptor such that it acquires a session when it needs one, but does it in that special way I mentioned before. You'll also need a way to contextually determine the "current user".
3) Keep this interceptor defined in the SessionFactoryInterceptor attribute on the MBean deployment.

So the code changes would look something like:
Code:
public class AuditLogInterceptor
      extends EmptyInterceptor
      implements Interceptor {

   private static final EMPTY_INTERCEPTOR = new EmptyInterceptor();

   public boolean onFlushDirty(
         Object entity,
         Serializable id,
         Object[] currentState,
         Object[] previousState,
         String[] propertyNames,
         Type[] types) throws CallbackException {
      if (entity instanceof Auditable) {
         Auditable myEntity = (Auditable) entity;
         saveAudit(
               new AuditLogRecord(
                     "update",
                     myEntity.getId(),
                     myEntity.getClass(),
                     determineCurrentUser()
               )
         );
      }
      return false;
   }

   public boolean onSave(
         Object entity,
         Serializable id,
         Object[] state,
         String[] propertyNames,
         Type[] types) throws CallbackException {
      if (entity instanceof Auditable) {
         Auditable myEntity = (Auditable) entity;
          saveAudit(
               new AuditLogRecord(
                     "create",
                     myEntity.getId(),
                     myEntity.getClass(),
                     determineCurrentUser()
               )
         );
      }
      return false;

   }

   private saveAudit(AuditLogRecord record) throws CallbackException {
      Session workSession = generateWorkSession();
      try {
         workSession.save( record );
         workSession.flush();
      }
      catch( HibernateException e ) {
         throw new CallbackException( e );
      }
      finally {
         release( workSession );
      }
   }

   private void release(Session session) {
      if ( session != null ) {
         try {
            session.close();
         }
         catch( Throwable ignore ) {
         }
      }
   }

   private Session generateWorkSession() {
      return getSessionFactory().openSession(
            getSessionFactory().getCurrentSession().connection(),
            EMPTY_INTERCEPTOR
      );
   }

   private String determineCurrentUser() {
      return ???;
   }

   private SessionFactory getSessionFactory() {
      return ???;
   }

}


Now a little secret here is that you do not really even need a completely different session (the 'workSession') as long as:
1) All you ever do here is a Session.save() and never try to access the "main" session for reading of additional data (not even initializing lazy associations);
2) AuditLogRecord itself is not Auditable :)

HTH (cause I'm spent ;)


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 6 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.