@@ -214,6 +214,93 @@ that is specific to Oracle Database and the Oracle JDBC Driver. Extended options
214214are declared in the
215215[ OracleR2dbcOptions] ( src/main/java/oracle/r2dbc/OracleR2dbcOptions.java ) class.
216216
217+ #### Support for Supplier and Publisher as Option Values
218+ Most options can have a value provided by a ` Supplier ` or ` Publisher ` .
219+
220+ Oracle R2DBC requests the value of an ` Option ` from a ` Supplier ` or ` Publisher `
221+ each time the ` Publisher ` returned by ` ConnectionFactory.create() ` creates a new
222+ ` Connection ` . Each ` Connection ` can then be configured with values that change
223+ over time, such as a password which is periodically rotated.
224+
225+ If a ` Supplier ` provides the value of an ` Option ` , then Oracle R2DBC requests
226+ the value by invoking ` Supplier.get() ` . If ` get() ` returns ` null ` ,
227+ then no value is configured for the ` Option ` . If ` get() ` throws a
228+ ` RuntimeException ` , then it is set as the initial cause of an
229+ ` R2dbcException ` emitted by the ` Publisher ` returned by
230+ ` ConnectionFactory.create() ` . The ` Supplier ` must have a thread safe ` get() `
231+ method, as multiple subscribers may request connections concurrently.
232+
233+ If a ` Publisher ` provides the value of an ` Option ` , then Oracle R2DBC requests
234+ the value by subscribing to the ` Publisher ` and signalling demand.
235+ The first value emitted to ` onNext ` will be used as the value of the ` Option ` .
236+ If the ` Publisher ` emits ` onComplete ` before ` onNext ` , then no value is
237+ configured for the ` Option ` . If the ` Publisher ` emits ` onError ` before ` onNext ` ,
238+ then the ` Throwable ` is set as the initial cause of an
239+ ` R2dbcException ` emitted by the ` Publisher ` returned by
240+ ` ConnectionFactory.create() ` .
241+
242+ The following example configures the ` PASSWORD ` option with a ` Supplier ` :
243+ ``` java
244+ void configurePassword(ConnectionFactoryOptions . Builder optionsBuilder) {
245+
246+ // Cast the PASSWORD option
247+ Option<Supplier<CharSequence > > suppliedOption = OracleR2dbcOptions . supplied(PASSWORD );
248+
249+ // Supply a password
250+ Supplier<CharSequence > supplier = () - > getPassword();
251+
252+ // Configure the builder
253+ optionsBuilder. option(suppliedOption, supplier);
254+ }
255+ ```
256+ A more concise example configures ` TLS_WALLET_PASSWORD ` as a ` Publisher `
257+ ``` java
258+ void configurePassword(ConnectionFactoryOptions . Builder optionsBuilder) {
259+ optionsBuilder. option(
260+ OracleR2dbcOptions . published(TLS_WALLET_PASSWORD ),
261+ Mono . fromSupplier(() - > getWalletPassword()));
262+ }
263+ ```
264+ These examples use the ` supplied(Option) ` and ` published(Option) ` methods
265+ declared by ` oracle.r2dbc.OracleR2dbcOptions ` . These methods cast an ` Option<T> `
266+ to ` Option<Supplier<T>> ` and ` Option<Publisher<T>> ` , respectively. It is
267+ necessary to cast the generic type of the ` Option ` when calling
268+ ` ConnectionFactoryOptions.Builder.option(Option<T>, T) ` in order for the call to
269+ compile and not throw a ` ClassCastException ` at runtime. It is not strictly
270+ required that ` supplied(Option) ` or ` published(Option) ` be used to cast the
271+ ` Option ` . These methods are only meant to offer code readability and
272+ convenience.
273+
274+ Note that the following code would compile, but fails at runtime with a
275+ ` ClassCastException ` :
276+ ``` java
277+ void configurePassword(ConnectionFactoryOptions . Builder optionsBuilder) {
278+ Publisher<CharSequence > publisher = Mono . fromSupplier(() - > getPassword());
279+ // Doesn't work. Throws ClassCastException at runtime:
280+ optionsBuilder. option(PASSWORD , PASSWORD . cast(publisher));
281+ }
282+ ```
283+ To avoid a ` ClassCastException ` , the generic type of an ` Option ` must match the
284+ actual type of the value passed to
285+ ` ConnectionFactoryOptions.Builder.option(Option<T>, T) ` .
286+
287+ For a small set of options, providing values with a ` Supplier ` or ` Publisher `
288+ is not supported:
289+ - ` DRIVER `
290+ - ` PROTOCOL `
291+
292+ Providing values for these options would not be interoperable with
293+ ` io.r2dbc.spi.ConnectionFactories ` and ` r2dbc-pool ` .
294+
295+ Normally, Oracle R2DBC will not retain references to ` Option ` values after
296+ ` ConnectionFactories.create(ConnectionFactoryOptions) ` returns. However, if
297+ the value of at least one ` Option ` is provided by a ` Supplier ` or ` Publisher ` ,
298+ then Oracle R2DBC will retain a reference to all ` Option ` values until the
299+ ` ConnectionFactory.create() ` ` Publisher ` emits a ` Connection ` or error. This is
300+ important to keep in mind when ` Option ` values may be mutated. In particular,
301+ a password may only be cleared from memory after the ` create() ` ` Publisher `
302+ emits a ` Connection ` or error.
303+
217304#### Configuring an Oracle Net Descriptor
218305The ` oracle.r2dbc.OracleR2dbcOptions.DESCRIPTOR ` option may be used to configure
219306an Oracle Net Descriptor of the form ``` (DESCRIPTION=...) ``` . If this option is
0 commit comments