I'm actually doing this right now with the "hybrid" approach. An Interceptor is handling the ubiquitous fields (creation and edit dates, creation and edit user) while lazy delete is handled by tight control over queries. All of the following methods are in a persistence utility class that controls access to Hibernate.
Here's the Interceptor:
Code:
class WritableInterceptor implements Interceptor {
private UserVO user;
private Date date = new Date();
LogisticsWritableInterceptor() {}
public void setUser(UserVO user) {
this.user = user;
}
public int[] findDirty(
Object entity,
Serializable id,
Object[] currentState,
Object[] previousState,
String[] propertyNames,
Type[] types) {
return null;
}
public Object instantiate(
Class clazz,
Serializable id){
return null;
}
public Boolean isUnsaved(Object entity) {
return null;
}
public void onDelete(
Object entity,
Serializable id,
Object[] state,
String[] propertyNames,
Type[] types
) {
//Do nothing
}
public boolean onFlushDirty(
Object entity,
Serializable id,
Object[] currentState,
Object[] previousState,
String[] propertyNames,
Type[] types
) {
if(this.user == null) {
throw new IllegalStateException("User not set!");
}
boolean modified = false;
for(int i = 0; i < propertyNames.length; i++) {
if(propertyNames[i].equals(PersistenceConstants.EDIT_DATE)) {
currentState[i] = this.date;
modified = true;
} else if(propertyNames[i].equals(PersistenceConstants.EDIT_USER)) {
currentState[i] = this.user;
modified = true;
}
}
return modified;
}
public boolean onLoad(
Object entity,
Serializable id,
Object[] state,
String[] propertyNames,
Type[] types
) {
return false;
}
public boolean onSave(
Object entity,
Serializable id,
Object[] state,
String[] propertyNames,
Type[] types
) {
if(this.user == null) {
throw new IllegalStateException("User not set!");
}
boolean modified = false;
for(int i = 0; i < propertyNames.length; i++) {
if(propertyNames[i].equals(PersistenceConstants.CREATE_DATE)) {
state[i] = this.date;
modified = true;
} else if(propertyNames[i].equals(PersistenceConstants.CREATE_USER)) {
state[i] = this.user;
modified = true;
} else if(propertyNames[i].equals(PersistenceConstants.STATUS)) {
state[i] = new Byte(PersistenceConstants.ACTIVE_STATUS);
modified = true;
}
}
return modified;
}
public void postFlush(Iterator entities) {
//Do nothing
}
public void preFlush(Iterator entities) {
//Do nothing
}
}
Creation of the Session must be controlled, and I get the editing User from the session and put it in the Interceptor before releasing it to the wild:
Code:
protected Session getWritableSession(int userId) {
String method = "getSession";
try {
SessionFactory factory = new Configuration().buildSessionFactory();
WritableInterceptor interceptor = new WritableInterceptor();
Session session =
factory.openSession(
connection,
interceptor
);
//Get user. This is possible because the interceptor does not
//need the user set for reading data, only writing
UserVO user = (UserVO)session.get(
UserVO.class,
new Integer(userId)
);
interceptor.setUser(user);
return session;
} catch(HibernateException he) {
//PANIC!!!
}
}
You can extend this to other ubiquitous fields.
For lazy delete I tightly control how queries are done. My current client only wants to do Criteria queries, so I can do this. :) Basically I've got one method for submitting a Criteria:
Code:
protected List get(Criteria criteria) throws HibernateException {
return criteria.add(
Expression.eq(
"status",
new Integer(PersistenceConstants.ACTIVE_STATUS)
)
).list();
}
This may not be doable for everyone as it rather restricts the usage of Hibernate, but it fits for my client. (All that matters, right? :P ) Also, this is with Hibernate 2.1. 3 might have a better solution available, but I don't know it well enough to be sure.