-->
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.  [ 5 posts ] 
Author Message
 Post subject: Using ThreadLocal Filter pattern with Struts AND JUnit
PostPosted: Thu Dec 18, 2003 6:45 pm 
Newbie

Joined: Thu Nov 27, 2003 5:27 pm
Posts: 10
I'm puzzling over how to make use of the Filter and ThreadLocal pattern when I run my data layer code both within Struts and also in JUnit tests. Obviously, I can't use the Filter in JUnit tests, since it is tied to the servlet container. So, I guess I need to make the ThreadLocal session separate from the Filter, so it can accessed from JUnit tests, as well as from servlets?

I'm confused about how the code will look within my data access layer to get a Hibernate Session. Obviously, I need to have the same call get a session, whether it's running in Struts or JUnit.

Off the top of my head, I'm thinking I need a Filter that accesses an external ThreadLocalSession object. The Filter (and the JUnit TestCase) will be responsible for making sure there is a valid Session in ThreadLocalSession. Then any data access code will call a static method in the ThreadLocalSession class to retrieve the appropriate session object for the currently running thread.

Does that sound right? Any sample code out there? :-)

Thanks,
Lee

_________________
http://www.URLinOne.com
http://www.AuctionRelay.com
http://www.OptionInsight.com


Top
 Profile  
 
 Post subject:
PostPosted: Thu Dec 18, 2003 8:08 pm 
Expert
Expert

Joined: Tue Sep 16, 2003 4:06 pm
Posts: 318
Location: St. Petersburg, Russia
Quote:
So, I guess I need to make the ThreadLocal session separate from the Filter, so it can accessed from JUnit tests, as well as from servlets?


Correct.

There are a lot of different implementation of this stuff you can find on the forum - look for "ThreadLocal" and "DAO implementation". I can show how we did than in our project:

We have class HibernateSession which serves two purposes:

1. It implements ThreadLocal pattern (keeps Session object)
2. It provides simple wrappers for most frequently used Session methods to catch Hibernate exceptions and convert them to our application exceptions.

Many methods omitted and code of some methods is skipped because as I already said, there is alot of examples how to implement ThreadLocal.

Code:
class HibernateSession
{
    static ThreadLocal localSession = new ThreadLocal();
    static SessionFactory sessionFactory = null;

    public static synchronized void configure(DataSource datasource) throws DataAccessException
    {
        // skipped to make source shorted
        // create session factory
    }

    static synchronized Session createSession() throws DatatecException
    {
        // skipped to make source shorted
        // basically - session.sessionFactory() with exception handling
    }

    static synchronized Session getSession() throws DataAccessException
    {
        Session session = (Session) localSession.get();

        if (session == null)
        {
            session = createSession();
            localSession.set(session);
        }

        return session;
    }

    private static synchronized void discard()
    {
        // skipped to make source shorted - nothing special,
        // just rollback transaction, close and discrard session
    }

    public static void rollback()
    {
        discard();
    }

    public static void close()
    {
        discard();
    }

    public static void commit() throws DatatecException
    {
        // skipped to make source shorted - nothing fancy,
        // just flush&commit
    }

    public static Serializable save(Object obj) throws DataAccessException
    {
        Session session = getSession();

        try
        {
            return session.save(obj);
        }
        catch (Exception exception)
        {
            log.error("save() failed", exception);

            discard();

            throw new DataAccessException(exception);
        }
    }

// ... other wrappers

}


Note - "save" is an example of a wrpper I told you before. It is needed because as Hibernate documentation says in case of any exception you need to close and discard session and I do not like the same code repeated over and over. With these wrappers I can just write somewhere

Code:
    HibernateSession.save(object);


Also note configure() method - it is used to configure HibernateSession with DataSource. It must be called only once (and it checks this).

What we have now: neither code running within servlet nor code running under JUnit do not care about Session object - they only use HibernateSession. The only thing remains is to configure latter.

Filter does this in the init() method - it obtains datasource and calls HibernateSession.configure(datasource).

Code:
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
                   throws IOException, ServletException
    {
        try
        {
            chain.doFilter(request, response);
        }
        finally
        {
            // Close session. This will rollback all uncommited changes
            HibernateSession.close();
        }
    }


Note that our Filter does rollback at the end. The idea was simple - if you want to modify database, you must commit explicitly.

It seem much people likes automatic commit more. In this case following implementation is better suited for you:

Code:
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
                   throws IOException, ServletException
    {
        try
        {
            chain.doFilter(request, response);
            HibernateSession.commit();
        }
        finally
        {
            HibernateSession.close();
        }
    }


For JUnit tests or our test classes extends CaseBase which configures Hibernate in the setUp method

Code:
class CaseBase extends junit.framework.TestCase
{
...

    private static boolean hibernateConfigured = false;

    protected void setUp() throws Exception
    {
        super.setUp();

        if (hibernateConfigured)
            return;

        HibernateSession.configure( DatabaseProvider.getDataSource() );

        hibernateConfigured = true;
    }

    protected void tearDown() throws Exception
    {
        HibernateSession.close();

        super.tearDown();
    }

...
}


Top
 Profile  
 
 Post subject:
PostPosted: Fri Dec 19, 2003 3:08 am 
Regular
Regular

Joined: Tue Sep 02, 2003 5:09 pm
Posts: 81
Location: Whitefish Montana
They are basically the same but in jUnit you would create the thread local in the setup/teardown method by creating the same thread local variable you create in your filter. In the Dao I use if a thread local session is not available a temporary session is created and a commit/rollback is applied after the operation. This makes it really easy to test. Also, I just create a placeholder for a session in the filter and don't actually create the hibernate session until a Dao requests one.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Dec 19, 2003 1:55 pm 
Newbie

Joined: Thu Nov 27, 2003 5:27 pm
Posts: 10
Great stuff, guys, thank you.

Dimas, I'm curious about why so much of your code is synchronized. Given the fact that you're using a ThreadLocal instance variable, isn't that unnecessary?

Thanks,
Lee

_________________
http://www.URLinOne.com
http://www.AuctionRelay.com
http://www.OptionInsight.com


Top
 Profile  
 
 Post subject:
PostPosted: Fri Dec 19, 2003 4:45 pm 
Expert
Expert

Joined: Tue Sep 16, 2003 4:06 pm
Posts: 318
Location: St. Petersburg, Russia
Yes, most of the syncronization can be removed. It was intended to protect from (almost impossible) situation when one thread configure()s HibernateSession at the same time another comes to createSession().

"synchronized" on getSession() and discard() can be omitted. Not a very efficient implementation. Because it is our first Hibernate expirience :)


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 5 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.