>();
- getManagedRecords(classes);
- for (Class extends PersistentRecord> rclass : classes) {
- _ctx.getMarshaller(rclass);
- }
- }
-
- /**
- * Provides a place where a repository can perform any initialization that requires database
- * operations.
- */
- protected void init ()
- throws DatabaseException
- {
- // run any registered data migrations
- for (DataMigration migration : _dataMigs) {
- runMigration(migration);
- }
- _dataMigs = null; // note that we've been initialized
- }
-
- /**
- * Registers a data migration for this repository. This migration will only be run once and its
- * unique identifier will be stored persistently to ensure that it is never run again on the
- * same database. Nonetheless, migrations should strive to be idempotent because someone might
- * come along and create a brand new system installation and all registered migrations will be
- * run once on the freshly created database. As with all database migrations, understand
- * clearly how the process works and think about edge cases when creating a migration.
- *
- * See {@link PersistenceContext#registerMigration} for details on how schema migrations
- * operate and how they might interact with data migrations.
- */
- protected void registerMigration (DataMigration migration)
- {
- if (_dataMigs == null) {
- // we've already been initialized, so we have to run this migration immediately
- runMigration(migration);
- } else {
- _dataMigs.add(migration);
- }
- }
-
- /**
- * Adds the persistent classes used by this repository to the supplied set.
- */
- protected abstract void getManagedRecords (Set> classes);
-
- /**
- * Loads the persistent object that matches the specified primary key.
- */
- protected T load (Class type, Comparable> primaryKey,
- QueryClause... clauses)
- throws DatabaseException
- {
- clauses = ArrayUtil.append(clauses, _ctx.getMarshaller(type).makePrimaryKey(primaryKey));
- return load(type, clauses);
- }
-
- /**
- * Loads the persistent object that matches the specified primary key.
- */
- protected T load (Class type, String ix, Comparable> val,
- QueryClause... clauses)
- throws DatabaseException
- {
- clauses = ArrayUtil.append(clauses, new Key(type, ix, val));
- return load(type, clauses);
- }
-
- /**
- * Loads the persistent object that matches the specified two-column primary key.
- */
- protected T load (Class type, String ix1, Comparable> val1,
- String ix2, Comparable> val2,
- QueryClause... clauses)
- throws DatabaseException
- {
- clauses = ArrayUtil.append(clauses, new Key(type, ix1, val1, ix2, val2));
- return load(type, clauses);
- }
-
- /**
- * Loads the persistent object that matches the specified three-column primary key.
- */
- protected T load (Class type, String ix1, Comparable> val1,
- String ix2, Comparable> val2, String ix3,
- Comparable> val3, QueryClause... clauses)
- throws DatabaseException
- {
- clauses = ArrayUtil.append(clauses, new Key(type, ix1, val1, ix2, val2, ix3, val3));
- return load(type, clauses);
- }
-
- /**
- * Loads the first persistent object that matches the supplied query clauses.
- */
- protected T load (
- Class type, Collection extends QueryClause> clauses)
- throws DatabaseException
- {
- return load(type, clauses.toArray(new QueryClause[clauses.size()]));
- }
-
- /**
- * Loads the first persistent object that matches the supplied query clauses.
- */
- protected T load (Class type, QueryClause... clauses)
- throws DatabaseException
- {
- return _ctx.invoke(new FindOneQuery(_ctx, type, clauses));
- }
-
- /**
- * Loads up all persistent records that match the supplied set of raw primary keys.
- */
- protected List loadAll (
- Class type, Collection extends Comparable>> primaryKeys)
- throws DatabaseException
- {
- // convert the raw keys into real key records
- DepotMarshaller marsh = _ctx.getMarshaller(type);
- List> keys = new ArrayList>();
- for (Comparable> key : primaryKeys) {
- keys.add(marsh.makePrimaryKey(key));
- }
- return loadAll(keys);
- }
-
- /**
- * Loads up all persistent records that match the supplied set of primary keys.
- */
- protected List loadAll (Collection> keys)
- throws DatabaseException
- {
- return (keys.size() == 0) ? Collections.emptyList() :
- _ctx.invoke(new FindAllQuery.WithKeys(_ctx, keys));
- }
-
- /**
- * A varargs version of {@link #findAll(Class,Collection)}.
- */
- protected List findAll (Class type, QueryClause... clauses)
- throws DatabaseException
- {
- return findAll(type, Arrays.asList(clauses));
- }
-
- /**
- * Loads all persistent objects that match the specified clauses.
- *
- * We have two strategies for doing this: one performs the query as-is, the second executes two
- * passes: first fetching only key columns and consulting the cache for each such key; then, in
- * the second pass, fetching the full entity only for keys that were not found in the cache.
- *
- * The more complex strategy could save a lot of data shuffling. On the other hand, its
- * complexity is an inherent drawback, and it does execute two separate database queries for
- * what the simple method does in one.
- */
- protected List findAll (
- Class type, Collection extends QueryClause> clauses)
- throws DatabaseException
- {
- return findAll(type, false, clauses);
- }
-
- /**
- * Loads all persistent objects that match the specified clauses.
- *
- * @param skipCache if true, our normal mixed select strategy that allows cached records to be
- * loaded from the cache will not be used even if it otherwise could. See {@link
- * #findAll(Class,Collection)} for details on the mixed strategy.
- */
- protected List findAll (
- Class type, boolean skipCache, Collection extends QueryClause> clauses)
- throws DatabaseException
- {
- DepotMarshaller marsh = _ctx.getMarshaller(type);
- boolean useExplicit = skipCache || (marsh.getTableName() == null) ||
- !marsh.hasPrimaryKey() || !_ctx.isUsingCache();
-
- // queries on @Computed records or the presence of FieldOverrides use the simple algorithm
- for (QueryClause clause : clauses) {
- useExplicit |= (clause instanceof FieldOverride);
- }
-
- return _ctx.invoke(useExplicit ? new FindAllQuery.Explicitly(_ctx, type, clauses) :
- new FindAllQuery.WithCache(_ctx, type, clauses));
- }
-
- /**
- * Looks up and returns {@link Key} records for all rows that match the supplied query clauses.
- *
- * @param forUpdate if true, the query will be run using a read-write connection to ensure that
- * it talks to the master database, if false, the query will be run on a read-only connection
- * and may load keys from a slave. For performance reasons, you should always pass false unless
- * you know you will be modifying the database as a result of this query and absolutely need
- * the latest data.
- */
- protected List> findAllKeys (
- Class type, boolean forUpdate, QueryClause... clause)
- throws DatabaseException
- {
- return findAllKeys(type, forUpdate, Arrays.asList(clause));
- }
-
- /**
- * Looks up and returns {@link Key} records for all rows that match the supplied query clauses.
- *
- * @param forUpdate if true, the query will be run using a read-write connection to ensure that
- * it talks to the master database, if false, the query will be run on a read-only connection
- * and may load keys from a slave. For performance reasons, you should always pass false unless
- * you know you will be modifying the database as a result of this query and absolutely need
- * the latest data.
- */
- protected List> findAllKeys (
- Class type, boolean forUpdate, Collection extends QueryClause> clauses)
- throws DatabaseException
- {
- final List> keys = new ArrayList>();
- final DepotMarshaller marsh = _ctx.getMarshaller(type);
- SelectClause select = new SelectClause(type, marsh.getPrimaryKeyFields(), clauses);
- final SQLBuilder builder = _ctx.getSQLBuilder(DepotTypes.getDepotTypes(_ctx, select));
- builder.newQuery(select);
-
- if (forUpdate) {
- _ctx.invoke(new Modifier(null) {
- @Override public Integer invoke (Connection conn, DatabaseLiaison liaison)
- throws SQLException {
- PreparedStatement stmt = builder.prepare(conn);
- try {
- ResultSet rs = stmt.executeQuery();
- while (rs.next()) {
- keys.add(marsh.makePrimaryKey(rs));
- }
- return 0;
- } finally {
- JDBCUtil.close(stmt);
- }
- }
- });
-
- } else {
- _ctx.invoke(new Query.Trivial() {
- @Override
- public Void invoke (Connection conn, DatabaseLiaison liaison) throws SQLException {
- PreparedStatement stmt = builder.prepare(conn);
- try {
- ResultSet rs = stmt.executeQuery();
- while (rs.next()) {
- keys.add(marsh.makePrimaryKey(rs));
- }
- return null;
- } finally {
- JDBCUtil.close(stmt);
- }
- }
- });
- }
-
- return keys;
- }
-
- /**
- * Inserts the supplied persistent object into the database, assigning its primary key (if it
- * has one) in the process.
- *
- * @return the number of rows modified by this action, this should always be one.
- */
- protected int insert (T record)
- throws DatabaseException
- {
- @SuppressWarnings("unchecked") final Class pClass = (Class) record.getClass();
- final DepotMarshaller marsh = _ctx.getMarshaller(pClass);
- Key key = marsh.getPrimaryKey(record, false);
-
- DepotTypes types = DepotTypes.getDepotTypes(_ctx);
- types.addClass(_ctx, pClass);
- final SQLBuilder builder = _ctx.getSQLBuilder(types);
-
- // key will be null if record was supplied without a primary key
- return _ctx.invoke(new CachingModifier(record, key, key) {
- @Override
- public Integer invoke (Connection conn, DatabaseLiaison liaison) throws SQLException {
- // if needed, update our modifier's key so that it can cache our results
- Set identityFields = Collections.emptySet();
- if (_key == null) {
- // set any auto-generated column values
- identityFields = marsh.generateFieldValues(conn, liaison, _result, false);
- updateKey(marsh.getPrimaryKey(_result, false));
- }
-
- builder.newQuery(new InsertClause(pClass, _result, identityFields));
-
- PreparedStatement stmt = builder.prepare(conn);
- try {
- int mods = stmt.executeUpdate();
- // run any post-factum value generators and potentially generate our key
- if (_key == null) {
- marsh.generateFieldValues(conn, liaison, _result, true);
- updateKey(marsh.getPrimaryKey(_result, false));
- }
- return mods;
-
- } finally {
- JDBCUtil.close(stmt);
- }
- }
- });
- }
-
- /**
- * Updates all fields of the supplied persistent object, using its primary key to identify the
- * row to be updated.
- *
- * @return the number of rows modified by this action.
- */
- protected int update (T record)
- throws DatabaseException
- {
- @SuppressWarnings("unchecked") Class pClass = (Class) record.getClass();
- requireNotComputed(pClass, "update");
-
- DepotMarshaller marsh = _ctx.getMarshaller(pClass);
- Key key = marsh.getPrimaryKey(record);
- if (key == null) {
- throw new IllegalArgumentException("Can't update record with null primary key.");
- }
-
- UpdateClause update = new UpdateClause(pClass, key, marsh._columnFields, record);
- final SQLBuilder builder = _ctx.getSQLBuilder(DepotTypes.getDepotTypes(_ctx, update));
- builder.newQuery(update);
-
- return _ctx.invoke(new CachingModifier(record, key, key) {
- @Override
- public Integer invoke (Connection conn, DatabaseLiaison liaison) throws SQLException {
- PreparedStatement stmt = builder.prepare(conn);
- try {
- return stmt.executeUpdate();
- } finally {
- JDBCUtil.close(stmt);
- }
- }
- });
- }
-
- /**
- * Updates just the specified fields of the supplied persistent object, using its primary key
- * to identify the row to be updated. This method currently flushes the associated record from
- * the cache, but in the future it should be modified to update the modified fields in the
- * cached value iff the record exists in the cache.
- *
- * @return the number of rows modified by this action.
- */
- protected int update (T record, final String... modifiedFields)
- throws DatabaseException
- {
- @SuppressWarnings("unchecked") Class pClass = (Class) record.getClass();
- requireNotComputed(pClass, "updatePartial");
-
- DepotMarshaller marsh = _ctx.getMarshaller(pClass);
- Key key = marsh.getPrimaryKey(record);
- if (key == null) {
- throw new IllegalArgumentException("Can't update record with null primary key.");
- }
-
- UpdateClause update = new UpdateClause(pClass, key, modifiedFields, record);
- final SQLBuilder builder = _ctx.getSQLBuilder(DepotTypes.getDepotTypes(_ctx, update));
- builder.newQuery(update);
-
- return _ctx.invoke(new CachingModifier(record, key, key) {
- @Override
- public Integer invoke (Connection conn, DatabaseLiaison liaison) throws SQLException {
- PreparedStatement stmt = builder.prepare(conn);
- // clear out _result so that we don't rewrite this partial record to the cache
- _result = null;
- try {
- return stmt.executeUpdate();
- } finally {
- JDBCUtil.close(stmt);
- }
- }
- });
- }
-
- /**
- * Updates the specified columns for all persistent objects matching the supplied primary key.
- *
- * @param type the type of the persistent object to be modified.
- * @param primaryKey the primary key to match in the update.
- * @param updates an mapping from the names of the fields/columns ti the values to be assigned.
- *
- * @return the number of rows modified by this action.
- */
- protected int updatePartial (
- Class type, Comparable> primaryKey, Map updates)
- throws DatabaseException
- {
- Object[] fieldsValues = new Object[updates.size()*2];
- int idx = 0;
- for (Map.Entry entry : updates.entrySet()) {
- fieldsValues[idx++] = entry.getKey();
- fieldsValues[idx++] = entry.getValue();
- }
- return updatePartial(type, primaryKey, fieldsValues);
- }
-
- /**
- * Updates the specified columns for all persistent objects matching the supplied primary key.
- *
- * @param type the type of the persistent object to be modified.
- * @param primaryKey the primary key to match in the update.
- * @param fieldsValues an array containing the names of the fields/columns and the values to be
- * assigned, in key, value, key, value, etc. order.
- *
- * @return the number of rows modified by this action.
- */
- protected int updatePartial (
- Class type, Comparable> primaryKey, Object... fieldsValues)
- throws DatabaseException
- {
- return updatePartial(_ctx.getMarshaller(type).makePrimaryKey(primaryKey), fieldsValues);
- }
-
- /**
- * Updates the specified columns for all persistent objects matching the supplied two-column
- * primary key.
- *
- * @param type the type of the persistent object to be modified.
- * @param fieldsValues an array containing the names of the fields/columns and the values to be
- * assigned, in key, value, key, value, etc. order.
- *
- * @return the number of rows modified by this action.
- */
- protected int updatePartial (
- Class type, String ix1, Comparable> val1, String ix2, Comparable> val2,
- Object... fieldsValues)
- throws DatabaseException
- {
- return updatePartial(new Key(type, ix1, val1, ix2, val2), fieldsValues);
- }
-
- /**
- * Updates the specified columns for all persistent objects matching the supplied three-column
- * primary key.
- *
- * @param type the type of the persistent object to be modified.
- * @param fieldsValues an array containing the names of the fields/columns and the values to be
- * assigned, in key, value, key, value, etc. order.
- *
- * @return the number of rows modified by this action.
- */
- protected int updatePartial (
- Class type, String ix1, Comparable> val1, String ix2, Comparable> val2,
- String ix3, Comparable> val3, Object... fieldsValues)
- throws DatabaseException
- {
- return updatePartial(new Key(type, ix1, val1, ix2, val2, ix3, val3), fieldsValues);
- }
-
- /**
- * Updates the specified columns for all persistent objects matching the supplied key.
- *
- * @param key the key for the persistent objects to be modified.
- * @param fieldsValues an array containing the names of the fields/columns and the values to be
- * assigned, in key, value, key, value, etc. order.
- *
- * @return the number of rows modified by this action.
- */
- protected int updatePartial (Key key, Object... fieldsValues)
- throws DatabaseException
- {
- return updatePartial(key.getPersistentClass(), key, key, fieldsValues);
- }
-
- /**
- * Updates the specified columns for all persistent objects matching the supplied key. This
- * method currently flushes the associated record from the cache, but in the future it should
- * be modified to update the modified fields in the cached value iff the record exists in the
- * cache.
- *
- * @param type the type of the persistent object to be modified.
- * @param key the key to match in the update.
- * @param invalidator a cache invalidator that will be run prior to the update to flush the
- * relevant persistent objects from the cache, or null if no invalidation is needed.
- * @param fieldsValues an array containing the names of the fields/columns and the values to be
- * assigned, in key, value, key, value, etc. order.
- *
- * @return the number of rows modified by this action.
- */
- protected int updatePartial (
- Class type, final WhereClause key, CacheInvalidator invalidator, Object... fieldsValues)
- throws DatabaseException
- {
- if (invalidator instanceof ValidatingCacheInvalidator) {
- ((ValidatingCacheInvalidator)invalidator).validateFlushType(type); // sanity check
- }
- key.validateQueryType(type); // and another
-
- // separate the arguments into keys and values
- final String[] fields = new String[fieldsValues.length/2];
- final SQLExpression[] values = new SQLExpression[fields.length];
- for (int ii = 0, idx = 0; ii < fields.length; ii++) {
- fields[ii] = (String)fieldsValues[idx++];
- values[ii] = new ValueExp(fieldsValues[idx++]);
- }
- UpdateClause update = new UpdateClause(type, key, fields, values);
- final SQLBuilder builder = _ctx.getSQLBuilder(DepotTypes.getDepotTypes(_ctx, update));
- builder.newQuery(update);
-
- return _ctx.invoke(new Modifier(invalidator) {
- @Override
- public Integer invoke (Connection conn, DatabaseLiaison liaison) throws SQLException {
- PreparedStatement stmt = builder.prepare(conn);
- try {
- return stmt.executeUpdate();
- } finally {
- JDBCUtil.close(stmt);
- }
- }
- });
- }
-
- /**
- * Updates the specified columns for all persistent objects matching the supplied primary
- * key. The values in this case must be literal SQL to be inserted into the update statement.
- * In general this is used when you want to do something like the following:
- *
- *
- * update FOO set BAR = BAR + 1;
- * update BAZ set BIF = NOW();
- *
- *
- * @param type the type of the persistent object to be modified.
- * @param primaryKey the key to match in the update.
- * @param fieldsValues an array containing the names of the fields/columns and the values to be
- * assigned, in key, literal value, key, literal value, etc. order.
- *
- * @return the number of rows modified by this action.
- */
- protected int updateLiteral (
- Class type, Comparable> primaryKey, Map fieldsValues)
- throws DatabaseException
- {
- Key key = _ctx.getMarshaller(type).makePrimaryKey(primaryKey);
- return updateLiteral(type, key, key, fieldsValues);
- }
-
- /**
- * Updates the specified columns for all persistent objects matching the supplied two-column
- * primary key. The values in this case must be literal SQL to be inserted into the update
- * statement. In general this is used when you want to do something like the following:
- *
- *
- * update FOO set BAR = BAR + 1;
- * update BAZ set BIF = NOW();
- *
- *
- * @param type the type of the persistent object to be modified.
- * @param fieldsValues an array containing the names of the fields/columns and the values to be
- * assigned, in key, literal value, key, literal value, etc. order.
- *
- * @return the number of rows modified by this action.
- */
- protected int updateLiteral (
- Class type, String ix1, Comparable> val1, String ix2, Comparable> val2,
- Map fieldsValues)
- throws DatabaseException
- {
- Key key = new Key(type, ix1, val1, ix2, val2);
- return updateLiteral(type, key, key, fieldsValues);
- }
-
- /**
- * Updates the specified columns for all persistent objects matching the supplied three-column
- * primary key. The values in this case must be literal SQL to be inserted into the update
- * statement. In general this is used when you want to do something like the following:
- *
- *
- * update FOO set BAR = BAR + 1;
- * update BAZ set BIF = NOW();
- *
- *
- * @param type the type of the persistent object to be modified.
- * @param fieldsValues an array containing the names of the fields/columns and the values to be
- * assigned, in key, literal value, key, literal value, etc. order.
- *
- * @return the number of rows modified by this action.
- */
- protected int updateLiteral (
- Class type, String ix1, Comparable> val1, String ix2, Comparable> val2,
- String ix3, Comparable> val3, Map fieldsValues)
- throws DatabaseException
- {
- Key key = new Key(type, ix1, val1, ix2, val2, ix3, val3);
- return updateLiteral(type, key, key, fieldsValues);
- }
-
- /**
- * Updates the specified columns for all persistent objects matching the supplied primary
- * key. The values in this case must be literal SQL to be inserted into the update statement.
- * In general this is used when you want to do something like the following:
- *
- *
- * update FOO set BAR = BAR + 1;
- * update BAZ set BIF = NOW();
- *
- *
- * @param type the type of the persistent object to be modified.
- * @param key the key to match in the update.
- * @param fieldsValues an array containing the names of the fields/columns and the values to be
- * assigned, in key, literal value, key, literal value, etc. order.
- *
- * @return the number of rows modified by this action.
- */
- protected int updateLiteral (
- Class type, final WhereClause key, CacheInvalidator invalidator,
- Map fieldsValues)
- throws DatabaseException
- {
- requireNotComputed(type, "updateLiteral");
-
- if (invalidator instanceof ValidatingCacheInvalidator) {
- ((ValidatingCacheInvalidator)invalidator).validateFlushType(type); // sanity check
- }
- key.validateQueryType(type); // and another
-
- // separate the arguments into keys and values
- final String[] fields = new String[fieldsValues.size()];
- final SQLExpression[] values = new SQLExpression[fields.length];
- int ii = 0;
- for (Map.Entry entry : fieldsValues.entrySet()) {
- fields[ii] = entry.getKey();
- values[ii] = entry.getValue();
- ii ++;
- }
-
- UpdateClause update = new UpdateClause(type, key, fields, values);
- final SQLBuilder builder = _ctx.getSQLBuilder(DepotTypes.getDepotTypes(_ctx, update));
- builder.newQuery(update);
-
- return _ctx.invoke(new Modifier(invalidator) {
- @Override
- public Integer invoke (Connection conn, DatabaseLiaison liaison) throws SQLException {
- PreparedStatement stmt = builder.prepare(conn);
- try {
- return stmt.executeUpdate();
- } finally {
- JDBCUtil.close(stmt);
- }
- }
- });
- }
-
- /**
- * Stores the supplied persisent object in the database. If it has no primary key assigned (it
- * is null or zero), it will be inserted directly. Otherwise an update will first be attempted
- * and if that matches zero rows, the object will be inserted.
- *
- * @return true if the record was created, false if it was updated.
- */
- protected boolean store (T record)
- throws DatabaseException
- {
- @SuppressWarnings("unchecked") final Class pClass = (Class) record.getClass();
- requireNotComputed(pClass, "store");
-
- final DepotMarshaller marsh = _ctx.getMarshaller(pClass);
- Key key = marsh.hasPrimaryKey() ? marsh.getPrimaryKey(record) : null;
- final UpdateClause update =
- new UpdateClause(pClass, key, marsh._columnFields, record);
- final SQLBuilder builder = _ctx.getSQLBuilder(DepotTypes.getDepotTypes(_ctx, update));
-
- // if our primary key isn't null, we start by trying to update rather than insert
- if (key != null) {
- builder.newQuery(update);
- }
-
- final boolean[] created = new boolean[1];
- _ctx.invoke(new CachingModifier(record, key, key) {
- @Override
- public Integer invoke (Connection conn, DatabaseLiaison liaison) throws SQLException {
- PreparedStatement stmt = null;
- try {
- if (_key != null) {
- // run the update
- stmt = builder.prepare(conn);
- int mods = stmt.executeUpdate();
- if (mods > 0) {
- // if it succeeded, we're done
- return mods;
- }
- JDBCUtil.close(stmt);
- }
-
- // if the update modified zero rows or the primary key was unset, insert
- Set identityFields = Collections.emptySet();
- if (_key == null) {
- // first, set any auto-generated column values
- identityFields = marsh.generateFieldValues(conn, liaison, _result, false);
- // update our modifier's key so that it can cache our results
- updateKey(marsh.getPrimaryKey(_result, false));
- }
-
- builder.newQuery(new InsertClause(pClass, _result, identityFields));
-
- stmt = builder.prepare(conn);
- int mods = stmt.executeUpdate();
-
- // run any post-factum value generators and potentially generate our key
- if (_key == null) {
- marsh.generateFieldValues(conn, liaison, _result, true);
- updateKey(marsh.getPrimaryKey(_result, false));
- }
- created[0] = true;
- return mods;
-
- } finally {
- JDBCUtil.close(stmt);
- }
- }
- });
- return created[0];
- }
-
- /**
- * Deletes all persistent objects from the database with a primary key matching the primary key
- * of the supplied object.
- *
- * @return the number of rows deleted by this action.
- */
- protected int delete (T record)
- throws DatabaseException
- {
- @SuppressWarnings("unchecked") Class type = (Class)record.getClass();
- Key primaryKey = _ctx.getMarshaller(type).getPrimaryKey(record);
- if (primaryKey == null) {
- throw new IllegalArgumentException("Can't delete record with null primary key.");
- }
- return delete(type, primaryKey);
- }
-
- /**
- * Deletes all persistent objects from the database with a primary key matching the supplied
- * primary key.
- *
- * @return the number of rows deleted by this action.
- */
- protected int delete (Class type, Comparable> primaryKeyValue)
- throws DatabaseException
- {
- return delete(type, _ctx.getMarshaller(type).makePrimaryKey(primaryKeyValue));
- }
-
- /**
- * Deletes all persistent objects from the database with a primary key matching the supplied
- * primary key.
- *
- * @return the number of rows deleted by this action.
- */
- protected int delete (Class type, Key primaryKey)
- throws DatabaseException
- {
- return deleteAll(type, primaryKey, primaryKey);
- }
-
- /**
- * Deletes all persistent objects from the database that match the supplied where clause.
- *
- * @return the number of rows deleted by this action.
- */
- protected int deleteAll (Class type, final WhereClause where)
- throws DatabaseException
- {
- if (_ctx.getMarshaller(type).hasPrimaryKey()) {
- // look up the primary keys for all rows matching our where clause and delete using those
- KeySet pwhere = new KeySet(type, findAllKeys(type, true, where));
- return deleteAll(type, pwhere, pwhere);
- } else {
- // otherwise just do the delete directly as we can't have cached a record that has no
- // primary key in the first place
- return deleteAll(type, where, null);
- }
- }
-
- /**
- * Deletes all persistent objects from the database that match the supplied key.
- *
- * @return the number of rows deleted by this action.
- */
- protected int deleteAll (
- Class type, final WhereClause where, CacheInvalidator invalidator)
- throws DatabaseException
- {
- if (invalidator instanceof ValidatingCacheInvalidator) {
- ((ValidatingCacheInvalidator)invalidator).validateFlushType(type); // sanity check
- }
- where.validateQueryType(type); // and another
-
- DeleteClause delete = new DeleteClause(type, where);
- final SQLBuilder builder = _ctx.getSQLBuilder(DepotTypes.getDepotTypes(_ctx, delete));
- builder.newQuery(delete);
-
- return _ctx.invoke(new Modifier(invalidator) {
- @Override
- public Integer invoke (Connection conn, DatabaseLiaison liaison) throws SQLException {
- PreparedStatement stmt = builder.prepare(conn);
- try {
- return stmt.executeUpdate();
- } finally {
- JDBCUtil.close(stmt);
- }
- }
- });
- }
-
- // make sure the given type corresponds to a concrete class
- protected void requireNotComputed (Class extends PersistentRecord> type, String action)
- throws DatabaseException
- {
- DepotMarshaller> marsh = _ctx.getMarshaller(type);
- if (marsh == null) {
- throw new DatabaseException("Unknown persistent type [class=" + type + "]");
- }
- if (marsh.getTableName() == null) {
- throw new DatabaseException(
- "Can't " + action + " computed entities [class=" + type + "]");
- }
- }
-
- /**
- * If the supplied migration has not already been run, it will be run and if it completes, we
- * will note in the DepotMigrationHistory table that it has been run.
- */
- protected void runMigration (DataMigration migration)
- throws DatabaseException
- {
- // attempt to get a lock to run this migration (or detect that it has already been run)
- DepotMigrationHistoryRecord record;
- while (true) {
- // check to see if the migration has already been completed
- record = load(DepotMigrationHistoryRecord.class, migration.getIdent());
- if (record != null && record.whenCompleted != null) {
- return; // great, no need to do anything
- }
-
- // if no record exists at all, try to insert one and thereby obtain the migration lock
- if (record == null) {
- try {
- record = new DepotMigrationHistoryRecord();
- record.ident = migration.getIdent();
- insert(record);
- break; // we got the lock, break out of this loop and run the migration
- } catch (DuplicateKeyException dke) {
- // someone beat us to the punch, so we have to wait for them to finish
- }
- }
-
- // we didn't get the lock, so wait 5 seconds and then check to see if the other process
- // finished the update or failed in which case we'll try to grab the lock ourselves
- try {
- log.info("Waiting on migration lock for " + migration.getIdent() + ".");
- Thread.sleep(5000);
- } catch (InterruptedException ie) {
- throw new DatabaseException("Interrupted while waiting on migration lock.");
- }
- }
-
- log.info("Running data migration", "ident", migration.getIdent());
- try {
- // run the migration
- migration.invoke();
-
- // report to the world that we've done so
- record.whenCompleted = new Timestamp(System.currentTimeMillis());
- update(record);
-
- } finally {
- // clear out our migration history record if we failed to get the job done
- if (record.whenCompleted == null) {
- try {
- delete(record);
- } catch (Throwable dt) {
- log.warning("Oh noez! Failed to delete history record for failed migration. " +
- "All clients will loop forever waiting for the lock.",
- "ident", migration.getIdent(), dt);
- }
- }
- }
- }
-
- protected PersistenceContext _ctx;
- protected List _dataMigs = new ArrayList();
-}
diff --git a/src/java/com/samskivert/jdbc/depot/DepotTypes.java b/src/java/com/samskivert/jdbc/depot/DepotTypes.java
deleted file mode 100644
index c0ff4e9f..00000000
--- a/src/java/com/samskivert/jdbc/depot/DepotTypes.java
+++ /dev/null
@@ -1,221 +0,0 @@
-//
-// $Id$
-//
-// samskivert library - useful routines for java programs
-// Copyright (C) 2006-2007 Michael Bayne, Pär Winzell
-//
-// 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.SQLException;
-
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-import com.samskivert.jdbc.depot.clause.QueryClause;
-import com.samskivert.jdbc.depot.expression.SQLExpression;
-
-/**
- * Maintains a record of the persistent classes brought into the context of the associated SQL,
- * i.e. any class associated with a concrete table that would appear in FROM or JOIN clauses or as
- * the target of an UPDATE or an INSERT or any other place where a table abbreviation could be
- * constructed.
- *
- * The main motivation for breaking this functionality out into its own class is to encapsulate the
- * operation that throws {@link DatabaseException} as separate from the operations that throw
- * {@link SQLException}. Once this class has been constructed, it may be used to create {@link
- * SQLBuilder} instances without any {@link DatabaseException} worries.
- */
-public class DepotTypes
-{
- /** A trivial instance that is accessible in places where we want the dialectal benefits of the
- * SQLBuilder without really requiring per-persistent-class context. */
- public static DepotTypes TRIVIAL = new DepotTypes();
-
- /**
- * Conveniently constructs a {@link DepotTypes} object given {@link QueryClause} objects, which
- * are interrogated for their class definition sets through {@link SQLExpression#addClasses}.
- */
- public static DepotTypes getDepotTypes (
- PersistenceContext ctx, Collection extends QueryClause> clauses)
- throws DatabaseException
- {
- Set> classSet =
- new HashSet>();
- for (QueryClause clause : clauses) {
- if (clause != null) {
- clause.addClasses(classSet);
- }
- }
- return new DepotTypes(ctx, classSet);
- }
-
- /**
- * A varargs version of {@link #getDepotTypes(PersistenceContext,Collection)}.
- */
- public static DepotTypes getDepotTypes (
- PersistenceContext ctx, QueryClause... clauses)
- throws DatabaseException
- {
- return getDepotTypes(ctx, Arrays.asList(clauses));
- }
-
- /**
- * Create a new DepotTypes with the given {@link PersistenceContext} and a collection of
- * persistent record classes.
- */
- public DepotTypes (PersistenceContext ctx, Collection> others)
- throws DatabaseException
- {
- for (Class extends PersistentRecord> c : others) {
- addClass(ctx, c);
- }
- }
-
- /**
- * Create a new DepotTypes with the given {@link PersistenceContext} and the given
- * persistent record.
- */
- public DepotTypes (PersistenceContext ctx, Class extends PersistentRecord> pClass)
- throws DatabaseException
- {
- addClass(ctx, pClass);
- }
-
- /**
- * Return the full table name of the given persistent class, which must have been previously
- * registered with this object.
- */
- public String getTableName (Class extends PersistentRecord> cl)
- {
- return getMarshaller(cl).getTableName();
- }
-
- /**
- * Return the current abbreviation by which we refer to the table associated with the given
- * persistent record -- which must have been previously registered with this object. If the
- * useTableAbbreviations flag is false, we return the full table name instead.
- *
- * @exception IllegalArgumentException thrown if the specified class is not known.
- */
- public String getTableAbbreviation (Class extends PersistentRecord> cl)
- {
- if (_useTableAbbreviations) {
- Integer ix = _classIx.get(cl);
- if (ix == null) {
- throw new IllegalArgumentException("Unknown persistence class: " + cl);
- }
- return "T" + (ix+1);
- }
- return getTableName(cl);
- }
-
- /**
- * Return the associated database column of the given field of the given persistent class,
- * throwing an exception if the record has not been registered with this object, or if the
- * field is unknown on the record.
- *
- * @exception IllegalArgumentException thrown if the specified field is not part of the
- * specified persistent class.
- */
- public String getColumnName (Class extends PersistentRecord> cl, String field)
- {
- FieldMarshaller> fm = getMarshaller(cl).getFieldMarshaller(field);
- if (fm == null) {
- throw new IllegalArgumentException(
- "Field not known on class [field=" + field + ", class=" + cl + "]");
- }
- return fm.getColumnName();
- }
-
- /**
- * Return the {@link DepotMarshaller} associated with the given persistent class, if it's been
- * registered with this object.
- *
- * @exception IllegalArgumentException thrown if the specified class is not known.
- */
- public DepotMarshaller> getMarshaller (Class extends PersistentRecord> cl)
- {
- DepotMarshaller> marsh = _classMap.get(cl);
- if (marsh == null) {
- throw new IllegalArgumentException("Persistent class not known: " + cl);
- }
- return marsh;
- }
-
- /**
- * Register a new persistent class with this object.
- */
- public void addClass (PersistenceContext ctx, Class extends PersistentRecord> type)
- throws DatabaseException
- {
- if (_classMap.containsKey(type)) {
- return;
- }
-
- // add the class in question
- DepotMarshaller> marsh = ctx.getMarshaller(type);
- _classMap.put(type, marsh);
- _classIx.put(type, _classIx.size());
-
- // if this class is @Computed and has a shadow, add its shadow
- if (marsh.getComputed() != null &&
- !PersistentRecord.class.equals(marsh.getComputed().shadowOf())) {
- addClass(ctx, marsh.getComputed().shadowOf());
- }
- }
-
- /**
- * Return the value of the useTableAbbreviations flag, which governs the behaviour when
- * referencing columns during SQL construction. Normally, this flag is on, and tables are
- * referenced as e.g. T1.itemId, but there are cases of weak/broken SQL where abbreviations
- * may not be brought into play. In these cases we prepend the full table name.
- */
- public boolean getUseTableAbbreviations ()
- {
- return _useTableAbbreviations;
- }
-
- /**
- * Sets the value of the useTableAbbreviations flag, which governs the behaviour when
- * referencing columns during SQL construction. Normally, this flag is on, and tables are
- * referenced as e.g. T1.itemId, but there are cases of weak/broken SQL where abbreviations
- * may not be brought into play. In these cases we prepend the full table name.
- */
- public void setUseTableAbbreviations (boolean doUse)
- {
- _useTableAbbreviations = doUse;
- }
-
- // constructor used to create TRIVIAL
- protected DepotTypes ()
- {
- }
-
- /** Classes mapped to integers, used for table abbreviation indexing. */
- protected Map, Integer> _classIx = new HashMap, Integer>();
-
- /** Classes mapped to marshallers, used for table names and field lists. */
- protected Map, DepotMarshaller>> _classMap =
- new HashMap, DepotMarshaller>>();
-
- /** When false, override the normal table abbreviations and return full table names instead. */
- protected boolean _useTableAbbreviations = true;
-}
diff --git a/src/java/com/samskivert/jdbc/depot/DuplicateKeyException.java b/src/java/com/samskivert/jdbc/depot/DuplicateKeyException.java
deleted file mode 100644
index 90960890..00000000
--- a/src/java/com/samskivert/jdbc/depot/DuplicateKeyException.java
+++ /dev/null
@@ -1,33 +0,0 @@
-//
-// $Id$
-//
-// samskivert library - useful routines for java programs
-// Copyright (C) 2001-2008 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;
-
-/**
- * Thrown when an insert or update results in a duplicate key on a column that has a uniqueness
- * constraint.
- */
-public class DuplicateKeyException extends DatabaseException
-{
- public DuplicateKeyException (String message)
- {
- super(message);
- }
-}
diff --git a/src/java/com/samskivert/jdbc/depot/EHCacheAdapter.java b/src/java/com/samskivert/jdbc/depot/EHCacheAdapter.java
deleted file mode 100644
index 54c543c8..00000000
--- a/src/java/com/samskivert/jdbc/depot/EHCacheAdapter.java
+++ /dev/null
@@ -1,169 +0,0 @@
-//
-// $Id$
-//
-// samskivert library - useful routines for java programs
-// Copyright (C) 2006-2007 Michael Bayne, Pär Winzell
-//
-// 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.io.Serializable;
-
-import net.sf.ehcache.Cache;
-import net.sf.ehcache.CacheManager;
-import net.sf.ehcache.Element;
-import net.sf.ehcache.distribution.CacheManagerPeerListener;
-import net.sf.ehcache.distribution.CacheManagerPeerProvider;
-import net.sf.ehcache.distribution.RMIAsynchronousCacheReplicator;
-
-import static com.samskivert.jdbc.depot.Log.log;
-
-/**
- * An implementation of {@link CacheAdapter} for ehcache.
- */
-public class EHCacheAdapter
- implements CacheAdapter
-{
- /**
- * Creates an adapter using the supplied cache manager. Note: this adapter does not shut down
- * the supplied manager when it is shutdown. The caller is responsible for shutting down the
- * cache manager when it knows that Depot and any other clients no longer need it.
- */
- public EHCacheAdapter (CacheManager cachemgr)
- {
- _cachemgr = cachemgr;
-
- CacheManagerPeerListener listener = _cachemgr.getCachePeerListener();
- CacheManagerPeerProvider provider = _cachemgr.getCachePeerProvider();
- if ((provider != null) != (listener != null)) {
- // we want either both listener and provider, or neither
- log.warning("EHCache misconfigured, distributed mode disabled [listener =" +
- listener + ", provider=" + provider);
- _distributed = false;
-
- } else {
- _distributed = (listener != null);
- }
- }
-
- public CacheBin getCache (String id)
- {
- return new EHCacheBin(id);
- }
-
- /**
- * The main ehcache-bridging class, a {@link CacheBin} interface against {@link Cache}.
- */
- protected class EHCacheBin implements CacheBin
- {
- // from CacheBin
- public CachedValue lookup (Serializable key)
- {
- Element hit = _cache.get(key);
- if (hit == null) {
- return null;
- }
-
- Serializable rawValue = hit.getValue();
- @SuppressWarnings("unchecked")
- final T value = (T) (rawValue instanceof NullValue ? null : rawValue);
- return new CachedValue() {
- public T getValue () {
- return value;
- }
- @Override public String toString () {
- return String.valueOf(value);
- }
- };
- }
-
- // from CacheBin
- public void store (Serializable key, T value)
- {
- _cache.put(new Element(key, value != null ? value : NULL));
- }
-
- // from CacheBin
- public void remove (Serializable key)
- {
- _cache.remove(key);
- }
-
- // from CacheBin
- public Iterable enumerateKeys ()
- {
- @SuppressWarnings("unchecked") Iterable keys = _cache.getKeys();
- return keys;
- }
-
- protected EHCacheBin (String id)
- {
- synchronized (_cachemgr) {
- _cache = _cachemgr.getCache(id);
- if (_cache == null) {
- // create the cache programatically with reasonable settings
- // TODO: we will eventually need this to be configurable in .properties
- _cache = new Cache(id,
- 1000, // keep 1000 elements in RAM
- true, // overflow the rest to disk
- false, // don't keep records around eternally
- 300, // keep them for 5 minutes after they're created
- 20); // or 20 seconds after last access
-
- if (_distributed) {
- // a programatically created cache has to have its replicator event
- // listener programatically added.
- _cache.getCacheEventNotificationService().registerListener(
- new RMIAsynchronousCacheReplicator(true, true, true, true, 1000));
- }
- _cachemgr.addCache(_cache);
- }
- }
- }
-
- protected Cache _cache;
- }
-
- // from CacheAdapter
- public void shutdown ()
- {
- }
-
- protected boolean _distributed;
- protected CacheManager _cachemgr;
-
- // this is just for convenience and memory use; we don't rely on pointer equality anywhere
- protected static Serializable NULL = new NullValue() {};
-
- /** A class to represent an explicitly Serializable concept of null for EHCache. */
- protected static class NullValue implements Serializable
- {
- @Override public String toString ()
- {
- return "";
- }
-
- @Override public boolean equals (Object other)
- {
- return other != null && other.getClass().equals(NullValue.class);
- }
-
- @Override public int hashCode ()
- {
- return 1;
- }
- }
-}
diff --git a/src/java/com/samskivert/jdbc/depot/FieldMarshaller.java b/src/java/com/samskivert/jdbc/depot/FieldMarshaller.java
deleted file mode 100644
index 37efe3fb..00000000
--- a/src/java/com/samskivert/jdbc/depot/FieldMarshaller.java
+++ /dev/null
@@ -1,477 +0,0 @@
-//
-// $Id$
-//
-// samskivert library - useful routines for java programs
-// Copyright (C) 2006-2007 Michael Bayne, Pär Winzell
-//
-// 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.lang.reflect.Field;
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.nio.ByteBuffer;
-
-import java.sql.Blob;
-import java.sql.Clob;
-import java.sql.Date;
-import java.sql.PreparedStatement;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.sql.Time;
-import java.sql.Timestamp;
-
-import com.samskivert.jdbc.ColumnDefinition;
-import com.samskivert.jdbc.depot.annotation.Column;
-import com.samskivert.jdbc.depot.annotation.Computed;
-import com.samskivert.jdbc.depot.annotation.GeneratedValue;
-
-import com.samskivert.util.StringUtil;
-
-/**
- * Handles the marshalling and unmarshalling of a particular field of a persistent object.
- *
- * @see DepotMarshaller
- */
-public abstract class FieldMarshaller
-{
- /**
- * Creates and returns a field marshaller for the specified field. Throws an exception if the
- * field in question cannot be marshalled.
- */
- public static FieldMarshaller> createMarshaller (Field field)
- {
- Class> ftype = field.getType();
- FieldMarshaller> marshaller;
-
- // primitive types
- if (ftype.equals(Boolean.TYPE)) {
- marshaller = new BooleanMarshaller();
- } else if (ftype.equals(Byte.TYPE)) {
- marshaller = new ByteMarshaller();
- } else if (ftype.equals(Short.TYPE)) {
- marshaller = new ShortMarshaller();
- } else if (ftype.equals(Integer.TYPE)) {
- marshaller = new IntMarshaller();
- } else if (ftype.equals(Long.TYPE)) {
- marshaller = new LongMarshaller();
- } else if (ftype.equals(Float.TYPE)) {
- marshaller = new FloatMarshaller();
- } else if (ftype.equals(Double.TYPE)) {
- marshaller = new DoubleMarshaller();
-
- // "natural" types
- } else if (ftype.equals(Byte.class) ||
- ftype.equals(Short.class) ||
- ftype.equals(Integer.class) ||
- ftype.equals(Long.class) ||
- ftype.equals(Float.class) ||
- ftype.equals(Double.class) ||
- ftype.equals(String.class)) {
- marshaller = new ObjectMarshaller();
-
- // some primitive array types
- } else if (ftype.equals(byte[].class)) {
- marshaller = new ByteArrayMarshaller();
-
- } else if (ftype.equals(int[].class)) {
- marshaller = new IntArrayMarshaller();
-
- // SQL types
- } else if (ftype.equals(Date.class) ||
- ftype.equals(Time.class) ||
- ftype.equals(Timestamp.class) ||
- ftype.equals(Blob.class) ||
- ftype.equals(Clob.class)) {
- marshaller = new ObjectMarshaller();
-
- // special Enum types
- } else if (ByteEnum.class.isAssignableFrom(ftype)) {
- marshaller = new ByteEnumMarshaller(ftype);
-
- } else {
- throw new IllegalArgumentException(
- "Cannot marshall field of type '" + ftype.getName() + "'.");
- }
-
- marshaller.create(field);
- return marshaller;
- }
-
- /**
- * Initializes this field marshaller with a SQL builder which it uses to construct its column
- * definition according to the appropriate database dialect.
- */
- public void init (SQLBuilder builder)
- throws DatabaseException
- {
- _columnDefinition = builder.buildColumnDefinition(this);
- }
-
- /**
- * Returns the {@link Field} handled by this marshaller.
- */
- public Field getField ()
- {
- return _field;
- }
-
- /**
- * Returns the Computed annotation on this field, if any.
- */
- public Computed getComputed ()
- {
- return _computed;
- }
-
- /**
- * Returns the GeneratedValue annotation on this field, if any.
- */
- public GeneratedValue getGeneratedValue ()
- {
- return _generatedValue;
- }
-
- /**
- * Returns the name of the table column used to store this field.
- */
- public String getColumnName ()
- {
- return _columnName;
- }
-
- /**
- * Returns the SQL used to define this field's column.
- */
- public ColumnDefinition getColumnDefinition ()
- {
- return _columnDefinition;
- }
-
- /**
- * Reads this field from the given persistent object.
- */
- public abstract T getFromObject (Object po)
- throws IllegalArgumentException, IllegalAccessException;
-
- /**
- * Sets the specified column of the given prepared statement to the given value.
- */
- public abstract void writeToStatement (PreparedStatement ps, int column, T value)
- throws SQLException;
-
- /**
- * Reads the value of our field from the supplied persistent object and sets that value into
- * the specified column of the supplied prepared statement.
- */
- public void getAndWriteToStatement (PreparedStatement ps, int column, Object po)
- throws SQLException, IllegalAccessException
- {
- writeToStatement(ps, column, getFromObject(po));
- }
-
- /**
- * Reads and returns this field from the result set.
- */
- public abstract T getFromSet (ResultSet rs)
- throws SQLException;
-
- /**
- * Writes the given value to the given persistent value.
- */
- public abstract void writeToObject (Object po, T value)
- throws IllegalArgumentException, IllegalAccessException;
-
- /**
- * Reads the specified column from the supplied result set and writes it to the appropriate
- * field of the persistent object.
- */
- public void getAndWriteToObject (ResultSet rset, Object po)
- throws SQLException, IllegalAccessException
- {
- writeToObject(po, getFromSet(rset));
- }
-
- protected void create (Field field)
- {
- _field = field;
- _columnName = field.getName();
-
- Column column = _field.getAnnotation(Column.class);
- if (column != null) {
- if (!StringUtil.isBlank(column.name())) {
- _columnName = column.name();
- }
- }
-
- _computed = field.getAnnotation(Computed.class);
- if (_computed != null) {
- return;
- }
-
- // figure out how we're going to generate our primary key values
- _generatedValue = field.getAnnotation(GeneratedValue.class);
- }
-
- protected static class BooleanMarshaller extends FieldMarshaller {
- @Override public Boolean getFromObject (Object po)
- throws IllegalArgumentException, IllegalAccessException {
- return _field.getBoolean(po);
- }
- @Override public Boolean getFromSet (ResultSet rs)
- throws SQLException {
- return rs.getBoolean(getColumnName());
- }
- @Override public void writeToObject (Object po, Boolean value)
- throws IllegalArgumentException, IllegalAccessException {
- _field.setBoolean(po, value);
- }
- @Override public void writeToStatement (PreparedStatement ps, int column, Boolean value)
- throws SQLException {
- ps.setBoolean(column, value);
- }
- }
-
- protected static class ByteMarshaller extends FieldMarshaller {
- @Override public Byte getFromObject (Object po)
- throws IllegalArgumentException, IllegalAccessException {
- return _field.getByte(po);
- }
- @Override public Byte getFromSet (ResultSet rs)
- throws SQLException {
- return rs.getByte(getColumnName());
- }
- @Override public void writeToObject (Object po, Byte value)
- throws IllegalArgumentException, IllegalAccessException {
- _field.setByte(po, value);
- }
- @Override public void writeToStatement (PreparedStatement ps, int column, Byte value)
- throws SQLException {
- ps.setByte(column, value);
- }
- }
-
- protected static class ShortMarshaller extends FieldMarshaller {
- @Override public Short getFromObject (Object po)
- throws IllegalArgumentException, IllegalAccessException {
- return _field.getShort(po);
- }
- @Override public Short getFromSet (ResultSet rs)
- throws SQLException {
- return rs.getShort(getColumnName());
- }
- @Override public void writeToObject (Object po, Short value)
- throws IllegalArgumentException, IllegalAccessException {
- _field.setShort(po, value);
- }
- @Override public void writeToStatement (PreparedStatement ps, int column, Short value)
- throws SQLException {
- ps.setShort(column, value);
- }
- }
-
- protected static class IntMarshaller extends FieldMarshaller {
- @Override public Integer getFromObject (Object po)
- throws IllegalArgumentException, IllegalAccessException {
- return _field.getInt(po);
- }
- @Override public Integer getFromSet (ResultSet rs)
- throws SQLException {
- return rs.getInt(getColumnName());
- }
- @Override public void writeToObject (Object po, Integer value)
- throws IllegalArgumentException, IllegalAccessException {
- _field.setInt(po, value);
- }
- @Override public void writeToStatement (PreparedStatement ps, int column, Integer value)
- throws SQLException {
- ps.setInt(column, value);
- }
- }
-
- protected static class LongMarshaller extends FieldMarshaller {
- @Override public Long getFromObject (Object po)
- throws IllegalArgumentException, IllegalAccessException {
- return _field.getLong(po);
- }
- @Override public Long getFromSet (ResultSet rs)
- throws SQLException {
- return rs.getLong(getColumnName());
- }
- @Override public void writeToObject (Object po, Long value)
- throws IllegalArgumentException, IllegalAccessException {
- _field.setLong(po, value);
- }
- @Override public void writeToStatement (PreparedStatement ps, int column, Long value)
- throws SQLException {
- ps.setLong(column, value);
- }
- }
-
- protected static class FloatMarshaller extends FieldMarshaller {
- @Override public Float getFromObject (Object po)
- throws IllegalArgumentException, IllegalAccessException {
- return _field.getFloat(po);
- }
- @Override public Float getFromSet (ResultSet rs)
- throws SQLException {
- return rs.getFloat(getColumnName());
- }
- @Override public void writeToObject (Object po, Float value)
- throws IllegalArgumentException, IllegalAccessException {
- _field.setFloat(po, value);
- }
- @Override public void writeToStatement (PreparedStatement ps, int column, Float value)
- throws SQLException {
- ps.setFloat(column, value);
- }
- }
-
- protected static class DoubleMarshaller extends FieldMarshaller {
- @Override public Double getFromObject (Object po)
- throws IllegalArgumentException, IllegalAccessException {
- return _field.getDouble(po);
- }
- @Override public Double getFromSet (ResultSet rs)
- throws SQLException {
- return rs.getDouble(getColumnName());
- }
- @Override public void writeToObject (Object po, Double value)
- throws IllegalArgumentException, IllegalAccessException {
- _field.setDouble(po, value);
- }
- @Override public void writeToStatement (PreparedStatement ps, int column, Double value)
- throws SQLException {
- ps.setDouble(column, value);
- }
- }
-
- protected static class ObjectMarshaller extends FieldMarshaller