Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to enable hibernate filter for sessionFactory.getCurrentSession()?

Say there is a User table with structure:

User

  • List item
  • userId (PK)
  • company (PK)
  • userName
  • address ...etc

And I want to retrieve users only for the current company (company can be changed by the user through UI, so the company is a runtime parameter)

Similarly there are many other tables that have similar structure with common column (company), and I want to restrict data to only the current company, so I am using hibernate filter to filter out data.

Hibernate annotations:

<bean id="sessionFactory"
    class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">

    <property name="dataSource">
        <ref bean="dataSource" />
    </property>
    <property name="hibernateProperties">
        <props>
            <prop key="hibernate.dialect">Dialect....</prop>
            <prop key="hibernate.show_sql">true</prop>
            <prop key="hibernate.generate_statistics">true</prop>
            <prop key="hibernate.connection.release_mode">after_transaction</prop>
            <prop key="hibernate.cache.use_second_level_cache">false</prop>
        </props>
    </property>
    <property name="annotatedClasses">
        <list>
            <value>User</value>
        .....
        </list>
    </property>
</bean>

Filter definitions:

@org.hibernate.annotations.FilterDef(name="restrictToCurrentCompany",
    parameters = {@org.hibernate.annotations.ParamDef(
            name = "currentCompanyNumber", type = "int"
        )
    }
)
@Entity
@Table(name = "USER")
@org.hibernate.annotations.Filter(
        name = "restrictToCurrentCompany",
        condition="company = :currentCompanyNumber"
)
public class User implements Serializable {
    private int company;
    private String userName;
    ...etc..
}

Dao's:


@Repository
@Transactional(readOnly = true)
public class UserDAOImpl implements UserDAO {

    @Autowired(required = true)
    private SessionFactory sessionFactory;

    public Set getUsers(){
        .....Criteria queries to retrieve users for the current company     
    }

    private Session getSession(){
        return sessionFactory.getCurrentSession();
    }

}

If I change the getSession like so;

private Session getSession(){
    Session session = sessionFactory.getCurrentSession();
    Filter filter = session.enableFilter("restrictToCurrentCompany");
    filter.setParameter("currentCompanyNumber", UserUtils.getCurrentCompany());
    return sessionFactory.getCurrentSession();
}

then I can enable the filter and everything looks good, but instead of enabling the filter during getting session is there a simpler alternative to apply and enable filter for the whole session factory/application level? If so, how could I do so using spring configuration?

I tried hooking into hibernate interceptors (pre-load event listerns) but I am bit unsure if this is a correct approach or should I rather use the getSession method listed above to enable filters?

like image 237
sachink Avatar asked Apr 15 '11 18:04

sachink


People also ask

How do I enable Hibernate filter in spring boot?

If you want to use a filter, you need to activate it on your Hibernate Session. You can do that by calling the enableFilter method on your Session with the name of the @FilterDef you want to activate. The method returns a Filter object, which you can then use to set the filter parameters.

What is SessionFactory getCurrentSession ()?

Hibernate SessionFactory getCurrentSession() method returns the session bound to the context. But for this to work, we need to configure it in hibernate configuration file like below. <property name="hibernate.current_session_context_class">thread</property>

How does SessionFactory work in hibernate?

Most importantly, the SessionFactory in Hibernate is responsible for the creation of Session objects. The Hibernate Session provides methods such as save, delete and update, all of which are used to perform CRUD-based operations on the database to which the SessionFactory connects.

What is SessionFactory Session and transaction in hibernate?

SessionFactory is an Interface which is present in org. hibernate package and it is used to create Session Object. It is immutable and thread-safe in nature. buildSessionFactory() method gathers the meta-data which is in the cfg Object. From cfg object it takes the JDBC information and create a JDBC Connection.


1 Answers

The solution you have is pretty simple, but I'm guessing what you are trying for is to make it so that you don't have to provide a "getSession" implementation in each of your DAOs. Ultimately your method of implementing this is going to depend on how flexible you want to be with this filter. Here's two ways I might solve this.

The simplest way would be to simply make your UserDAOImpl extend a new base class that contains the "getSession" logic in it. This method would allow you to reduce code in that you would have this filter logic applied in most cases, but then you could override the filtering when you need to.

You could create something like this:

public class BaseDAO
{

    // ... possibly some other methods and variables

    @Autowired(required = true)
    private SessionFactory sessionFactory;

    protected Session getSession()
    {
        //Your session filter logic above
    }
}

Now you could just have your UserDAOImpl subclass this and get a session when it needs to do something. This is a very simple way to do what you are looking for, but it isn't foolproof. If you are writing a framework for others to use, then what would stop them from simply getting their own reference to your SessionFactory by having Spring inject it and then they could get an unfiltered Session? You might want this in certain circumstances for administrative processes that can act on all data, but the next way I'll describe should prevent this from happening.

This second way to solve the problem involves using AOP to wrap the getSession method of SessionFactory with your logic to apply the filter before the session is returned. This method means that even if someone gets a reference to your SessionFactory themselves, they will still have this filtering logic applied.

First, if you aren't familiar with AOP in spring have a look at the reference http://static.springsource.org/spring/docs/current/spring-framework-reference/html/aop.html. I'm going to use the schema based method to apply advice to Hibernate, because we don't want to modify the source of Hibernate. ;) You can find the specifics of this method at http://static.springsource.org/spring/docs/current/spring-framework-reference/html/aop.html#aop-schema.

First, make sure you have the following schema and aop:config section in your application context XML for spring:

<?xml version="1.0" encoding="UTF-8"?>
<beans ...
    xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="
        ...
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">

    ...

<aop:config>
    <aop:aspect id="forceFilter" ref="sessionFilterAdvice">
        <aop:pointcut id="hibernateSessionFactoryGetSession"
            expression="execution(* org.hibernate.SessionFactory.openSession(..))" />
        <aop:after-returning method="setupFilter"
            pointcut-ref="hibernateSessionFactoryGetSession" returning="session" />
    </aop:aspect>
</aop:config>

    ...
</beans>

Next, you need to add a bean to your project to implement the sessionFilterAdvice bean we reference above with the aop:aspect tag. Create the following class:

package net.grogscave.example;

import org.hibernate.Filter;
import org.hibernate.Session;
import org.springframework.stereotype.Service;

@Service
public class SessionFilterAdvice
{
    public void setupFilter(Session session)
    {
        Session session = sessionFactory.getCurrentSession();
        Filter filter = session.enableFilter("restrictToCurrentCompany");
        filter.setParameter("currentCompanyNumber", UserUtils.getCurrentCompany());
    }
}

The final thing to make sure of is that your project includes the spring-aop jar and the aspectjweaver jar. I don't know if you use dependency management or not, but you somehow need to get those jars into your project classpath.

You should now be able to recompile your project, and now any calls to any of the openSession methods on classes that implement SessionFactory will add your filter to them.

like image 145
Chris DeLashmutt Avatar answered Sep 28 '22 02:09

Chris DeLashmutt