Java Database Application Library


Get JDAL (Java Database Application Library) at SourceForge.net. Fast, secure and Free Open Source software downloads

Database Schema

The database has only three tables, Books, Authors and Categories. The SQL script to create the database schema for MySql is located in jdal-sample/db/create.sql.

CREATE TABLE authors (
	id INTEGER PRIMARY KEY AUTO_INCREMENT,
	name VARCHAR(100),
	surname VARCHAR(100)
) ENGINE=InnoDB;
 
 
CREATE TABLE categories (
	id INTEGER PRIMARY KEY AUTO_INCREMENT,
	name VARCHAR(100)
) ENGINE=InnoDB;
 
 
CREATE TABLE books (
	id INTEGER PRIMARY KEY AUTO_INCREMENT,
	name VARCHAR(250),
	ISBN varchar(32),
	publishedDate DATE,
	authorid INTEGER,
	categoryid INTEGER
) ENGINE=InnoDB;
 
ALTER TABLE books ADD CONSTRAINT category_fk FOREIGN KEY (categoryid) REFERENCES categories (id);
ALTER TABLE books ADD CONSTRAINT author_fk FOREIGN KEY (authorid) REFERENCES authors (id);
 

Domain Model

We start creating the Java classes to model data. The models are one to one to database tables and have not behavior. Obviously, this is not a requeriment, it's only a simple example. Models are located in package org.jdal.samples.library.model.

We use JPA annotations to map the model properties to the database schema. The class info.joseluismartin.model.Entity is a simple class with Long id and String name properties with @MappedSuperClass annotation.

@Entity
@Table(name="categories")
public class Category extends info.joseluismartin.model.Entity {
	// nothing to add a Entity class.
}
 

In Author class we define a hibernate filter named "patternFilter". We use this filter in presentation to add autocompletion on a JComboBox.

 
@Entity
@Table(name="authors")
@Filter(name="patternFilter", condition="name like :pattern or surname like :pattern")
@FilterDef(name="patternFilter", parameters=@ParamDef(name="pattern", type="string"))
public class Author  extends info.joseluismartin.model.Entity {
 
	private String surname;
 
	public String getSurname() {
		return surname;
	}
 
	public void setSurname(String surname) {
		this.surname = surname;
	}
 
	public String toString() {
		return name + " " + surname;
	}
 
	// Overwrite equals and hashcode using name and surname 
	...
}
 

Finally the Book class.

@Entity
@Table(name="books")
public class Book extends info.joseluismartin.model.Entity {
 
	private static final long serialVersionUID = 1L;
	@ManyToOne
	@JoinColumn(name="authorid")
	private Author author;
	@ManyToOne
	@JoinColumn(name="categoryid")
	private Category category;
	private String isbn;
	private Date publishedDate;
 
	public String toString() {
		return name;
	}
 
	// Getters and Setters
}
 

There is nothing new here. lets go to handle the Book Filter.

Filters

As we have seen before, the sample has a filter panel to look for books. Real applications have many similar filters, so we need an easy way to handle them. Jdal provides you with some ways to create filters. At the moment we use the most simple and powerfull one, CriteriaBuilder.

CriteriaBuilder interface declares only a method: Criteria build(Criteria criteria, Object filter). Most times we simply extend the AbstractCriteriaBuilder to setup the filter. In order to add the filter feature to the application, we need to create two classes:

BookFilter must implements info.joseluismartin.dao.hibernate.Filter. The most simple way is to extend info.joseluismartin.dao.BeanFilter and add Java properties with filter data.

public class BookFilter extends BeanFilter {
 
	private String name;
	private String authorName;
	private String authorSurname;
	private Date before;
	private Date after;
	private String isbn;
	private Category category;
 
	public BookFilter() {
		this("bookFilter");
	}
 
	public BookFilter(String filterName) {
		super(filterName);
	}
 
	// Getter And Setters...
}
 

We sets the filter name in constructor, bookFilter. This name is important because we'll use it later to link the bean filter with the CriteriaBuilder using this name in spring context configuration files.

Before creating the CriteriaBuilder, review filter specification:

Now, write the CriteriaBuilder, BookCriteriaBuilder is very straight forward

public class BookCriteriaBuilder extends AbstractCriteriaBuilder {
 
	public Criteria build(Criteria criteria, Object filter) {
		BookFilter f = (BookFilter) filter;
 
		like(criteria, "name", f.getName());
		eq(criteria, "category", f.getCategory());
		le(criteria, "publishedDate", f.getBefore());
		ge(criteria, "publishedDate", f.getAfter());
 
		// Author, add alias (join) only if needed.
		if (StringUtils.hasText(f.getAuthorName()) || StringUtils.hasText(f.getAuthorSurname())) {
			criteria.createAlias("author", "author");
			like(criteria, "author.name", f.getAuthorName());
			like(criteria, "author.surname", f.getAuthorSurname());
		}
 
		return criteria;
	}
 

Now all Java coding in this tier is done.
- ¿Really? ¿and what about Daos or paging and sorting querys?.
Don't worry, that's really done before you started coding the application.

Spring Context Configuration

I normally write four application context configuracion files.

This is, of course a preference. You can do it in any way

Jdal library doesn´t include any context configuration files on jars. So we need to create all the necesary configuration files.

Writing the applicationContext-dao.xml is the last step of the integration layer. We define here the common dataSource, transactionManager and sessionFactory beans and a dao for Book, Category, and Author models.

<!-- DAOs -->
<bean id="dao" abstract="true">
	<property name="sessionFactory" ref="sessionFactory" />
</bean>
 
<bean id="basicDao" class="info.joseluismartin.dao.hibernate.HibernateDao" parent="dao" />
 
<bean id="bookDao" class="info.joseluismartin.dao.hibernate.HibernateDao"
	parent="dao">
	<constructor-arg value="org.jdal.samples.library.model.Book" />
	<!-- Add the bookCriteriaBuilder to map whit 'filterName' as key -->
	<property name="criteriaBuilderMap">
		<map key-type="java.lang.String" value-type="info.joseluismartin.dao.hibernate.CriteriaBuilder">
			<entry key="bookFilter" value-ref="bookCriteriaBuilder" />
		</map>
	</property>
</bean>
 
<!-- Book Criteria Builder -->
<bean id="bookCriteriaBuilder" class="org.jdal.samples.library.dao.filter.BookCriteriaBuilder" />
 
<bean id="authorDao" class="info.joseluismartin.dao.hibernate.HibernateDao"
	parent="dao">
	<constructor-arg value="org.jdal.samples.library.model.Author" />
</bean>
 
<bean id="categoryDao" class="info.joseluismartin.dao.hibernate.HibernateDao" parent="dao">
	<constructor-arg value="org.jdal.samples.library.model.Category" />
</bean>
 
 

We define all daos, bookDao, authorDao and categoryDao of type HibernateDao. HibernateDao is a main class within jdal-core, so we´ll explain it a little.

The more basic interface of data access library is PageableDataSource<T>. It's define two methods for requesting for data:

The class Page, holds all the necesary information to request a page of data:

The interface Dao<T, Serializable> add CRUD methos to PageableDataSource, and HibernateDao is an hibernate Dao implementation. In code, you may ask for pages of data as follows:

Dao<Book> bookDao = // get HibernateDao, JpaDao or IBatisDao reference, usually from DI
Page<Book> page = new Page(pageSize);
// Search for Fowler's books, ordered by published date
BookFilter filter = new BookFilter();
filter.setAuthorSurname("Fowler");
page.setFilter(filter);
page.serSortName("publishedDate");
// Now we can load Page from dao
bookDao.getPage(page);
// Or use page directly
page.setPageableDataSource(bookDao)
page.firstPage();
// get total records, i.e. all records, not page size.
int recordCount = page.getCount();
// As page implements paginator we can use it directly as PaginatorView model and let 
// the user to control the page load.
PaginatorView view = new PaginatorView(page)
...
// Gets the page results
List<Book> books = page.getData();
...

Page Filters are interpreted by Daos. In the case of HibernateDao implementation there are diferent posibilities

Now is more clear how our BookCriteriaBuilder works and why we added it to bookDao CriteriaBuilderMap in spring configuration.

In all cases, HibernateDao creates an Order by means of page.getSortName() and applies it before executing criteria. If Order is null, it wil try to find a 'name' property. If this is not found, then it will order by primary key as default.

Summary

We do this work to create the Book Application Data Access Layer:

The next step, is the service tier.