Promoted a number of classes out of DepotRepository because they are used all
across the package. Moved marshaller creation and management into the PersistenceContext because marshallers should be shared across a persistence context. Also moved the actual "get a connection and do the query" code into the persistence context which is sort of a nice separation. The repository and friends now just put together Query and Modifier objects and pass them to the context for execution. The context will eventually handle interaction with the cache as well (exposing manual manipulation mechanisms as needed to the DepotRepository).
This commit is contained in:
@@ -223,7 +223,7 @@ public class DepotMarshaller<T>
|
|||||||
* Throws an exception if the persistent object did not declare a primary
|
* Throws an exception if the persistent object did not declare a primary
|
||||||
* key.
|
* key.
|
||||||
*/
|
*/
|
||||||
public DepotRepository.Key getPrimaryKey (Object object)
|
public Key getPrimaryKey (Object object)
|
||||||
{
|
{
|
||||||
if (!hasPrimaryKey()) {
|
if (!hasPrimaryKey()) {
|
||||||
throw new UnsupportedOperationException(
|
throw new UnsupportedOperationException(
|
||||||
@@ -245,7 +245,7 @@ public class DepotMarshaller<T>
|
|||||||
* Creates a primary key record for the type of object handled by this
|
* Creates a primary key record for the type of object handled by this
|
||||||
* marshaller, using the supplied primary key vlaue.
|
* marshaller, using the supplied primary key vlaue.
|
||||||
*/
|
*/
|
||||||
public DepotRepository.Key makePrimaryKey (Comparable... values)
|
public Key makePrimaryKey (Comparable... values)
|
||||||
{
|
{
|
||||||
if (!hasPrimaryKey()) {
|
if (!hasPrimaryKey()) {
|
||||||
throw new UnsupportedOperationException(
|
throw new UnsupportedOperationException(
|
||||||
@@ -261,7 +261,7 @@ public class DepotMarshaller<T>
|
|||||||
FieldMarshaller field = _pkColumns.get(ii);
|
FieldMarshaller field = _pkColumns.get(ii);
|
||||||
indices[ii] = field.getColumnName();
|
indices[ii] = field.getColumnName();
|
||||||
}
|
}
|
||||||
return new DepotRepository.Key(indices, values);
|
return new Key(indices, values);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -354,8 +354,7 @@ public class DepotMarshaller<T>
|
|||||||
* Creates a query for instances of this persistent object type using the
|
* Creates a query for instances of this persistent object type using the
|
||||||
* supplied key. If null is supplied all instances will be loaded.
|
* supplied key. If null is supplied all instances will be loaded.
|
||||||
*/
|
*/
|
||||||
public PreparedStatement createQuery (
|
public PreparedStatement createQuery (Connection conn, Key key)
|
||||||
Connection conn, DepotRepository.Key key)
|
|
||||||
throws SQLException
|
throws SQLException
|
||||||
{
|
{
|
||||||
String query = "select " + _fullColumnList + " from " + getTableName();
|
String query = "select " + _fullColumnList + " from " + getTableName();
|
||||||
@@ -440,8 +439,7 @@ public class DepotMarshaller<T>
|
|||||||
* @return the newly assigned primary key or null if the object does not
|
* @return the newly assigned primary key or null if the object does not
|
||||||
* use primary keys or this is not the right time to assign the key.
|
* use primary keys or this is not the right time to assign the key.
|
||||||
*/
|
*/
|
||||||
public DepotRepository.Key assignPrimaryKey (
|
public Key assignPrimaryKey (Connection conn, Object po, boolean postFactum)
|
||||||
Connection conn, Object po, boolean postFactum)
|
|
||||||
throws SQLException
|
throws SQLException
|
||||||
{
|
{
|
||||||
// if we have no primary key or no generator, then we're done
|
// if we have no primary key or no generator, then we're done
|
||||||
@@ -469,8 +467,7 @@ public class DepotMarshaller<T>
|
|||||||
* Creates a statement that will update the supplied persistent object
|
* Creates a statement that will update the supplied persistent object
|
||||||
* using the supplied key.
|
* using the supplied key.
|
||||||
*/
|
*/
|
||||||
public PreparedStatement createUpdate (
|
public PreparedStatement createUpdate (Connection conn, Object po, Key key)
|
||||||
Connection conn, Object po, DepotRepository.Key key)
|
|
||||||
throws SQLException
|
throws SQLException
|
||||||
{
|
{
|
||||||
return createUpdate(conn, po, key, _allFields);
|
return createUpdate(conn, po, key, _allFields);
|
||||||
@@ -481,8 +478,7 @@ public class DepotMarshaller<T>
|
|||||||
* using the supplied key.
|
* using the supplied key.
|
||||||
*/
|
*/
|
||||||
public PreparedStatement createUpdate (
|
public PreparedStatement createUpdate (
|
||||||
Connection conn, Object po, DepotRepository.Key key,
|
Connection conn, Object po, Key key, String[] modifiedFields)
|
||||||
String[] modifiedFields)
|
|
||||||
throws SQLException
|
throws SQLException
|
||||||
{
|
{
|
||||||
StringBuilder update = new StringBuilder();
|
StringBuilder update = new StringBuilder();
|
||||||
@@ -523,7 +519,7 @@ public class DepotMarshaller<T>
|
|||||||
* persistent objects that match the supplied key.
|
* persistent objects that match the supplied key.
|
||||||
*/
|
*/
|
||||||
public PreparedStatement createPartialUpdate (
|
public PreparedStatement createPartialUpdate (
|
||||||
Connection conn, DepotRepository.Key key,
|
Connection conn, Key key,
|
||||||
String[] modifiedFields, Object[] modifiedValues)
|
String[] modifiedFields, Object[] modifiedValues)
|
||||||
throws SQLException
|
throws SQLException
|
||||||
{
|
{
|
||||||
@@ -553,8 +549,7 @@ public class DepotMarshaller<T>
|
|||||||
/**
|
/**
|
||||||
* Creates a statement that will delete all rows matching the supplied key.
|
* Creates a statement that will delete all rows matching the supplied key.
|
||||||
*/
|
*/
|
||||||
public PreparedStatement createDelete (
|
public PreparedStatement createDelete (Connection conn, Key key)
|
||||||
Connection conn, DepotRepository.Key key)
|
|
||||||
throws SQLException
|
throws SQLException
|
||||||
{
|
{
|
||||||
String query = "delete from " + getTableName() +
|
String query = "delete from " + getTableName() +
|
||||||
@@ -570,7 +565,7 @@ public class DepotMarshaller<T>
|
|||||||
* the supplied key.
|
* the supplied key.
|
||||||
*/
|
*/
|
||||||
public PreparedStatement createLiteralUpdate (
|
public PreparedStatement createLiteralUpdate (
|
||||||
Connection conn, DepotRepository.Key key,
|
Connection conn, Key key,
|
||||||
String[] modifiedFields, Object[] modifiedValues)
|
String[] modifiedFields, Object[] modifiedValues)
|
||||||
throws SQLException
|
throws SQLException
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -31,7 +31,6 @@ import java.util.HashMap;
|
|||||||
|
|
||||||
import com.samskivert.io.PersistenceException;
|
import com.samskivert.io.PersistenceException;
|
||||||
import com.samskivert.jdbc.ConnectionProvider;
|
import com.samskivert.jdbc.ConnectionProvider;
|
||||||
import com.samskivert.jdbc.DuplicateKeyException;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides a base for classes that provide access to persistent objects. Also
|
* Provides a base for classes that provide access to persistent objects. Also
|
||||||
@@ -46,18 +45,15 @@ public class DepotRepository
|
|||||||
*/
|
*/
|
||||||
protected DepotRepository (ConnectionProvider conprov)
|
protected DepotRepository (ConnectionProvider conprov)
|
||||||
{
|
{
|
||||||
this(conprov, new PersistenceContext());
|
_ctx = new PersistenceContext(getClass().getName(), conprov);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a repository with the supplied connection provider and
|
* Creates a repository with the supplied persistence context.
|
||||||
* persistence context.
|
|
||||||
*/
|
*/
|
||||||
protected DepotRepository (
|
protected DepotRepository (PersistenceContext context)
|
||||||
ConnectionProvider conprov, PersistenceContext context)
|
|
||||||
{
|
{
|
||||||
_conprov = conprov;
|
_ctx = context;
|
||||||
_context = context;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -66,7 +62,7 @@ public class DepotRepository
|
|||||||
protected <T> T load (Class<T> type, Comparable primaryKey)
|
protected <T> T load (Class<T> type, Comparable primaryKey)
|
||||||
throws PersistenceException
|
throws PersistenceException
|
||||||
{
|
{
|
||||||
return load(type, getMarshaller(type).makePrimaryKey(primaryKey));
|
return load(type, _ctx.getMarshaller(type).makePrimaryKey(primaryKey));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -75,8 +71,8 @@ public class DepotRepository
|
|||||||
protected <T> T load (Class<T> type, Key key)
|
protected <T> T load (Class<T> type, Key key)
|
||||||
throws PersistenceException
|
throws PersistenceException
|
||||||
{
|
{
|
||||||
final DepotMarshaller<T> marsh = getMarshaller(type);
|
final DepotMarshaller<T> marsh = _ctx.getMarshaller(type);
|
||||||
return invoke(new Query<T>(key) {
|
return _ctx.invoke(new Query<T>(key) {
|
||||||
public T invoke (Connection conn) throws SQLException {
|
public T invoke (Connection conn) throws SQLException {
|
||||||
PreparedStatement stmt = marsh.createQuery(conn, _key);
|
PreparedStatement stmt = marsh.createQuery(conn, _key);
|
||||||
try {
|
try {
|
||||||
@@ -112,8 +108,8 @@ public class DepotRepository
|
|||||||
Class<T> type, Key key)
|
Class<T> type, Key key)
|
||||||
throws PersistenceException
|
throws PersistenceException
|
||||||
{
|
{
|
||||||
final DepotMarshaller<T> marsh = getMarshaller(type);
|
final DepotMarshaller<T> marsh = _ctx.getMarshaller(type);
|
||||||
return invoke(new Query<ArrayList<T>>(key) {
|
return _ctx.invoke(new Query<ArrayList<T>>(key) {
|
||||||
public ArrayList<T> invoke (Connection conn) throws SQLException {
|
public ArrayList<T> invoke (Connection conn) throws SQLException {
|
||||||
PreparedStatement stmt = marsh.createQuery(conn, _key);
|
PreparedStatement stmt = marsh.createQuery(conn, _key);
|
||||||
try {
|
try {
|
||||||
@@ -141,8 +137,8 @@ public class DepotRepository
|
|||||||
protected int insert (final Object record)
|
protected int insert (final Object record)
|
||||||
throws PersistenceException
|
throws PersistenceException
|
||||||
{
|
{
|
||||||
final DepotMarshaller marsh = getMarshaller(record.getClass());
|
final DepotMarshaller marsh = _ctx.getMarshaller(record.getClass());
|
||||||
return invoke(new Modifier(null) {
|
return _ctx.invoke(new Modifier(null) {
|
||||||
public int invoke (Connection conn) throws SQLException {
|
public int invoke (Connection conn) throws SQLException {
|
||||||
// update our modifier's key so that it can cache our results
|
// update our modifier's key so that it can cache our results
|
||||||
updateKey(marsh.assignPrimaryKey(conn, record, false));
|
updateKey(marsh.assignPrimaryKey(conn, record, false));
|
||||||
@@ -168,8 +164,8 @@ public class DepotRepository
|
|||||||
protected int update (final Object record)
|
protected int update (final Object record)
|
||||||
throws PersistenceException
|
throws PersistenceException
|
||||||
{
|
{
|
||||||
final DepotMarshaller marsh = getMarshaller(record.getClass());
|
final DepotMarshaller marsh = _ctx.getMarshaller(record.getClass());
|
||||||
return invoke(new Modifier(marsh.getPrimaryKey(record)) {
|
return _ctx.invoke(new Modifier(marsh.getPrimaryKey(record)) {
|
||||||
public int invoke (Connection conn) throws SQLException {
|
public int invoke (Connection conn) throws SQLException {
|
||||||
PreparedStatement stmt = marsh.createUpdate(conn, record, _key);
|
PreparedStatement stmt = marsh.createUpdate(conn, record, _key);
|
||||||
try {
|
try {
|
||||||
@@ -190,8 +186,8 @@ public class DepotRepository
|
|||||||
protected int update (final Object record, final String ... modifiedFields)
|
protected int update (final Object record, final String ... modifiedFields)
|
||||||
throws PersistenceException
|
throws PersistenceException
|
||||||
{
|
{
|
||||||
final DepotMarshaller marsh = getMarshaller(record.getClass());
|
final DepotMarshaller marsh = _ctx.getMarshaller(record.getClass());
|
||||||
return invoke(new Modifier(marsh.getPrimaryKey(record)) {
|
return _ctx.invoke(new Modifier(marsh.getPrimaryKey(record)) {
|
||||||
public int invoke (Connection conn) throws SQLException {
|
public int invoke (Connection conn) throws SQLException {
|
||||||
PreparedStatement stmt = marsh.createUpdate(
|
PreparedStatement stmt = marsh.createUpdate(
|
||||||
conn, record, _key, modifiedFields);
|
conn, record, _key, modifiedFields);
|
||||||
@@ -220,7 +216,8 @@ public class DepotRepository
|
|||||||
throws PersistenceException
|
throws PersistenceException
|
||||||
{
|
{
|
||||||
return updatePartial(
|
return updatePartial(
|
||||||
type, getMarshaller(type).makePrimaryKey(primaryKey), fieldsValues);
|
type, _ctx.getMarshaller(type).makePrimaryKey(primaryKey),
|
||||||
|
fieldsValues);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -246,8 +243,8 @@ public class DepotRepository
|
|||||||
values[ii] = fieldsValues[idx++];
|
values[ii] = fieldsValues[idx++];
|
||||||
}
|
}
|
||||||
|
|
||||||
final DepotMarshaller marsh = getMarshaller(type);
|
final DepotMarshaller marsh = _ctx.getMarshaller(type);
|
||||||
return invoke(new Modifier(key) {
|
return _ctx.invoke(new Modifier(key) {
|
||||||
public int invoke (Connection conn) throws SQLException {
|
public int invoke (Connection conn) throws SQLException {
|
||||||
PreparedStatement stmt = marsh.createPartialUpdate(
|
PreparedStatement stmt = marsh.createPartialUpdate(
|
||||||
conn, _key, fields, values);
|
conn, _key, fields, values);
|
||||||
@@ -284,7 +281,8 @@ public class DepotRepository
|
|||||||
throws PersistenceException
|
throws PersistenceException
|
||||||
{
|
{
|
||||||
return updateLiteral(
|
return updateLiteral(
|
||||||
type, getMarshaller(type).makePrimaryKey(primaryKey), fieldsValues);
|
type, _ctx.getMarshaller(type).makePrimaryKey(primaryKey),
|
||||||
|
fieldsValues);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -318,8 +316,8 @@ public class DepotRepository
|
|||||||
values[ii] = fieldsValues[idx++];
|
values[ii] = fieldsValues[idx++];
|
||||||
}
|
}
|
||||||
|
|
||||||
final DepotMarshaller marsh = getMarshaller(type);
|
final DepotMarshaller marsh = _ctx.getMarshaller(type);
|
||||||
return invoke(new Modifier(key) {
|
return _ctx.invoke(new Modifier(key) {
|
||||||
public int invoke (Connection conn) throws SQLException {
|
public int invoke (Connection conn) throws SQLException {
|
||||||
PreparedStatement stmt = marsh.createLiteralUpdate(
|
PreparedStatement stmt = marsh.createLiteralUpdate(
|
||||||
conn, _key, fields, values);
|
conn, _key, fields, values);
|
||||||
@@ -344,9 +342,9 @@ public class DepotRepository
|
|||||||
protected int store (final Object record)
|
protected int store (final Object record)
|
||||||
throws PersistenceException
|
throws PersistenceException
|
||||||
{
|
{
|
||||||
final DepotMarshaller marsh = getMarshaller(record.getClass());
|
final DepotMarshaller marsh = _ctx.getMarshaller(record.getClass());
|
||||||
Key key = marsh.hasPrimaryKey() ? marsh.getPrimaryKey(record) : null;
|
Key key = marsh.hasPrimaryKey() ? marsh.getPrimaryKey(record) : null;
|
||||||
return invoke(new Modifier(key) {
|
return _ctx.invoke(new Modifier(key) {
|
||||||
public int invoke (Connection conn) throws SQLException {
|
public int invoke (Connection conn) throws SQLException {
|
||||||
PreparedStatement stmt = null;
|
PreparedStatement stmt = null;
|
||||||
try {
|
try {
|
||||||
@@ -387,7 +385,7 @@ public class DepotRepository
|
|||||||
{
|
{
|
||||||
@SuppressWarnings("unchecked") Class<T> type =
|
@SuppressWarnings("unchecked") Class<T> type =
|
||||||
(Class<T>)record.getClass();
|
(Class<T>)record.getClass();
|
||||||
DepotMarshaller<T> marsh = getMarshaller(type);
|
DepotMarshaller<T> marsh = _ctx.getMarshaller(type);
|
||||||
return deleteAll(type, marsh.getPrimaryKey(record));
|
return deleteAll(type, marsh.getPrimaryKey(record));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -400,7 +398,8 @@ public class DepotRepository
|
|||||||
protected <T> int delete (Class<T> type, Comparable primaryKey)
|
protected <T> int delete (Class<T> type, Comparable primaryKey)
|
||||||
throws PersistenceException
|
throws PersistenceException
|
||||||
{
|
{
|
||||||
return deleteAll(type, getMarshaller(type).makePrimaryKey(primaryKey));
|
return deleteAll(
|
||||||
|
type, _ctx.getMarshaller(type).makePrimaryKey(primaryKey));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -412,8 +411,8 @@ public class DepotRepository
|
|||||||
protected <T> int deleteAll (Class<T> type, Key key)
|
protected <T> int deleteAll (Class<T> type, Key key)
|
||||||
throws PersistenceException
|
throws PersistenceException
|
||||||
{
|
{
|
||||||
final DepotMarshaller marsh = getMarshaller(type);
|
final DepotMarshaller marsh = _ctx.getMarshaller(type);
|
||||||
return invoke(new Modifier(key) {
|
return _ctx.invoke(new Modifier(key) {
|
||||||
public int invoke (Connection conn) throws SQLException {
|
public int invoke (Connection conn) throws SQLException {
|
||||||
PreparedStatement stmt = marsh.createDelete(conn, _key);
|
PreparedStatement stmt = marsh.createDelete(conn, _key);
|
||||||
try {
|
try {
|
||||||
@@ -425,146 +424,6 @@ public class DepotRepository
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
protected <T> DepotMarshaller<T> getMarshaller (Class<T> type)
|
|
||||||
throws PersistenceException
|
|
||||||
{
|
|
||||||
@SuppressWarnings("unchecked")DepotMarshaller<T> marshaller =
|
|
||||||
(DepotMarshaller<T>)_marshallers.get(type);
|
|
||||||
if (marshaller == null) {
|
|
||||||
_marshallers.put(
|
|
||||||
type, marshaller = new DepotMarshaller<T>(type, _context));
|
|
||||||
// initialize the marshaller which may create or migrate the table
|
|
||||||
// for its underlying persistent object
|
|
||||||
final DepotMarshaller<T> fm = marshaller;
|
|
||||||
invoke(new Modifier(null) {
|
|
||||||
public int invoke (Connection conn) throws SQLException {
|
|
||||||
fm.init(conn);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return marshaller;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected <T> T invoke (Query<T> query)
|
|
||||||
throws PersistenceException
|
|
||||||
{
|
|
||||||
// TODO: check the cache using query.getKey()
|
|
||||||
|
|
||||||
// TODO: retry query on transient failure
|
|
||||||
Connection conn = _conprov.getConnection(getIdent(), true);
|
|
||||||
try {
|
|
||||||
return query.invoke(conn);
|
|
||||||
|
|
||||||
} catch (SQLException sqe) {
|
|
||||||
throw new PersistenceException("Query failure " + query, sqe);
|
|
||||||
|
|
||||||
} finally {
|
|
||||||
_conprov.releaseConnection(getIdent(), true, conn);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected int invoke (Modifier modifier)
|
|
||||||
throws PersistenceException
|
|
||||||
{
|
|
||||||
// TODO: invalidate the cache using the modifier's key
|
|
||||||
|
|
||||||
// TODO: retry query on transient failure
|
|
||||||
Connection conn = _conprov.getConnection(getIdent(), false);
|
|
||||||
try {
|
|
||||||
int result = modifier.invoke(conn);
|
|
||||||
// TODO: (optionally) cache the results of the modifier
|
|
||||||
return result;
|
|
||||||
|
|
||||||
} catch (SQLException sqe) {
|
|
||||||
// convert this exception to a DuplicateKeyException if appropriate
|
|
||||||
String msg = sqe.getMessage();
|
|
||||||
if (msg != null && msg.indexOf("Duplicate entry") != -1) {
|
|
||||||
throw new DuplicateKeyException(msg);
|
|
||||||
} else {
|
|
||||||
throw new PersistenceException(
|
|
||||||
"Modifier failure " + modifier, sqe);
|
|
||||||
}
|
|
||||||
|
|
||||||
} finally {
|
|
||||||
_conprov.releaseConnection(getIdent(), false, conn);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the identifier to be used when obtaining JDBC connections from
|
|
||||||
* our connection provider. The default implementation uses the class name
|
|
||||||
* of this repository.
|
|
||||||
*/
|
|
||||||
protected String getIdent ()
|
|
||||||
{
|
|
||||||
return getClass().getName();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static class Key
|
|
||||||
{
|
|
||||||
public String[] indices;
|
|
||||||
public Comparable[] values;
|
|
||||||
|
|
||||||
public Key (String[] indices, Comparable[] values)
|
|
||||||
{
|
|
||||||
this.indices = indices;
|
|
||||||
this.values = values;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Key (String index, Comparable value)
|
|
||||||
{
|
|
||||||
this(new String[] { index }, new Comparable[] { value });
|
|
||||||
}
|
|
||||||
|
|
||||||
public String toWhereClause ()
|
|
||||||
{
|
|
||||||
StringBuilder where = new StringBuilder();
|
|
||||||
for (int ii = 0; ii < indices.length; ii++) {
|
|
||||||
if (ii > 0) {
|
|
||||||
where.append(" and ");
|
|
||||||
}
|
|
||||||
where.append(indices[ii]).append(" = ?");
|
|
||||||
}
|
|
||||||
return where.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void bindArguments (PreparedStatement stmt, int startIdx)
|
|
||||||
throws SQLException
|
|
||||||
{
|
|
||||||
for (int ii = 0; ii < indices.length; ii++) {
|
|
||||||
stmt.setObject(startIdx++, values[ii]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static class Key2 extends Key
|
|
||||||
{
|
|
||||||
public Key2 (String index1, Comparable value1,
|
|
||||||
String index2, Comparable value2)
|
|
||||||
{
|
|
||||||
super(new String[] { index1, index2 },
|
|
||||||
new Comparable[] { value1, value2 });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static abstract class Query<T>
|
|
||||||
{
|
|
||||||
public Key getKey ()
|
|
||||||
{
|
|
||||||
return _key;
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract T invoke (Connection conn) throws SQLException;
|
|
||||||
|
|
||||||
protected Query (Key key)
|
|
||||||
{
|
|
||||||
_key = key;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Key _key;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected static abstract class CollectionQuery<T extends Collection>
|
protected static abstract class CollectionQuery<T extends Collection>
|
||||||
extends Query<T>
|
extends Query<T>
|
||||||
{
|
{
|
||||||
@@ -575,32 +434,5 @@ public class DepotRepository
|
|||||||
public abstract T invoke (Connection conn) throws SQLException;
|
public abstract T invoke (Connection conn) throws SQLException;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static abstract class Modifier
|
protected PersistenceContext _ctx;
|
||||||
{
|
|
||||||
public Key getKey ()
|
|
||||||
{
|
|
||||||
return _key;
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract int invoke (Connection conn) throws SQLException;
|
|
||||||
|
|
||||||
protected Modifier (Key key)
|
|
||||||
{
|
|
||||||
_key = key;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void updateKey (Key key)
|
|
||||||
{
|
|
||||||
if (key != null) {
|
|
||||||
_key = key;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Key _key;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected ConnectionProvider _conprov;
|
|
||||||
protected PersistenceContext _context;
|
|
||||||
protected HashMap<Class<?>, DepotMarshaller<?>> _marshallers =
|
|
||||||
new HashMap<Class<?>, DepotMarshaller<?>>();
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,64 @@
|
|||||||
|
//
|
||||||
|
// $Id$
|
||||||
|
//
|
||||||
|
// samskivert library - useful routines for java programs
|
||||||
|
// Copyright (C) 2006 Michael Bayne
|
||||||
|
//
|
||||||
|
// This library is free software; you can redistribute it and/or modify it
|
||||||
|
// under the terms of the GNU Lesser General Public License as published
|
||||||
|
// by the Free Software Foundation; either version 2.1 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public
|
||||||
|
// License along with this library; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
|
package com.samskivert.jdbc.depot;
|
||||||
|
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encapsulates a key used to match persistent objects in a query.
|
||||||
|
*/
|
||||||
|
public class Key
|
||||||
|
{
|
||||||
|
public String[] indices;
|
||||||
|
public Comparable[] values;
|
||||||
|
|
||||||
|
public Key (String[] indices, Comparable[] values)
|
||||||
|
{
|
||||||
|
this.indices = indices;
|
||||||
|
this.values = values;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Key (String index, Comparable value)
|
||||||
|
{
|
||||||
|
this(new String[] { index }, new Comparable[] { value });
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toWhereClause ()
|
||||||
|
{
|
||||||
|
StringBuilder where = new StringBuilder();
|
||||||
|
for (int ii = 0; ii < indices.length; ii++) {
|
||||||
|
if (ii > 0) {
|
||||||
|
where.append(" and ");
|
||||||
|
}
|
||||||
|
where.append(indices[ii]).append(" = ?");
|
||||||
|
}
|
||||||
|
return where.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void bindArguments (PreparedStatement stmt, int startIdx)
|
||||||
|
throws SQLException
|
||||||
|
{
|
||||||
|
for (int ii = 0; ii < indices.length; ii++) {
|
||||||
|
stmt.setObject(startIdx++, values[ii]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
//
|
||||||
|
// $Id$
|
||||||
|
//
|
||||||
|
// samskivert library - useful routines for java programs
|
||||||
|
// Copyright (C) 2006 Michael Bayne
|
||||||
|
//
|
||||||
|
// This library is free software; you can redistribute it and/or modify it
|
||||||
|
// under the terms of the GNU Lesser General Public License as published
|
||||||
|
// by the Free Software Foundation; either version 2.1 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public
|
||||||
|
// License along with this library; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
|
package com.samskivert.jdbc.depot;
|
||||||
|
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encapsulates a modification of persistent objects.
|
||||||
|
*/
|
||||||
|
public abstract class Modifier
|
||||||
|
{
|
||||||
|
public Key getKey ()
|
||||||
|
{
|
||||||
|
return _key;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract int invoke (Connection conn) throws SQLException;
|
||||||
|
|
||||||
|
protected Modifier (Key key)
|
||||||
|
{
|
||||||
|
_key = key;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void updateKey (Key key)
|
||||||
|
{
|
||||||
|
if (key != null) {
|
||||||
|
_key = key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Key _key;
|
||||||
|
}
|
||||||
@@ -23,12 +23,114 @@ package com.samskivert.jdbc.depot;
|
|||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import javax.persistence.TableGenerator;
|
import javax.persistence.TableGenerator;
|
||||||
|
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
|
||||||
|
import com.samskivert.io.PersistenceException;
|
||||||
|
import com.samskivert.jdbc.ConnectionProvider;
|
||||||
|
import com.samskivert.jdbc.DuplicateKeyException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Defines a scope in which global annotations are shared.
|
* Defines a scope in which global annotations are shared.
|
||||||
*/
|
*/
|
||||||
public class PersistenceContext
|
public class PersistenceContext
|
||||||
{
|
{
|
||||||
/** Map {@link TableGenerator} instances by name. */
|
/** Map {@link TableGenerator} instances by name. */
|
||||||
public static HashMap<String, TableGenerator> tableGenerators =
|
public HashMap<String, TableGenerator> tableGenerators =
|
||||||
new HashMap<String, TableGenerator>();
|
new HashMap<String, TableGenerator>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a persistence context that will use the supplied provider to
|
||||||
|
* obtain JDBC connections.
|
||||||
|
*
|
||||||
|
* @param ident the identifier to provide to the connection provider when
|
||||||
|
* requesting a connection.
|
||||||
|
*/
|
||||||
|
public PersistenceContext (String ident, ConnectionProvider conprov)
|
||||||
|
{
|
||||||
|
_ident = ident;
|
||||||
|
_conprov = conprov;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the marshaller for the specified persistent object class,
|
||||||
|
* creating and initializing it if necessary.
|
||||||
|
*/
|
||||||
|
public <T> DepotMarshaller<T> getMarshaller (Class<T> type)
|
||||||
|
throws PersistenceException
|
||||||
|
{
|
||||||
|
@SuppressWarnings("unchecked") DepotMarshaller<T> marshaller =
|
||||||
|
(DepotMarshaller<T>)_marshallers.get(type);
|
||||||
|
if (marshaller == null) {
|
||||||
|
_marshallers.put(
|
||||||
|
type, marshaller = new DepotMarshaller<T>(type, this));
|
||||||
|
// initialize the marshaller which may create or migrate the table
|
||||||
|
// for its underlying persistent object
|
||||||
|
final DepotMarshaller<T> fm = marshaller;
|
||||||
|
invoke(new Modifier(null) {
|
||||||
|
public int invoke (Connection conn) throws SQLException {
|
||||||
|
fm.init(conn);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return marshaller;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invokes a non-modifying query and returns its result.
|
||||||
|
*/
|
||||||
|
public <T> T invoke (Query<T> query)
|
||||||
|
throws PersistenceException
|
||||||
|
{
|
||||||
|
// TODO: check the cache using query.getKey()
|
||||||
|
|
||||||
|
// TODO: retry query on transient failure
|
||||||
|
Connection conn = _conprov.getConnection(_ident, true);
|
||||||
|
try {
|
||||||
|
return query.invoke(conn);
|
||||||
|
|
||||||
|
} catch (SQLException sqe) {
|
||||||
|
throw new PersistenceException("Query failure " + query, sqe);
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
_conprov.releaseConnection(_ident, true, conn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Invokes a modifying query and returns the number of rows modified.
|
||||||
|
*/
|
||||||
|
public int invoke (Modifier modifier)
|
||||||
|
throws PersistenceException
|
||||||
|
{
|
||||||
|
// TODO: invalidate the cache using the modifier's key
|
||||||
|
|
||||||
|
// TODO: retry query on transient failure
|
||||||
|
Connection conn = _conprov.getConnection(_ident, false);
|
||||||
|
try {
|
||||||
|
int result = modifier.invoke(conn);
|
||||||
|
// TODO: (optionally) cache the results of the modifier
|
||||||
|
return result;
|
||||||
|
|
||||||
|
} catch (SQLException sqe) {
|
||||||
|
// convert this exception to a DuplicateKeyException if appropriate
|
||||||
|
String msg = sqe.getMessage();
|
||||||
|
if (msg != null && msg.indexOf("Duplicate entry") != -1) {
|
||||||
|
throw new DuplicateKeyException(msg);
|
||||||
|
} else {
|
||||||
|
throw new PersistenceException(
|
||||||
|
"Modifier failure " + modifier, sqe);
|
||||||
|
}
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
_conprov.releaseConnection(_ident, false, conn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String _ident;
|
||||||
|
protected ConnectionProvider _conprov;
|
||||||
|
|
||||||
|
protected HashMap<Class<?>, DepotMarshaller<?>> _marshallers =
|
||||||
|
new HashMap<Class<?>, DepotMarshaller<?>>();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
//
|
||||||
|
// $Id$
|
||||||
|
//
|
||||||
|
// samskivert library - useful routines for java programs
|
||||||
|
// Copyright (C) 2006 Michael Bayne
|
||||||
|
//
|
||||||
|
// This library is free software; you can redistribute it and/or modify it
|
||||||
|
// under the terms of the GNU Lesser General Public License as published
|
||||||
|
// by the Free Software Foundation; either version 2.1 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This library is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// Lesser General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU Lesser General Public
|
||||||
|
// License along with this library; if not, write to the Free Software
|
||||||
|
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
|
package com.samskivert.jdbc.depot;
|
||||||
|
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encapsulates a non-modifying query of persistent objects.
|
||||||
|
*/
|
||||||
|
public abstract class Query<T>
|
||||||
|
{
|
||||||
|
public Key getKey ()
|
||||||
|
{
|
||||||
|
return _key;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract T invoke (Connection conn) throws SQLException;
|
||||||
|
|
||||||
|
protected Query (Key key)
|
||||||
|
{
|
||||||
|
_key = key;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Key _key;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user