diff --git a/src/java/com/samskivert/jdbc/depot/DepotRepository.java b/src/java/com/samskivert/jdbc/depot/DepotRepository.java
index 45b73b1..7b9dad4 100644
--- a/src/java/com/samskivert/jdbc/depot/DepotRepository.java
+++ b/src/java/com/samskivert/jdbc/depot/DepotRepository.java
@@ -29,6 +29,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -56,17 +57,10 @@ import com.samskivert.jdbc.depot.expression.ValueExp;
public abstract class DepotRepository
{
/**
- * Creates a repository with the supplied connection provider and its own private persistence
- * context.
- */
- protected DepotRepository (ConnectionProvider conprov)
- {
- _ctx = new PersistenceContext(getClass().getName(), conprov);
- _ctx.repositoryCreated(this);
- }
-
- /**
- * Creates a repository with the supplied persistence context.
+ * Creates a repository with the supplied persistence context. Any schema migrations needed by
+ * this repository should be registered in its constructor. A repository should not
+ * perform any actual database operations in its constructor, only register schema
+ * migrations. Initialization related database operations should be performed in {@link #init}.
*/
protected DepotRepository (PersistenceContext context)
{
@@ -74,6 +68,35 @@ public abstract class DepotRepository
_ctx.repositoryCreated(this);
}
+ /**
+ * Creates a repository with the supplied connection provider and its own private persistence
+ * context. This should generally not be used for new systems, and is only included to
+ * facilitate the integration of small numbers of Depot-based repositories into systems using
+ * the older samskivert SimpleRepository system.
+ */
+ protected DepotRepository (ConnectionProvider conprov)
+ {
+ _ctx = new PersistenceContext();
+ _ctx.init(getClass().getName(), conprov, null);
+ _ctx.repositoryCreated(this);
+ }
+
+ /**
+ * Provides a place where a repository can perform any initialization that requires database
+ * operations. The default implementation resolves all records managed by this repository so
+ * that their schema migrations are run.
+ */
+ protected void init ()
+ throws DatabaseException
+ {
+ Set> classes =
+ new HashSet>();
+ getManagedRecords(classes);
+ for (Class extends PersistentRecord> rclass : classes) {
+ _ctx.getMarshaller(rclass);
+ }
+ }
+
/**
* Adds the persistent classes used by this repository to the supplied set.
*/
diff --git a/src/java/com/samskivert/jdbc/depot/PersistenceContext.java b/src/java/com/samskivert/jdbc/depot/PersistenceContext.java
index 9e77021..c74b81d 100644
--- a/src/java/com/samskivert/jdbc/depot/PersistenceContext.java
+++ b/src/java/com/samskivert/jdbc/depot/PersistenceContext.java
@@ -20,8 +20,10 @@
package com.samskivert.jdbc.depot;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -114,33 +116,6 @@ public class PersistenceContext
protected abstract boolean testForEviction (Serializable key, T record);
}
- /**
- * 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)
- {
- this(ident, conprov, null);
- }
-
- /**
- * 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, CacheAdapter adapter)
- {
- _ident = ident;
- _conprov = conprov;
- _liaison = LiaisonRegistry.getLiaison(conprov.getURL(ident));
- _cache = adapter;
- }
-
/**
* Returns the cache adapter used by this context or null if caching is disabled.
*/
@@ -149,6 +124,22 @@ public class PersistenceContext
return _cache;
}
+ /**
+ * Initializes this context with its connection provider and cache adapter.
+ *
+ * @param ident the identifier to provide to the connection provider when requesting a
+ * connection.
+ * @param conprov provides JDBC {@link Connection} instances.
+ * @param adapter an optional adapter to a cache management system.
+ */
+ public void init (String ident, ConnectionProvider conprov, CacheAdapter adapter)
+ {
+ _ident = ident;
+ _conprov = conprov;
+ _liaison = LiaisonRegistry.getLiaison(conprov.getURL(ident));
+ _cache = adapter;
+ }
+
/**
* Shuts this persistence context down, shutting down any caching system in use and shutting
* down the JDBC connection pool.
@@ -220,6 +211,7 @@ public class PersistenceContext
public DepotMarshaller getMarshaller (Class type)
throws DatabaseException
{
+ checkAreInitialized(); // le check du sanity
DepotMarshaller marshaller = getRawMarshaller(type);
try {
if (!marshaller.isInitialized()) {
@@ -447,22 +439,28 @@ public class PersistenceContext
}
/**
- * Iterates over all {@link PersistentRecord} classes managed by this context and initializes
- * their {@link DepotMarshaller}. This forces migrations to run and the database schema to be
- * created.
+ * Initializes all repositories that have been created and registered with this persistence
+ * context. Any repositories that are constructed after this call will be immediately
+ * initialized at the time they are constructed (which is probably undesirable). When a
+ * repository is initialized, schema migrations for all of its managed persistent records are
+ * run. It is best to do all schema migrations when the system initializes which is why lazy
+ * initialization of repositories is undesirable.
*
- * @param warnOnLazyInit if true, any persistent records that are resolved after this method is
- * called will result in a warning so that the application developer can restructure their code
- * to ensure that those records are properly registered prior to this call.
+ * @param warnOnLazyInit if true, any repositories are constructed after this method is called
+ * will result in a warning so that the application developer can restructure their code to
+ * ensure that those repositories are properly created prior to this call.
*/
- public void initializeManagedRecords (boolean warnOnLazyInit)
+ public void initializeRepositories (boolean warnOnLazyInit)
throws DatabaseException
{
- for (Class extends PersistentRecord> rclass : _managedRecords) {
- getMarshaller(rclass);
+ // initialize our repositories
+ for (DepotRepository repo : _repositories) {
+ repo.init();
}
+ // note that we've now been initialized
+ _repositories = null;
// now issue a warning if we lazily initialize any other persistent record
- _warnOnLazyInit = true;
+ _warnOnLazyInit = warnOnLazyInit;
}
/**
@@ -472,12 +470,18 @@ public class PersistenceContext
*/
protected void repositoryCreated (DepotRepository repo)
{
- repo.getManagedRecords(_managedRecords);
+ if (_repositories == null) {
+ if (_warnOnLazyInit) {
+ log.warning("Repository created lazily: " + repo.getClass().getName());
+ }
+ repo.init();
+ } else {
+ _repositories.add(repo);
+ }
}
/**
- * Looks up and creates, but does not initialize, the marshaller for the specified Entity
- * type.
+ * Looks up and creates, but does not initialize, the marshaller for the specified Entity type.
*/
protected DepotMarshaller getRawMarshaller (Class type)
{
@@ -490,13 +494,13 @@ public class PersistenceContext
}
/**
- * Internal invoke method that takes care of transient retries
- * for both queries and modifiers.
+ * Internal invoke method that takes care of transient retries for both queries and modifiers.
*/
- protected Object invoke (
- Query query, Modifier modifier, boolean retryOnTransientFailure)
+ protected Object invoke (Query query, Modifier modifier, boolean retryOnTransientFailure)
throws DatabaseException
{
+ checkAreInitialized(); // le check du sanity
+
boolean isReadOnlyQuery = (query != null);
Connection conn;
try {
@@ -556,6 +560,15 @@ public class PersistenceContext
return invoke(query, modifier, false);
}
+ protected void checkAreInitialized ()
+ {
+ if (_conprov == null) {
+ throw new IllegalStateException(
+ "This persistence context has not yet been initialized. You are probably " +
+ "doing something too early, like in a repository's constructor. Don't do that.");
+ }
+ }
+
protected String _ident;
protected ConnectionProvider _conprov;
protected DatabaseLiaison _liaison;
@@ -564,16 +577,14 @@ public class PersistenceContext
/** The object through which all our caching is relayed, or null, for no caching. */
protected CacheAdapter _cache;
- protected Map>> _listenerSets =
- new HashMap>>();
+ /** Tracks repositories during the pre-initialization phase. */
+ protected List _repositories = new ArrayList();
+ /** A mapping from persistent record class to resolved marshaller. */
protected Map, DepotMarshaller>> _marshallers =
new HashMap, DepotMarshaller>>();
- /**
- * The set of persistent records for which this context is responsible. This data is used by
- * {@link #initializeManagedRecords} to force migration/schema initialization.
- */
- protected Set> _managedRecords =
- new HashSet>();
+ /** A mapping of cache listeners by cache id. */
+ protected Map>> _listenerSets =
+ new HashMap>>();
}