Dave Johnson on open web technologies, social software and software development
« Thanks. | Main | One of my issues. »
Roller has changed quite a bit since the Roller article was published on the O'Reilly site. Roller has moved from a two layer architecture with a Presentation Layer and a Business Layer to a three layer architecture with Presentation, Business, and Persistence Layers. This article covers the transition and will bring you up to date with the current Roller persistence architecture.
Then, as now, the Roller Business layer was a small collection of interfaces. The Roller
interface was the entry point and provided access to the various Roller manager interfaces. Back then, the Business Layer interfaces were implemented in the org.roller.business
package and used the Castor O/R mapping framework APIs directly. The diagram below illustrates this point. The org.roller.business
package implements the Business Layer intefaces defined in org.roller.model
and depends on org.exolab.castor
.
Earlier this year, during Roller 0.9.7 development, we decided to create an implementation of the Roller Business Layer using the Hibernate O/R framework. We moved the Castor implementation into the org.roller.business.castor package
and added the new Hibernate implementation in org.roller.business.hibernate
. In the process we noticed a lot of code duplication and we tried to move common code back up into org.roller.business
, but we had limited success. The diagram below illustrates this situation: separate Castor and Hibernate implementations of the Roller Business Layer with some shared code.
Since Roller 0.9.7, the Roller Business Layer implementation has been evolving and moving towards that three layer architecture mentioned at the start of this article. We introduced a
PersistenceStrategy
interface and a persistence package in
org.roller.persistence
. Over time we have slowly moved almost all Castor and Hibernate specific code behind the PersistenceStrategy
interface. I say almost because, there are a couple of cases where the Persistence Layer abstraction is not powerful enough to handle the queries needed by the Business Layer. Specifically, the RefererManager.getHits()
and RefererManager.getDaysPopularWebsites()
methods need to drop down to raw SQL because, apparently, neither Castor nor Hibernate can handle the queries we need to do.
The diagram below illustrates the current situation. The Business Layer calls upon the Persistence Layer for object storage, retrieval, and queries. The org.roller.business.castor
and org.roller.business.hibernate
packages are shown in grey because they still exist but are on the way out.
Thus far, we've been looking at things at the package level. Let's zoom in on the
org.roller.persistence
package and take a close look at the key interfaces in that package:
<a href=
"http://www.rollerweblogger.org/javadoc/org/roller/persistence/PersistenceStrategy.html">
PersistenceStrategy
,
<a href=
"http://www.rollerweblogger.org/javadoc/org/roller/persistence/QueryFactory.html">
QueryFactory
, and
<a href=
"http://www.rollerweblogger.org/javadoc/org/roller/persistence/Query.html">
Query
.
PersistenceStrategy
supports storage, retrieval, and removal of objects. To execute a query, you create a Query
object using the QueryFactory
, create a where clause by adding Conditions together, set a limit if desired, set an order-by if desired, and call the Query.execute()
method. At that point, the Query
implementation will generate an HQL query for Hibernate or an OQL query string for Castor and will call the appropriate method to execute the query. Below is some example code to illustrate typical usage of the Query API.
public List getTodaysReferers(WebsiteData website) throws RollerException { if (website==null ) throw new RollerException("Website is null"); QueryFactory factory = mStrategy.getQueryFactory(); Query query = factory.createQuery(RefererData.class.getName()); Condition specifiedUser = factory.createCondition( "website", Query.EQ, website); Condition hasDayHits = factory.createCondition( "dayHits", Query.GT, new Integer(0)); Condition userEnabled = factory.createCondition( "website.user.userEnabled", Query.EQ, new Boolean(true)); List conditions = new LinkedList(); conditions.add(specifiedUser); conditions.add(hasDayHits); conditions.add(userEnabled); query.setWhere(factory.createCondition(Query.AND, conditions)); query.setOrderBy(Query.DESC, "dayHits"); return query.execute(); }
The PersistenceStrategy
interface is a fairly simple abstraction, sort of a least common denominator approach, but it is expressive enough to handle all of the requirements of Roller. This approach allows the Roller Business Layer to be completely independent of the underlying persistence mechanism. This is really nothing new. PersistenceStrategy
is essentially a generic Data Access Object (DAO). I use the word "generic" because most DAOs I've seen are specific to one type of object, a CustomerDAO or EmployeeDAO for example, but PersistenceStrategy
handles any persistent object in the system. I'm interested to see how this approach holds up. Will we eventually find the simple API to be too limiting? Will it be possible to implement PersistentStrategy
with other persistence technologies such as JDO?
Dave Johnson in Roller
04:18PM Nov 30, 2003
Comments [1]
Tags:
Roller
« Thanks. | Main | One of my issues. »
This is just one entry in the weblog Blogging Roller. You may want to visit the main page of the weblog
Below are the most recent entries in the category Roller, some may be related to this entry.
Posted by Bo on December 01, 2003 at 01:30 PM EST #