This is an automated email from the ASF dual-hosted git repository.

asf-gitbox-commits pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/cayenne.git

commit 4926422fcd5db784bb43ff08e02c988558095a50
Author: Andrus Adamchik <[email protected]>
AuthorDate: Sun Jul 26 17:04:19 2026 +0300

    CAY-2985 DataDomain init and structure cleanup
---
 .../java/org/apache/cayenne/access/DataDomain.java | 170 +++--------
 .../configuration/runtime/DataDomainProvider.java  | 108 ++++---
 .../cayenne/access/DataContextQueryCachingIT.java  |  36 +--
 .../org/apache/cayenne/access/DataDomainIT.java    |  72 ++---
 .../cayenne/access/DataDomainQueryActionIT.java    |  58 ++--
 .../access/DefaultDataRowStoreFactoryIT.java       | 109 +-------
 .../DefaultDataRowStoreFactory_CacheSizeIT.java    |  48 ++++
 .../DefaultDataRowStoreFactory_EventBridgeIT.java  |  46 +++
 .../runtime/DataContextFactoryTest.java            | 155 -----------
 .../DataContextFactory_DedicatedCacheIT.java       |  52 ++++
 .../runtime/DataContextFactory_ValidationIT.java   |  52 ++++
 .../runtime/DataDomainProviderIT.java              | 187 +++++++++++++
 .../runtime/DataDomainProviderTest.java            | 310 ---------------------
 .../cayenne/event/MockEventBridgeProvider.java     |  11 +-
 .../org/apache/cayenne/unit/CayenneProjects.java   |   1 +
 .../src/test/resources/cayenne-domain-provider.xml |  18 ++
 .../editor/datadomain/main/DataDomainMainView.java |  24 +-
 17 files changed, 587 insertions(+), 870 deletions(-)

diff --git a/cayenne/src/main/java/org/apache/cayenne/access/DataDomain.java 
b/cayenne/src/main/java/org/apache/cayenne/access/DataDomain.java
index 6bba60781..2e2cd7fc9 100644
--- a/cayenne/src/main/java/org/apache/cayenne/access/DataDomain.java
+++ b/cayenne/src/main/java/org/apache/cayenne/access/DataDomain.java
@@ -33,7 +33,6 @@ import org.apache.cayenne.cache.QueryCache;
 import org.apache.cayenne.configuration.Constants;
 import org.apache.cayenne.di.AdhocObjectFactory;
 import org.apache.cayenne.di.BeforeScopeEnd;
-import org.apache.cayenne.di.Inject;
 import org.apache.cayenne.event.EventManager;
 import org.apache.cayenne.graph.CompoundDiff;
 import org.apache.cayenne.graph.GraphDiff;
@@ -61,57 +60,57 @@ import java.util.concurrent.CopyOnWriteArrayList;
  * transparently routed to an appropriate DataNode.
  */
 public class DataDomain implements DataChannel {
+    
+    protected final String name;
+    protected final TransactionManager transactionManager;
+    protected final TransactionFactory transactionFactory;
+    protected final DataDomainFlushActionFactory flushActionFactory;
+    protected final AdhocObjectFactory objectFactory;
+    protected final EventManager eventManager;
+    protected final EntitySorter entitySorter;
+    protected final QueryCache queryCache;
+
+    protected final EntityResolver entityResolver;
 
-    public static final String SHARED_CACHE_ENABLED_PROPERTY = 
"cayenne.DataDomain.sharedCache";
-    public static final boolean SHARED_CACHE_ENABLED_DEFAULT = true;
-
-    public static final String VALIDATING_OBJECTS_ON_COMMIT_PROPERTY = 
"cayenne.DataDomain.validatingObjectsOnCommit";
-    public static final boolean VALIDATING_OBJECTS_ON_COMMIT_DEFAULT = true;
-
-    @Inject
-    protected TransactionManager transactionManager;
-    @Inject
-    protected TransactionFactory transactionFactory;
-    @Inject
-    protected DataDomainFlushActionFactory flushActionFactory;
-    @Inject
-    protected AdhocObjectFactory objectFactory;
-
-    protected DataRowStoreFactory dataRowStoreFactory;
     protected int maxIdQualifierSize;
     protected List<DataChannelQueryFilter> queryFilters;
     protected List<DataChannelSyncFilter> syncFilters;
     protected Map<String, DataNode> nodes;
     protected Map<String, DataNode> nodesByDataMapName;
     protected DataNode defaultNode;
-    protected EntityResolver entityResolver;
     protected DataRowStore sharedSnapshotCache;
-    protected String name;
-    protected QueryCache queryCache;
-    protected EventManager eventManager;
-    protected EntitySorter entitySorter;
-    protected boolean stopped;
 
-    // these are initialized from properties...
-    protected boolean sharedCacheEnabled;
     protected boolean validatingObjectsOnCommit;
+    protected boolean stopped;
 
-    /**
-     * Creates a DataDomain and assigns it a name.
-     */
-    public DataDomain(String name) {
-        init(name);
-        resetProperties();
-    }
+    public DataDomain(
+            String name,
+            TransactionManager transactionManager,
+            TransactionFactory transactionFactory,
+            DataDomainFlushActionFactory flushActionFactory,
+            AdhocObjectFactory objectFactory,
+            EventManager eventManager,
+            EntitySorter entitySorter,
+            QueryCache queryCache,
+            EntityResolver entityResolver
+    ) {
 
-    private void init(String name) {
+        this.name = name;
+        this.transactionManager = transactionManager;
+        this.transactionFactory = transactionFactory;
+        this.flushActionFactory = flushActionFactory;
+        this.objectFactory = objectFactory;
+        this.eventManager = eventManager;
+        this.entitySorter = entitySorter;
+        this.queryCache = queryCache;
+        this.entityResolver = entityResolver;
 
         this.queryFilters = new CopyOnWriteArrayList<>();
         this.syncFilters = new CopyOnWriteArrayList<>();
         this.nodesByDataMapName = new ConcurrentHashMap<>();
         this.nodes = new ConcurrentHashMap<>();
 
-        setName(name);
+        refreshEntitySorter();
     }
 
     /**
@@ -134,23 +133,6 @@ public class DataDomain implements DataChannel {
         return entitySorter;
     }
 
-    /**
-     * @since 3.1
-     */
-    public void setEntitySorter(EntitySorter entitySorter) {
-        this.entitySorter = entitySorter;
-    }
-
-    /**
-     * Resets the domain's behavioral flags to their defaults.
-     *
-     * @since 1.1
-     */
-    protected void resetProperties() {
-        sharedCacheEnabled = SHARED_CACHE_ENABLED_DEFAULT;
-        validatingObjectsOnCommit = VALIDATING_OBJECTS_ON_COMMIT_DEFAULT;
-    }
-
     /**
      * Returns EventManager used by this DataDomain.
      *
@@ -160,19 +142,6 @@ public class DataDomain implements DataChannel {
         return eventManager;
     }
 
-    /**
-     * Sets EventManager used by this DataDomain.
-     *
-     * @since 1.2
-     */
-    public void setEventManager(EventManager eventManager) {
-        this.eventManager = eventManager;
-
-        if (sharedSnapshotCache != null) {
-            sharedSnapshotCache.setEventManager(eventManager);
-        }
-    }
-
     /**
      * Returns "name" property value.
      */
@@ -180,16 +149,6 @@ public class DataDomain implements DataChannel {
         return name;
     }
 
-    /**
-     * Sets "name" property to a new value.
-     */
-    public synchronized void setName(String name) {
-        this.name = name;
-        if (sharedSnapshotCache != null) {
-            this.sharedSnapshotCache.setName(name);
-        }
-    }
-
     /**
      * Returns <code>true</code> if DataContexts produced by this DataDomain 
are
      * using shared DataRowStore. Returns <code>false</code> if each 
DataContext
@@ -197,11 +156,7 @@ public class DataDomain implements DataChannel {
      * overwritten per DataContext.
      */
     public boolean isSharedCacheEnabled() {
-        return sharedCacheEnabled;
-    }
-
-    public void setSharedCacheEnabled(boolean sharedCacheEnabled) {
-        this.sharedCacheEnabled = sharedCacheEnabled;
+        return sharedSnapshotCache != null;
     }
 
     /**
@@ -229,22 +184,6 @@ public class DataDomain implements DataChannel {
      * the first call if 'sharedCacheEnabled' flag is true.
      */
     public DataRowStore getSharedSnapshotCache() {
-        if (sharedSnapshotCache == null && sharedCacheEnabled) {
-            this.sharedSnapshotCache = nonNullSharedSnapshotCache();
-        }
-
-        return sharedSnapshotCache;
-    }
-
-    /**
-     * Returns a guaranteed non-null shared snapshot cache regardless of the
-     * 'sharedCacheEnabled' flag setting.
-     */
-    synchronized DataRowStore nonNullSharedSnapshotCache() {
-        if (sharedSnapshotCache == null) {
-            this.sharedSnapshotCache = 
dataRowStoreFactory.createDataRowStore(name);
-        }
-
         return sharedSnapshotCache;
     }
 
@@ -400,25 +339,6 @@ public class DataDomain implements DataChannel {
         return node;
     }
 
-    /**
-     * Sets EntityResolver. If not set explicitly, DataDomain creates a default
-     * EntityResolver internally on demand.
-     *
-     * @since 1.1
-     */
-    public void setEntityResolver(EntityResolver entityResolver) {
-        this.entityResolver = entityResolver;
-    }
-
-    // creates default entity resolver if there is none set yet
-    private synchronized void createEntityResolver() {
-        if (entityResolver == null) {
-            // entity resolver will be self-indexing as we add all our maps
-            // to it as they are added to the DataDomain
-            entityResolver = new EntityResolver();
-        }
-    }
-
     /**
      * Shutdowns all owned data nodes and marks this domain as stopped.
      */
@@ -467,10 +387,6 @@ public class DataDomain implements DataChannel {
      */
     @Override
     public EntityResolver getEntityResolver() {
-        if (entityResolver == null) {
-            createEntityResolver();
-        }
-
         return entityResolver;
     }
 
@@ -534,24 +450,6 @@ public class DataDomain implements DataChannel {
         return queryCache;
     }
 
-    public void setQueryCache(QueryCache queryCache) {
-        this.queryCache = queryCache;
-    }
-
-    /**
-     * @since 4.0
-     */
-    public DataRowStoreFactory getDataRowStoreFactory() {
-        return dataRowStoreFactory;
-    }
-
-    /**
-     * @since 4.0
-     */
-    public void setDataRowStoreFactory(DataRowStoreFactory 
dataRowStoreFactory) {
-        this.dataRowStoreFactory = dataRowStoreFactory;
-    }
-
     void refreshEntitySorter() {
         if (entitySorter != null) {
             entitySorter.setEntityResolver(getEntityResolver());
diff --git 
a/cayenne/src/main/java/org/apache/cayenne/configuration/runtime/DataDomainProvider.java
 
b/cayenne/src/main/java/org/apache/cayenne/configuration/runtime/DataDomainProvider.java
index cf8582d0c..6c5758b2d 100644
--- 
a/cayenne/src/main/java/org/apache/cayenne/configuration/runtime/DataDomainProvider.java
+++ 
b/cayenne/src/main/java/org/apache/cayenne/configuration/runtime/DataDomainProvider.java
@@ -24,7 +24,9 @@ import org.apache.cayenne.DataChannelQueryFilter;
 import org.apache.cayenne.DataChannelSyncFilter;
 import org.apache.cayenne.access.DataDomain;
 import org.apache.cayenne.access.DataNode;
+import org.apache.cayenne.access.DataRowStore;
 import org.apache.cayenne.access.DataRowStoreFactory;
+import org.apache.cayenne.access.flush.DataDomainFlushActionFactory;
 import org.apache.cayenne.access.types.ValueObjectTypeRegistry;
 import org.apache.cayenne.cache.NestedQueryCache;
 import org.apache.cayenne.cache.QueryCache;
@@ -41,10 +43,13 @@ import org.apache.cayenne.di.Injector;
 import org.apache.cayenne.di.Provider;
 import org.apache.cayenne.event.EventManager;
 import org.apache.cayenne.map.DataMap;
+import org.apache.cayenne.map.EntityResolver;
 import org.apache.cayenne.map.EntitySorter;
 import org.apache.cayenne.reflect.generic.ValueComparisonStrategyFactory;
 import org.apache.cayenne.resource.Resource;
 import org.apache.cayenne.resource.ResourceLocator;
+import org.apache.cayenne.tx.TransactionFactory;
+import org.apache.cayenne.tx.TransactionManager;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -61,6 +66,11 @@ import java.util.Map;
  */
 public class DataDomainProvider implements Provider<DataDomain> {
 
+    public static final String SHARED_CACHE_ENABLED_PROPERTY = 
"cayenne.DataDomain.sharedCache";
+    public static final String SHARED_CACHE_ENABLED_DEFAULT = "true";
+    public static final String VALIDATING_OBJECTS_ON_COMMIT_PROPERTY = 
"cayenne.DataDomain.validatingObjectsOnCommit";
+    public static final String VALIDATING_OBJECTS_ON_COMMIT_DEFAULT = "true";
+
     private static final Logger LOGGER = 
LoggerFactory.getLogger(DataDomainProvider.class);
 
     @Inject
@@ -102,6 +112,24 @@ public class DataDomainProvider implements 
Provider<DataDomain> {
     @Inject
     protected DataNodeFactory dataNodeFactory;
 
+    @Inject
+    protected TransactionManager transactionManager;
+
+    @Inject
+    protected TransactionFactory transactionFactory;
+
+    @Inject
+    protected DataDomainFlushActionFactory flushActionFactory;
+
+    @Inject
+    protected AdhocObjectFactory objectFactory;
+
+    @Inject
+    protected EventManager eventManager;
+
+    @Inject
+    protected EntitySorter entitySorter;
+
     @Override
     public DataDomain get() throws ConfigurationException {
 
@@ -116,54 +144,49 @@ public class DataDomainProvider implements 
Provider<DataDomain> {
         }
     }
 
-    protected DataDomain createDataDomain(String name) {
-        return new DataDomain(name);
-    }
-
     protected DataDomain createAndInitDataDomain() throws Exception {
 
         DataChannelDescriptor descriptor = loadDescriptor();
 
-        DataDomain dataDomain = createDataDomain(descriptor.getName());
+        DataDomain domain = new DataDomain(
+                descriptor.getName(),
+                transactionManager,
+                transactionFactory,
+                flushActionFactory,
+                objectFactory,
+                eventManager,
+                entitySorter,
+                new NestedQueryCache(queryCache),
+                createEntityResolver(descriptor));
 
-        
dataDomain.setMaxIdQualifierSize(runtimeProperties.getInt(Constants.MAX_ID_QUALIFIER_SIZE_PROPERTY,
 -1));
+        
domain.setMaxIdQualifierSize(runtimeProperties.getInt(Constants.MAX_ID_QUALIFIER_SIZE_PROPERTY,
 -1));
 
-        dataDomain.setQueryCache(new NestedQueryCache(queryCache));
-        dataDomain.setEntitySorter(injector.getInstance(EntitySorter.class));
-        dataDomain.setEventManager(injector.getInstance(EventManager.class));
-        
dataDomain.setDataRowStoreFactory(injector.getInstance(DataRowStoreFactory.class));
 
         Map<String, String> properties = descriptor.getProperties();
-        if 
("true".equalsIgnoreCase(properties.get(DataDomain.SHARED_CACHE_ENABLED_PROPERTY)))
 {
-            dataDomain.setSharedCacheEnabled(true);
-        }
-
-        if 
("true".equalsIgnoreCase(properties.get(DataDomain.VALIDATING_OBJECTS_ON_COMMIT_PROPERTY)))
 {
-            dataDomain.setValidatingObjectsOnCommit(true);
-        }
 
-        for (DataMap dataMap : descriptor.getDataMaps()) {
-            dataDomain.addDataMap(dataMap);
+        boolean sharedCache = 
"true".equals(properties.getOrDefault(SHARED_CACHE_ENABLED_PROPERTY, 
SHARED_CACHE_ENABLED_DEFAULT));
+        if (sharedCache) {
+            DataRowStore cache = 
injector.getInstance(DataRowStoreFactory.class).createDataRowStore(descriptor.getName());
+            // TODO: setSharedSnapshotCache mutates cache internally; also 
DataDomain.setName() does
+            domain.setSharedSnapshotCache(cache);
         }
 
-        dataDomain.getEntityResolver().applyDBLayerDefaults();
-        
dataDomain.getEntityResolver().setValueObjectTypeRegistry(injector.getInstance(ValueObjectTypeRegistry.class));
-        
dataDomain.getEntityResolver().setValueComparisonStrategyFactory(injector.getInstance(ValueComparisonStrategyFactory.class));
-        
dataDomain.getEntityResolver().setObjectFactory(injector.getInstance(AdhocObjectFactory.class));
+        boolean validatingOnCommit = 
"true".equals(properties.getOrDefault(VALIDATING_OBJECTS_ON_COMMIT_PROPERTY, 
VALIDATING_OBJECTS_ON_COMMIT_DEFAULT));
+        domain.setValidatingObjectsOnCommit(validatingOnCommit);
 
         for (DataNodeDescriptor nodeDescriptor : 
descriptor.getNodeDescriptors()) {
-            addDataNode(dataDomain, nodeDescriptor);
+            addDataNode(domain, nodeDescriptor);
         }
 
         // init default node
         DataNode defaultNode = null;
 
         if (descriptor.getDefaultNodeName() != null) {
-            defaultNode = 
dataDomain.getDataNode(descriptor.getDefaultNodeName());
+            defaultNode = domain.getDataNode(descriptor.getDefaultNodeName());
         }
 
         if (defaultNode == null) {
-            Collection<DataNode> allNodes = dataDomain.getDataNodes();
+            Collection<DataNode> allNodes = domain.getDataNodes();
             if (allNodes.size() == 1) {
                 defaultNode = allNodes.iterator().next();
             }
@@ -172,22 +195,45 @@ public class DataDomainProvider implements 
Provider<DataDomain> {
         if (defaultNode != null) {
             LOGGER.info("setting DataNode '{}' as default, used by all 
unlinked DataMaps", defaultNode.getName());
 
-            dataDomain.setDefaultNode(defaultNode);
+            domain.setDefaultNode(defaultNode);
         }
 
         for (DataChannelQueryFilter filter : queryFilters) {
-            dataDomain.addQueryFilter(filter);
+            domain.addQueryFilter(filter);
         }
 
         for (DataChannelSyncFilter filter : syncFilters) {
-            dataDomain.addSyncFilter(filter);
+            domain.addSyncFilter(filter);
         }
 
         for (Object listener : listeners) {
-            dataDomain.addListener(listener);
+            domain.addListener(listener);
+        }
+
+        return domain;
+    }
+
+    /**
+     * Creates an EntityResolver fully configured off the descriptor, so that 
the DataDomain can take it as a
+     * constructor argument.
+     *
+     * @since 5.0
+     */
+    protected EntityResolver createEntityResolver(DataChannelDescriptor 
descriptor) {
+
+        EntityResolver entityResolver = new EntityResolver();
+
+        // must go through "addDataMap" - unlike the Collection constructor, 
it sets the map namespace
+        for (DataMap dataMap : descriptor.getDataMaps()) {
+            entityResolver.addDataMap(dataMap);
         }
 
-        return dataDomain;
+        entityResolver.applyDBLayerDefaults();
+        
entityResolver.setValueObjectTypeRegistry(injector.getInstance(ValueObjectTypeRegistry.class));
+        
entityResolver.setValueComparisonStrategyFactory(injector.getInstance(ValueComparisonStrategyFactory.class));
+        entityResolver.setObjectFactory(objectFactory);
+
+        return entityResolver;
     }
 
     /**
diff --git 
a/cayenne/src/test/java/org/apache/cayenne/access/DataContextQueryCachingIT.java
 
b/cayenne/src/test/java/org/apache/cayenne/access/DataContextQueryCachingIT.java
index df3e9bdb2..608f06efc 100644
--- 
a/cayenne/src/test/java/org/apache/cayenne/access/DataContextQueryCachingIT.java
+++ 
b/cayenne/src/test/java/org/apache/cayenne/access/DataContextQueryCachingIT.java
@@ -21,8 +21,6 @@ package org.apache.cayenne.access;
 
 import org.apache.cayenne.DataRow;
 import org.apache.cayenne.Persistent;
-import org.apache.cayenne.cache.MapQueryCache;
-import org.apache.cayenne.cache.QueryCache;
 import org.apache.cayenne.query.ObjectSelect;
 import org.apache.cayenne.query.QueryCacheStrategy;
 import org.apache.cayenne.query.QueryMetadata;
@@ -30,38 +28,30 @@ import org.apache.cayenne.test.jdbc.TableHelper;
 import org.apache.cayenne.testdo.testmap.Artist;
 import org.apache.cayenne.unit.CayenneProjects;
 import org.apache.cayenne.unit.CayenneTestsEnv;
-import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.extension.RegisterExtension;
 import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
 
 import java.util.ArrayList;
 import java.util.List;
 
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNull;
-import static org.junit.jupiter.api.Assertions.assertSame;
-import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.*;
 
-public class DataContextQueryCachingIT  {
+public class DataContextQueryCachingIT {
 
     @RegisterExtension
     static final CayenneTestsEnv env = 
CayenneTestsEnv.forProject(CayenneProjects.TESTMAP_PROJECT);
 
-        protected DataContext context;
-
-
     protected TableHelper tArtist;
     protected TableHelper tPainting;
 
-    protected QueryCache oldCache;
+    protected DataContext context;
     protected DataDomain domain;
 
     protected DataNode getNode() {
         return this.domain.getDataNodes().iterator().next();
     }
 
-    
     @BeforeEach
     public void setUp() throws Exception {
         context = env.context();
@@ -73,15 +63,6 @@ public class DataContextQueryCachingIT  {
                 "ESTIMATED_PRICE");
 
         domain = context.getParentDataDomain();
-        oldCache = domain.getQueryCache();
-        domain.setQueryCache(new MapQueryCache(50));
-        context.setQueryCache(new MapQueryCache(50));
-    }
-
-    
-    @AfterEach
-    public void tearDown() throws Exception {
-        domain.setQueryCache(oldCache);
     }
 
     protected void createInsertDataSet() throws Exception {
@@ -128,8 +109,7 @@ public class DataContextQueryCachingIT  {
             assertEquals(rows2, freshResultRows);
             
assertNull(context.getParentDataDomain().getQueryCache().get(cacheKey));
             assertEquals(rows2, context.getQueryCache().get(cacheKey));
-        }
-        finally {
+        } finally {
             engine.stopInterceptNode();
         }
     }
@@ -168,8 +148,7 @@ public class DataContextQueryCachingIT  {
             assertEquals(rows2, 
context.getParentDataDomain().getQueryCache().get(
                     cacheKey));
             assertNull(context.getQueryCache().get(cacheKey));
-        }
-        finally {
+        } finally {
             engine.stopInterceptNode();
         }
     }
@@ -207,8 +186,7 @@ public class DataContextQueryCachingIT  {
             assertTrue(resultRows.get(0) instanceof Persistent);
             
assertNull(context.getParentDataDomain().getQueryCache().get(cacheKey));
             assertEquals(freshResultRows, 
context.getQueryCache().get(cacheKey));
-        }
-        finally {
+        } finally {
             engine.stopInterceptNode();
         }
     }
diff --git a/cayenne/src/test/java/org/apache/cayenne/access/DataDomainIT.java 
b/cayenne/src/test/java/org/apache/cayenne/access/DataDomainIT.java
index 7ac546804..c6b334568 100644
--- a/cayenne/src/test/java/org/apache/cayenne/access/DataDomainIT.java
+++ b/cayenne/src/test/java/org/apache/cayenne/access/DataDomainIT.java
@@ -26,6 +26,7 @@ import org.apache.cayenne.annotation.PostAdd;
 import org.apache.cayenne.configuration.DefaultRuntimeProperties;
 import org.apache.cayenne.event.DefaultEventManager;
 import org.apache.cayenne.map.DataMap;
+import org.apache.cayenne.map.EntityResolver;
 import org.apache.cayenne.map.ObjEntity;
 import org.apache.cayenne.testdo.testmap.Artist;
 import org.apache.cayenne.testdo.testmap.Exhibit;
@@ -44,20 +45,15 @@ import static org.junit.jupiter.api.Assertions.*;
 public class DataDomainIT {
 
     @RegisterExtension
-    static final CayenneTestsEnv env = 
CayenneTestsEnv.forProject(CayenneProjects.TESTMAP_PROJECT);
-
-    @Test
-    public void name() throws Exception {
-        DataDomain domain = new DataDomain("some name");
-        assertEquals("some name", domain.getName());
-        domain.setName("tst_name");
-        assertEquals("tst_name", domain.getName());
-    }
+    final CayenneTestsEnv env = 
CayenneTestsEnv.forProject(CayenneProjects.TESTMAP_PROJECT);
 
     @Test
     public void lookupDataNode() {
 
-        DataDomain domain = new DataDomain("test");
+        DataDomain domain = env.runtime().getDataDomain();
+
+        // an unmapped DataMap falls back to the default node, so drop it to 
test the "no node" case below
+        domain.setDefaultNode(null);
 
         DataMap m1 = new DataMap("m1");
         DataNode n1 = new DataNode("n1");
@@ -78,7 +74,7 @@ public class DataDomainIT {
     @Test
     public void lookupDataNode_Default() {
 
-        DataDomain domain = new DataDomain("test");
+        DataDomain domain = env.runtime().getDataDomain();
 
         DataMap m1 = new DataMap("m1");
         DataNode n1 = new DataNode("n1");
@@ -99,19 +95,19 @@ public class DataDomainIT {
 
     @Test
     public void nodes() throws Exception {
-        DataDomain domain = new DataDomain("dom1");
-        assertEquals(0, domain.getDataNodes().size());
+        DataDomain domain = env.runtime().getDataDomain();
+        assertEquals(1, domain.getDataNodes().size());
         DataNode node = new DataNode("1");
         domain.addNode(node);
-        assertEquals(1, domain.getDataNodes().size());
+        assertEquals(2, domain.getDataNodes().size());
         node = new DataNode("2");
         domain.addNode(node);
-        assertEquals(2, domain.getDataNodes().size());
+        assertEquals(3, domain.getDataNodes().size());
     }
 
     @Test
-    public void nodeMaps() throws Exception {
-        DataDomain domain = new DataDomain("dom1");
+    public void nodeMaps() {
+        DataDomain domain = env.runtime().getDataDomain();
         assertNull(domain.getDataMap("map"));
 
         DataNode node = new DataNode("1");
@@ -123,7 +119,7 @@ public class DataDomainIT {
 
     @Test
     public void maps() throws Exception {
-        DataDomain d1 = new DataDomain("dom1");
+        DataDomain d1 = env.runtime().getDataDomain();
 
         DataMap m1 = new DataMap("m1");
         d1.addDataMap(m1);
@@ -135,8 +131,8 @@ public class DataDomainIT {
 
     @Test
     public void entityResolverRefresh() throws Exception {
-        DataDomain domain = new DataDomain("dom1");
-        org.apache.cayenne.map.EntityResolver resolver = 
domain.getEntityResolver();
+        DataDomain domain = env.runtime().getDataDomain();
+        EntityResolver resolver = domain.getEntityResolver();
         assertNotNull(resolver);
 
         DataMap map = new DataMap("map");
@@ -148,41 +144,9 @@ public class DataDomainIT {
         assertSame(entity, resolver.getObjEntity("TestEntity"));
     }
 
-    @Test
-    public void entityResolver() {
-        assertNotNull(env.runtime().getDataDomain().getEntityResolver());
-
-        DataDomain domain = new DataDomain("dom1");
-        assertNotNull(domain.getEntityResolver());
-    }
-
-    @Test
-    public void sharedCacheEnabledDefault() {
-        assertTrue(new DataDomain("d1").isSharedCacheEnabled());
-    }
-
-    @Test
-    public void sharedCacheEnabled() {
-        DataDomain domain = new DataDomain("d1");
-        domain.setSharedCacheEnabled(false);
-        assertFalse(domain.isSharedCacheEnabled());
-    }
-
-    @Test
-    public void validatingObjectsOnCommitDefault() {
-        assertTrue(new DataDomain("d1").isValidatingObjectsOnCommit());
-    }
-
-    @Test
-    public void validatingObjectsOnCommit() {
-        DataDomain domain = new DataDomain("d1");
-        domain.setValidatingObjectsOnCommit(false);
-        assertFalse(domain.isValidatingObjectsOnCommit());
-    }
-
     @Test
     public void shutdownCache() {
-        DataDomain domain = new DataDomain("X");
+        DataDomain domain = env.runtime().getDataDomain();
 
         final boolean[] cacheShutdown = new boolean[1];
 
@@ -232,7 +196,7 @@ public class DataDomainIT {
 
         StringBuilder callbackBuffer = new StringBuilder();
 
-        @PostAdd({ Gallery.class, Painting.class })
+        @PostAdd({Gallery.class, Painting.class})
         void postAddEntities(Persistent object) {
             
callbackBuffer.append("e:").append(object.getObjectId().getEntityName()).append(";");
         }
diff --git 
a/cayenne/src/test/java/org/apache/cayenne/access/DataDomainQueryActionIT.java 
b/cayenne/src/test/java/org/apache/cayenne/access/DataDomainQueryActionIT.java
index c46582a70..f101a3773 100644
--- 
a/cayenne/src/test/java/org/apache/cayenne/access/DataDomainQueryActionIT.java
+++ 
b/cayenne/src/test/java/org/apache/cayenne/access/DataDomainQueryActionIT.java
@@ -18,9 +18,6 @@
  ****************************************************************/
 package org.apache.cayenne.access;
 
-import java.io.Serializable;
-import java.util.List;
-
 import org.apache.cayenne.cache.MockQueryCache;
 import org.apache.cayenne.cache.QueryCache;
 import org.apache.cayenne.cache.QueryCacheEntryFactory;
@@ -30,21 +27,37 @@ import org.apache.cayenne.query.QueryMetadata;
 import org.apache.cayenne.testdo.testmap.Painting;
 import org.apache.cayenne.unit.CayenneProjects;
 import org.apache.cayenne.unit.CayenneTestsEnv;
-import org.junit.jupiter.api.extension.RegisterExtension;
-import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
 
+import java.io.Serializable;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.assertInstanceOf;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
 public class DataDomainQueryActionIT {
 
-    @RegisterExtension
-    static final CayenneTestsEnv env = 
CayenneTestsEnv.forProject(CayenneProjects.TESTMAP_PROJECT);
+    static QueryCache testQQ = new MockQueryCache() {
 
-    @AfterEach
-    public void tearDown() {
-        env.runtime().getDataDomain().resetProperties();
-    }
+        @Override
+        public List<?> get(QueryMetadata metadata, QueryCacheEntryFactory 
factory) {
+            Object results = factory.createObject();
+            assertInstanceOf(Serializable.class, results, "Query cache is not 
serializable.");
+
+            return null;
+        }
+
+        @SuppressWarnings("all")
+        @Override
+        public void put(QueryMetadata metadata, List results) {
+            assertTrue(results instanceof Serializable, "Query cache is not 
serializable.");
+        }
+    };
+
+    @RegisterExtension
+    static final CayenneTestsEnv env = 
CayenneTestsEnv.forProject(CayenneProjects.TESTMAP_PROJECT)
+            .withExtraModules(b -> 
b.bind(QueryCache.class).toInstance(testQQ));
 
     @Test
     public void cachedQuery() {
@@ -61,29 +74,8 @@ public class DataDomainQueryActionIT {
                 .cacheStrategy(QueryCacheStrategy.SHARED_CACHE)
                 .pageSize(5);
 
-        QueryCache cache = domain.queryCache;
-
-        domain.queryCache = new MockQueryCache() {
-
-            @Override
-            public List<?> get(QueryMetadata metadata, QueryCacheEntryFactory 
factory) {
-                Object results = factory.createObject();
-                assertTrue(results instanceof Serializable, "Query cache is 
not serializable.");
-
-                return null;
-            }
-
-            @SuppressWarnings("all")
-            @Override
-            public void put(QueryMetadata metadata, List results) {
-                assertTrue(results instanceof Serializable, "Query cache is 
not serializable.");
-            }
-        };
-
-        DataDomainQueryAction action = new 
DataDomainQueryAction(env.context(), domain, query);
-        action.execute();
 
-        domain.queryCache = cache;
+        new DataDomainQueryAction(env.context(), domain, query).execute();
     }
 
 }
diff --git 
a/cayenne/src/test/java/org/apache/cayenne/access/DefaultDataRowStoreFactoryIT.java
 
b/cayenne/src/test/java/org/apache/cayenne/access/DefaultDataRowStoreFactoryIT.java
index c38b2f5d9..fd76e64a5 100644
--- 
a/cayenne/src/test/java/org/apache/cayenne/access/DefaultDataRowStoreFactoryIT.java
+++ 
b/cayenne/src/test/java/org/apache/cayenne/access/DefaultDataRowStoreFactoryIT.java
@@ -19,126 +19,27 @@
 
 package org.apache.cayenne.access;
 
-import org.apache.cayenne.access.flush.DataDomainFlushActionFactory;
-import org.apache.cayenne.access.flush.operation.DbRowOpSorter;
-import org.apache.cayenne.access.flush.DefaultDataDomainFlushActionFactory;
-import org.apache.cayenne.access.flush.operation.DefaultDbRowOpSorter;
-import org.apache.cayenne.access.flush.operation.HardDeleteDbRowOpFactory;
-import org.apache.cayenne.access.flush.operation.DeleteDbRowOpFactory;
-import org.apache.cayenne.configuration.DefaultRuntimeProperties;
-import org.apache.cayenne.configuration.RuntimeProperties;
-import org.apache.cayenne.configuration.runtime.CoreModule;
-import org.apache.cayenne.configuration.runtime.CoreModuleExtender;
-import org.apache.cayenne.di.AdhocObjectFactory;
-import org.apache.cayenne.di.Binder;
-import org.apache.cayenne.di.ClassLoaderManager;
-import org.apache.cayenne.di.DIBootstrap;
-import org.apache.cayenne.di.Injector;
-import org.apache.cayenne.di.Module;
-import org.apache.cayenne.di.spi.DefaultAdhocObjectFactory;
-import org.apache.cayenne.di.spi.DefaultClassLoaderManager;
-import org.apache.cayenne.event.DefaultEventManager;
-import org.apache.cayenne.event.EventBridge;
-import org.apache.cayenne.event.EventManager;
-import org.apache.cayenne.event.MockEventBridge;
-import org.apache.cayenne.event.MockEventBridgeProvider;
-import org.apache.cayenne.event.NoopEventBridgeProvider;
-import org.apache.cayenne.log.SQLLogger;
-import org.apache.cayenne.log.Slf4jSQLLogger;
 import org.apache.cayenne.runtime.CayenneRuntime;
-import org.apache.cayenne.tx.DefaultTransactionFactory;
-import org.apache.cayenne.tx.DefaultTransactionManager;
-import org.apache.cayenne.tx.TransactionFactory;
-import org.apache.cayenne.tx.TransactionManager;
 import org.apache.cayenne.unit.CayenneProjects;
 import org.apache.cayenne.unit.CayenneTestsEnv;
-import org.junit.jupiter.api.extension.RegisterExtension;
 import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
 
-import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
-import static org.junit.jupiter.api.Assertions.assertNull;
 
 public class DefaultDataRowStoreFactoryIT {
 
     @RegisterExtension
     static final CayenneTestsEnv env = 
CayenneTestsEnv.forProject(CayenneProjects.MULTI_TIER_PROJECT);
 
-
     @Test
-    public void getDataRowStore() {
+    public void createDataRowStore() {
         CayenneRuntime runtime = env.runtime();
-        DataRowStore dataStore = 
runtime.getInjector().getInstance(DataRowStoreFactory.class)
-                .createDataRowStore("test");
-
-        assertNotNull(dataStore);
-    }
-
-    @Test
-    public void getDataRowStoreWithParameters() {
-        final DataDomain DOMAIN = new DataDomain("test");
-        final EventManager EVENT_MANAGER = new DefaultEventManager();
-        final int CACHE_SIZE = 500;
-
-        Module testModule = binder -> {
-            binder.bind(DataDomain.class).toInstance(DOMAIN);
-            binder.bind(EventManager.class).toInstance(EVENT_MANAGER);
-            
binder.bind(TransactionManager.class).to(DefaultTransactionManager.class);
-            
binder.bind(TransactionFactory.class).to(DefaultTransactionFactory.class);
-            binder.bind(SQLLogger.class).to(Slf4jSQLLogger.class);
-            
binder.bind(RuntimeProperties.class).to(DefaultRuntimeProperties.class);
-            
binder.bind(EventBridge.class).toProvider(NoopEventBridgeProvider.class);
-            
binder.bind(DataRowStoreFactory.class).to(DefaultDataRowStoreFactory.class);
-            CoreModule.extend(binder).snapshotCacheSize(CACHE_SIZE);
-        };
-
-        Injector injector = DIBootstrap.createInjector(testModule);
-        DataRowStore dataStore = 
injector.getInstance(DataRowStoreFactory.class)
+        DataRowStore dataStore = runtime
+                .getInjector()
+                .getInstance(DataRowStoreFactory.class)
                 .createDataRowStore("test");
 
         assertNotNull(dataStore);
-        assertEquals(dataStore.maximumSize(), CACHE_SIZE);
-        assertNull(dataStore.getEventBridge());
     }
-
-    @Test
-    public void getDataRowStoreWithBridge() {
-        final DataDomain DOMAIN = new DataDomain("test");
-        final EventManager EVENT_MANAGER = new DefaultEventManager();
-
-        Module testModule = binder -> {
-            binder.bind(DataDomain.class).toInstance(DOMAIN);
-            binder.bind(EventManager.class).toInstance(EVENT_MANAGER);
-            
binder.bind(TransactionManager.class).to(DefaultTransactionManager.class);
-            
binder.bind(TransactionFactory.class).to(DefaultTransactionFactory.class);
-            binder.bind(SQLLogger.class).to(Slf4jSQLLogger.class);
-            
binder.bind(RuntimeProperties.class).to(DefaultRuntimeProperties.class);
-            
binder.bind(EventBridge.class).toProvider(MockEventBridgeProvider.class);
-            
binder.bind(DataRowStoreFactory.class).to(DefaultDataRowStoreFactory.class);
-            
binder.bind(DataDomainFlushActionFactory.class).to(DefaultDataDomainFlushActionFactory.class);
-            binder.bind(DbRowOpSorter.class).to(DefaultDbRowOpSorter.class);
-            
binder.bind(DeleteDbRowOpFactory.class).to(HardDeleteDbRowOpFactory.class);
-            
binder.bind(AdhocObjectFactory.class).to(DefaultAdhocObjectFactory.class);
-            
binder.bind(ClassLoaderManager.class).to(DefaultClassLoaderManager.class);
-            new TestExtender(binder).initAllExtensions();
-        };
-
-        Injector injector = DIBootstrap.createInjector(testModule);
-        DataRowStore dataStore = 
injector.getInstance(DataRowStoreFactory.class)
-                .createDataRowStore("test");
-
-        assertEquals(dataStore.getEventBridge().getClass(), 
MockEventBridge.class);
-    }
-
-    static class TestExtender extends CoreModuleExtender {
-        public TestExtender(Binder binder) {
-            super(binder);
-        }
-
-        @Override
-        protected CoreModuleExtender initAllExtensions() {
-            return super.initAllExtensions();
-        }
-    }
-
 }
diff --git 
a/cayenne/src/test/java/org/apache/cayenne/access/DefaultDataRowStoreFactory_CacheSizeIT.java
 
b/cayenne/src/test/java/org/apache/cayenne/access/DefaultDataRowStoreFactory_CacheSizeIT.java
new file mode 100644
index 000000000..0c2d57821
--- /dev/null
+++ 
b/cayenne/src/test/java/org/apache/cayenne/access/DefaultDataRowStoreFactory_CacheSizeIT.java
@@ -0,0 +1,48 @@
+/*****************************************************************
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    https://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ ****************************************************************/
+
+package org.apache.cayenne.access;
+
+import org.apache.cayenne.configuration.runtime.CoreModule;
+import org.apache.cayenne.unit.CayenneProjects;
+import org.apache.cayenne.unit.CayenneTestsEnv;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+public class DefaultDataRowStoreFactory_CacheSizeIT {
+
+    static int CACHE_SIZE = 500;
+
+    @RegisterExtension
+    static final CayenneTestsEnv env = 
CayenneTestsEnv.forProject(CayenneProjects.MULTI_TIER_PROJECT)
+            .withExtraModules(b -> 
CoreModule.extend(b).snapshotCacheSize(CACHE_SIZE));
+
+    @Test
+    public void createDataRowStore() {
+        DataRowStore dataStore = env.runtime().getInjector()
+                .getInstance(DataRowStoreFactory.class)
+                .createDataRowStore("test");
+
+        assertNotNull(dataStore);
+        assertEquals(dataStore.maximumSize(), CACHE_SIZE);
+        assertNull(dataStore.getEventBridge());
+    }
+}
diff --git 
a/cayenne/src/test/java/org/apache/cayenne/access/DefaultDataRowStoreFactory_EventBridgeIT.java
 
b/cayenne/src/test/java/org/apache/cayenne/access/DefaultDataRowStoreFactory_EventBridgeIT.java
new file mode 100644
index 000000000..f627c69c5
--- /dev/null
+++ 
b/cayenne/src/test/java/org/apache/cayenne/access/DefaultDataRowStoreFactory_EventBridgeIT.java
@@ -0,0 +1,46 @@
+/*****************************************************************
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    https://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ ****************************************************************/
+
+package org.apache.cayenne.access;
+
+import org.apache.cayenne.event.EventBridge;
+import org.apache.cayenne.event.MockEventBridge;
+import org.apache.cayenne.event.MockEventBridgeProvider;
+import org.apache.cayenne.unit.CayenneProjects;
+import org.apache.cayenne.unit.CayenneTestsEnv;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+public class DefaultDataRowStoreFactory_EventBridgeIT {
+
+    @RegisterExtension
+    static final CayenneTestsEnv env = 
CayenneTestsEnv.forProject(CayenneProjects.MULTI_TIER_PROJECT)
+            .withExtraModules(b -> 
b.bind(EventBridge.class).toProvider(MockEventBridgeProvider.class));
+
+    @Test
+    public void createDataRowStore() {
+        DataRowStore dataStore = env.runtime().getInjector()
+                .getInstance(DataRowStoreFactory.class)
+                .createDataRowStore("test");
+
+        assertEquals(MockEventBridge.class, 
dataStore.getEventBridge().getClass());
+    }
+}
diff --git 
a/cayenne/src/test/java/org/apache/cayenne/configuration/runtime/DataContextFactoryTest.java
 
b/cayenne/src/test/java/org/apache/cayenne/configuration/runtime/DataContextFactoryTest.java
deleted file mode 100644
index 82e38b2b2..000000000
--- 
a/cayenne/src/test/java/org/apache/cayenne/configuration/runtime/DataContextFactoryTest.java
+++ /dev/null
@@ -1,155 +0,0 @@
-/*****************************************************************
- *   Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    https://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- ****************************************************************/
-package org.apache.cayenne.configuration.runtime;
-
-import org.apache.cayenne.access.DataContext;
-import org.apache.cayenne.access.DataDomain;
-import org.apache.cayenne.access.DataRowStoreFactory;
-import org.apache.cayenne.access.DefaultDataRowStoreFactory;
-import org.apache.cayenne.access.DefaultObjectMapRetainStrategy;
-import org.apache.cayenne.access.ObjectMapRetainStrategy;
-import org.apache.cayenne.access.flush.DataDomainFlushActionFactory;
-import org.apache.cayenne.access.flush.operation.DbRowOpSorter;
-import org.apache.cayenne.access.flush.DefaultDataDomainFlushActionFactory;
-import org.apache.cayenne.access.flush.operation.DefaultDbRowOpSorter;
-import org.apache.cayenne.access.flush.operation.HardDeleteDbRowOpFactory;
-import org.apache.cayenne.access.flush.operation.DeleteDbRowOpFactory;
-import org.apache.cayenne.ashwood.AshwoodEntitySorter;
-import org.apache.cayenne.cache.MapQueryCache;
-import org.apache.cayenne.cache.QueryCache;
-import org.apache.cayenne.configuration.DefaultObjectStoreFactory;
-import org.apache.cayenne.configuration.DefaultRuntimeProperties;
-import org.apache.cayenne.configuration.ObjectStoreFactory;
-import org.apache.cayenne.configuration.RuntimeProperties;
-import org.apache.cayenne.di.AdhocObjectFactory;
-import org.apache.cayenne.di.ClassLoaderManager;
-import org.apache.cayenne.di.DIBootstrap;
-import org.apache.cayenne.di.Injector;
-import org.apache.cayenne.di.Module;
-import org.apache.cayenne.di.spi.DefaultAdhocObjectFactory;
-import org.apache.cayenne.di.spi.DefaultClassLoaderManager;
-import org.apache.cayenne.event.EventBridge;
-import org.apache.cayenne.event.EventManager;
-import org.apache.cayenne.event.MockEventManager;
-import org.apache.cayenne.event.NoopEventBridgeProvider;
-import org.apache.cayenne.log.SQLLogger;
-import org.apache.cayenne.log.Slf4jSQLLogger;
-import org.apache.cayenne.map.EntitySorter;
-import org.apache.cayenne.tx.DefaultTransactionFactory;
-import org.apache.cayenne.tx.DefaultTransactionManager;
-import org.apache.cayenne.tx.TransactionFactory;
-import org.apache.cayenne.tx.TransactionManager;
-import org.junit.jupiter.api.Test;
-
-import java.util.Collections;
-
-import static org.junit.jupiter.api.Assertions.*;
-
-public class DataContextFactoryTest {
-
-    @Test
-    public void createDataContextWithDedicatedCache() throws Exception {
-
-        final EventManager eventManager = new MockEventManager();
-        final DataDomain domain = new DataDomain("d1");
-
-        domain.setSharedCacheEnabled(false);
-
-        Module testModule = binder -> {
-            binder.bind(SQLLogger.class).to(Slf4jSQLLogger.class);
-            binder.bind(DataDomain.class).toInstance(domain);
-            binder.bind(EventManager.class).toInstance(eventManager);
-            binder.bind(QueryCache.class).toInstance(new MapQueryCache(5));
-            binder.bind(RuntimeProperties.class).toInstance(
-                    new DefaultRuntimeProperties(Collections.<String, 
String>emptyMap()));
-            binder.bind(ObjectMapRetainStrategy.class).to(
-                    DefaultObjectMapRetainStrategy.class);
-            
binder.bind(ObjectStoreFactory.class).to(DefaultObjectStoreFactory.class);
-            
binder.bind(TransactionFactory.class).to(DefaultTransactionFactory.class);
-            
binder.bind(TransactionManager.class).to(DefaultTransactionManager.class);
-            
binder.bind(DataRowStoreFactory.class).to(DefaultDataRowStoreFactory.class);
-            
binder.bind(EventBridge.class).toProvider(NoopEventBridgeProvider.class);
-            
binder.bind(DataRowStoreFactory.class).to(DefaultDataRowStoreFactory.class);
-            
binder.bind(DataDomainFlushActionFactory.class).to(DefaultDataDomainFlushActionFactory.class);
-            binder.bind(DbRowOpSorter.class).to(DefaultDbRowOpSorter.class);
-            
binder.bind(DeleteDbRowOpFactory.class).to(HardDeleteDbRowOpFactory.class);
-            binder.bind(EntitySorter.class).to(AshwoodEntitySorter.class);
-            
binder.bind(AdhocObjectFactory.class).to(DefaultAdhocObjectFactory.class);
-            
binder.bind(ClassLoaderManager.class).to(DefaultClassLoaderManager.class);
-        };
-
-        Injector injector = DIBootstrap.createInjector(testModule);
-
-        DataContextFactory factory = new DataContextFactory();
-        injector.injectMembers(factory);
-
-        DataContext c3 = (DataContext) factory.createContext();
-        assertNotNull(c3.getObjectStore().getDataRowCache());
-        assertNull(domain.getSharedSnapshotCache());
-        assertNotSame(
-                c3.getObjectStore().getDataRowCache(),
-                domain.getSharedSnapshotCache());
-    }
-
-    @Test
-    public void createDataContextValidation() throws Exception {
-        final EventManager eventManager = new MockEventManager();
-        final DataDomain domain = new DataDomain("d1");
-
-        domain.setValidatingObjectsOnCommit(true);
-
-        Module testModule = binder -> {
-            binder.bind(SQLLogger.class).to(Slf4jSQLLogger.class);
-            binder.bind(DataDomain.class).toInstance(domain);
-            binder.bind(EventManager.class).toInstance(eventManager);
-            binder.bind(QueryCache.class).toInstance(new MapQueryCache(5));
-            binder.bind(RuntimeProperties.class).toInstance(
-                    new DefaultRuntimeProperties(Collections.<String, 
String>emptyMap()));
-            binder.bind(ObjectMapRetainStrategy.class).to(
-                    DefaultObjectMapRetainStrategy.class);
-            
binder.bind(ObjectStoreFactory.class).to(DefaultObjectStoreFactory.class);
-            
binder.bind(TransactionFactory.class).to(DefaultTransactionFactory.class);
-            
binder.bind(TransactionManager.class).to(DefaultTransactionManager.class);
-            
binder.bind(EventBridge.class).toProvider(NoopEventBridgeProvider.class);
-            
binder.bind(DataRowStoreFactory.class).to(DefaultDataRowStoreFactory.class);
-            
binder.bind(DataDomainFlushActionFactory.class).to(DefaultDataDomainFlushActionFactory.class);
-            binder.bind(DbRowOpSorter.class).to(DefaultDbRowOpSorter.class);
-            
binder.bind(DeleteDbRowOpFactory.class).to(HardDeleteDbRowOpFactory.class);
-            binder.bind(EntitySorter.class).to(AshwoodEntitySorter.class);
-            
binder.bind(AdhocObjectFactory.class).to(DefaultAdhocObjectFactory.class);
-            
binder.bind(ClassLoaderManager.class).to(DefaultClassLoaderManager.class);
-        };
-
-        Injector injector = DIBootstrap.createInjector(testModule);
-
-        
domain.setDataRowStoreFactory(injector.getInstance(DataRowStoreFactory.class));
-
-        DataContextFactory factory = new DataContextFactory();
-        injector.injectMembers(factory);
-
-        DataContext c1 = (DataContext) factory.createContext();
-        assertTrue(c1.isValidatingObjectsOnCommit());
-
-        domain.setValidatingObjectsOnCommit(false);
-
-        DataContext c2 = (DataContext) factory.createContext();
-        assertFalse(c2.isValidatingObjectsOnCommit());
-    }
-
-}
diff --git 
a/cayenne/src/test/java/org/apache/cayenne/configuration/runtime/DataContextFactory_DedicatedCacheIT.java
 
b/cayenne/src/test/java/org/apache/cayenne/configuration/runtime/DataContextFactory_DedicatedCacheIT.java
new file mode 100644
index 000000000..2be76e9d9
--- /dev/null
+++ 
b/cayenne/src/test/java/org/apache/cayenne/configuration/runtime/DataContextFactory_DedicatedCacheIT.java
@@ -0,0 +1,52 @@
+/*****************************************************************
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    https://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ ****************************************************************/
+package org.apache.cayenne.configuration.runtime;
+
+import org.apache.cayenne.access.DataContext;
+import org.apache.cayenne.access.DataDomain;
+import org.apache.cayenne.configuration.ObjectContextFactory;
+import org.apache.cayenne.unit.CayenneProjects;
+import org.apache.cayenne.unit.CayenneTestsEnv;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+public class DataContextFactory_DedicatedCacheIT {
+
+    @RegisterExtension
+    static final CayenneTestsEnv env = 
CayenneTestsEnv.forProject(CayenneProjects.MULTI_TIER_PROJECT);
+
+    @Test
+    public void createDataContextWithDedicatedCache() {
+
+        DataDomain domain = env.runtime().getDataDomain();
+        domain.setSharedSnapshotCache(null);
+
+        DataContext c3 = (DataContext) env.runtime().getInjector()
+                .getInstance(ObjectContextFactory.class)
+                .createContext();
+
+        assertNotNull(c3.getObjectStore().getDataRowCache());
+        assertNull(domain.getSharedSnapshotCache());
+        assertNotSame(
+                c3.getObjectStore().getDataRowCache(),
+                domain.getSharedSnapshotCache());
+    }
+}
diff --git 
a/cayenne/src/test/java/org/apache/cayenne/configuration/runtime/DataContextFactory_ValidationIT.java
 
b/cayenne/src/test/java/org/apache/cayenne/configuration/runtime/DataContextFactory_ValidationIT.java
new file mode 100644
index 000000000..66a735141
--- /dev/null
+++ 
b/cayenne/src/test/java/org/apache/cayenne/configuration/runtime/DataContextFactory_ValidationIT.java
@@ -0,0 +1,52 @@
+/*****************************************************************
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    https://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ ****************************************************************/
+package org.apache.cayenne.configuration.runtime;
+
+import org.apache.cayenne.access.DataContext;
+import org.apache.cayenne.access.DataDomain;
+import org.apache.cayenne.configuration.ObjectContextFactory;
+import org.apache.cayenne.unit.CayenneProjects;
+import org.apache.cayenne.unit.CayenneTestsEnv;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+public class DataContextFactory_ValidationIT {
+
+    @RegisterExtension
+    static final CayenneTestsEnv env = 
CayenneTestsEnv.forProject(CayenneProjects.MULTI_TIER_PROJECT);
+
+    @Test
+    public void createDataContextValidation() {
+        DataDomain domain = env.runtime().getDataDomain();
+        domain.setValidatingObjectsOnCommit(true);
+
+        ObjectContextFactory factory = 
env.runtime().getInjector().getInstance(ObjectContextFactory.class);
+        DataContext c1 = (DataContext) factory.createContext();
+        assertTrue(c1.isValidatingObjectsOnCommit());
+
+        domain.setValidatingObjectsOnCommit(false);
+
+        DataContext c2 = (DataContext) factory.createContext();
+        assertFalse(c2.isValidatingObjectsOnCommit());
+    }
+
+}
diff --git 
a/cayenne/src/test/java/org/apache/cayenne/configuration/runtime/DataDomainProviderIT.java
 
b/cayenne/src/test/java/org/apache/cayenne/configuration/runtime/DataDomainProviderIT.java
new file mode 100644
index 000000000..08889e730
--- /dev/null
+++ 
b/cayenne/src/test/java/org/apache/cayenne/configuration/runtime/DataDomainProviderIT.java
@@ -0,0 +1,187 @@
+/*****************************************************************
+ *   Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    https://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ ****************************************************************/
+package org.apache.cayenne.configuration.runtime;
+
+import org.apache.cayenne.DataChannelQueryFilter;
+import org.apache.cayenne.DataChannelQueryFilterChain;
+import org.apache.cayenne.DataChannelSyncFilter;
+import org.apache.cayenne.DataChannelSyncFilterChain;
+import org.apache.cayenne.ObjectContext;
+import org.apache.cayenne.QueryResponse;
+import org.apache.cayenne.access.DataDomain;
+import org.apache.cayenne.access.DataNode;
+import org.apache.cayenne.access.dbsync.SkipSchemaUpdateStrategy;
+import org.apache.cayenne.access.dbsync.ThrowOnPartialOrCreateSchemaStrategy;
+import org.apache.cayenne.annotation.PostLoad;
+import org.apache.cayenne.event.EventManager;
+import org.apache.cayenne.graph.GraphDiff;
+import org.apache.cayenne.map.DataMap;
+import org.apache.cayenne.map.LifecycleEvent;
+import org.apache.cayenne.query.Query;
+import org.apache.cayenne.testdo.db1.CrossdbM1E1;
+import org.apache.cayenne.unit.CayenneProjects;
+import org.apache.cayenne.unit.CayenneTestsEnv;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertSame;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * Tests a fully DI-initialized {@link DataDomain} produced by {@link 
DataDomainProvider} off a two-node project.
+ */
+public class DataDomainProviderIT {
+
+    static final TestListener LISTENER = new TestListener();
+    static final NoopQueryFilter QUERY_FILTER = new NoopQueryFilter();
+    static final NoopSyncFilter SYNC_FILTER = new NoopSyncFilter();
+
+    @RegisterExtension
+    static final CayenneTestsEnv env = 
CayenneTestsEnv.forProject(CayenneProjects.DOMAIN_PROVIDER_PROJECT)
+            .withExtraModules(b -> CoreModule.extend(b)
+                    .addListener(LISTENER)
+                    .addQueryFilter(QUERY_FILTER)
+                    .addSyncFilter(SYNC_FILTER));
+
+    @Test
+    public void dataMaps() {
+        DataDomain domain = env.runtime().getDataDomain();
+
+        assertEquals("domain-provider", domain.getName());
+        assertEquals(2, domain.getDataMaps().size());
+        assertNotNull(domain.getDataMap("map-db1"));
+        assertNotNull(domain.getDataMap("map-db2"));
+    }
+
+    @Test
+    public void eventManagerFromDI() {
+        DataDomain domain = env.runtime().getDataDomain();
+
+        
assertSame(env.runtime().getInjector().getInstance(EventManager.class), 
domain.getEventManager());
+    }
+
+    @Test
+    public void dataNodes() {
+        DataDomain domain = env.runtime().getDataDomain();
+        assertEquals(2, domain.getDataNodes().size());
+
+        DataMap map1 = domain.getDataMap("map-db1");
+        DataNode node1 = domain.getDataNode("node1");
+        assertNotNull(node1);
+        assertEquals(1, node1.getDataMaps().size());
+        assertSame(map1, node1.getDataMaps().iterator().next());
+        assertSame(node1, domain.lookupDataNode(map1));
+
+        DataMap map2 = domain.getDataMap("map-db2");
+        DataNode node2 = domain.getDataNode("node2");
+        assertNotNull(node2);
+        assertEquals(1, node2.getDataMaps().size());
+        assertSame(map2, node2.getDataMaps().iterator().next());
+        assertSame(node2, domain.lookupDataNode(map2));
+    }
+
+    @Test
+    public void dataNodeConfig() {
+        DataDomain domain = env.runtime().getDataDomain();
+
+        for (DataNode node : domain.getDataNodes()) {
+            assertEquals(XMLPoolingDataSourceFactory.class.getName(), 
node.getDataSourceFactory());
+            assertNotNull(node.getDataSource());
+            assertNotNull(node.getAdapter());
+        }
+
+        // "node1" declares an explicit strategy, "node2" gets the default
+        assertEquals(
+                ThrowOnPartialOrCreateSchemaStrategy.class,
+                
domain.getDataNode("node1").getSchemaUpdateStrategy().getClass());
+        assertEquals(
+                SkipSchemaUpdateStrategy.class,
+                
domain.getDataNode("node2").getSchemaUpdateStrategy().getClass());
+    }
+
+    @Test
+    public void noDefaultNodeWithMultipleNodes() {
+        // a default node is only inferred when the project declares exactly 
one node
+        assertNull(env.runtime().getDataDomain().getDefaultNode());
+    }
+
+    @Test
+    public void domainProperties() {
+        DataDomain domain = env.runtime().getDataDomain();
+
+        // "validatingObjectsOnCommit" is turned off by a <property> in the 
project file, shared cache is left at its
+        // default
+        assertFalse(domain.isValidatingObjectsOnCommit());
+        assertTrue(domain.isSharedCacheEnabled());
+        assertNotNull(domain.getSharedSnapshotCache());
+    }
+
+    @Test
+    public void listenersFromDI() {
+        DataDomain domain = env.runtime().getDataDomain();
+
+        int before = LISTENER.counter.get();
+        domain.getEntityResolver().getCallbackRegistry()
+                .performCallbacks(LifecycleEvent.POST_LOAD, 
env.context().newObject(CrossdbM1E1.class));
+
+        assertEquals(before + 1, LISTENER.counter.get(), "Should call 
postLoadCallback()");
+    }
+
+    @Test
+    public void filtersFromDI() {
+        DataDomain domain = env.runtime().getDataDomain();
+
+        assertTrue(domain.getQueryFilters().contains(QUERY_FILTER));
+        assertTrue(domain.getSyncFilters().contains(SYNC_FILTER));
+    }
+
+    static class TestListener {
+
+        final AtomicInteger counter = new AtomicInteger();
+
+        @PostLoad
+        public void postLoadCallback(Object object) {
+            counter.incrementAndGet();
+        }
+    }
+
+    static class NoopQueryFilter implements DataChannelQueryFilter {
+
+        @Override
+        public QueryResponse onQuery(ObjectContext originatingContext, Query 
query,
+                                     DataChannelQueryFilterChain filterChain) {
+            return filterChain.onQuery(originatingContext, query);
+        }
+    }
+
+    static class NoopSyncFilter implements DataChannelSyncFilter {
+
+        @Override
+        public GraphDiff onSync(ObjectContext originatingContext, GraphDiff 
changes, int syncType,
+                                DataChannelSyncFilterChain filterChain) {
+            return filterChain.onSync(originatingContext, changes, syncType);
+        }
+    }
+}
diff --git 
a/cayenne/src/test/java/org/apache/cayenne/configuration/runtime/DataDomainProviderTest.java
 
b/cayenne/src/test/java/org/apache/cayenne/configuration/runtime/DataDomainProviderTest.java
deleted file mode 100644
index 2d74d35d8..000000000
--- 
a/cayenne/src/test/java/org/apache/cayenne/configuration/runtime/DataDomainProviderTest.java
+++ /dev/null
@@ -1,310 +0,0 @@
-/*****************************************************************
- *   Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    https://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- ****************************************************************/
-package org.apache.cayenne.configuration.runtime;
-
-import org.apache.cayenne.ConfigurationException;
-import org.apache.cayenne.DataChannel;
-import org.apache.cayenne.ObjectId;
-import org.apache.cayenne.Persistent;
-import org.apache.cayenne.access.DataDomain;
-import org.apache.cayenne.access.DataNode;
-import org.apache.cayenne.access.DataRowStoreFactory;
-import org.apache.cayenne.access.DefaultDataRowStoreFactory;
-import org.apache.cayenne.access.dbsync.DefaultSchemaUpdateStrategyFactory;
-import org.apache.cayenne.access.dbsync.SchemaUpdateStrategyFactory;
-import org.apache.cayenne.access.dbsync.SkipSchemaUpdateStrategy;
-import org.apache.cayenne.access.dbsync.ThrowOnPartialOrCreateSchemaStrategy;
-import org.apache.cayenne.access.translator.SQLTemplateTranslator;
-import org.apache.cayenne.access.jdbc.reader.RowReaderFactory;
-import org.apache.cayenne.access.translator.BatchTranslator;
-import org.apache.cayenne.access.translator.batch.DeleteBatchTranslator;
-import org.apache.cayenne.access.translator.batch.InsertBatchTranslator;
-import org.apache.cayenne.access.translator.batch.UpdateBatchTranslator;
-import 
org.apache.cayenne.access.translator.procedure.DbAdapterDelegatedProcedureTranslator;
-import org.apache.cayenne.access.translator.ProcedureTranslator;
-import 
org.apache.cayenne.access.translator.ejbql.DbAdapterDelegatedEJBQLTranslator;
-import org.apache.cayenne.access.translator.EJBQLTranslator;
-import 
org.apache.cayenne.access.translator.select.DbAdapterDelegatedSelectTranslator;
-import org.apache.cayenne.access.translator.SelectTranslator;
-import org.apache.cayenne.access.types.DefaultValueObjectTypeRegistry;
-import org.apache.cayenne.access.types.ValueObjectTypeRegistry;
-import org.apache.cayenne.annotation.PostLoad;
-import org.apache.cayenne.ashwood.AshwoodEntitySorter;
-import org.apache.cayenne.cache.QueryCache;
-import org.apache.cayenne.configuration.ConfigurationNameMapper;
-import org.apache.cayenne.configuration.ConfigurationTree;
-import org.apache.cayenne.configuration.Constants;
-import org.apache.cayenne.configuration.DataChannelDescriptor;
-import org.apache.cayenne.configuration.DataChannelDescriptorLoader;
-import org.apache.cayenne.configuration.DataChannelDescriptorMerger;
-import org.apache.cayenne.configuration.DataNodeDescriptor;
-import org.apache.cayenne.configuration.DefaultConfigurationNameMapper;
-import org.apache.cayenne.configuration.DefaultDataChannelDescriptorMerger;
-import org.apache.cayenne.configuration.DefaultRuntimeProperties;
-import org.apache.cayenne.configuration.RuntimeProperties;
-import org.apache.cayenne.configuration.mock.MockDataSourceFactory;
-import org.apache.cayenne.dba.JdbcPkGenerator;
-import org.apache.cayenne.dba.PkGenerator;
-import org.apache.cayenne.dba.db2.DB2Adapter;
-import org.apache.cayenne.dba.db2.DB2PkGenerator;
-import org.apache.cayenne.dba.db2.DB2Sniffer;
-import org.apache.cayenne.dba.derby.DerbyAdapter;
-import org.apache.cayenne.dba.derby.DerbyPkGenerator;
-import org.apache.cayenne.dba.derby.DerbySniffer;
-import org.apache.cayenne.dba.firebird.FirebirdSniffer;
-import org.apache.cayenne.dba.frontbase.FrontBaseAdapter;
-import org.apache.cayenne.dba.frontbase.FrontBasePkGenerator;
-import org.apache.cayenne.dba.frontbase.FrontBaseSniffer;
-import org.apache.cayenne.dba.h2.H2Adapter;
-import org.apache.cayenne.dba.h2.H2PkGenerator;
-import org.apache.cayenne.dba.h2.H2Sniffer;
-import org.apache.cayenne.dba.hsqldb.HSQLDBSniffer;
-import org.apache.cayenne.dba.ingres.IngresAdapter;
-import org.apache.cayenne.dba.ingres.IngresPkGenerator;
-import org.apache.cayenne.dba.ingres.IngresSniffer;
-import org.apache.cayenne.dba.mariadb.MariaDBSniffer;
-import org.apache.cayenne.dba.mysql.MySQLAdapter;
-import org.apache.cayenne.dba.mysql.MySQLPkGenerator;
-import org.apache.cayenne.dba.mysql.MySQLSniffer;
-import org.apache.cayenne.dba.oracle.OracleAdapter;
-import org.apache.cayenne.dba.oracle.OraclePkGenerator;
-import org.apache.cayenne.dba.oracle.OracleSniffer;
-import org.apache.cayenne.dba.postgres.PostgresAdapter;
-import org.apache.cayenne.dba.postgres.PostgresPkGenerator;
-import org.apache.cayenne.dba.postgres.PostgresSniffer;
-import org.apache.cayenne.dba.sqlite.SQLiteSniffer;
-import org.apache.cayenne.dba.sqlserver.SQLServerAdapter;
-import org.apache.cayenne.dba.sqlserver.SQLServerSniffer;
-import org.apache.cayenne.dba.sybase.SybaseAdapter;
-import org.apache.cayenne.dba.sybase.SybasePkGenerator;
-import org.apache.cayenne.dba.sybase.SybaseSniffer;
-import org.apache.cayenne.di.AdhocObjectFactory;
-import org.apache.cayenne.di.ClassLoaderManager;
-import org.apache.cayenne.di.DIBootstrap;
-import org.apache.cayenne.di.Injector;
-import org.apache.cayenne.di.Key;
-import org.apache.cayenne.di.Module;
-import org.apache.cayenne.di.spi.DefaultAdhocObjectFactory;
-import org.apache.cayenne.di.spi.DefaultClassLoaderManager;
-import org.apache.cayenne.event.EventBridge;
-import org.apache.cayenne.event.EventManager;
-import org.apache.cayenne.event.MockEventManager;
-import org.apache.cayenne.event.NoopEventBridgeProvider;
-import org.apache.cayenne.log.SQLLogger;
-import org.apache.cayenne.log.Slf4jSQLLogger;
-import org.apache.cayenne.map.DataMap;
-import org.apache.cayenne.map.EntitySorter;
-import org.apache.cayenne.map.LifecycleEvent;
-import 
org.apache.cayenne.reflect.generic.DefaultValueComparisonStrategyFactory;
-import org.apache.cayenne.reflect.generic.ValueComparisonStrategyFactory;
-import org.apache.cayenne.resource.ClassLoaderResourceLocator;
-import org.apache.cayenne.resource.Resource;
-import org.apache.cayenne.resource.ResourceLocator;
-import org.apache.cayenne.resource.mock.MockResource;
-import org.junit.jupiter.api.Test;
-
-import java.util.Collection;
-import java.util.Collections;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import static org.junit.jupiter.api.Assertions.*;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-public class DataDomainProviderTest {
-
-    @Test
-    public void get() {
-
-        // create dependencies
-        final String testConfigName = "testConfig";
-        final DataChannelDescriptor testDescriptor = new 
DataChannelDescriptor();
-
-        DataMap map1 = new DataMap("map1");
-        testDescriptor.getDataMaps().add(map1);
-
-        DataMap map2 = new DataMap("map2");
-        testDescriptor.getDataMaps().add(map2);
-
-        DataNodeDescriptor nodeDescriptor1 = new DataNodeDescriptor();
-        nodeDescriptor1.setName("node1");
-        nodeDescriptor1.getDataMapNames().add("map1");
-        nodeDescriptor1.setAdapterType(OracleAdapter.class.getName());
-        
nodeDescriptor1.setDataSourceFactoryType(MockDataSourceFactory.class.getName());
-        nodeDescriptor1.setParameters("jdbc/testDataNode1");
-        
nodeDescriptor1.setSchemaUpdateStrategyType(ThrowOnPartialOrCreateSchemaStrategy.class.getName());
-        testDescriptor.getNodeDescriptors().add(nodeDescriptor1);
-
-        DataNodeDescriptor nodeDescriptor2 = new DataNodeDescriptor();
-        nodeDescriptor2.setName("node2");
-        nodeDescriptor2.getDataMapNames().add("map2");
-        nodeDescriptor2.setParameters("testDataNode2.driver.xml");
-        testDescriptor.getNodeDescriptors().add(nodeDescriptor2);
-
-        final DataChannelDescriptorLoader testLoader = new 
DataChannelDescriptorLoader() {
-
-            @Override
-            public ConfigurationTree<DataChannelDescriptor> load(Resource 
configurationResource)
-                    throws ConfigurationException {
-                return new ConfigurationTree<>(testDescriptor, null);
-            }
-        };
-
-        final EventManager eventManager = new MockEventManager();
-        final TestListener mockListener = new TestListener();
-
-        Module testModule = b -> {
-
-            ClassLoaderManager classLoaderManager = new 
DefaultClassLoaderManager();
-            b.bind(ClassLoaderManager.class).toInstance(classLoaderManager);
-            
b.bind(AdhocObjectFactory.class).to(DefaultAdhocObjectFactory.class);
-            b.bind(PkGenerator.class).to(JdbcPkGenerator.class);
-            
b.bind(PkGeneratorFactoryProvider.class).to(PkGeneratorFactoryProvider.class);
-
-            CoreModule.extend(b)
-                    .initAllExtensions()
-
-                    .addAdapterDetector(FirebirdSniffer.class)
-                    
.addAdapterDetector(FrontBaseSniffer.class).addAdapterDetector(IngresSniffer.class)
-                    
.addAdapterDetector(SQLiteSniffer.class).addAdapterDetector(DB2Sniffer.class)
-                    
.addAdapterDetector(H2Sniffer.class).addAdapterDetector(HSQLDBSniffer.class)
-                    
.addAdapterDetector(SybaseSniffer.class).addAdapterDetector(DerbySniffer.class)
-                    
.addAdapterDetector(SQLServerSniffer.class).addAdapterDetector(OracleSniffer.class)
-                    
.addAdapterDetector(PostgresSniffer.class).addAdapterDetector(MySQLSniffer.class)
-                    .addAdapterDetector(MariaDBSniffer.class)
-
-                    .addListener(mockListener)
-                    .addProjectLocation(testConfigName)
-
-                    .addPkGenerator(DB2Adapter.class, DB2PkGenerator.class)
-                    .addPkGenerator(DerbyAdapter.class, DerbyPkGenerator.class)
-                    .addPkGenerator(FrontBaseAdapter.class, 
FrontBasePkGenerator.class)
-                    .addPkGenerator(H2Adapter.class, H2PkGenerator.class)
-                    .addPkGenerator(IngresAdapter.class, 
IngresPkGenerator.class)
-                    .addPkGenerator(MySQLAdapter.class, MySQLPkGenerator.class)
-                    .addPkGenerator(OracleAdapter.class, 
OraclePkGenerator.class)
-                    .addPkGenerator(PostgresAdapter.class, 
PostgresPkGenerator.class)
-                    .addPkGenerator(SQLServerAdapter.class, 
SybasePkGenerator.class)
-                    .addPkGenerator(SybaseAdapter.class, 
SybasePkGenerator.class);
-
-            b.bind(EventManager.class).toInstance(eventManager);
-            b.bind(EntitySorter.class).toInstance(new AshwoodEntitySorter());
-            
b.bind(SchemaUpdateStrategyFactory.class).to(DefaultSchemaUpdateStrategyFactory.class);
-
-            final ResourceLocator locator = new 
ClassLoaderResourceLocator(classLoaderManager) {
-
-                public Collection<Resource> findResources(String name) {
-                    assertEquals(testConfigName, name);
-                    return Collections.<Resource>singleton(new MockResource());
-                }
-            };
-
-            b.bind(ResourceLocator.class).toInstance(locator);
-            b.bind(Key.get(ResourceLocator.class, 
Constants.RESOURCE_LOCATOR)).toInstance(locator);
-            
b.bind(ConfigurationNameMapper.class).to(DefaultConfigurationNameMapper.class);
-            
b.bind(DataChannelDescriptorMerger.class).to(DefaultDataChannelDescriptorMerger.class);
-            b.bind(DataChannelDescriptorLoader.class).toInstance(testLoader);
-            b.bind(DbAdapterFactory.class).to(DefaultDbAdapterFactory.class);
-            b.bind(RuntimeProperties.class).to(DefaultRuntimeProperties.class);
-            b.bind(Key.get(BatchTranslator.class, 
BatchTranslator.INSERT)).to(InsertBatchTranslator.class);
-            b.bind(Key.get(BatchTranslator.class, 
BatchTranslator.UPDATE)).to(UpdateBatchTranslator.class);
-            b.bind(Key.get(BatchTranslator.class, 
BatchTranslator.DELETE)).to(DeleteBatchTranslator.class);
-            
b.bind(SelectTranslator.class).to(DbAdapterDelegatedSelectTranslator.class);
-            
b.bind(ProcedureTranslator.class).to(DbAdapterDelegatedProcedureTranslator.class);
-            
b.bind(EJBQLTranslator.class).to(DbAdapterDelegatedEJBQLTranslator.class);
-
-            b.bind(DataSourceFactory.class).toInstance(new 
MockDataSourceFactory());
-            b.bind(SQLLogger.class).to(Slf4jSQLLogger.class);
-            b.bind(QueryCache.class).toInstance(mock(QueryCache.class));
-            
b.bind(RowReaderFactory.class).toInstance(mock(RowReaderFactory.class));
-            b.bind(DataNodeFactory.class).to(DefaultDataNodeFactory.class);
-            
b.bind(SQLTemplateTranslator.class).toInstance(mock(SQLTemplateTranslator.class));
-
-            
b.bind(EventBridge.class).toProvider(NoopEventBridgeProvider.class);
-            
b.bind(DataRowStoreFactory.class).to(DefaultDataRowStoreFactory.class);
-
-            
b.bind(ValueObjectTypeRegistry.class).to(DefaultValueObjectTypeRegistry.class);
-            
b.bind(ValueComparisonStrategyFactory.class).to(DefaultValueComparisonStrategyFactory.class);
-        };
-
-        Injector injector = DIBootstrap.createInjector(testModule);
-
-        // create and initialize provide instance to test
-        DataDomainProvider provider = new DataDomainProvider();
-        injector.injectMembers(provider);
-
-        DataChannel channel = provider.get();
-        assertNotNull(channel);
-
-        assertTrue(channel instanceof DataDomain);
-
-        DataDomain domain = (DataDomain) channel;
-        assertSame(eventManager, domain.getEventManager());
-        assertEquals(2, domain.getDataMaps().size());
-        assertTrue(domain.getDataMaps().contains(map1));
-        assertTrue(domain.getDataMaps().contains(map2));
-
-        assertEquals(2, domain.getDataNodes().size());
-        DataNode node1 = domain.getDataNode("node1");
-        assertNotNull(node1);
-        assertEquals(1, node1.getDataMaps().size());
-        assertSame(map1, node1.getDataMaps().iterator().next());
-        assertSame(node1, domain.lookupDataNode(map1));
-        assertEquals(nodeDescriptor1.getDataSourceFactoryType(), 
node1.getDataSourceFactory());
-        assertNotNull(node1.getDataSource());
-
-        assertNotNull(node1.getSchemaUpdateStrategy());
-        assertEquals(nodeDescriptor1.getSchemaUpdateStrategyType(), 
node1.getSchemaUpdateStrategy().getClass()
-                .getName());
-
-        assertNotNull(node1.getAdapter());
-        assertEquals(OracleAdapter.class, node1.getAdapter().getClass());
-
-        DataNode node2 = domain.getDataNode("node2");
-        assertNotNull(node2);
-        assertEquals(1, node2.getDataMaps().size());
-        assertSame(map2, node2.getDataMaps().iterator().next());
-        assertSame(node2, domain.lookupDataNode(map2));
-        assertNull(node2.getDataSourceFactory());
-        assertNotNull(node2.getDataSource());
-        assertNotNull(node2.getSchemaUpdateStrategy());
-        assertEquals(SkipSchemaUpdateStrategy.class.getName(), 
node2.getSchemaUpdateStrategy().getClass().getName());
-
-        assertNotNull(node2.getAdapter());
-
-        // check that we have mock listener passed correctly
-        Persistent mockPersistent = mock(Persistent.class);
-        ObjectId mockObjectId = mock(ObjectId.class);
-        when(mockObjectId.getEntityName()).thenReturn("mock-entity-name");
-        when(mockPersistent.getObjectId()).thenReturn(mockObjectId);
-        
domain.getEntityResolver().getCallbackRegistry().performCallbacks(LifecycleEvent.POST_LOAD,
 mockPersistent);
-
-        assertEquals(1, TestListener.counter.get(), "Should call 
postLoadCallback() method");
-    }
-
-    static class TestListener {
-
-        static private AtomicInteger counter = new AtomicInteger();
-
-        @PostLoad
-        public void postLoadCallback(Object object) {
-            counter.incrementAndGet();
-        }
-    }
-}
diff --git 
a/cayenne/src/test/java/org/apache/cayenne/event/MockEventBridgeProvider.java 
b/cayenne/src/test/java/org/apache/cayenne/event/MockEventBridgeProvider.java
index ad9cc21c2..34ae3a895 100644
--- 
a/cayenne/src/test/java/org/apache/cayenne/event/MockEventBridgeProvider.java
+++ 
b/cayenne/src/test/java/org/apache/cayenne/event/MockEventBridgeProvider.java
@@ -19,21 +19,20 @@
 
 package org.apache.cayenne.event;
 
-import org.apache.cayenne.access.DataDomain;
 import org.apache.cayenne.di.DIRuntimeException;
-import org.apache.cayenne.di.Inject;
 import org.apache.cayenne.di.Provider;
 
 import java.util.Collections;
 
+/**
+ * Note that this provider can't depend on the DataDomain: the shared snapshot 
cache, and hence the EventBridge, is
+ * created while the DataDomain itself is being assembled.
+ */
 public class MockEventBridgeProvider implements Provider<EventBridge> {
 
-    @Inject
-    protected DataDomain dataDomain;
-
     @Override
     public EventBridge get() throws DIRuntimeException {
-        EventSubject snapshotEventSubject = 
EventSubject.getSubject(this.getClass(), dataDomain.getName());;
+        EventSubject snapshotEventSubject = 
EventSubject.getSubject(this.getClass(), "mock-snapshot-events");
 
         return new MockEventBridge(
                 Collections.singleton(snapshotEventSubject),
diff --git a/cayenne/src/test/java/org/apache/cayenne/unit/CayenneProjects.java 
b/cayenne/src/test/java/org/apache/cayenne/unit/CayenneProjects.java
index 1d6bc3c4e..b7648d003 100644
--- a/cayenne/src/test/java/org/apache/cayenne/unit/CayenneProjects.java
+++ b/cayenne/src/test/java/org/apache/cayenne/unit/CayenneProjects.java
@@ -26,6 +26,7 @@ public class CayenneProjects {
     public static final String CAY_2032 = "cayenne-cay-2032.xml";
     public static final String COMPOUND_PROJECT = "cayenne-compound.xml";
     public static final String DATE_TIME_PROJECT = "cayenne-date-time.xml";
+    public static final String DOMAIN_PROVIDER_PROJECT = 
"cayenne-domain-provider.xml";
     public static final String EMBEDDABLE_PROJECT = "cayenne-embeddable.xml";
     public static final String EMPTY_PROJECT = "cayenne-empty.xml";
     public static final String ENUM_PROJECT = "cayenne-enum.xml";
diff --git a/cayenne/src/test/resources/cayenne-domain-provider.xml 
b/cayenne/src/test/resources/cayenne-domain-provider.xml
new file mode 100644
index 000000000..ff9fb537b
--- /dev/null
+++ b/cayenne/src/test/resources/cayenne-domain-provider.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<domain xmlns="http://cayenne.apache.org/schema/12/domain";
+        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+        xsi:schemaLocation="http://cayenne.apache.org/schema/12/domain 
https://cayenne.apache.org/schema/12/domain.xsd";
+        project-version="12">
+       <property name="cayenne.DataDomain.validatingObjectsOnCommit" 
value="false"/>
+       <map name="map-db1"/>
+       <map name="map-db2"/>
+       <node name="node1"
+                
factory="org.apache.cayenne.configuration.runtime.XMLPoolingDataSourceFactory"
+                
schema-update-strategy="org.apache.cayenne.access.dbsync.ThrowOnPartialOrCreateSchemaStrategy">
+               <map-ref name="map-db1"/>
+       </node>
+       <node name="node2"
+                
factory="org.apache.cayenne.configuration.runtime.XMLPoolingDataSourceFactory">
+               <map-ref name="map-db2"/>
+       </node>
+</domain>
diff --git 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/datadomain/main/DataDomainMainView.java
 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/datadomain/main/DataDomainMainView.java
index 0e35fff37..488dd39a5 100644
--- 
a/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/datadomain/main/DataDomainMainView.java
+++ 
b/modeler/cayenne-modeler/src/main/java/org/apache/cayenne/modeler/ui/project/editor/datadomain/main/DataDomainMainView.java
@@ -22,21 +22,21 @@ package 
org.apache.cayenne.modeler.ui.project.editor.datadomain.main;
 import com.jgoodies.forms.builder.PanelBuilder;
 import com.jgoodies.forms.layout.CellConstraints;
 import com.jgoodies.forms.layout.FormLayout;
-import org.apache.cayenne.access.DataDomain;
 import org.apache.cayenne.configuration.DataChannelDescriptor;
+import org.apache.cayenne.configuration.runtime.DataDomainProvider;
 import org.apache.cayenne.modeler.event.display.DomainDisplayEvent;
 import org.apache.cayenne.modeler.event.display.DomainDisplayListener;
 import org.apache.cayenne.modeler.event.model.DomainEvent;
+import org.apache.cayenne.modeler.project.ProjectSession;
+import org.apache.cayenne.modeler.toolkit.ProjectPanel;
 import org.apache.cayenne.modeler.toolkit.checkbox.CMCheckBox;
 import org.apache.cayenne.modeler.toolkit.text.CMUndoableTextField;
-import org.apache.cayenne.modeler.toolkit.ProjectPanel;
-import org.apache.cayenne.modeler.project.ProjectSession;
-import java.util.Objects;
 import org.apache.cayenne.validation.ValidationException;
 
 import javax.swing.*;
 import java.awt.*;
 import java.util.Map;
+import java.util.Objects;
 
 /**
  * Panel for editing DataDomain.
@@ -96,17 +96,17 @@ public class DataDomainMainView extends ProjectPanel 
implements DomainDisplayLis
         objectValidation.addItemListener(e -> {
             String value = objectValidation.isSelected() ? "true" : "false";
             setDomainProperty(
-                    DataDomain.VALIDATING_OBJECTS_ON_COMMIT_PROPERTY,
+                    DataDomainProvider.VALIDATING_OBJECTS_ON_COMMIT_PROPERTY,
                     value,
-                    
Boolean.toString(DataDomain.VALIDATING_OBJECTS_ON_COMMIT_DEFAULT));
+                    DataDomainProvider.VALIDATING_OBJECTS_ON_COMMIT_DEFAULT);
         });
 
         sharedCache.addItemListener(e -> {
             String value = sharedCache.isSelected() ? "true" : "false";
             setDomainProperty(
-                    DataDomain.SHARED_CACHE_ENABLED_PROPERTY,
+                    DataDomainProvider.SHARED_CACHE_ENABLED_PROPERTY,
                     value,
-                    Boolean.toString(DataDomain.SHARED_CACHE_ENABLED_DEFAULT));
+                    DataDomainProvider.SHARED_CACHE_ENABLED_DEFAULT);
         });
 
     }
@@ -177,12 +177,12 @@ public class DataDomainMainView extends ProjectPanel 
implements DomainDisplayLis
         name.setText(domain.getName());
 
         objectValidation.setSelected(getDomainBooleanProperty(
-                DataDomain.VALIDATING_OBJECTS_ON_COMMIT_PROPERTY,
-                
Boolean.toString(DataDomain.VALIDATING_OBJECTS_ON_COMMIT_DEFAULT)));
+                DataDomainProvider.VALIDATING_OBJECTS_ON_COMMIT_PROPERTY,
+                DataDomainProvider.VALIDATING_OBJECTS_ON_COMMIT_DEFAULT));
 
         sharedCache.setSelected(getDomainBooleanProperty(
-                DataDomain.SHARED_CACHE_ENABLED_PROPERTY,
-                Boolean.toString(DataDomain.SHARED_CACHE_ENABLED_DEFAULT)));
+                DataDomainProvider.SHARED_CACHE_ENABLED_PROPERTY,
+                DataDomainProvider.SHARED_CACHE_ENABLED_DEFAULT));
     }
 
     void setDomainName(String newName) {


Reply via email to