Search code examples
databasehibernatedaocrudtapestry

Tapestry Hibernate database empty on page reload


I have just recently started learning Tapestry, trying to make my own Celebrity Collector application.

Everything worked fine, until I wanted to provide a database support instead of mocked database.

I'm using Hibernate 3.6 with Tapestry 5.3.7.

I have configured my database like this:

<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>
        <property name="hibernate.connection.driver_class">org.h2.Driver</property>
        <property name="hibernate.connection.url">jdbc:h2:target\database</property>
        <property name="hibernate.dialect">org.hibernate.dialect.H2Dialect</property>
        <property name="hibernate.connection.username">sa</property>
        <property name="hibernate.connection.password">sa</property>
        <property name="hbm2ddl.auto">create-drop</property>
        <property name="hibernate.show_sql">true</property>
        <property name="hibernate.format_sql">true</property>
    </session-factory>
</hibernate-configuration>

My DAO interface and implementation looks like this:

package com.example.addressbook.data;

import java.util.List;

import org.apache.tapestry5.hibernate.annotations.CommitAfter;
import org.apache.tapestry5.ioc.annotations.PostInjection;

import com.example.addressbook.entities.Celebrity;

public interface CelebrityDao {
    @CommitAfter
    int count();

    @CommitAfter
    void add(Celebrity celebrity);

    @CommitAfter
    Celebrity get(long id);

    @CommitAfter
    List<Celebrity> getAll();

    @CommitAfter
    List<Celebrity> getRange(long startIndex, long endIndex);

    @PostInjection
    void prepare();
}

package com.example.addressbook.data.impl;

import java.util.ArrayList;
import java.util.List;

import org.apache.tapestry5.ioc.annotations.Inject;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.criterion.Restrictions;

import com.example.addressbook.data.CelebrityDao;
import com.example.addressbook.entities.Celebrity;

public class CelebrityDaoImpl implements CelebrityDao {

    @Inject
    protected Session session;

    public void add(Celebrity celebrity) {
        session.persist(celebrity);
    }

    public Celebrity get(long id) {
        Criteria criteria = session.createCriteria(Celebrity.class);
        criteria.add(Restrictions.eq("id", id));

        Celebrity celebrity = (Celebrity) criteria.uniqueResult();

        return celebrity;
    }

    public List<Celebrity> getAll() {
        Criteria criteria = session.createCriteria(Celebrity.class);
        List rawResults = criteria.list();

        List<Celebrity> results = new ArrayList<Celebrity>();

        for (Object object : rawResults) {
            results.add((Celebrity) object);
        }

        return results;
    }

    public List<Celebrity> getRange(long startIndex, long endIndex) {
        Criteria criteria = session.createCriteria(Celebrity.class);
        criteria.add(Restrictions.between("id", startIndex, endIndex));
        List rawResults = criteria.list();

        List<Celebrity> results = new ArrayList<Celebrity>();

        for (Object object : rawResults) {
            results.add((Celebrity) object);
        }

        return results;
    }

    public void prepare() {
 // adding some initial records in the database

    }

    public int count() {
        return getAll().size();
    }

}

My ShowAll class is here:

package com.example.addressbook.pages;

import java.text.Format;
import java.util.List;

import org.apache.tapestry5.SelectModel;
import org.apache.tapestry5.ValueEncoder;
import org.apache.tapestry5.annotations.InjectPage;
import org.apache.tapestry5.annotations.OnEvent;
import org.apache.tapestry5.annotations.Persist;
import org.apache.tapestry5.annotations.Property;
import org.apache.tapestry5.annotations.SessionState;
import org.apache.tapestry5.beaneditor.BeanModel;
import org.apache.tapestry5.grid.GridDataSource;
import org.apache.tapestry5.ioc.Messages;
import org.apache.tapestry5.ioc.annotations.Inject;
import org.apache.tapestry5.services.BeanModelSource;

import com.example.addressbook.data.CelebrityDao;
import com.example.addressbook.entities.Celebrity;
import com.example.addressbook.model.User;
import com.example.addressbook.util.CelebrityEncoder;
import com.example.addressbook.util.CelebritySelectModel;
import com.example.addressbook.util.Formats;
import com.example.addressbook.util.HibernateEntityDataSource;

public class ShowAll {
    @SessionState
    private User user;

    private boolean userExists;

    @Inject
    private CelebrityDao dao;

    @InjectPage
    private Details detailsPage;

    @Property
    private Celebrity celebrity;

    @Inject
    private BeanModelSource beanModelSource;

    @Inject
    private Messages messages;

    String onActivate() {
        if (!userExists)
            return "Index";

        return null;
    }

    @OnEvent(component = "detailsLink")
    Object onShowDetails(long id) {
        Celebrity celebrity = dao.get(id);
        detailsPage.setCelebrity(celebrity);

        System.err.println("Requested ID: " + id);
        System.err.println("Result: " + celebrity.getLastName());
        return detailsPage;
    }

    public BeanModel<Celebrity> getModel() {
        return beanModelSource.createDisplayModel(Celebrity.class, messages);
    }

    public List<Celebrity> getAllCelebrities() {
        return this.dao.getAll();
    }

    public Format getDateFormat() {
        return Formats.getDateFormat();
    }

    public User getUser() {
        return user;
    }

    public GridDataSource getCelebritySource() {
        return new HibernateEntityDataSource<Celebrity>(Celebrity.class, dao);
    }

    public SelectModel getCelebrityModel() {
        return new CelebritySelectModel(getAllCelebrities());
    }

    public ValueEncoder<Celebrity> getCelebrityEncoder() {
        return new CelebrityEncoder(dao);
    }

    @Persist
    private Celebrity selectedCelebrity;

    public Celebrity getSelectedCelebrity() {
        return selectedCelebrity;
    }

    public void setSelectedCelebrity(Celebrity selectedCelebrity) {
        this.selectedCelebrity = selectedCelebrity;
    }

    public String getSelectedCelebrityName() {
        if (selectedCelebrity == null) {
            return "";
        }

        return selectedCelebrity.getFirstName() + " " + selectedCelebrity.getLastName();
    }
}

And here is how I add new ones:

package com.example.addressbook.pages;

import org.apache.tapestry5.ioc.annotations.Inject;

import com.example.addressbook.data.CelebrityDao;
import com.example.addressbook.entities.Celebrity;

public class AddCelebrity {

    private Celebrity celebrity;

    @Inject
    private CelebrityDao dao;

    public void onActivate() {
        System.out.println("OnActivate: " + dao.getAll().toString());
        if (celebrity == null) {
            celebrity = new Celebrity();
        }
    }

    public Celebrity getCelebrity() {
        return celebrity;
    }

    public void setCelebrity(Celebrity celebrity) {
        this.celebrity = celebrity;
    }

    Object onSuccess() {
        dao.add(celebrity);
        System.out.println("All celebrities: " + dao.getAll().toString());
        return ShowAll.class;
    }
}

The problem is the following: When I first come to ShowAll page, my records are pulled from the database and rendered. When I refresh the page, the records are removed magically and nothing is displayed. The database is empty (dao.getAll() returns and empty list) When I add a new Celebrity via AddCelebrity page, it is inserted into the database, but as the page is refreshed, the magic happens again and the database is empty again.

I have binded my DAO interface and implementation in AppModule class:

public static void bind(ServiceBinder binder) {
    binder.bind(SupportedLocales.class, SupportedLocalesImpl.class);
    binder.bind(CelebrityDao.class, CelebrityDaoImpl.class);
}

HELP!! :)


Solution

  • The answer was to add another method to AppModule class

    @Match("*Dao")
    public static void adviseTransactions(HibernateTransactionAdvisor advisor,
            MethodAdviceReceiver receiver) {
        advisor.addTransactionCommitAdvice(receiver);
    }
    

    So that Tapestry could actually do something with @CommitAfter annotation on my DAO methods.