You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@tapestry.apache.org by Julian Wood <wo...@ucalgary.ca> on 2008/03/18 18:54:28 UTC

Re: T5: HibernateSessionManager

I have a UserService:

public class UserServiceImpl implements UserService {
     private Session session;

     public UserServiceImpl(@InjectService("Session")Session session) {
         this.session = session;
     }

     public void save(User user) {
         session.save(user);
     }
}

I bind this in the AppModule, and then I can use it in any page or  
component class. This is great.

Now for unit testing my UserService, I make my own RegistryBuilder as  
others have recommended, and can do a test:

     @BeforeClass
     protected void setup() {
         RegistryBuilder builder = new RegistryBuilder();

         builder.add(HibernateModule.class);
         builder.add(SetupForTest.class);
         builder.add(AppModule.class);

         Registry registry = builder.build();

         registry.performRegistryStartup();

         userService = registry.getService("userService",  
UserService.class);

     }

     @Test
     public void testAddUsers() throws Exception {

         User user = createRandomUser();
         userService.save(user);

         List<User> users = userService.getUsers();
         assertEquals(1, users.size());
     }

Now, the first problem is that this will not be committed to the  
database, when you have hibernate configured with autocommit=false. To  
accomplish that, I need to grab the session out of the registry and  
add this:

     @AfterClass
     protected void closeSession() throws Exception {
         session.getTransaction().commit();
         session.close();
     }

I would have thought that Tapestry-hibernate would take care of that  
(it does when run as a webapp, so no real problem here), given it is  
supposed to commit or rollback when the thread ends (in this case the  
thread is running all the tests).

My real question comes when I want to test some of the constraints on  
my database. For instance, there is a unique constraint on the  
username in the User class. So a test might be:

     @Test
     public void testAddUsersWithSameUsernames() throws Exception {

         User user = createRandomUser("woodj");
         userService.save(user);

         User duplicateUser = createRandomUser("woodj");
         try {
             userService.save(duplicateUser);

             Assert.fail("Should have thrown exception with duplicate  
username constraint exception.");
         } catch (HibernateException e) {
             //success
         }
    }

Now when this test is run I get a failure (don't flush the Session  
after an exception occurs), because of my closeSession method. I can  
remove the closeSession, which shouldn't really be there anyway, and  
everything passes, but I don't get the additional comfort of checking  
my db to make sure hibernate synched things up properly.

I can rollback manually in the exception, by getting the current txn  
from the session service, but I get the same failure. It seems that no  
matter what you do, once an exception is thrown, and regardless of how  
you handle it, that session is done.

I've also tried all the aforementioned, but using the  
HibernateSessionManager service to grab the session, which should  
allow me to commit and abort midsession, but it suffers the exact same  
failures, despite it's assurance in the javadoc:

Manages the Hibernate session for the current thread. This includes  
creating the session as
needed, allowing the session to checkpoint (commit the current  
transaction and continue) and
commit the transaction automatically at the end of the request.

So my question is: can I test my services, under the  
HibernateSessionManager, and have the flexibility to commit and  
rollback midsession? It seems not, but maybe I missed something.

And just BTW, if I create my own SessionFactory and handle the session  
and txn's myself, everything works as expected.

Thanks for any thoughts.

J

On Feb 4, 2008, at 8:01 AM, Davor Hrg wrote:

> HibernateSessionManager handles session for a request,
> and does commit at the end.
>
> if you want to have more than one commit you should not call it
> directly on the injected session since it will confuse  
> HibernateSessionManager.
> Same goes for rollback.
>
> Davor Hrg
>
>
> On Feb 4, 2008 3:52 PM, Angelo Chen <an...@yahoo.com.hk>  
> wrote:
>>
>> hi,
>>
>> I have used Session session in my app and it works, I have seen
>> HibernateSessionManager being mentioned many times in the list,  
>> what are the
>> advantages of using HibernateSessionManager compared app which does  
>> not
>> explicitly use it?
>>
>> Thanks,
>>
>> Angelo
>> --
>> View this message in context: http://www.nabble.com/T5%3A-HibernateSessionManager-tp15268872p15268872.html
>> Sent from the Tapestry - User mailing list archive at Nabble.com.
>>
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
>> For additional commands, e-mail: users-help@tapestry.apache.org
>>
>>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
> For additional commands, e-mail: users-help@tapestry.apache.org
>
>


---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org


Re: T5: HibernateSessionManager

Posted by Julian Wood <wo...@ucalgary.ca>.
Given your recommendation that using HibernateSessionManager in unit  
tests is not appropriate, and Howard's little hint about constructor- 
based injection, I was able to come up with an acceptable strategy,  
whereby I create the sessionfactory and the session for my unit tests,  
and pass that session to each of my services. This means I don't need  
to create the registry anymore, which is fine, because I'm not testing  
the registry (nor HSM, for that matter).

     @BeforeClass
     protected void setup() {
         AnnotationConfiguration configuration = new  
AnnotationConfiguration();
         configuration.addAnnotatedClass(User.class);
         SessionFactory sessionFactory =  
configuration.configure().buildSessionFactory();
         session = sessionFactory.openSession();

         userService = new UserServiceImpl(session);

     }

Thanks,

J


On Mar 18, 2008, at 5:05 PM, Josh Canfield wrote:

> You need to call session.flush after you save, this will send your
> data to the database and trigger any constraint exceptions.
> http://www.hibernate.org/hib_docs/v3/api/org/hibernate/Session.html#flush()
>
> I'm pretty sure that the tapestry-hibernate thread/request management
> is done within the context of a request and you will need to plumb
> that yourself, perhaps in @Before and @After methods. I can't look it
> up now, but if I think about it later I'll track it down.
>
> I wouldn't recommend this approach though. In your tests you should
> want to have more control over what is happening with your objects.
> For instance, letting tapestry-hibernate take care of the flush/commit
> of the session/transaction means that you can't write tests like your
> second one because it wouldn't throw an exception until
> tapestry-hibernate cleanup happend after the method has exited.
>
> Josh
>
> On Tue, Mar 18, 2008 at 10:54 AM, Julian Wood <wo...@ucalgary.ca>  
> wrote:
>> I have a UserService:
>>
>> public class UserServiceImpl implements UserService {
>>    private Session session;
>>
>>    public UserServiceImpl(@InjectService("Session")Session session) {
>>        this.session = session;
>>    }
>>
>>    public void save(User user) {
>>        session.save(user);
>>    }
>> }
>>
>> I bind this in the AppModule, and then I can use it in any page or
>> component class. This is great.
>>
>> Now for unit testing my UserService, I make my own RegistryBuilder as
>> others have recommended, and can do a test:
>>
>>    @BeforeClass
>>    protected void setup() {
>>        RegistryBuilder builder = new RegistryBuilder();
>>
>>        builder.add(HibernateModule.class);
>>        builder.add(SetupForTest.class);
>>        builder.add(AppModule.class);
>>
>>        Registry registry = builder.build();
>>
>>        registry.performRegistryStartup();
>>
>>        userService = registry.getService("userService",
>> UserService.class);
>>
>>    }
>>
>>    @Test
>>    public void testAddUsers() throws Exception {
>>
>>        User user = createRandomUser();
>>        userService.save(user);
>>
>>        List<User> users = userService.getUsers();
>>        assertEquals(1, users.size());
>>    }
>>
>> Now, the first problem is that this will not be committed to the
>> database, when you have hibernate configured with autocommit=false.  
>> To
>> accomplish that, I need to grab the session out of the registry and
>> add this:
>>
>>    @AfterClass
>>    protected void closeSession() throws Exception {
>>        session.getTransaction().commit();
>>        session.close();
>>    }
>>
>> I would have thought that Tapestry-hibernate would take care of that
>> (it does when run as a webapp, so no real problem here), given it is
>> supposed to commit or rollback when the thread ends (in this case the
>> thread is running all the tests).
>>
>> My real question comes when I want to test some of the constraints on
>> my database. For instance, there is a unique constraint on the
>> username in the User class. So a test might be:
>>
>>    @Test
>>    public void testAddUsersWithSameUsernames() throws Exception {
>>
>>        User user = createRandomUser("woodj");
>>        userService.save(user);
>>
>>        User duplicateUser = createRandomUser("woodj");
>>        try {
>>            userService.save(duplicateUser);
>>
>>            Assert.fail("Should have thrown exception with duplicate
>> username constraint exception.");
>>        } catch (HibernateException e) {
>>            //success
>>        }
>>   }
>>
>> Now when this test is run I get a failure (don't flush the Session
>> after an exception occurs), because of my closeSession method. I can
>> remove the closeSession, which shouldn't really be there anyway, and
>> everything passes, but I don't get the additional comfort of checking
>> my db to make sure hibernate synched things up properly.
>>
>> I can rollback manually in the exception, by getting the current txn
>> from the session service, but I get the same failure. It seems that  
>> no
>> matter what you do, once an exception is thrown, and regardless of  
>> how
>> you handle it, that session is done.
>>
>> I've also tried all the aforementioned, but using the
>> HibernateSessionManager service to grab the session, which should
>> allow me to commit and abort midsession, but it suffers the exact  
>> same
>> failures, despite it's assurance in the javadoc:
>>
>> Manages the Hibernate session for the current thread. This includes
>> creating the session as
>> needed, allowing the session to checkpoint (commit the current
>> transaction and continue) and
>> commit the transaction automatically at the end of the request.
>>
>> So my question is: can I test my services, under the
>> HibernateSessionManager, and have the flexibility to commit and
>> rollback midsession? It seems not, but maybe I missed something.
>>
>> And just BTW, if I create my own SessionFactory and handle the  
>> session
>> and txn's myself, everything works as expected.
>>
>> Thanks for any thoughts.
>>
>> J
>>
>>
>> On Feb 4, 2008, at 8:01 AM, Davor Hrg wrote:
>>
>>> HibernateSessionManager handles session for a request,
>>> and does commit at the end.
>>>
>>> if you want to have more than one commit you should not call it
>>> directly on the injected session since it will confuse
>>> HibernateSessionManager.
>>> Same goes for rollback.
>>>
>>> Davor Hrg
>>>
>>>
>>> On Feb 4, 2008 3:52 PM, Angelo Chen <an...@yahoo.com.hk>
>>> wrote:
>>>>
>>>> hi,
>>>>
>>>> I have used Session session in my app and it works, I have seen
>>>> HibernateSessionManager being mentioned many times in the list,
>>>> what are the
>>>> advantages of using HibernateSessionManager compared app which does
>>>> not
>>>> explicitly use it?
>>>>
>>>> Thanks,
>>>>
>>>> Angelo
>>>> --
>>>> View this message in context: http://www.nabble.com/T5%3A-HibernateSessionManager-tp15268872p15268872.html
>>>> Sent from the Tapestry - User mailing list archive at Nabble.com.
>>>>
>>>>
>>>> ---------------------------------------------------------------------
>>>> To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
>>>> For additional commands, e-mail: users-help@tapestry.apache.org
>>>>
>>>>
>>>
>>> ---------------------------------------------------------------------
>>> To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
>>> For additional commands, e-mail: users-help@tapestry.apache.org
>>>
>>>
>>
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
>> For additional commands, e-mail: users-help@tapestry.apache.org
>>
>>
>
>
>
> -- 
> --
> TheDailyTube.com. Sign up and get the best new videos on the internet
> delivered fresh to your inbox.
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
> For additional commands, e-mail: users-help@tapestry.apache.org
>
>


---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org


Re: T5: HibernateSessionManager

Posted by Josh Canfield <jo...@thedailytube.com>.
You need to call session.flush after you save, this will send your
data to the database and trigger any constraint exceptions.
http://www.hibernate.org/hib_docs/v3/api/org/hibernate/Session.html#flush()

I'm pretty sure that the tapestry-hibernate thread/request management
is done within the context of a request and you will need to plumb
that yourself, perhaps in @Before and @After methods. I can't look it
up now, but if I think about it later I'll track it down.

I wouldn't recommend this approach though. In your tests you should
want to have more control over what is happening with your objects.
For instance, letting tapestry-hibernate take care of the flush/commit
of the session/transaction means that you can't write tests like your
second one because it wouldn't throw an exception until
tapestry-hibernate cleanup happend after the method has exited.

Josh

On Tue, Mar 18, 2008 at 10:54 AM, Julian Wood <wo...@ucalgary.ca> wrote:
> I have a UserService:
>
> public class UserServiceImpl implements UserService {
>     private Session session;
>
>     public UserServiceImpl(@InjectService("Session")Session session) {
>         this.session = session;
>     }
>
>     public void save(User user) {
>         session.save(user);
>     }
> }
>
> I bind this in the AppModule, and then I can use it in any page or
> component class. This is great.
>
> Now for unit testing my UserService, I make my own RegistryBuilder as
> others have recommended, and can do a test:
>
>     @BeforeClass
>     protected void setup() {
>         RegistryBuilder builder = new RegistryBuilder();
>
>         builder.add(HibernateModule.class);
>         builder.add(SetupForTest.class);
>         builder.add(AppModule.class);
>
>         Registry registry = builder.build();
>
>         registry.performRegistryStartup();
>
>         userService = registry.getService("userService",
> UserService.class);
>
>     }
>
>     @Test
>     public void testAddUsers() throws Exception {
>
>         User user = createRandomUser();
>         userService.save(user);
>
>         List<User> users = userService.getUsers();
>         assertEquals(1, users.size());
>     }
>
> Now, the first problem is that this will not be committed to the
> database, when you have hibernate configured with autocommit=false. To
> accomplish that, I need to grab the session out of the registry and
> add this:
>
>     @AfterClass
>     protected void closeSession() throws Exception {
>         session.getTransaction().commit();
>         session.close();
>     }
>
> I would have thought that Tapestry-hibernate would take care of that
> (it does when run as a webapp, so no real problem here), given it is
> supposed to commit or rollback when the thread ends (in this case the
> thread is running all the tests).
>
> My real question comes when I want to test some of the constraints on
> my database. For instance, there is a unique constraint on the
> username in the User class. So a test might be:
>
>     @Test
>     public void testAddUsersWithSameUsernames() throws Exception {
>
>         User user = createRandomUser("woodj");
>         userService.save(user);
>
>         User duplicateUser = createRandomUser("woodj");
>         try {
>             userService.save(duplicateUser);
>
>             Assert.fail("Should have thrown exception with duplicate
> username constraint exception.");
>         } catch (HibernateException e) {
>             //success
>         }
>    }
>
> Now when this test is run I get a failure (don't flush the Session
> after an exception occurs), because of my closeSession method. I can
> remove the closeSession, which shouldn't really be there anyway, and
> everything passes, but I don't get the additional comfort of checking
> my db to make sure hibernate synched things up properly.
>
> I can rollback manually in the exception, by getting the current txn
> from the session service, but I get the same failure. It seems that no
> matter what you do, once an exception is thrown, and regardless of how
> you handle it, that session is done.
>
> I've also tried all the aforementioned, but using the
> HibernateSessionManager service to grab the session, which should
> allow me to commit and abort midsession, but it suffers the exact same
> failures, despite it's assurance in the javadoc:
>
> Manages the Hibernate session for the current thread. This includes
> creating the session as
> needed, allowing the session to checkpoint (commit the current
> transaction and continue) and
> commit the transaction automatically at the end of the request.
>
> So my question is: can I test my services, under the
> HibernateSessionManager, and have the flexibility to commit and
> rollback midsession? It seems not, but maybe I missed something.
>
> And just BTW, if I create my own SessionFactory and handle the session
> and txn's myself, everything works as expected.
>
> Thanks for any thoughts.
>
> J
>
>
> On Feb 4, 2008, at 8:01 AM, Davor Hrg wrote:
>
> > HibernateSessionManager handles session for a request,
> > and does commit at the end.
> >
> > if you want to have more than one commit you should not call it
> > directly on the injected session since it will confuse
> > HibernateSessionManager.
> > Same goes for rollback.
> >
> > Davor Hrg
> >
> >
> > On Feb 4, 2008 3:52 PM, Angelo Chen <an...@yahoo.com.hk>
> > wrote:
> >>
> >> hi,
> >>
> >> I have used Session session in my app and it works, I have seen
> >> HibernateSessionManager being mentioned many times in the list,
> >> what are the
> >> advantages of using HibernateSessionManager compared app which does
> >> not
> >> explicitly use it?
> >>
> >> Thanks,
> >>
> >> Angelo
> >> --
> >> View this message in context: http://www.nabble.com/T5%3A-HibernateSessionManager-tp15268872p15268872.html
> >> Sent from the Tapestry - User mailing list archive at Nabble.com.
> >>
> >>
> >> ---------------------------------------------------------------------
> >> To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
> >> For additional commands, e-mail: users-help@tapestry.apache.org
> >>
> >>
> >
> > ---------------------------------------------------------------------
> > To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
> > For additional commands, e-mail: users-help@tapestry.apache.org
> >
> >
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
> For additional commands, e-mail: users-help@tapestry.apache.org
>
>



-- 
--
TheDailyTube.com. Sign up and get the best new videos on the internet
delivered fresh to your inbox.

---------------------------------------------------------------------
To unsubscribe, e-mail: users-unsubscribe@tapestry.apache.org
For additional commands, e-mail: users-help@tapestry.apache.org