Added some sanity checks to notice and catch programmer errors as early as
possible.
This commit is contained in:
@@ -27,6 +27,16 @@ package com.samskivert.jdbc.depot;
|
||||
*/
|
||||
public interface CacheInvalidator
|
||||
{
|
||||
/**
|
||||
* Validates that this invalidator operates on the supplied persistent record class. This helps
|
||||
* to catch programmer errors where one record type is used for a query clause and another is
|
||||
* used for the cache invalidator.
|
||||
*
|
||||
* @exception IllegalArgumentException thrown if the supplied persistent record class does not
|
||||
* match the class that this invalidator will flush from the cache.
|
||||
*/
|
||||
public void validateFlushType (Class<?> pClass);
|
||||
|
||||
/**
|
||||
* Must invalidate all cache entries that depend on the records being modified or deleted.
|
||||
* This method is called just before the database statement is executed.
|
||||
|
||||
@@ -392,6 +392,9 @@ public abstract class DepotRepository
|
||||
Class<T> type, final WhereClause key, CacheInvalidator invalidator, Object... fieldsValues)
|
||||
throws PersistenceException
|
||||
{
|
||||
// sanity check
|
||||
invalidator.validateFlushType(type);
|
||||
|
||||
// separate the arguments into keys and values
|
||||
final String[] fields = new String[fieldsValues.length/2];
|
||||
final SQLExpression[] values = new SQLExpression[fields.length];
|
||||
@@ -516,6 +519,9 @@ public abstract class DepotRepository
|
||||
{
|
||||
requireNotComputed(type, "updateLiteral");
|
||||
|
||||
// sanity check
|
||||
invalidator.validateFlushType(type);
|
||||
|
||||
// separate the arguments into keys and values
|
||||
final String[] fields = new String[fieldsToValues.size()];
|
||||
final SQLExpression[] values = new SQLExpression[fields.length];
|
||||
|
||||
@@ -43,6 +43,7 @@ public class FindOneQuery<T extends PersistentRecord>
|
||||
{
|
||||
_marsh = ctx.getMarshaller(type);
|
||||
_select = new SelectClause<T>(type, _marsh.getFieldNames(), clauses);
|
||||
_select.getWhereClause().validateQueryType(type); // sanity check
|
||||
_builder = ctx.getSQLBuilder(DepotTypes.getDepotTypes(ctx, _select));
|
||||
_builder.newQuery(_select);
|
||||
}
|
||||
@@ -58,7 +59,8 @@ public class FindOneQuery<T extends PersistentRecord>
|
||||
}
|
||||
|
||||
// from Query
|
||||
public T invoke (Connection conn, DatabaseLiaison liaison) throws SQLException {
|
||||
public T invoke (Connection conn, DatabaseLiaison liaison) throws SQLException
|
||||
{
|
||||
PreparedStatement stmt = _builder.prepare(conn);
|
||||
try {
|
||||
T result = null;
|
||||
@@ -76,7 +78,8 @@ public class FindOneQuery<T extends PersistentRecord>
|
||||
}
|
||||
|
||||
// from Query
|
||||
public void updateCache (PersistenceContext ctx, T result) {
|
||||
public void updateCache (PersistenceContext ctx, T result)
|
||||
{
|
||||
CacheKey key = getCacheKey();
|
||||
if (key == null) {
|
||||
// no row-specific cache key was given
|
||||
|
||||
@@ -188,12 +188,30 @@ public class Key<T extends PersistentRecord> extends WhereClause
|
||||
return this; // TODO: Optimally return a special class here containing only _values.
|
||||
}
|
||||
|
||||
// from CacheInvalidator
|
||||
public void validateFlushType (Class<?> pClass)
|
||||
{
|
||||
if (!pClass.equals(condition.getPersistentClass())) {
|
||||
throw new IllegalArgumentException(
|
||||
"Class mismatch between persistent record and cache invalidator " +
|
||||
"[record=" + pClass.getSimpleName() +
|
||||
", invtype=" + condition.getPersistentClass().getSimpleName() + "].");
|
||||
}
|
||||
}
|
||||
|
||||
// from CacheInvalidator
|
||||
public void invalidate (PersistenceContext ctx)
|
||||
{
|
||||
ctx.cacheInvalidate(this);
|
||||
}
|
||||
|
||||
@Override // from WhereClause
|
||||
public void validateQueryType (Class<?> pClass)
|
||||
{
|
||||
super.validateQueryType(pClass);
|
||||
validateTypesMatch(pClass, condition.getPersistentClass());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals (Object obj)
|
||||
{
|
||||
|
||||
@@ -80,28 +80,6 @@ public class MultiKey<T extends PersistentRecord> extends WhereClause
|
||||
}
|
||||
}
|
||||
|
||||
// from SQLExpression
|
||||
public void accept (ExpressionVisitor builder) throws Exception
|
||||
{
|
||||
builder.visit(this);
|
||||
}
|
||||
|
||||
// from SQLExpression
|
||||
public void addClasses (Collection<Class<? extends PersistentRecord>> classSet)
|
||||
{
|
||||
// nothing to add
|
||||
}
|
||||
|
||||
// from CacheInvalidator
|
||||
public void invalidate (PersistenceContext ctx)
|
||||
{
|
||||
HashMap<String, Comparable> newMap = new HashMap<String, Comparable>(_map);
|
||||
for (int i = 0; i < _mValues.length; i ++) {
|
||||
newMap.put(_mField, _mValues[i]);
|
||||
ctx.cacheInvalidate(new SimpleCacheKey(_pClass, newMap));
|
||||
}
|
||||
}
|
||||
|
||||
public Class<T> getPersistentClass ()
|
||||
{
|
||||
return _pClass;
|
||||
@@ -122,6 +100,46 @@ public class MultiKey<T extends PersistentRecord> extends WhereClause
|
||||
return _mValues;
|
||||
}
|
||||
|
||||
// from SQLExpression
|
||||
public void accept (ExpressionVisitor builder) throws Exception
|
||||
{
|
||||
builder.visit(this);
|
||||
}
|
||||
|
||||
// from SQLExpression
|
||||
public void addClasses (Collection<Class<? extends PersistentRecord>> classSet)
|
||||
{
|
||||
// nothing to add
|
||||
}
|
||||
|
||||
// from CacheInvalidator
|
||||
public void validateFlushType (Class<?> pClass)
|
||||
{
|
||||
if (!pClass.equals(_pClass)) {
|
||||
throw new IllegalArgumentException(
|
||||
"Class mismatch between persistent record and cache invalidator " +
|
||||
"[record=" + pClass.getSimpleName() +
|
||||
", invtype=" + _pClass.getSimpleName() + "].");
|
||||
}
|
||||
}
|
||||
|
||||
// from CacheInvalidator
|
||||
public void invalidate (PersistenceContext ctx)
|
||||
{
|
||||
HashMap<String, Comparable> newMap = new HashMap<String, Comparable>(_map);
|
||||
for (int i = 0; i < _mValues.length; i ++) {
|
||||
newMap.put(_mField, _mValues[i]);
|
||||
ctx.cacheInvalidate(new SimpleCacheKey(_pClass, newMap));
|
||||
}
|
||||
}
|
||||
|
||||
@Override // from WhereClause
|
||||
public void validateQueryType (Class<?> pClass)
|
||||
{
|
||||
super.validateQueryType(pClass);
|
||||
validateTypesMatch(pClass, _pClass);
|
||||
}
|
||||
|
||||
protected String _mField;
|
||||
protected Comparable[] _mValues;
|
||||
protected Class<T> _pClass;
|
||||
|
||||
@@ -27,4 +27,28 @@ import com.samskivert.jdbc.depot.clause.QueryClause;
|
||||
*/
|
||||
public abstract class WhereClause extends QueryClause
|
||||
{
|
||||
/**
|
||||
* Validates that the supplied persistent record type is the type matched by this where clause.
|
||||
* Not all clauses will be able to perform this validation, but those that can, should do so to
|
||||
* help alleviate programmer error.
|
||||
*
|
||||
* @exception IllegalArgumentException thrown if the supplied class is known not to by the type
|
||||
* matched by this where clause.
|
||||
*/
|
||||
public void validateQueryType (Class<?> pClass)
|
||||
{
|
||||
// nothing by default
|
||||
}
|
||||
|
||||
/**
|
||||
* A helper function for implementing {@link #validateQueryType}.
|
||||
*/
|
||||
protected void validateTypesMatch (Class<?> qClass, Class<?> kClass)
|
||||
{
|
||||
if (!qClass.equals(kClass)) {
|
||||
throw new IllegalArgumentException(
|
||||
"Class mismatch between persistent record and key in query " +
|
||||
"[qtype=" + qClass.getSimpleName() + ", ktype=" + kClass.getSimpleName() + "].");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user