You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by aa...@apache.org on 2016/12/11 09:25:06 UTC

cayenne git commit: CAY-2164 Relocate builder bootstrap methods from ServerRuntimeBuilder to ServerRuntime

Repository: cayenne
Updated Branches:
  refs/heads/master 835711858 -> 15d6d2fdc


CAY-2164 Relocate builder bootstrap methods from ServerRuntimeBuilder to ServerRuntime


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

Branch: refs/heads/master
Commit: 15d6d2fdc020626253f6757525055c0606c46b26
Parents: 8357118
Author: Andrus Adamchik <an...@objectstyle.com>
Authored: Sun Dec 11 12:19:04 2016 +0300
Committer: Andrus Adamchik <an...@objectstyle.com>
Committed: Sun Dec 11 12:21:45 2016 +0300

----------------------------------------------------------------------
 .../lifecycle/unit/AuditableServerCase.java     |   2 +-
 .../lifecycle/unit/FlattenedServerCase.java     |   2 +-
 .../configuration/server/ServerRuntime.java     | 242 +++++-----
 .../server/ServerRuntimeBuilder.java            | 483 ++++++++++---------
 docs/doc/src/main/resources/RELEASE-NOTES.txt   |   3 +-
 docs/doc/src/main/resources/UPGRADE.txt         |   6 +
 6 files changed, 386 insertions(+), 352 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cayenne/blob/15d6d2fd/cayenne-lifecycle/src/test/java/org/apache/cayenne/lifecycle/unit/AuditableServerCase.java
----------------------------------------------------------------------
diff --git a/cayenne-lifecycle/src/test/java/org/apache/cayenne/lifecycle/unit/AuditableServerCase.java b/cayenne-lifecycle/src/test/java/org/apache/cayenne/lifecycle/unit/AuditableServerCase.java
index 6513273..fb66e46 100644
--- a/cayenne-lifecycle/src/test/java/org/apache/cayenne/lifecycle/unit/AuditableServerCase.java
+++ b/cayenne-lifecycle/src/test/java/org/apache/cayenne/lifecycle/unit/AuditableServerCase.java
@@ -86,7 +86,7 @@ public abstract class AuditableServerCase {
 	}
 
 	protected ServerRuntimeBuilder configureCayenne() {
-		return ServerRuntimeBuilder.builder().addConfig("cayenne-lifecycle.xml");
+		return ServerRuntime.builder().addConfig("cayenne-lifecycle.xml");
 	}
 
 	@After

http://git-wip-us.apache.org/repos/asf/cayenne/blob/15d6d2fd/cayenne-lifecycle/src/test/java/org/apache/cayenne/lifecycle/unit/FlattenedServerCase.java
----------------------------------------------------------------------
diff --git a/cayenne-lifecycle/src/test/java/org/apache/cayenne/lifecycle/unit/FlattenedServerCase.java b/cayenne-lifecycle/src/test/java/org/apache/cayenne/lifecycle/unit/FlattenedServerCase.java
index 42eaaa5..b9d1b0c 100644
--- a/cayenne-lifecycle/src/test/java/org/apache/cayenne/lifecycle/unit/FlattenedServerCase.java
+++ b/cayenne-lifecycle/src/test/java/org/apache/cayenne/lifecycle/unit/FlattenedServerCase.java
@@ -49,7 +49,7 @@ public class FlattenedServerCase {
 	}
 
 	protected ServerRuntimeBuilder configureCayenne() {
-		return ServerRuntimeBuilder.builder().addConfig("cayenne-lifecycle.xml");
+		return ServerRuntime.builder().addConfig("cayenne-lifecycle.xml");
 	}
 
 	@After

http://git-wip-us.apache.org/repos/asf/cayenne/blob/15d6d2fd/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/ServerRuntime.java
----------------------------------------------------------------------
diff --git a/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/ServerRuntime.java b/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/ServerRuntime.java
index dc71ae5..51ec9bf 100644
--- a/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/ServerRuntime.java
+++ b/cayenne-server/src/main/java/org/apache/cayenne/configuration/server/ServerRuntime.java
@@ -36,119 +36,139 @@ import javax.sql.DataSource;
  * "server" is used as opposed to ROP "client" (see {@link CayenneRuntime}). Any
  * application, desktop, server, etc. that has a direct JDBC connection should
  * be using this runtime.
- * 
+ *
  * @since 3.1
  */
 public class ServerRuntime extends CayenneRuntime {
 
-	private static ModuleCollection mainModule(String... configurationLocations) {
-		return new ModuleCollection(new ServerModule(configurationLocations));
-	}
-
-	/**
-	 * Creates a server runtime configuring it with a standard set of services
-	 * contained in {@link ServerModule}. CayenneServerModule is created with
-	 * provided 'configurationLocation'. An optional array of extra modules may
-	 * contain service overrides and/or user services.
-	 */
-	public ServerRuntime(String configurationLocation, Module... extraModules) {
-		super(mainModule(configurationLocation).add(extraModules));
-	}
-
-	/**
-	 * Creates a server runtime configuring it with a standard set of services
-	 * contained in {@link ServerModule}. CayenneServerModule is created with
-	 * one or more 'configurationLocations'. An optional array of extra modules
-	 * may contain service overrides and/or user services.
-	 */
-	public ServerRuntime(String[] configurationLocations, Module... extraModules) {
-		super(mainModule(configurationLocations).add(extraModules));
-	}
-
-	/**
-	 * Runs provided operation wrapped in a single transaction. Transaction
-	 * handling delegated to the internal {@link TransactionManager}. Nested
-	 * calls to 'performInTransaction' are safe and attached to the same
-	 * in-progress transaction. TransactionalOperation can be some arbitrary
-	 * user code, which most often than not will consist of multiple Cayenne
-	 * operations.
-	 * 
-	 * @since 4.0
-	 */
-	public <T> T performInTransaction(TransactionalOperation<T> op) {
-		TransactionManager tm = injector.getInstance(TransactionManager.class);
-		return tm.performInTransaction(op);
-	}
-
-	/**
-	 * Runs provided operation wrapped in a single transaction. Transaction
-	 * handling delegated to the internal {@link TransactionManager}. Nested
-	 * calls to 'performInTransaction' are safe and attached to the same
-	 * in-progress transaction. TransactionalOperation can be some arbitrary
-	 * user code, which most often than not will consist of multiple Cayenne
-	 * operations.
-	 *
-	 * @since 4.0
-	 */
-	public <T> T performInTransaction(TransactionalOperation<T> op, TransactionListener callback) {
-		TransactionManager tm = injector.getInstance(TransactionManager.class);
-		return tm.performInTransaction(op, callback);
-	}
-
-	/**
-	 * Returns the main runtime DataDomain. Note that by default the returned
-	 * DataDomain is the same as the main DataChannel returned by
-	 * {@link #getChannel()}. Although users may redefine DataChannel provider
-	 * in the DI registry, for instance to decorate this DataDomain with a
-	 * custom wrapper.
-	 */
-	public DataDomain getDataDomain() {
-		return injector.getInstance(DataDomain.class);
-	}
-
-	/**
-	 * Returns a default DataSource for this runtime. If no default DataSource
-	 * exists, an exception is thrown.
-	 * 
-	 * @since 4.0
-	 */
-	public DataSource getDataSource() {
-		DataDomain domain = getDataDomain();
-		DataNode defaultNode = domain.getDefaultNode();
-		if (defaultNode == null) {
-
-			int s = domain.getDataNodes().size();
-			if (s == 0) {
-				throw new IllegalStateException("No DataSources configured");
-			} else {
-				throw new IllegalArgumentException(
-						"No default DataSource configured. You can get explicitly named DataSource by using 'getDataSource(String)'");
-			}
-		}
-
-		return defaultNode.getDataSource();
-	}
-
-	/**
-	 * Provides access to the JDBC DataSource assigned to a given DataNode. A
-	 * null argument will work if there's only one DataNode configured.
-	 * <p>
-	 * Normally Cayenne applications don't need to access DataSource or any
-	 * other JDBC code directly, however in some unusual conditions it may be
-	 * needed, and this method provides a shortcut to raw JDBC.
-	 */
-	public DataSource getDataSource(String dataNodeName) {
-		DataDomain domain = getDataDomain();
-
-		if (dataNodeName == null) {
-			return getDataSource();
-		}
-
-		DataNode node = domain.getDataNode(dataNodeName);
-		if (node == null) {
-			throw new IllegalArgumentException("Unknown DataNode name: " + dataNodeName);
-		}
-
-		return node.getDataSource();
-	}
+    /**
+     * Creates a builder of ServerRuntime.
+     *
+     * @return a builder of ServerRuntime.
+     * @since 4.0
+     */
+    public static ServerRuntimeBuilder builder() {
+        return new ServerRuntimeBuilder();
+    }
+
+    /**
+     * Creates a builder of ServerRuntime.
+     *
+     * @param name
+     * @return a named builder of ServerRuntime.
+     */
+    public static ServerRuntimeBuilder builder(String name) {
+        return new ServerRuntimeBuilder(name);
+    }
+
+    private static ModuleCollection mainModule(String... configurationLocations) {
+        return new ModuleCollection(new ServerModule(configurationLocations));
+    }
+
+    /**
+     * Creates a server runtime configuring it with a standard set of services
+     * contained in {@link ServerModule}. CayenneServerModule is created with
+     * provided 'configurationLocation'. An optional array of extra modules may
+     * contain service overrides and/or user services.
+     */
+    public ServerRuntime(String configurationLocation, Module... extraModules) {
+        super(mainModule(configurationLocation).add(extraModules));
+    }
+
+    /**
+     * Creates a server runtime configuring it with a standard set of services
+     * contained in {@link ServerModule}. CayenneServerModule is created with
+     * one or more 'configurationLocations'. An optional array of extra modules
+     * may contain service overrides and/or user services.
+     */
+    public ServerRuntime(String[] configurationLocations, Module... extraModules) {
+        super(mainModule(configurationLocations).add(extraModules));
+    }
+
+    /**
+     * Runs provided operation wrapped in a single transaction. Transaction
+     * handling delegated to the internal {@link TransactionManager}. Nested
+     * calls to 'performInTransaction' are safe and attached to the same
+     * in-progress transaction. TransactionalOperation can be some arbitrary
+     * user code, which most often than not will consist of multiple Cayenne
+     * operations.
+     *
+     * @since 4.0
+     */
+    public <T> T performInTransaction(TransactionalOperation<T> op) {
+        TransactionManager tm = injector.getInstance(TransactionManager.class);
+        return tm.performInTransaction(op);
+    }
+
+    /**
+     * Runs provided operation wrapped in a single transaction. Transaction
+     * handling delegated to the internal {@link TransactionManager}. Nested
+     * calls to 'performInTransaction' are safe and attached to the same
+     * in-progress transaction. TransactionalOperation can be some arbitrary
+     * user code, which most often than not will consist of multiple Cayenne
+     * operations.
+     *
+     * @since 4.0
+     */
+    public <T> T performInTransaction(TransactionalOperation<T> op, TransactionListener callback) {
+        TransactionManager tm = injector.getInstance(TransactionManager.class);
+        return tm.performInTransaction(op, callback);
+    }
+
+    /**
+     * Returns the main runtime DataDomain. Note that by default the returned
+     * DataDomain is the same as the main DataChannel returned by
+     * {@link #getChannel()}. Although users may redefine DataChannel provider
+     * in the DI registry, for instance to decorate this DataDomain with a
+     * custom wrapper.
+     */
+    public DataDomain getDataDomain() {
+        return injector.getInstance(DataDomain.class);
+    }
+
+    /**
+     * Returns a default DataSource for this runtime. If no default DataSource
+     * exists, an exception is thrown.
+     *
+     * @since 4.0
+     */
+    public DataSource getDataSource() {
+        DataDomain domain = getDataDomain();
+        DataNode defaultNode = domain.getDefaultNode();
+        if (defaultNode == null) {
+
+            int s = domain.getDataNodes().size();
+            if (s == 0) {
+                throw new IllegalStateException("No DataSources configured");
+            } else {
+                throw new IllegalArgumentException(
+                        "No default DataSource configured. You can get explicitly named DataSource by using 'getDataSource(String)'");
+            }
+        }
+
+        return defaultNode.getDataSource();
+    }
+
+    /**
+     * Provides access to the JDBC DataSource assigned to a given DataNode. A
+     * null argument will work if there's only one DataNode configured.
+     * <p>
+     * Normally Cayenne applications don't need to access DataSource or any
+     * other JDBC code directly, however in some unusual conditions it may be
+     * needed, and this method provides a shortcut to raw JDBC.
+     */
+    public DataSource getDataSource(String dataNodeName) {
+        DataDomain domain = getDataDomain();
+
+        if (dataNodeName == null) {
+            return getDataSource();
+        }
+
+        DataNode node = domain.getDataNode(dataNodeName);
+        if (node == null) {
+            throw new IllegalArgumentException("Unknown DataNode name: " + dataNodeName);
+        }
+
+        return node.getDataSource();
+    }
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/15d6d2fd/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 ea649eb..f1a447b 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
@@ -37,246 +37,253 @@ import org.apache.cayenne.di.Module;
  * A convenience class to assemble custom ServerRuntime. It allows to easily
  * configure custom modules, multiple config locations, or quickly create a
  * global DataSource.
- * 
+ *
  * @since 4.0
  */
 public class ServerRuntimeBuilder {
 
-	static final String DEFAULT_NAME = "cayenne";
-
-	private String name;
-	private Collection<String> configs;
-	private List<Module> modules;
-	private DataSourceFactory dataSourceFactory;
-	private String jdbcUrl;
-	private String jdbcDriver;
-	private String jdbcUser;
-	private String jdbcPassword;
-	private int jdbcMinConnections;
-	private int jdbcMaxConnections;
-	private long maxQueueWaitTime;
-	private String validationQuery;
-
-	public static ServerRuntimeBuilder builder() {
-		return new ServerRuntimeBuilder();
-	}
-
-	public static ServerRuntimeBuilder builder(String name) {
-		return new ServerRuntimeBuilder(name);
-	}
-
-	/**
-	 * Creates an empty builder.
-	 */
-	public ServerRuntimeBuilder() {
-		this(null);
-	}
-
-	/**
-	 * 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 name) {
-		this.configs = new LinkedHashSet<String>();
-		this.modules = new ArrayList<Module>();
-		this.name = name;
-	}
-
-	/**
-	 * Sets a DataSource that will override any DataSources found in the
-	 * mapping. If the mapping contains no DataNodes, and the DataSource is set
-	 * with this method, the builder would create a single default DataNode.
-	 * 
-	 * @see DataSourceBuilder
-	 */
-	public ServerRuntimeBuilder dataSource(DataSource dataSource) {
-		this.dataSourceFactory = new FixedDataSourceFactory(dataSource);
-		return this;
-	}
-
-	/**
-	 * Sets JNDI location for the default DataSource. If the mapping contains no
-	 * DataNodes, and the DataSource is set with this method, the builder would
-	 * create a single default DataNode.
-	 */
-	public ServerRuntimeBuilder jndiDataSource(String location) {
-		this.dataSourceFactory = new FixedJNDIDataSourceFactory(location);
-		return this;
-	}
-
-	/**
-	 * Sets a database URL for the default DataSource.
-	 */
-	public ServerRuntimeBuilder url(String url) {
-		this.jdbcUrl = url;
-		return this;
-	}
-
-	/**
-	 * Sets a driver Java class for the default DataSource.
-	 */
-	public ServerRuntimeBuilder jdbcDriver(String driver) {
-		// TODO: guess the driver from URL
-		this.jdbcDriver = driver;
-		return this;
-	}
-
-	/**
-	 * Sets a validation query for the default DataSource.
-	 * 
-	 * @param validationQuery
-	 *            a SQL string that returns some result. It will be used to
-	 *            validate connections in the pool.
-	 */
-	public ServerRuntimeBuilder validationQuery(String validationQuery) {
-		this.validationQuery = validationQuery;
-		return this;
-	}
-	
-	public ServerRuntimeBuilder maxQueueWaitTime(long maxQueueWaitTime) {
-		this.maxQueueWaitTime = maxQueueWaitTime;
-		return this;
-	}
-
-	/**
-	 * Sets a user name for the default DataSource.
-	 */
-	public ServerRuntimeBuilder user(String user) {
-		this.jdbcUser = user;
-		return this;
-	}
-
-	/**
-	 * Sets a password for the default DataSource.
-	 */
-	public ServerRuntimeBuilder password(String password) {
-		this.jdbcPassword = password;
-		return this;
-	}
-
-	public ServerRuntimeBuilder minConnections(int minConnections) {
-		this.jdbcMinConnections = minConnections;
-		return this;
-	}
-
-	public ServerRuntimeBuilder maxConnections(int maxConnections) {
-		this.jdbcMaxConnections = maxConnections;
-		return this;
-	}
-
-	public ServerRuntimeBuilder addConfig(String configurationLocation) {
-		configs.add(configurationLocation);
-		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;
-	}
-
-	public ServerRuntimeBuilder addModule(Module module) {
-		modules.add(module);
-		return this;
-	}
-
-	public ServerRuntimeBuilder addModules(Collection<Module> modules) {
-		this.modules.addAll(modules);
-		return this;
-	}
-
-	public ServerRuntime build() {
-
-		buildModules();
-
-		String[] configs = this.configs.toArray(new String[this.configs.size()]);
-		Module[] modules = this.modules.toArray(new Module[this.modules.size()]);
-		return new ServerRuntime(configs, modules);
-	}
-
-	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() {
-				@Override
-				public void configure(Binder binder) {
-					binder.bind(DataDomain.class).toProvider(SyntheticNodeDataDomainProvider.class);
-					binder.bind(DataSourceFactory.class).toInstance(dataSourceFactory);
-				}
-			});
-
-		}
-		// URL and driver are the minimal requirement for
-		// DelegatingDataSourceFactory to work
-		else if (jdbcUrl != null && jdbcDriver != null) {
-			prepend(new Module() {
-				@Override
-				public void configure(Binder binder) {
-					binder.bind(DataDomain.class).toProvider(SyntheticNodeDataDomainProvider.class);
-					MapBuilder<Object> props = binder.bindMap(Constants.PROPERTIES_MAP)
-							.put(Constants.JDBC_DRIVER_PROPERTY, jdbcDriver).put(Constants.JDBC_URL_PROPERTY, jdbcUrl);
-
-					if (jdbcUser != null) {
-						props.put(Constants.JDBC_USERNAME_PROPERTY, jdbcUser);
-					}
-
-					if (jdbcPassword != null) {
-						props.put(Constants.JDBC_PASSWORD_PROPERTY, jdbcPassword);
-					}
-
-					if (jdbcMinConnections > 0) {
-						props.put(Constants.JDBC_MIN_CONNECTIONS_PROPERTY, Integer.toString(jdbcMinConnections));
-					}
-
-					if (jdbcMaxConnections > 0) {
-						props.put(Constants.JDBC_MAX_CONNECTIONS_PROPERTY, Integer.toString(jdbcMaxConnections));
-					}
-					
-					if (maxQueueWaitTime > 0) {
-						props.put(Constants.JDBC_MAX_QUEUE_WAIT_TIME, Long.toString(maxQueueWaitTime));
-					}
-
-					if (validationQuery != null) {
-						props.put(Constants.JDBC_VALIDATION_QUERY_PROPERTY, validationQuery);
-					}
-				}
-			});
-		}
-	}
-
-	private void prepend(Module module) {
-		// prepend any special modules BEFORE custom modules, to allow callers
-		// to override our stuff
-		modules.add(0, module);
-	}
+    static final String DEFAULT_NAME = "cayenne";
+
+    private String name;
+    private Collection<String> configs;
+    private List<Module> modules;
+    private DataSourceFactory dataSourceFactory;
+    private String jdbcUrl;
+    private String jdbcDriver;
+    private String jdbcUser;
+    private String jdbcPassword;
+    private int jdbcMinConnections;
+    private int jdbcMaxConnections;
+    private long maxQueueWaitTime;
+    private String validationQuery;
+
+    /**
+     * @deprecated since 4.0.M5 in favor of {@link ServerRuntime#builder()}
+     */
+    @Deprecated
+    public static ServerRuntimeBuilder builder() {
+        return ServerRuntime.builder();
+    }
+
+    /**
+     * @deprecated since 4.0.M5 in favor of {@link ServerRuntime#builder(String)}
+     */
+    @Deprecated
+    public static ServerRuntimeBuilder builder(String name) {
+        return ServerRuntime.builder(name);
+    }
+
+    /**
+     * Creates an empty builder.
+     */
+    public ServerRuntimeBuilder() {
+        this(null);
+    }
+
+    /**
+     * 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 name) {
+        this.configs = new LinkedHashSet<String>();
+        this.modules = new ArrayList<Module>();
+        this.name = name;
+    }
+
+    /**
+     * Sets a DataSource that will override any DataSources found in the
+     * mapping. If the mapping contains no DataNodes, and the DataSource is set
+     * with this method, the builder would create a single default DataNode.
+     *
+     * @see DataSourceBuilder
+     */
+    public ServerRuntimeBuilder dataSource(DataSource dataSource) {
+        this.dataSourceFactory = new FixedDataSourceFactory(dataSource);
+        return this;
+    }
+
+    /**
+     * Sets JNDI location for the default DataSource. If the mapping contains no
+     * DataNodes, and the DataSource is set with this method, the builder would
+     * create a single default DataNode.
+     */
+    public ServerRuntimeBuilder jndiDataSource(String location) {
+        this.dataSourceFactory = new FixedJNDIDataSourceFactory(location);
+        return this;
+    }
+
+    /**
+     * Sets a database URL for the default DataSource.
+     */
+    public ServerRuntimeBuilder url(String url) {
+        this.jdbcUrl = url;
+        return this;
+    }
+
+    /**
+     * Sets a driver Java class for the default DataSource.
+     */
+    public ServerRuntimeBuilder jdbcDriver(String driver) {
+        // TODO: guess the driver from URL
+        this.jdbcDriver = driver;
+        return this;
+    }
+
+    /**
+     * Sets a validation query for the default DataSource.
+     *
+     * @param validationQuery a SQL string that returns some result. It will be used to
+     *                        validate connections in the pool.
+     */
+    public ServerRuntimeBuilder validationQuery(String validationQuery) {
+        this.validationQuery = validationQuery;
+        return this;
+    }
+
+    public ServerRuntimeBuilder maxQueueWaitTime(long maxQueueWaitTime) {
+        this.maxQueueWaitTime = maxQueueWaitTime;
+        return this;
+    }
+
+    /**
+     * Sets a user name for the default DataSource.
+     */
+    public ServerRuntimeBuilder user(String user) {
+        this.jdbcUser = user;
+        return this;
+    }
+
+    /**
+     * Sets a password for the default DataSource.
+     */
+    public ServerRuntimeBuilder password(String password) {
+        this.jdbcPassword = password;
+        return this;
+    }
+
+    public ServerRuntimeBuilder minConnections(int minConnections) {
+        this.jdbcMinConnections = minConnections;
+        return this;
+    }
+
+    public ServerRuntimeBuilder maxConnections(int maxConnections) {
+        this.jdbcMaxConnections = maxConnections;
+        return this;
+    }
+
+    public ServerRuntimeBuilder addConfig(String configurationLocation) {
+        configs.add(configurationLocation);
+        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;
+    }
+
+    public ServerRuntimeBuilder addModule(Module module) {
+        modules.add(module);
+        return this;
+    }
+
+    public ServerRuntimeBuilder addModules(Collection<Module> modules) {
+        this.modules.addAll(modules);
+        return this;
+    }
+
+    public ServerRuntime build() {
+
+        buildModules();
+
+        String[] configs = this.configs.toArray(new String[this.configs.size()]);
+        Module[] modules = this.modules.toArray(new Module[this.modules.size()]);
+        return new ServerRuntime(configs, modules);
+    }
+
+    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() {
+                @Override
+                public void configure(Binder binder) {
+                    binder.bind(DataDomain.class).toProvider(SyntheticNodeDataDomainProvider.class);
+                    binder.bind(DataSourceFactory.class).toInstance(dataSourceFactory);
+                }
+            });
+
+        }
+        // URL and driver are the minimal requirement for
+        // DelegatingDataSourceFactory to work
+        else if (jdbcUrl != null && jdbcDriver != null) {
+            prepend(new Module() {
+                @Override
+                public void configure(Binder binder) {
+                    binder.bind(DataDomain.class).toProvider(SyntheticNodeDataDomainProvider.class);
+                    MapBuilder<Object> props = binder.bindMap(Constants.PROPERTIES_MAP)
+                            .put(Constants.JDBC_DRIVER_PROPERTY, jdbcDriver).put(Constants.JDBC_URL_PROPERTY, jdbcUrl);
+
+                    if (jdbcUser != null) {
+                        props.put(Constants.JDBC_USERNAME_PROPERTY, jdbcUser);
+                    }
+
+                    if (jdbcPassword != null) {
+                        props.put(Constants.JDBC_PASSWORD_PROPERTY, jdbcPassword);
+                    }
+
+                    if (jdbcMinConnections > 0) {
+                        props.put(Constants.JDBC_MIN_CONNECTIONS_PROPERTY, Integer.toString(jdbcMinConnections));
+                    }
+
+                    if (jdbcMaxConnections > 0) {
+                        props.put(Constants.JDBC_MAX_CONNECTIONS_PROPERTY, Integer.toString(jdbcMaxConnections));
+                    }
+
+                    if (maxQueueWaitTime > 0) {
+                        props.put(Constants.JDBC_MAX_QUEUE_WAIT_TIME, Long.toString(maxQueueWaitTime));
+                    }
+
+                    if (validationQuery != null) {
+                        props.put(Constants.JDBC_VALIDATION_QUERY_PROPERTY, validationQuery);
+                    }
+                }
+            });
+        }
+    }
+
+    private void prepend(Module module) {
+        // prepend any special modules BEFORE custom modules, to allow callers
+        // to override our stuff
+        modules.add(0, module);
+    }
 }

http://git-wip-us.apache.org/repos/asf/cayenne/blob/15d6d2fd/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 3cccbd6..9562878 100644
--- a/docs/doc/src/main/resources/RELEASE-NOTES.txt
+++ b/docs/doc/src/main/resources/RELEASE-NOTES.txt
@@ -13,7 +13,8 @@ Date:
 ----------------------------------
 Changes/New Features:
 
-CAY-2153 Property.path() , ExpressionFactory.pathExp()
+CAY-2163 Property.path() , ExpressionFactory.pathExp()
+CAY-2164 Relocate builder bootstrap methods from ServerRuntimeBuilder to ServerRuntime
 
 Bug Fixes:
 

http://git-wip-us.apache.org/repos/asf/cayenne/blob/15d6d2fd/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 90c3430..b352224 100644
--- a/docs/doc/src/main/resources/UPGRADE.txt
+++ b/docs/doc/src/main/resources/UPGRADE.txt
@@ -4,6 +4,12 @@ Apache Cayenne Upgrade Information
 IMPORTANT: be sure to read all notes for the intermediate releases between your
            current release and the release you are upgrading to.
 -------------------------------------------------------------------------------
+UPGRADING TO 4.0.M5
+
+* Per CAY-2164, creating a ServerRuntimeBuilder is done via a static method on ServerRuntime ("ServerRuntime.builder()").
+  The previous style (ServerRuntimeBuilder.builder()) is deprecated and will soon be removed, so you should replace it
+  with the new API.
+
 UPGRADING TO 4.0.M4
 
 * Per CAY-2133, LegacyObjectNameGenerator is no longer provided, as it wasn't possible to maintain it in a fully backwards-