About This Blog

This blog contains some information about Java programming strongly connected to making web pages, and JEE applications.

8 July 2008 - 21:27Wicket project nearly finished

There pass some time from my last writing here, there is no one, simple reason for that - maybe the most importat was that I went from theory to the practice with my Wicket skills. Previous posts were rather theroretical, books based news  - now my knowledge of the Wicket stuff is much more wide. In March company I work for started project which was related to car parts advertisements, now the project grows to quite nice car portal. There are advertisement section, questions and answers (or forum if you like the difference is subtle), picture gallery, user inbox stuff, full i18n.

All is powered by Wicket, Hibernate, Spring, search job are done by Hibernate Search (great collection indexing feature), lot of data is cached  by Ehcache. There are also plans of use Databinder, Terracotta and even Scala if my friend and great co-worker Tomek teach rest of the team this fabulous language.

Most important - link to the project http://www.auxto.pl/ - this is Polish version, but soon I think we launch others.

Thanks to the team Marcin, Tomek and Paweł - great work gentelmans :)

No Comments | Tags: Lucene, Wicket, hibernate, search, spring

18 February 2008 - 19:36Wicket and Hibernate Search

Hibernate Search is a full-text search based on Lucene which integrates near transparently with Hibernate ORM. Creating Lucene index on entities is really simple when you can use annotations in your code. First you need to mark your class as @Indexed, next assign @DocumentId to the entity primary key, last thing would be mark instance fields as indexable with @Field annotation - see the example below.

@Entity
@Indexed
public class Advertisement implements Serializable {
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	@DocumentId
	private Integer id;
 
	@Field(index=Index.TOKENIZED, store=Store.NO)
	private String title;
 
	private String body;
 
	@Field(index=Index.TOKENIZED, store=Store.YES)
	public String getRawBody() {
		Pattern pattern = Pattern.compile("<[^>]*>");
		Matcher matcher = pattern.matcher(this.body);
		return matcher.replaceAll("");
	}
 
	//getters / setters
}
 

You need to add some properties to Hibernate SessionFactory - e.g. in Spring Framework it would be something like this:

<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="hibernateProperties">
<props>
<prop key="hibernate.search.default.directory_provider">org.hibernate.search.store.FSDirectoryProvider</prop>
<prop key="hibernate.search.default.indexBase">/usr/home/ghost/workspace/AdvertisementSystem/target/search</prop>
	    	</props>
	</property>
<bean>
 

All of above is well described in Hibernate Search documentation, but some troubles could be with Wicket integration, in which we use DataView to show paginated data. This view needs to get DataProvider object which have to implements iterator() and size() methods, and it's quite obvious when using databases, but not when using Hibernate Search - why? Because it returns number of all results when querying even for part of them, so why you would ask search twice - my solution for this problem is:

class SearchDataProvider implements IDataProvider {
 
	private String query;
 
	private int resultsPerPage;
 
	private SearchDAO.SearchResults searchedAdverts;
 
	private Integer resultsCount; 
 
	public SearchDataProvider(String query, int resultsPerPage) {
		this.query = query;
		this.resultsPerPage = resultsPerPage;
	}
 
	public Iterator iterator(int first, int count) {
		if(searchedAdverts == null) {
			searchedAdverts = searchDAO.getSearchedAdverts(this.query, first, count);
		}
		return searchedAdverts.getResults().iterator();
	}
 
	public IModel model(Object object) {
		return new Model((Advertisement) object);
	}
 
	public int size() {
		if(resultsCount == null) {
			searchedAdverts = searchDAO.getSearchedAdverts(this.query, 0, this.resultsPerPage);
			resultsCount = searchedAdverts.getCount();
		}
		return resultsCount;
	}
 
	public void detach() {
		searchedAdverts = null;
	}
}
 

In DAO:

public SearchResults getSearchedAdverts(final String queryString, int first, int count) {
	Session session = getSession(true);
	FullTextSession fullTextSession = Search.createFullTextSession(session);
	SearchResults results = null;
	Transaction tx = fullTextSession.beginTransaction();
	MultiFieldQueryParser parser = new MultiFieldQueryParser( new String[]{"title", "rawBody"}, new StandardAnalyzer());
	Query query;
	try {
		query = parser.parse(queryString);
		FullTextQuery hibQuery = fullTextSession.createFullTextQuery(query, Advertisement.class)
			.setFirstResult(first)
			.setMaxResults(count);
		results = new SearchResults(hibQuery.list(), hibQuery.getResultSize());
	} catch (ParseException e) {
		e.printStackTrace();
	} finally {
		tx.commit();
		session.close();
	}
}
 

In my case SearchResults is private class which wraps list of results and ALL result counter, there is some problem in Spring with using HibernateTemplate() so I manually get new session. In DataProvider size() is asked only once when new DataView is instanced, and it takes first 20 results, store them as detached object, and set up number of results for a later use (when processing to next pages).

No Comments | Tags: Lucene, Wicket, hibernate, search

3 January 2008 - 14:13Hibernate in Spring

Probably most people use getHibernateTemplate() (extends HibernateDaoSupport) when invoking Hibernate in Spring - it's very good option for most cases, but for beginnings there are some of hidden features, which are used in different way in pure Hibernate. So two of them I have to use today - first was narrowing results when using Criteria - it's very simple when using HibernateTemplate:

public List<QueueElement> getObjectsFromQueue(int first, int count) {
    return getHibernateTemplate().findByCriteria(DetachedCriteria.forClass(QueueElement.class), first, count);
}
 

Using this method we get nicely narrowed results for a given class. The second example considers object counting for given Criteria:

public int getQueueSize() {
    return (Integer) getHibernateTemplate().findByCriteria(DetachedCriteria.forClass(QueueElement.class)
        .setProjection(Projections.rowCount())).get(0);
}

It's very simple way to get rows counted without using Hibernate HibernateCallback and uniqueResult() method, as we can see in older example:

public int getConsumersSize() {
    return (Integer) getHibernateTemplate().execute(new HibernateCallback() {
        public Object doInHibernate(Session session) throws HibernateException, SQLException {
            return session.createCriteria(Consumer.class)
                .setProjection(Projections.rowCount())
                .uniqueResult();
            }
    });
}

No Comments | Tags: hibernate, spring