views:

2244

answers:

4

How to get Hibernate session inside a Hibernate Interceptor?

I'm trying to use Hibernate to enforce data access by organization id transparently. I have set a global Filter to filter all queries by organization id. Now, I need to use an Entity interceptor to set Organizational Id on all Entities before Save/Update.

The organization id comes from HttpSession

I've set Organizational Id as a Filter property in Hibernate session which i want to retrieve inside my interceptor and use for all Inserts and Updates as well. The problem is i dont seem to have access to Session inside the Interceptor. Any workarounds for this?

+1  A: 

If all you need is the Organizational Id, you could put it in a static ThreadLocal and then access it in the interceptor.

On the other hand if you are dead set on getting the session, and this depends on what your environment is, you could ditch the interceptor and use an org.hibernate.event.FlushEntityEventListener which seems to be more along the lines of what you need anyways. You can get the session like this (rough pseudo code):

FlushEntityEventListener.onFlushEntity(FlushEntityEvent event)
EntityEvent entityEvent = event.getEntityEntry();
EntityPersister persister = entityEvent.getPersister();
SessionFactoryImplementor sessionFactoryImplor = persister.getFactory();
Session session = sessionFactoryImplor.getCurrentSession();

From the Hibernate 3 On Line Docs: The event system can be used in addition or as a replacement for interceptors.

Nicholas
Do you mean to say that i can have a ThreadLocal variable in my Servlet/Controller and get it in the Hibernate interceptor?How do i access the ThreadLocal variable. Should it be public static in Servlet?
Sathish
Providing 2nd answer.
Nicholas
+2  A: 

You can, but I would use a simple POJO just to keep things cleanly separated. Keep in mind that the value stored in the singleton will only be accessible by the same thread that handled the servlet request, so if you're doing any asynch, you will need to account for that. Here's a super basic impl:

public class OrgId {
   public static ThreadLocal<Integer> orgId = new ThreadLocal<Integer>();
}

Since the Organizational Id is resident in the session, you could set the value of the ThreadLocal in an early servlet filter like this (not much error checking):

public class OrgIdFilter implements Filter {
   public void doFilter(ServletRequest servletrequest, ServletResponse servletresponse, FilterChain filterchain) throws java.io.IOException, javax.servlet.ServletException {
      int orgId = 0;
      HttpServletRequest req = (HttpServletRequest) servletRequest;
      HttpSession session = req.getSession();
      orgId = Integer.parseInt(session.getAttribute("OrganizationalIdAttr"));
      try {
         OrgId.orgId.set(orgId);
         filterChain.doFilter(servletRequest, servletresponse);
      } finally {
         OrgId.orgId.set(null); // Important to clear after request !!
      }
   }
}

This assumes that the orgId is in the session when the filter is called, but if not, you get the idea....

Then in your interceptor (or pretty much anywhere) you can get the thread's current orgId with:

OrgId.orgId.get();   // Might be null.....

A potential snafu here is that all these components (filter, OrgId and interceptor) need to be loaded by the same class loader to ensure that the OrgId class is effectively a singleton, otherwise, with multiple instances of the ThreadLocal hanging around it won't work consistently, or at all. Needless to say, all this needs to be happening in the same VM.

I am not sure if this is the cleanest way to solve this problem, but it does get you your orgId where you need it.

Nicholas
+1  A: 

When you create your Interceptor, if you can provide it with a reference to the SessionFactory, you can use SessionFactory#getCurrentSession

osi
A: 

Interceptor can be made BeanFactoryAware and SessionFactory can be obtained using the bean factory from which current session can be obtained.

Since it seemed like a bad design because of the circular dependency and making the Interceptor aware of Spring container, i used ThreadLocal as suggested by Nicholas

Sathish