CAY-1972 A property to override DataSources of multi-module projects

Project: http://git-wip-us.apache.org/repos/asf/cayenne/repo
Commit: http://git-wip-us.apache.org/repos/asf/cayenne/commit/15297cca
Tree: http://git-wip-us.apache.org/repos/asf/cayenne/tree/15297cca
Diff: http://git-wip-us.apache.org/repos/asf/cayenne/diff/15297cca

Branch: refs/heads/CAY-1946_1
Commit: 15297ccafa761bddb89eac98b35806d777cbbe74
Parents: 3c51a77
Author: aadamchik <aadamc...@apache.org>
Authored: Sat Nov 22 18:06:09 2014 +0300
Committer: aadamchik <aadamc...@apache.org>
Committed: Sat Nov 22 19:03:31 2014 +0300

----------------------------------------------------------------------
 .../apache/cayenne/configuration/Constants.java | 298 ++++++++++---------
 .../server/DataDomainProvider.java              | 241 ++++++++-------
 .../server/ServerRuntimeBuilder.java            |  52 +++-
 .../server/SyntheticNodeDataDomainProvider.java |  27 +-
 .../server/ServerRuntimeBuilderIT.java          | 109 +++++++
 .../server/ServerRuntimeBuilderTest.java        |  53 +++-
 .../ServerRuntimeBuilder_InAction_IT.java       |  88 ------
 docs/doc/src/main/resources/RELEASE-NOTES.txt   |   1 +
 docs/doc/src/main/resources/UPGRADE.txt         |   8 +
 9 files changed, 491 insertions(+), 386 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cayenne/blob/15297cca/cayenne-server/src/main/java/org/apache/cayenne/configuration/Constants.java
----------------------------------------------------------------------
diff --git 
a/cayenne-server/src/main/java/org/apache/cayenne/configuration/Constants.java 
b/cayenne-server/src/main/java/org/apache/cayenne/configuration/Constants.java
index 12953e6..1b0f887 100644
--- 
a/cayenne-server/src/main/java/org/apache/cayenne/configuration/Constants.java
+++ 
b/cayenne-server/src/main/java/org/apache/cayenne/configuration/Constants.java
@@ -26,151 +26,159 @@ package org.apache.cayenne.configuration;
  */
 public interface Constants {
 
-    // DI "collections"
+       // DI "collections"
+
+       /**
+        * A DI container key for the Map&lt;String, String&gt; storing 
properties
+        * used by built-in Cayenne service.
+        */
+       public static final String PROPERTIES_MAP = "cayenne.properties";
+
+       /**
+        * A DI container key for the List&lt;DbAdapterDetector&gt; that 
contains
+        * objects that can discover the type of current database and install 
the
+        * correct DbAdapter in runtime.
+        */
+       public static final String SERVER_ADAPTER_DETECTORS_LIST = 
"cayenne.server.adapter_detectors";
 
-    /**
-     * A DI container key for the Map&lt;String, String&gt; storing properties
-     * used by built-in Cayenne service.
-     */
-    public static final String PROPERTIES_MAP = "cayenne.properties";
-
-    /**
-     * A DI container key for the List&lt;DbAdapterDetector&gt; that contains
-     * objects that can discover the type of current database and install the
-     * correct DbAdapter in runtime.
-     */
-    public static final String SERVER_ADAPTER_DETECTORS_LIST = 
"cayenne.server.adapter_detectors";
-
-    /**
-     * A DI container key for the List&lt;DataChannelFilter&gt; storing
-     * DataDomain filters.
-     */
-    public static final String SERVER_DOMAIN_FILTERS_LIST = 
"cayenne.server.domain_filters";
-
-    /**
-     * A DI container key for the List&lt;String&gt; storing locations of the
-     * one of more project configuration files.
-     */
-    public static final String SERVER_PROJECT_LOCATIONS_LIST = 
"cayenne.server.project_locations";
-
-    /**
-     * A DI container key for the List&lt;ExtendedType&gt; storing default
-     * adapter-agnostic ExtendedTypes.
-     */
-    public static final String SERVER_DEFAULT_TYPES_LIST = 
"cayenne.server.default_types";
-
-    /**
-     * A DI container key for the List&lt;ExtendedType&gt; storing a
-     * user-provided ExtendedTypes.
-     */
-    public static final String SERVER_USER_TYPES_LIST = 
"cayenne.server.user_types";
-
-    /**
-     * A DI container key for the List&lt;ExtendedTypeFactory&gt; storing
-     * default and user-provided ExtendedTypeFactories.
-     */
-    public static final String SERVER_TYPE_FACTORIES_LIST = 
"cayenne.server.type_factories";
-
-    /**
-     * A server-side DI container key for the Map&lt;String, String&gt; storing
-     * event bridge properties passed to the ROP client on bootstrap.
-     */
-    public static final String SERVER_ROP_EVENT_BRIDGE_PROPERTIES_MAP = 
"cayenne.server.rop_event_bridge_properties";
-
-    // Runtime properties
-
-    public static final String JDBC_DRIVER_PROPERTY = "cayenne.jdbc.driver";
-
-    public static final String JDBC_URL_PROPERTY = "cayenne.jdbc.url";
-
-    public static final String JDBC_USERNAME_PROPERTY = 
"cayenne.jdbc.username";
-
-    public static final String JDBC_PASSWORD_PROPERTY = 
"cayenne.jdbc.password";
-
-    public static final String JDBC_MIN_CONNECTIONS_PROPERTY = 
"cayenne.jdbc.min_connections";
-
-    public static final String JDBC_MAX_CONNECTIONS_PROPERTY = 
"cayenne.jdbc.max_connections";
-
-    /**
-     * An integer property defining the maximum number of entries in the query
-     * cache. Note that not all QueryCache providers may respect this property.
-     * MapQueryCache uses it, but the rest would use alternative configuration
-     * methods.
-     */
-    public static final String QUERY_CACHE_SIZE_PROPERTY = 
"cayenne.querycache.size";
-
-    /**
-     * A boolean property defining whether cross-contexts synchronization is
-     * enabled. Possible values are "true" or "false".
-     */
-    public static final String SERVER_CONTEXTS_SYNC_PROPERTY = 
"cayenne.server.contexts_sync_strategy";
-
-    /**
-     * A String property that defines how ObjectContexts should retain cached
-     * committed objects. Possible values are "weak", "soft", "hard".
-     */
-    public static final String SERVER_OBJECT_RETAIN_STRATEGY_PROPERTY = 
"cayenne.server.object_retain_strategy";
-
-    /**
-     * A boolean property that defines whether runtime should use external
-     * transactions. Possible values are "true" or "false".
-     */
-    public static final String SERVER_EXTERNAL_TX_PROPERTY = 
"cayenne.server.external_tx";
-
-    public static final String ROP_SERVICE_URL_PROPERTY = 
"cayenne.rop.service_url";
-
-    public static final String ROP_SERVICE_USERNAME_PROPERTY = 
"cayenne.rop.service_username";
-
-    public static final String ROP_SERVICE_PASSWORD_PROPERTY = 
"cayenne.rop.service_password";
-
-    public static final String ROP_SERVICE_SHARED_SESSION_PROPERTY = 
"cayenne.rop.shared_session_name";
-
-    public static final String ROP_SERVICE_TIMEOUT_PROPERTY = 
"cayenne.rop.service_timeout";
-
-    public static final String ROP_CHANNEL_EVENTS_PROPERTY = 
"cayenne.rop.channel_events";
-
-    public static final String ROP_CONTEXT_CHANGE_EVENTS_PROPERTY = 
"cayenne.rop.context_change_events";
-
-    public static final String ROP_CONTEXT_LIFECYCLE_EVENTS_PROPERTY = 
"cayenne.rop.context_lifecycle_events";
-
-    /**
-     * The name of the {@link org.apache.cayenne.event.EventBridgeFactory} that
-     * is passed from the ROP server to the client. Client would instantiate 
the
-     * factory to receive events from the server. Note that this property is
-     * stored in {@link #SERVER_ROP_EVENT_BRIDGE_PROPERTIES_MAP}, not
-     * {@link #PROPERTIES_MAP}.
-     */
-    public static final String SERVER_ROP_EVENT_BRIDGE_FACTORY_PROPERTY = 
"cayenne.server.rop_event_bridge_factory";
-
-    /**
-     * A property that defines a maximum number of ID qualifiers in where 
clause
-     * of queries that are generated for example in
-     * {@link org.apache.cayenne.access.IncrementalFaultList} or in
-     * DISJOINT_BY_ID prefetch processing. This is needed to avoid where clause
-     * size limitations and memory usage efficiency.
-     */
-    public static final String SERVER_MAX_ID_QUALIFIER_SIZE_PROPERTY = 
"cayenne.server.max_id_qualifier_size";
-
-    /**
-     * Defines a maximum time in milliseconds that a connection request could
-     * wait in the connection queue. After this period expires, an exception
-     * will be thrown in the calling method. A value of zero will make the
-     * thread wait until a connection is available with no time out. Defaults 
to
-     * 20 seconds.
-     */
-    public static final String SERVER_MAX_QUEUE_WAIT_TIME = 
"cayenne.jdbc.max_wait";
-
-    /** Defines if database uses case-insensitive collation */
-    public final static String CI_PROPERTY = 
"cayenne.runtime.db.collation.assume.ci";
-
-    /**
-     * A integer property that enables logging for just long running queries
-     * (rather than all queries). The value is the minimum number of
-     * milliseconds a query must run before is logged. A value less than or
-     * equal to zero (the default) disables this feature.
-     * 
-     * @since 4.0
-     * */
-    public final static String QUERY_EXECUTION_TIME_LOGGING_THRESHOLD_PROPERTY 
= "cayenne.server.query_execution_time_logging_threshold";
+       /**
+        * A DI container key for the List&lt;DataChannelFilter&gt; storing
+        * DataDomain filters.
+        */
+       public static final String SERVER_DOMAIN_FILTERS_LIST = 
"cayenne.server.domain_filters";
+
+       /**
+        * A DI container key for the List&lt;String&gt; storing locations of 
the
+        * one of more project configuration files.
+        */
+       public static final String SERVER_PROJECT_LOCATIONS_LIST = 
"cayenne.server.project_locations";
+
+       /**
+        * A DI container key for the List&lt;ExtendedType&gt; storing default
+        * adapter-agnostic ExtendedTypes.
+        */
+       public static final String SERVER_DEFAULT_TYPES_LIST = 
"cayenne.server.default_types";
+
+       /**
+        * A DI container key for the List&lt;ExtendedType&gt; storing a
+        * user-provided ExtendedTypes.
+        */
+       public static final String SERVER_USER_TYPES_LIST = 
"cayenne.server.user_types";
+
+       /**
+        * A DI container key for the List&lt;ExtendedTypeFactory&gt; storing
+        * default and user-provided ExtendedTypeFactories.
+        */
+       public static final String SERVER_TYPE_FACTORIES_LIST = 
"cayenne.server.type_factories";
+
+       /**
+        * A server-side DI container key for the Map&lt;String, String&gt; 
storing
+        * event bridge properties passed to the ROP client on bootstrap.
+        */
+       public static final String SERVER_ROP_EVENT_BRIDGE_PROPERTIES_MAP = 
"cayenne.server.rop_event_bridge_properties";
+
+       // Runtime properties
+
+       public static final String JDBC_DRIVER_PROPERTY = "cayenne.jdbc.driver";
+
+       public static final String JDBC_URL_PROPERTY = "cayenne.jdbc.url";
+
+       public static final String JDBC_USERNAME_PROPERTY = 
"cayenne.jdbc.username";
+
+       public static final String JDBC_PASSWORD_PROPERTY = 
"cayenne.jdbc.password";
+
+       public static final String JDBC_MIN_CONNECTIONS_PROPERTY = 
"cayenne.jdbc.min_connections";
+
+       public static final String JDBC_MAX_CONNECTIONS_PROPERTY = 
"cayenne.jdbc.max_connections";
+
+       /**
+        * An integer property defining the maximum number of entries in the 
query
+        * cache. Note that not all QueryCache providers may respect this 
property.
+        * MapQueryCache uses it, but the rest would use alternative 
configuration
+        * methods.
+        */
+       public static final String QUERY_CACHE_SIZE_PROPERTY = 
"cayenne.querycache.size";
+
+       /**
+        * An optional name of the runtime DataDomain. If not specified (which 
is
+        * normally the case), the name is inferred from the configuration name.
+        * 
+        * @since 4.0
+        */
+       public static final String SERVER_DOMAIN_NAME_PROPERTY = 
"cayenne.server.domain.name";
+
+       /**
+        * A boolean property defining whether cross-contexts synchronization is
+        * enabled. Possible values are "true" or "false".
+        */
+       public static final String SERVER_CONTEXTS_SYNC_PROPERTY = 
"cayenne.server.contexts_sync_strategy";
+
+       /**
+        * A String property that defines how ObjectContexts should retain 
cached
+        * committed objects. Possible values are "weak", "soft", "hard".
+        */
+       public static final String SERVER_OBJECT_RETAIN_STRATEGY_PROPERTY = 
"cayenne.server.object_retain_strategy";
+
+       /**
+        * A boolean property that defines whether runtime should use external
+        * transactions. Possible values are "true" or "false".
+        */
+       public static final String SERVER_EXTERNAL_TX_PROPERTY = 
"cayenne.server.external_tx";
+
+       public static final String ROP_SERVICE_URL_PROPERTY = 
"cayenne.rop.service_url";
+
+       public static final String ROP_SERVICE_USERNAME_PROPERTY = 
"cayenne.rop.service_username";
+
+       public static final String ROP_SERVICE_PASSWORD_PROPERTY = 
"cayenne.rop.service_password";
+
+       public static final String ROP_SERVICE_SHARED_SESSION_PROPERTY = 
"cayenne.rop.shared_session_name";
+
+       public static final String ROP_SERVICE_TIMEOUT_PROPERTY = 
"cayenne.rop.service_timeout";
+
+       public static final String ROP_CHANNEL_EVENTS_PROPERTY = 
"cayenne.rop.channel_events";
+
+       public static final String ROP_CONTEXT_CHANGE_EVENTS_PROPERTY = 
"cayenne.rop.context_change_events";
+
+       public static final String ROP_CONTEXT_LIFECYCLE_EVENTS_PROPERTY = 
"cayenne.rop.context_lifecycle_events";
+
+       /**
+        * The name of the {@link org.apache.cayenne.event.EventBridgeFactory} 
that
+        * is passed from the ROP server to the client. Client would 
instantiate the
+        * factory to receive events from the server. Note that this property is
+        * stored in {@link #SERVER_ROP_EVENT_BRIDGE_PROPERTIES_MAP}, not
+        * {@link #PROPERTIES_MAP}.
+        */
+       public static final String SERVER_ROP_EVENT_BRIDGE_FACTORY_PROPERTY = 
"cayenne.server.rop_event_bridge_factory";
+
+       /**
+        * A property that defines a maximum number of ID qualifiers in where 
clause
+        * of queries that are generated for example in
+        * {@link org.apache.cayenne.access.IncrementalFaultList} or in
+        * DISJOINT_BY_ID prefetch processing. This is needed to avoid where 
clause
+        * size limitations and memory usage efficiency.
+        */
+       public static final String SERVER_MAX_ID_QUALIFIER_SIZE_PROPERTY = 
"cayenne.server.max_id_qualifier_size";
+
+       /**
+        * Defines a maximum time in milliseconds that a connection request 
could
+        * wait in the connection queue. After this period expires, an exception
+        * will be thrown in the calling method. A value of zero will make the
+        * thread wait until a connection is available with no time out. 
Defaults to
+        * 20 seconds.
+        */
+       public static final String SERVER_MAX_QUEUE_WAIT_TIME = 
"cayenne.jdbc.max_wait";
+
+       /** Defines if database uses case-insensitive collation */
+       public final static String CI_PROPERTY = 
"cayenne.runtime.db.collation.assume.ci";
+
+       /**
+        * A integer property that enables logging for just long running queries
+        * (rather than all queries). The value is the minimum number of
+        * milliseconds a query must run before is logged. A value less than or
+        * equal to zero (the default) disables this feature.
+        * 
+        * @since 4.0
+        * */
+       public final static String 
QUERY_EXECUTION_TIME_LOGGING_THRESHOLD_PROPERTY = 
"cayenne.server.query_execution_time_logging_threshold";
 
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/15297cca/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/DataDomainProvider.java
----------------------------------------------------------------------
diff --git 
a/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/DataDomainProvider.java
 
b/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/DataDomainProvider.java
index f1a8d57..4815fe4 100644
--- 
a/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/DataDomainProvider.java
+++ 
b/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/DataDomainProvider.java
@@ -55,173 +55,172 @@ import org.apache.commons.logging.LogFactory;
  */
 public class DataDomainProvider implements Provider<DataDomain> {
 
-    /**
-     * @since 4.0
-     */
-    static final String DEFAULT_NAME = "cayenne";
+       private static Log logger = LogFactory.getLog(DataDomainProvider.class);
 
-    private static Log logger = LogFactory.getLog(DataDomainProvider.class);
+       @Inject
+       protected ResourceLocator resourceLocator;
 
-    @Inject
-    protected ResourceLocator resourceLocator;
+       @Inject
+       protected DataChannelDescriptorMerger descriptorMerger;
 
-    @Inject
-    protected DataChannelDescriptorMerger descriptorMerger;
+       @Inject
+       protected DataChannelDescriptorLoader loader;
 
-    @Inject
-    protected DataChannelDescriptorLoader loader;
+       @Inject(Constants.SERVER_DOMAIN_FILTERS_LIST)
+       protected List<DataChannelFilter> filters;
 
-    @Inject(Constants.SERVER_DOMAIN_FILTERS_LIST)
-    protected List<DataChannelFilter> filters;
+       @Inject(Constants.SERVER_PROJECT_LOCATIONS_LIST)
+       protected List<String> locations;
 
-    @Inject(Constants.SERVER_PROJECT_LOCATIONS_LIST)
-    protected List<String> locations;
+       @Inject
+       protected Injector injector;
 
-    @Inject
-    protected Injector injector;
+       @Inject
+       protected QueryCache queryCache;
 
-    @Inject
-    protected QueryCache queryCache;
+       @Inject
+       protected RuntimeProperties runtimeProperties;
 
-    @Inject
-    protected RuntimeProperties runtimeProperties;
+       @Inject
+       protected DataNodeFactory dataNodeFactory;
 
-    @Inject
-    protected DataNodeFactory dataNodeFactory;
+       @Override
+       public DataDomain get() throws ConfigurationException {
 
-    @Override
-    public DataDomain get() throws ConfigurationException {
+               try {
+                       return createAndInitDataDomain();
+               } catch (ConfigurationException e) {
+                       throw e;
+               } catch (Exception e) {
+                       throw new DataDomainLoadException("Error loading 
DataChannel: '%s'", e, e.getMessage());
+               }
+       }
 
-        try {
-            return createAndInitDataDomain();
-        } catch (ConfigurationException e) {
-            throw e;
-        } catch (Exception e) {
-            throw new DataDomainLoadException("Error loading DataChannel: 
'%s'", e, e.getMessage());
-        }
-    }
+       protected DataDomain createDataDomain(String name) {
+               return new DataDomain(name);
+       }
 
-    protected DataDomain createDataDomain(String name) {
-        return new DataDomain(name);
-    }
+       protected DataDomain createAndInitDataDomain() throws Exception {
 
-    protected DataDomain createAndInitDataDomain() throws Exception {
+               DataChannelDescriptor descriptor;
 
-        DataChannelDescriptor descriptor;
+               if (locations.isEmpty()) {
+                       descriptor = new DataChannelDescriptor();
+               } else {
+                       descriptor = descriptorFromConfigs();
+               }
 
-        if (locations.isEmpty()) {
-            descriptor = new DataChannelDescriptor();
-            descriptor.setName(DEFAULT_NAME);
-        } else {
-            descriptor = descriptorFromConfigs();
-        }
+               String nameOverride = 
runtimeProperties.get(Constants.SERVER_DOMAIN_NAME_PROPERTY);
+               if (nameOverride != null) {
+                       descriptor.setName(nameOverride);
+               }
 
-        DataDomain dataDomain = createDataDomain(descriptor.getName());
+               DataDomain dataDomain = createDataDomain(descriptor.getName());
 
-        
dataDomain.setMaxIdQualifierSize(runtimeProperties.getInt(Constants.SERVER_MAX_ID_QUALIFIER_SIZE_PROPERTY,
 -1));
+               
dataDomain.setMaxIdQualifierSize(runtimeProperties.getInt(Constants.SERVER_MAX_ID_QUALIFIER_SIZE_PROPERTY,
 -1));
 
-        dataDomain.setQueryCache(new NestedQueryCache(queryCache));
-        dataDomain.setEntitySorter(injector.getInstance(EntitySorter.class));
-        dataDomain.setEventManager(injector.getInstance(EventManager.class));
+               dataDomain.setQueryCache(new NestedQueryCache(queryCache));
+               
dataDomain.setEntitySorter(injector.getInstance(EntitySorter.class));
+               
dataDomain.setEventManager(injector.getInstance(EventManager.class));
 
-        dataDomain.initWithProperties(descriptor.getProperties());
+               dataDomain.initWithProperties(descriptor.getProperties());
 
-        for (DataMap dataMap : descriptor.getDataMaps()) {
-            dataDomain.addDataMap(dataMap);
-        }
+               for (DataMap dataMap : descriptor.getDataMaps()) {
+                       dataDomain.addDataMap(dataMap);
+               }
 
-        dataDomain.getEntityResolver().applyDBLayerDefaults();
-        dataDomain.getEntityResolver().applyObjectLayerDefaults();
+               dataDomain.getEntityResolver().applyDBLayerDefaults();
+               dataDomain.getEntityResolver().applyObjectLayerDefaults();
 
-        for (DataNodeDescriptor nodeDescriptor : 
descriptor.getNodeDescriptors()) {
-            addDataNode(dataDomain, nodeDescriptor);
-        }
+               for (DataNodeDescriptor nodeDescriptor : 
descriptor.getNodeDescriptors()) {
+                       addDataNode(dataDomain, nodeDescriptor);
+               }
 
-        // init default node
-        DataNode defaultNode = null;
+               // init default node
+               DataNode defaultNode = null;
 
-        if (descriptor.getDefaultNodeName() != null) {
-            defaultNode = 
dataDomain.getDataNode(descriptor.getDefaultNodeName());
-        }
+               if (descriptor.getDefaultNodeName() != null) {
+                       defaultNode = 
dataDomain.getDataNode(descriptor.getDefaultNodeName());
+               }
 
-        if (defaultNode == null) {
-            Collection<DataNode> allNodes = dataDomain.getDataNodes();
-            if (allNodes.size() == 1) {
-                defaultNode = allNodes.iterator().next();
-            }
-        }
+               if (defaultNode == null) {
+                       Collection<DataNode> allNodes = 
dataDomain.getDataNodes();
+                       if (allNodes.size() == 1) {
+                               defaultNode = allNodes.iterator().next();
+                       }
+               }
 
-        if (defaultNode != null) {
-            logger.info("setting DataNode '" + defaultNode.getName() + "' as 
default, used by all unlinked DataMaps");
+               if (defaultNode != null) {
+                       logger.info("setting DataNode '" + 
defaultNode.getName() + "' as default, used by all unlinked DataMaps");
 
-            dataDomain.setDefaultNode(defaultNode);
-        }
+                       dataDomain.setDefaultNode(defaultNode);
+               }
 
-        for (DataChannelFilter filter : filters) {
-            dataDomain.addFilter(filter);
-        }
+               for (DataChannelFilter filter : filters) {
+                       dataDomain.addFilter(filter);
+               }
 
-        return dataDomain;
-    }
+               return dataDomain;
+       }
 
-    /**
-     * @since 4.0
-     */
-    protected DataNode addDataNode(DataDomain dataDomain, DataNodeDescriptor 
nodeDescriptor) throws Exception {
-        DataNode dataNode = dataNodeFactory.createDataNode(nodeDescriptor);
+       /**
+        * @since 4.0
+        */
+       protected DataNode addDataNode(DataDomain dataDomain, 
DataNodeDescriptor nodeDescriptor) throws Exception {
+               DataNode dataNode = 
dataNodeFactory.createDataNode(nodeDescriptor);
 
-        // DataMaps
-        for (String dataMapName : nodeDescriptor.getDataMapNames()) {
-            dataNode.addDataMap(dataDomain.getDataMap(dataMapName));
-        }
+               // DataMaps
+               for (String dataMapName : nodeDescriptor.getDataMapNames()) {
+                       dataNode.addDataMap(dataDomain.getDataMap(dataMapName));
+               }
 
-        dataDomain.addNode(dataNode);
-        return dataNode;
-    }
+               dataDomain.addNode(dataNode);
+               return dataNode;
+       }
 
-    private DataChannelDescriptor descriptorFromConfigs() {
+       private DataChannelDescriptor descriptorFromConfigs() {
 
-        long t0 = System.currentTimeMillis();
+               long t0 = System.currentTimeMillis();
 
-        if (logger.isDebugEnabled()) {
-            logger.debug("starting configuration loading: " + locations);
-        }
+               if (logger.isDebugEnabled()) {
+                       logger.debug("starting configuration loading: " + 
locations);
+               }
 
-        DataChannelDescriptor[] descriptors = new 
DataChannelDescriptor[locations.size()];
+               DataChannelDescriptor[] descriptors = new 
DataChannelDescriptor[locations.size()];
 
-        for (int i = 0; i < locations.size(); i++) {
+               for (int i = 0; i < locations.size(); i++) {
 
-            String location = locations.get(i);
+                       String location = locations.get(i);
 
-            Collection<Resource> configurations = 
resourceLocator.findResources(location);
+                       Collection<Resource> configurations = 
resourceLocator.findResources(location);
 
-            if (configurations.isEmpty()) {
-                throw new DataDomainLoadException("Configuration resource 
\"%s\" is not found.", location);
-            }
+                       if (configurations.isEmpty()) {
+                               throw new 
DataDomainLoadException("Configuration resource \"%s\" is not found.", 
location);
+                       }
 
-            Resource configurationResource = configurations.iterator().next();
+                       Resource configurationResource = 
configurations.iterator().next();
 
-            // no support for multiple configs yet, but this is not a hard 
error
-            if (configurations.size() > 1) {
-                logger.info("found " + configurations.size() + " 
configurations for " + location
-                        + ", will use the first one: " + 
configurationResource.getURL());
-            }
+                       // no support for multiple configs yet, but this is not 
a hard error
+                       if (configurations.size() > 1) {
+                               logger.info("found " + configurations.size() + 
" configurations for " + location
+                                               + ", will use the first one: " 
+ configurationResource.getURL());
+                       }
 
-            ConfigurationTree<DataChannelDescriptor> tree = 
loader.load(configurationResource);
-            if (!tree.getLoadFailures().isEmpty()) {
-                // TODO: andrus 03/10/2010 - log the errors before throwing?
-                throw new DataDomainLoadException(tree, "Error loading 
DataChannelDescriptor");
-            }
+                       ConfigurationTree<DataChannelDescriptor> tree = 
loader.load(configurationResource);
+                       if (!tree.getLoadFailures().isEmpty()) {
+                               // TODO: andrus 03/10/2010 - log the errors 
before throwing?
+                               throw new DataDomainLoadException(tree, "Error 
loading DataChannelDescriptor");
+                       }
 
-            descriptors[i] = tree.getRootNode();
-        }
+                       descriptors[i] = tree.getRootNode();
+               }
 
-        long t1 = System.currentTimeMillis();
+               long t1 = System.currentTimeMillis();
 
-        if (logger.isDebugEnabled()) {
-            logger.debug("finished configuration loading in " + (t1 - t0) + " 
ms.");
-        }
+               if (logger.isDebugEnabled()) {
+                       logger.debug("finished configuration loading in " + (t1 
- t0) + " ms.");
+               }
 
-        return descriptorMerger.merge(descriptors);
-    }
+               return descriptorMerger.merge(descriptors);
+       }
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/15297cca/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/ServerRuntimeBuilder.java
----------------------------------------------------------------------
diff --git 
a/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/ServerRuntimeBuilder.java
 
b/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/ServerRuntimeBuilder.java
index 01115b7..33dc60e 100644
--- 
a/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/ServerRuntimeBuilder.java
+++ 
b/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/ServerRuntimeBuilder.java
@@ -19,6 +19,7 @@
 package org.apache.cayenne.configuration.server;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.LinkedHashSet;
 import java.util.List;
@@ -40,6 +41,12 @@ import org.apache.cayenne.di.Module;
  */
 public class ServerRuntimeBuilder {
 
+       /**
+        * @since 4.0
+        */
+       static final String DEFAULT_NAME = "cayenne";
+
+       private String name;
        private Collection<String> configs;
        private List<Module> modules;
        private DataSourceFactory dataSourceFactory;
@@ -54,17 +61,18 @@ public class ServerRuntimeBuilder {
         * Creates an empty builder.
         */
        public ServerRuntimeBuilder() {
-               this.configs = new LinkedHashSet<String>();
-               this.modules = new ArrayList<Module>();
+               this(null);
        }
 
        /**
-        * An equivalent to creating builder with default constructor and 
calling
-        * {@link #addConfig(String)}.
+        * Creates a builder with a fixed name of the DataDomain of the 
resulting
+        * ServerRuntime. Specifying explicit name is often needed for 
consistency
+        * in runtimes merged from multiple configs, each having its own name.
         */
-       public ServerRuntimeBuilder(String configurationLocation) {
-               this();
-               addConfig(configurationLocation);
+       public ServerRuntimeBuilder(String name) {
+               this.configs = new LinkedHashSet<String>();
+               this.modules = new ArrayList<Module>();
+               this.name = name;
        }
 
        /**
@@ -134,6 +142,13 @@ public class ServerRuntimeBuilder {
                return this;
        }
 
+       public ServerRuntimeBuilder addConfigs(String... 
configurationLocations) {
+               if (configurationLocations != null) {
+                       configs.addAll(Arrays.asList(configurationLocations));
+               }
+               return this;
+       }
+
        public ServerRuntimeBuilder addConfigs(Collection<String> 
configurationLocations) {
                configs.addAll(configurationLocations);
                return this;
@@ -160,6 +175,28 @@ public class ServerRuntimeBuilder {
 
        private void buildModules() {
 
+               String nameOverride = name;
+
+               if (nameOverride == null) {
+                       // check if we need to force the default name ... we do 
when no
+                       // configs or multiple configs are supplied.
+                       if (configs.size() != 1) {
+                               nameOverride = DEFAULT_NAME;
+                       }
+               }
+
+               if (nameOverride != null) {
+
+                       final String finalNameOverride = nameOverride;
+                       prepend(new Module() {
+                               @Override
+                               public void configure(Binder binder) {
+                                       
binder.bindMap(Constants.PROPERTIES_MAP).put(Constants.SERVER_DOMAIN_NAME_PROPERTY,
+                                                       finalNameOverride);
+                               }
+                       });
+               }
+
                if (dataSourceFactory != null) {
 
                        prepend(new Module() {
@@ -196,6 +233,7 @@ public class ServerRuntimeBuilder {
                                        if (jdbcMaxConnections > 0) {
                                                
props.put(Constants.JDBC_MAX_CONNECTIONS_PROPERTY, 
Integer.toString(jdbcMaxConnections));
                                        }
+
                                }
                        });
                }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/15297cca/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/SyntheticNodeDataDomainProvider.java
----------------------------------------------------------------------
diff --git 
a/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/SyntheticNodeDataDomainProvider.java
 
b/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/SyntheticNodeDataDomainProvider.java
index 56751fe..dbd0ec2 100644
--- 
a/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/SyntheticNodeDataDomainProvider.java
+++ 
b/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/SyntheticNodeDataDomainProvider.java
@@ -28,24 +28,23 @@ import org.apache.cayenne.configuration.DataNodeDescriptor;
  */
 class SyntheticNodeDataDomainProvider extends DataDomainProvider {
 
-    @Override
-    protected DataDomain createAndInitDataDomain() throws Exception {
+       @Override
+       protected DataDomain createAndInitDataDomain() throws Exception {
 
-        DataDomain dataDomain = super.createAndInitDataDomain();
+               DataDomain dataDomain = super.createAndInitDataDomain();
 
-        // no nodes... add a synthetic node... it will become the default
-        if (dataDomain.getDataNodes().isEmpty()) {
+               // no nodes... add a synthetic node... it will become the 
default
+               if (dataDomain.getDataNodes().isEmpty()) {
 
-            DataChannelDescriptor channelDescriptor = new 
DataChannelDescriptor();
-            channelDescriptor.setName(DEFAULT_NAME);
+                       DataChannelDescriptor channelDescriptor = new 
DataChannelDescriptor();
 
-            DataNodeDescriptor nodeDescriptor = new 
DataNodeDescriptor(DEFAULT_NAME);
-            nodeDescriptor.setDataChannelDescriptor(channelDescriptor);
+                       DataNodeDescriptor nodeDescriptor = new 
DataNodeDescriptor(ServerRuntimeBuilder.DEFAULT_NAME);
+                       
nodeDescriptor.setDataChannelDescriptor(channelDescriptor);
 
-            DataNode node = addDataNode(dataDomain, nodeDescriptor);
-            dataDomain.setDefaultNode(node);
-        }
-        return dataDomain;
-    }
+                       DataNode node = addDataNode(dataDomain, nodeDescriptor);
+                       dataDomain.setDefaultNode(node);
+               }
+               return dataDomain;
+       }
 
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/15297cca/cayenne-server/src/test/java/org/apache/cayenne/configuration/server/ServerRuntimeBuilderIT.java
----------------------------------------------------------------------
diff --git 
a/cayenne-server/src/test/java/org/apache/cayenne/configuration/server/ServerRuntimeBuilderIT.java
 
b/cayenne-server/src/test/java/org/apache/cayenne/configuration/server/ServerRuntimeBuilderIT.java
new file mode 100644
index 0000000..27b64e4
--- /dev/null
+++ 
b/cayenne-server/src/test/java/org/apache/cayenne/configuration/server/ServerRuntimeBuilderIT.java
@@ -0,0 +1,109 @@
+/*****************************************************************
+ *   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
+ *
+ *    http://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.server;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.List;
+
+import javax.sql.DataSource;
+
+import org.apache.cayenne.DataRow;
+import org.apache.cayenne.conn.DataSourceInfo;
+import org.apache.cayenne.di.Inject;
+import org.apache.cayenne.query.SQLSelect;
+import org.apache.cayenne.test.jdbc.DBHelper;
+import org.apache.cayenne.test.jdbc.TableHelper;
+import org.apache.cayenne.unit.di.server.CayenneProjects;
+import org.apache.cayenne.unit.di.server.ServerCase;
+import org.apache.cayenne.unit.di.server.UseServerRuntime;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+@UseServerRuntime(CayenneProjects.TESTMAP_PROJECT)
+public class ServerRuntimeBuilderIT extends ServerCase {
+
+       @Inject
+       private DBHelper dbHelper;
+
+       @Inject
+       private ServerRuntime runtime;
+
+       @Inject
+       private DataSourceInfo dsi;
+
+       private ServerRuntime localRuntime;
+       private DataSource dataSource;
+
+       @After
+       public void stopLocalRuntime() {
+
+               // even though we don't supply real configs here, we sometimes 
access
+               // DataDomain, and this starts EventManager threads that need 
to be
+               // shutdown
+               if (localRuntime != null) {
+                       localRuntime.shutdown();
+               }
+       }
+
+       @Before
+       public void testSetUp() throws Exception {
+               TableHelper tArtist = new TableHelper(dbHelper, "ARTIST");
+               tArtist.setColumns("ARTIST_ID", "ARTIST_NAME");
+               tArtist.insert(33001, "AA1");
+               tArtist.insert(33002, "AA2");
+
+               this.dataSource = runtime.getDataSource("testmap");
+       }
+
+       @Test
+       public void testConfigFree_WithDataSource() {
+
+               localRuntime = new 
ServerRuntimeBuilder().dataSource(dataSource).build();
+
+               List<DataRow> result = SQLSelect.dataRowQuery("SELECT * FROM 
ARTIST").select(localRuntime.newContext());
+               assertEquals(2, result.size());
+       }
+
+       @Test
+       public void testConfigFree_WithDBParams() {
+
+               localRuntime = new 
ServerRuntimeBuilder().jdbcDriver(dsi.getJdbcDriver()).url(dsi.getDataSourceUrl())
+                               
.password(dsi.getPassword()).user(dsi.getUserName()).minConnections(1).maxConnections(2).build();
+
+               List<DataRow> result = SQLSelect.dataRowQuery("SELECT * FROM 
ARTIST").select(localRuntime.newContext());
+               assertEquals(2, result.size());
+       }
+
+       @Test
+       public void test_UnnamedDomain_MultiLocation() {
+               localRuntime = new 
ServerRuntimeBuilder().addConfigs(CayenneProjects.TESTMAP_PROJECT,
+                               CayenneProjects.EMBEDDABLE_PROJECT).build();
+
+               assertEquals("cayenne", localRuntime.getDataDomain().getName());
+       }
+
+       @Test
+       public void test_NamedDomain_MultiLocation() {
+               localRuntime = new 
ServerRuntimeBuilder("myd").addConfigs(CayenneProjects.TESTMAP_PROJECT,
+                               CayenneProjects.EMBEDDABLE_PROJECT).build();
+               assertEquals("myd", localRuntime.getDataDomain().getName());
+       }
+}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/15297cca/cayenne-server/src/test/java/org/apache/cayenne/configuration/server/ServerRuntimeBuilderTest.java
----------------------------------------------------------------------
diff --git 
a/cayenne-server/src/test/java/org/apache/cayenne/configuration/server/ServerRuntimeBuilderTest.java
 
b/cayenne-server/src/test/java/org/apache/cayenne/configuration/server/ServerRuntimeBuilderTest.java
index 19c9447..9177fac 100644
--- 
a/cayenne-server/src/test/java/org/apache/cayenne/configuration/server/ServerRuntimeBuilderTest.java
+++ 
b/cayenne-server/src/test/java/org/apache/cayenne/configuration/server/ServerRuntimeBuilderTest.java
@@ -18,8 +18,10 @@
  ****************************************************************/
 package org.apache.cayenne.configuration.server;
 
+import static org.hamcrest.CoreMatchers.instanceOf;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertThat;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.mock;
 
@@ -32,15 +34,29 @@ import org.apache.cayenne.configuration.Constants;
 import org.apache.cayenne.configuration.ModuleCollection;
 import org.apache.cayenne.di.Key;
 import org.apache.cayenne.di.Module;
+import org.junit.After;
 import org.junit.Test;
 
 public class ServerRuntimeBuilderTest {
 
+       private ServerRuntime runtime;
+
+       @After
+       public void stopRuntime() {
+
+               // even though we don't supply real configs here, we sometimes 
access
+               // DataDomain, and this starts EventManager threads that need 
to be
+               // shutdown
+               if (runtime != null) {
+                       runtime.shutdown();
+               }
+       }
+
        @Test
        public void test_NoLocation() {
 
                // this is meaningless (no DataSource), but should work...
-               ServerRuntime runtime = new ServerRuntimeBuilder().build();
+               runtime = new ServerRuntimeBuilder().build();
 
                List<?> locations = runtime.getInjector().getInstance(
                                Key.get(List.class, 
Constants.SERVER_PROJECT_LOCATIONS_LIST));
@@ -49,14 +65,14 @@ public class ServerRuntimeBuilderTest {
                assertTrue(runtime.getModule() instanceof ModuleCollection);
 
                Collection<Module> modules = ((ModuleCollection) 
runtime.getModule()).getModules();
-               assertEquals(1, modules.size());
-               assertTrue(modules.iterator().next() instanceof ServerModule);
+               assertEquals(2, modules.size());
+               assertThat(modules.iterator().next(), 
instanceOf(ServerModule.class));
        }
 
        @Test
        public void test_SingleLocation() {
 
-               ServerRuntime runtime = new 
ServerRuntimeBuilder("xxxx").build();
+               runtime = new ServerRuntimeBuilder().addConfig("xxxx").build();
 
                List<?> locations = runtime.getInjector().getInstance(
                                Key.get(List.class, 
Constants.SERVER_PROJECT_LOCATIONS_LIST));
@@ -65,14 +81,14 @@ public class ServerRuntimeBuilderTest {
 
                Collection<Module> modules = ((ModuleCollection) 
runtime.getModule()).getModules();
                assertEquals(1, modules.size());
-               assertTrue(modules.iterator().next() instanceof ServerModule);
+               assertThat(modules.iterator().next(), 
instanceOf(ServerModule.class));
 
        }
 
        @Test
        public void test_MultipleLocations() {
 
-               ServerRuntime runtime = new 
ServerRuntimeBuilder("xxxx").addConfig("yyyy").build();
+               runtime = new ServerRuntimeBuilder().addConfigs("xxxx", 
"yyyy").build();
 
                List<?> locations = runtime.getInjector().getInstance(
                                Key.get(List.class, 
Constants.SERVER_PROJECT_LOCATIONS_LIST));
@@ -80,8 +96,8 @@ public class ServerRuntimeBuilderTest {
                assertEquals(Arrays.asList("xxxx", "yyyy"), locations);
 
                Collection<Module> modules = ((ModuleCollection) 
runtime.getModule()).getModules();
-               assertEquals(1, modules.size());
-               assertTrue(modules.iterator().next() instanceof ServerModule);
+               assertEquals(2, modules.size());
+               assertThat(modules.iterator().next(), 
instanceOf(ServerModule.class));
        }
 
        @Test
@@ -89,15 +105,30 @@ public class ServerRuntimeBuilderTest {
 
                Module m = mock(Module.class);
 
-               ServerRuntime runtime = new 
ServerRuntimeBuilder("xxxx").addModule(m).build();
+               runtime = new ServerRuntimeBuilder().addModule(m).build();
 
                Collection<Module> modules = ((ModuleCollection) 
runtime.getModule()).getModules();
-               assertEquals(2, modules.size());
+               assertEquals(3, modules.size());
 
                Iterator<Module> it = modules.iterator();
 
-               assertTrue(it.next() instanceof ServerModule);
+               assertThat(it.next(), instanceOf(ServerModule.class));
+
+               // rewind - this module is name fix module
+               it.next();
+               
                assertSame(m, it.next());
        }
 
+       @Test
+       public void test_UnnamedDomain_NoLocation() {
+               runtime = new ServerRuntimeBuilder().build();
+               assertEquals("cayenne", runtime.getDataDomain().getName());
+       }
+
+       @Test
+       public void test_NamedDomain_NoLocation() {
+               runtime = new ServerRuntimeBuilder("myd").build();
+               assertEquals("myd", runtime.getDataDomain().getName());
+       }
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/15297cca/cayenne-server/src/test/java/org/apache/cayenne/configuration/server/ServerRuntimeBuilder_InAction_IT.java
----------------------------------------------------------------------
diff --git 
a/cayenne-server/src/test/java/org/apache/cayenne/configuration/server/ServerRuntimeBuilder_InAction_IT.java
 
b/cayenne-server/src/test/java/org/apache/cayenne/configuration/server/ServerRuntimeBuilder_InAction_IT.java
deleted file mode 100644
index 25c0aa4..0000000
--- 
a/cayenne-server/src/test/java/org/apache/cayenne/configuration/server/ServerRuntimeBuilder_InAction_IT.java
+++ /dev/null
@@ -1,88 +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
- *
- *    http://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.server;
-
-import org.apache.cayenne.DataRow;
-import org.apache.cayenne.conn.DataSourceInfo;
-import org.apache.cayenne.di.Inject;
-import org.apache.cayenne.query.SQLSelect;
-import org.apache.cayenne.test.jdbc.DBHelper;
-import org.apache.cayenne.test.jdbc.TableHelper;
-import org.apache.cayenne.unit.di.server.CayenneProjects;
-import org.apache.cayenne.unit.di.server.ServerCase;
-import org.apache.cayenne.unit.di.server.UseServerRuntime;
-import org.junit.Before;
-import org.junit.Test;
-
-import javax.sql.DataSource;
-import java.util.List;
-
-import static org.junit.Assert.assertEquals;
-
-@UseServerRuntime(CayenneProjects.TESTMAP_PROJECT)
-public class ServerRuntimeBuilder_InAction_IT extends ServerCase {
-
-    @Inject
-    private DBHelper dbHelper;
-
-    @Inject
-    private ServerRuntime runtime;
-
-    @Inject
-    private DataSourceInfo dsi;
-
-    private DataSource dataSource;
-
-    @Before
-    public void testSetUp() throws Exception { TableHelper tArtist = new 
TableHelper(dbHelper, "ARTIST");
-        tArtist.setColumns("ARTIST_ID", "ARTIST_NAME");
-        tArtist.insert(33001, "AA1");
-        tArtist.insert(33002, "AA2");
-
-        this.dataSource = runtime.getDataSource("testmap");
-    }
-
-    @Test
-    public void testConfigFree_WithDataSource() {
-
-        ServerRuntime localRuntime = new 
ServerRuntimeBuilder().dataSource(dataSource).build();
-
-        try {
-            List<DataRow> result = SQLSelect.dataRowQuery("SELECT * FROM 
ARTIST").select(localRuntime.newContext());
-            assertEquals(2, result.size());
-        } finally {
-            localRuntime.shutdown();
-        }
-    }
-
-    @Test
-    public void testConfigFree_WithDBParams() {
-
-        ServerRuntime localRuntime = new 
ServerRuntimeBuilder().jdbcDriver(dsi.getJdbcDriver())
-                
.url(dsi.getDataSourceUrl()).password(dsi.getPassword()).user(dsi.getUserName()).minConnections(1)
-                .maxConnections(2).build();
-
-        try {
-            List<DataRow> result = SQLSelect.dataRowQuery("SELECT * FROM 
ARTIST").select(localRuntime.newContext());
-            assertEquals(2, result.size());
-        } finally {
-            localRuntime.shutdown();
-        }
-    }
-}

http://git-wip-us.apache.org/repos/asf/cayenne/blob/15297cca/docs/doc/src/main/resources/RELEASE-NOTES.txt
----------------------------------------------------------------------
diff --git a/docs/doc/src/main/resources/RELEASE-NOTES.txt 
b/docs/doc/src/main/resources/RELEASE-NOTES.txt
index ec297f8..ddc6f5c 100644
--- a/docs/doc/src/main/resources/RELEASE-NOTES.txt
+++ b/docs/doc/src/main/resources/RELEASE-NOTES.txt
@@ -74,6 +74,7 @@ CAY-1966 SQLTemplate/SQLSelect positional parameter binding
 CAY-1967 Deprecate SQLTemplate parameter batches
 CAY-1968 SQLSelect cleanup and omissions
 CAY-1971 Variants of Property.like(..) : contains(..), startsWith(..), 
endsWith(..)
+CAY-1972 A property to override DataSources of multi-module projects 
 
 Bug Fixes:
 

http://git-wip-us.apache.org/repos/asf/cayenne/blob/15297cca/docs/doc/src/main/resources/UPGRADE.txt
----------------------------------------------------------------------
diff --git a/docs/doc/src/main/resources/UPGRADE.txt 
b/docs/doc/src/main/resources/UPGRADE.txt
index 94f8f72..c7ade60 100644
--- a/docs/doc/src/main/resources/UPGRADE.txt
+++ b/docs/doc/src/main/resources/UPGRADE.txt
@@ -35,9 +35,17 @@ UPGRADING TO 4.0.M2
 
 * External transactions are no longer configured in the Modeler. Instead they 
are provided as a DI property
   defined in Constants.SERVER_EXTERNAL_TX_PROPERTY.
+
 * TransactionDelegate is no longer present. Similar functionality can be 
achieved by writing a decorator for 
   Transaction interface and using a custom TransactionFactory to decorate 
standard transactions.
 
+* When switching to ServerRuntimeBuilder, users of multi-config projects may 
erroneously assume it has the same 
+  behavior as 3.1 ServerRuntime in assigning domain name to the resulting 
merged project. Which is to use the 
+  name of the last project config. We are trying to move away from this 
behavior, so ServerRuntimeBuilder 
+  will only use config name if there's only one config and no override. 
Otherwise it will use the override, 
+   or if not set - "cayenne" as the default name. Reference Jira: CAY-1972
+
+
 
 UPGRADING TO 3.1B1
 

Reply via email to