Search code examples
javahibernatetapestry

Tapestry services implemetation with Hibernate usage


I'm talking about T5, Java 1.7.

I can not find any enough detailed tutorial about using hibernate inside Tapestry services. What I need is to create Tapestry service which could deal with hibernate independently. This could be scheduler service, for example. This service will deal with some objects and their state in DB, and work in background of application.

The question is, how correctly bind it with Hibernate? Which object of Hibernate should be injected for further work inside this Service?


The current approach is to inject inside this service a HibernateSessionSource object (passing its instance through constructor of service), and then manually create sessions, begin the transactions and so on. E.g.:

public synchronized void deleteJob(long id) {
    Session session = hss.create();
    JobItem job = (JobItem) session.get(JobItem.class, id);
    if (job != null) {
        Transaction tx = session.beginTransaction();
        try {
            session.delete(job);
            tx.commit();
        } catch (HibernateException e) {
            tx.rollback();
        } finally {
            session.close();
        }
    }
}

It looks very ugly, not in style of Tapestry. What it is the smart approach?


Solution

  • This question consists of 2 parts:

    How to use hibernate inside tapestry managed services?

    You can inject hibernate session in your service using @Inject annotation:

    @Inject
    private Session session;
    

    or as a constructor parameter:

    public MyService buildMyService(Session session) {
      return new MyAwsomeService(session);
    }
    

    Then you can use it inside service. This session is managed by tapestry as a perthread service. It will be opened on first usage and be closed after end of request.

    How to use hiberanate transations inside tapestry managed services?

    You can do this manually using injected HibernateSessionManager:

    @Inject
    private HibernateSessionManager manager;
    
    public void doSomeWork(Entity entity) {
      try {
        session.delete(entity);
        manager.commit();
      } catch (Exception e) {
        manager.abort();
      }
    }
    

    Or you can annotate all transactional methods with @CommitAfter and advise services using HibernateTransactionAdvisor:

    public interface MyService {
    
      @CommitAfter
      void doSomeWork(Entity entity);
    
    }
    
    public class MyTapestryModule {
      @Match("*Service")
      public void adviseTransactions(HibernateTransactionAdvisor advisor,
                                     MethodAdviceReceiver receiver) {
        advisor.addTransactionCommitAdvice(receiver);
      }
    }
    

    Or you can decorate sevices using HibernateTransactionDecorator:

    public class MyTapestryModule {
      @Match("*Service")
      public <T> T decorateTransactions(Class<T> serviceInterface,
                                        T delegate,
                                        String serviceId,
                                        HibernateTransactionDecorator decorator) {
        return decorator.build(serviceInterface, delegate, serviceId);
      }
    }
    

    How it works. It will start new transaction before method invocation and try to commit after. If any error occurs during method invocation this transaction will be rolled back.