Help

I'm the guy you can blame if this website is crashing. In fact, send me an e-mail if it does, so I can fix it. If you only want to read my entries, subscribe to my blog.

Location: Switzerland, CET
Books I'm currently reading
Google Web Toolkit Applications
Didn't like the first GWT book I read, so this is now an attempt with another book. Halfway through the book and so far it's quite good.
My Books
Java Persistence with Hibernate
with Gavin King
November 2006
Manning Publications
841 pages (English), PDF ebook
703 pages (German)
Hibernate in Action
with Gavin King
August 2004
Manning Publications
408 pages (English), PDF ebook
Unternehmen im Internet
with Ingo Petzke, Michael Mueller
1998
Oldenbourg
300 pages (German)
Tags
Seam Wiki (5)
Seam (4)
Books (1)
Seam News (1)
Archive
Repository Pattern vs. Transparent Persistence
10. Nov 2007, 17:39 CET, by Christian Bauer

I've recently read the book Domain Driven Design, which apparently is now the new bible for some folks who totally think in objects. I even mentioned it in HiA and JPwH - unfortunately I didn't read it before.

I now think that quite a few of the patterns promoted by this book are actually a step backwards. I also miss a list of Pros and Cons of each pattern (like in the GoF book). So readers have to guess why and when a pattern might be applicable and when not. Or, when the Cons bullet items would outweigh the Pros.

One example would be the /Repository/ pattern. If I understand it correctly, this is how it works (the DDD author says that this similar summary is correct):

  • Developers don't want to decide if they should call order.getLineItems() or rather lineItemDAO.findAllForOrderId(order.getId()) if they need a bunch of line items from the data store. (I completely agree that this is a typical and common issue - however, I don't agree with the proposed solution.)
  • We can restrict that and take away that decision by forcing access to always go through a repository. For example, there is only an OrderRepository and the only way to get line items would be OrderRepository.getLineItems(order). This repository thing uses DAOs internally to actually get the data. So we wrap DAOs in repositories, creating an additional layer. You are not supposed to call the DAO anymore.
  • Now, we generalize the OrderRepository into an interface and put the DAO access into OrderRepositoryImpl.
  • And finally: We then inject this concrete OrderRepository instance into the Order class, so that when you call order.getLineItems(), it will internally access the repository. This requires interception of domain model instance creation but that is easy enough to do these days with containers/factories/services everywhere. Nobody creates a /new/ instance anymore, right?

The advantages seem to be that repositories speak the language of the domain (eh, what? This seems to be related to passing IDs as DAO finder arguments...) and that, well, you no longer have to make these difficult choices when you want to access a data store, because there is only one way to get the stuff.

I think this pattern is a step backwards and should not be recommended:

  1. If you do not want to have to decide between order.getLineItems() and lineItemDAO.findAllForOrderId(order.getId()) - kick out one of these methods! Nobody forces you to map a persistent lineItems collection on your Order class. You did that because you like the features you get when you load data that way (in Hibernate: transparent pre-fetching of other lineItems collections with batches or subselects, can't do that nicely in DAO finders). If you don't need that, don't create it. The same is true for any other association in your domain model. Or, vice versa, if there is no difference between a DAO finder method and a domain model traversal, remove the DAO method.
  2. If there really is a difference between order.getLineItems() and lineItemDAO.findAllForOrderId(order.getId()) - for example, one returns more associated stuff, like the product for each line item - keep them both. I do that all the time. I document it properly, saying this finder method does eager fetching of the product for each line item and on the getter method I write this returns line items, the products are unloaded proxies. And of course I need them both. Actually, I rename the DAO finder to lineItemDAO.findAllForOrderIdWithProducts(order.getId()) or, if I want to speak the language of the domain nothing stops me from defining it as lineItemDAO.findAllForOrderWithProducts(order). Because I don't like repeating myself, I finally end up with lineItemDAO.findWithProducts(order). It's now quite easy to decide if I call this, or rather order.getLineItems() - they have a different fetch strategy and fetch plan.
  3. You could argue that it would be nice if everything would /look/ the same. That is, following this repository pattern I would end up with an API like order.getLineItems() and order.getLineItemsWithProducts(). But the price I'd have to pay is A) a completely new layer in my application that is at least as complex as the DAO layer (conceptually there really is not much difference between them) and B) coupling my domain model to these repositories. And because I think there is really no difference between a generic, interface-based DAO architecture and these repositories, it means injecting DAOs into my domain model instances at runtime. That means they don't run anymore without DAOs (mock or real). Wrapping the DAOs again and again does not change that.
  4. If you do not inject and call repositories in your domain model classes, you gained nothing. You created a layer on top of the DAOs that looks like the DAOs, albeit with funny new names.

My personal best practices, when you have to decide how the persistence layer and services are integrated with the rest of the system, would be these:

  • Optimize access paths and simplify data access by carefully designing the domain model associations and persistence layer API (the latter following some good DAO pattern and related best practices - yes, there are books about this). Use the features of your transparent persistence service to make sure that all these access paths do the right thing, depending on what you need.
  • Document the access paths properly, and when each should be used. I adopt some simple conventions, for example: Never map a persistent collection unless it is absolutely necessary - this already makes things a lot easier.
  • Keep the domain model implementation clean, testable, and reusable: no security checks, transaction demarcation, or explicit data store access in any of these classes.
Seam presentation video
07. Nov 2007, 17:46 CET, by Christian Bauer

Two weeks ago I presented Seam at Grails eXchange in London. This presentation was recorded, unfortunately without the slides in the visible frame:

The attached slide deck[1] from September is almost the same as the one I used in the video. I guess the slides are actually more interesting than watching me walk around a table. Hm, I could find out how to cut a slide + audio version with the new iMovie...

I need to mention that I spent more time on JSF and EJB3 than usual because nobody in the room knew much about them (it was a Grails conference, after all). So if you just want to know something about Seam - and again, all quite basic - skip half an hour into the video.

JBoss AS 5 presentation liveblog
25. Oct 2007, 16:28 CET, by Christian Bauer

Mark Newton presents JBoss application server 5.0 What's New at the JUG Switzerland.

History of JBoss AS

119 days average release cycle, 9 releases of JBoss 3.2.x, J2EE 1.3 certification, JDK 1.3.

126 days average release cycle, 6 releases of JBoss 4.0.x, J2EE 1.4 certification, JDK 1.4.

55 days average release cycle, 3 releases of JBoss 4.2.x, JEE 5.0 compatible implementation, not certification, does 95% of it and requires JDK 5.0.

For JBoss AS 5.0.x new standalone implementations:

  • JBoss Messaging (replaces old JBoss MQ)
  • JBoss Security
  • JBoss Federated SSO

New kernel is JBoss Microcontainer 2.0 and a profile service which is responsible for managing the POJOs that now bind the services together. Aiming for a Q1 2008 final release date and a CR in 2007.

JBoss Messaging 1.4

The new JMS 1.1 compatible messaging implementation supports distributed queues and topics as well as transparent failover and load distribution - internally it uses JGroups as transport.

Clustering

New major revision of JBoss Cache (2.1) with a much simpler API and a greater emphasis on usage outside of JBoss AS.

JBoss AOP 2.0

Integrated with the microcontainer: If you add behavior to a POJO using AOP, and you deploy it, you get dependency management - you can't call a POJO without the aspect, it won't be deployed before the aspect is available. And vice versa, aspects are not deployed if the POJOs they depend on are not deployed so far. Aspects can be bound to POJO lifecycle, e.g an aspect that binds a proxy into JNDI when the POJO enters the deployed state. It also has some new plain AOP features: Before, Afer, Throwing, Finally flows for interception.

What does the kernel do?

A microkernel needs to support dynamic loading and unloading of services. For that we need:

  • a way to deploy new services
  • a bus so that the client does not communicate with a service directly, clients are decoupled from services

How was this done in JBoss 3.x and 4.x? We used an MBeanServer to provide the bus and deployers that load services into the kernel together with a simple dependency injection mechanism. MBeans were used to implement services and configured with XML descriptors which injected attribute values into the MBeans at deployment. XMBean are special MBeans that allow you to add method interception to an MBean. Calls pass through the bus and interceptors with a level of indirection through a generic invoke(method, arguments, argumentTypes) operation.

For performance reasons the bus wasn't actually used much: A reference to a services would be looked up directly in the registry. So the interceptors were not used.

What was bad about the JBoss JMX microkernel:

  • JMX is restrictive, lifecycle and classloading were a problem
  • You can't run JMX on Java ME
  • You actually need to know how to implement MBeans
  • If you access services directly through a reference, interceptors are not applied

Design objectives for JBoss AS 5.x

Services should be POJOs and behavior should be added through AOP - effectively reproducing all the features of the JMX microkernel. Much improved dependency injection and classloading. Layered and easily extensible design (no references to JBoss classes), should be usable without JBoss AS.

The new name for this kernel is Microcontainer.

The core of the microcontainer is Container, Kernel, Dependency. Behavior is added with JBoss AOP.

Kernel: Provides the bus and registry, and an event manager.

Container: Wrapper for POJOs, AOP jointpoints and reflection on the actual service implementation POJO.

Dependency: Basically an abstract state machine that manages service dependencies.

Some optional packages on top of the core: OSGI integration, Guice integration.

Creating a service

Define the POJO with <bean> and <property> declarations in jboss-beans.xml (replaces the old jboss-service.xml). Beans have a name and a class, properties support injection with references to (other) bean names.

Add behavior using the <aop:aspect> namespace and elements and pointcut expressions. You can also extract the aspect/pointcut to a separate file.

Profile service

Management system for POJOs instead of the old JMX based administration which was based on editing XML files. People would manage configurations by keeping these files in CVS. The web console only supported changing the runtime values in memory, didn't write back into the files.

What we want:

  • Centralized maintenance as profiles, e.g. all, minimal, default, ...
  • Persistence of changes made to a profile across server restarts
  • Propagation of profile changes across a cluster
  • Versioning of profiles

Implementation similar to JDK 6 Open MBeans specification: A deployment has a collection of ManagedObjects, you define them with annotations in your service, e.g. @ManagedOperation(description="A setting you can change")

Summary

  • JBoss AS 5.0 has a completely new architecture based on the microcontainer with POJOs and AOP
  • Management improved with the addition of profile service
  • Clustering and security is much enhanced
  • It will be fully Java EE 5.0 compliant
JBoss MC and AS 5.0 presentation at JUGS Zurich
22. Oct 2007, 17:05 CET, by Christian Bauer

Ales Justin and Mark Newton are going to present the new JBoss application server core and kernel on Thursday this week, at a meeting of the JBoss special interest group. See you there.

Java Persistence with Hibernate book available in German
10. Oct 2007, 15:59 CET, by Christian Bauer

Our book Java Persistence with Hibernate is now available in German. You can get it from Hanser Verlag and they also have an eBook edition available. This is a literal translation of the English original. However, to finish the translation faster we decided to cut the bonus chapter with the Seam introduction. Sorry folks, I will ask Manning if we can get this chapter published for free in the English original version. With Seam 2.0 approaching final release this is a bit outdated anyway.

Showing 6 to 10 of 39 blog entries