In normal scenario, your Application Module(AM) may have a static JDBC data source configured and will be connected to the single data base in all conditions. However there are cases where the application may need to display data from different data bases based on user profile. In today's post, I talk about an example for the above use case. Well, this is not a new topic as such. In fact, this has been discussed previously many times.
1. Dynamic JDBC Credentials example by Steve Muench
2. How To Support Dynamic JDBC Credentials
I'm copying the same solution in a slightly modified form ;)
Programmatically setting DataSource for an Application Module
A bit of theory before get in to the implementation. When a Fusion Web Page is getting rendered, UI controls may try to get data by evaluating the expression set for the value attribute. At this stage binding layer comes in to action, and will identify the underlying data provider(your Application Module) for the the specific attribute. When the binding layer refers Application Module, run time would either an instance or check out one from the AM pool. By default, AM instance is configured using the static meta data from bc4j.xcfg file, which is generated at design time. The design time configuration can be very well overridden by system parameters supplied at run time (java -Dproperty=value).
In the above use case, the requirement is to override the default data source specified for an AM. Interestingly, ADF BC provides a mechanism to override the configuration properties dynamically using a custom EnvInfoProvider. This part is well explained in Fusion Developer's Guide - 41.2.4 How to Programmatically Set Configuration Properties.
In this example, I'm trying to make use of this custom EnvInfoProvider which may get engaged whenever run time needs configuration properties for an Application Module. You may also need to keep jbo.ampool.dynamicjdbccredentials=true(default is true) to enable additional pooling lifecycle events to allow developer-written code to change the db credential.
The custom EnvInfoProvider used in this example may look like as shown in the following picture. You can see that the DynamicEnvInfoProvider::getInfo(...) overrides the default configuration property for Configuration.JDBC_DS_NAME(JDBC DataSource) using value from a session variable.
Note
Configuring a custom EnvInfoProvider for AM
There are two possible approaches for hooking your custom EnvInfoProvider with AM.
Approach 1 - Using custom session cookie factory class
a) Implement a custom session cookie factory class to set the custom EnvInfoProvider on the SessionCookie instance. Runtime will check for overridden EnvInfoProvider on the session cookie whenever JDBC data source needs to be created.
The following class diagram depicts the runtime engagement between the classes.
Approach 2 - Using Application Module configuration parameter - jbo.envinfoprovider
Configure 'jbo.envinfoprovider' to use custom EnvInfoProvider class using the AM configuration editor as shown in the following screen shot. Well, this seems to be more straight forward and much simpler compared to Approach 1.
The above action may update the bc4j.xcfg file as shown below.
Please note that, you may face some weird error at design time if you try modifying this property using JDeveloper 11.1.1.4.0 release. In case if the editor errors out while manipulating this property, then please follow the Approach 1(though you may need to add a couple of 'infrastructural' classes)
Download
You can download the sample workspace from here.
[Runs with Oracle JDeveloper 11g R1 PS3 + HR Schema]
How to run this sample?
The 'CoreBindingRuntime' project in the example workspace contains custom implementations for EnvInfoProvider and HttpSessionCookieFactory classes. Take a look at this project to see the implementations.
1. To run this example you may need to configure a JDBC Data Source (pointing to HR schema) in your weblogic server. You can do this using weblogic admin console.
2. Run the entry.jspx, key in the JNDI name of the JDBC data source(refer step 1) and click on command button
3. You can see the data source what you keyed at step 2 is used by the next page to execute the view object.
Learn More ...
There are a lot more points like this. If you are curious to learn the internals of the ADF Business Components and ADF Binding Layer, the following book is for you - Oracle ADF Real World Developer’s Guide.
More details about this book can be found in this post- http://jobinesh.blogspot.in/2012/07/pre-order-your-copy-of-oracle-adf-real.html
1. Dynamic JDBC Credentials example by Steve Muench
2. How To Support Dynamic JDBC Credentials
I'm copying the same solution in a slightly modified form ;)
Programmatically setting DataSource for an Application Module
A bit of theory before get in to the implementation. When a Fusion Web Page is getting rendered, UI controls may try to get data by evaluating the expression set for the value attribute. At this stage binding layer comes in to action, and will identify the underlying data provider(your Application Module) for the the specific attribute. When the binding layer refers Application Module, run time would either an instance or check out one from the AM pool. By default, AM instance is configured using the static meta data from bc4j.xcfg file, which is generated at design time. The design time configuration can be very well overridden by system parameters supplied at run time (java -Dproperty=value).
In the above use case, the requirement is to override the default data source specified for an AM. Interestingly, ADF BC provides a mechanism to override the configuration properties dynamically using a custom EnvInfoProvider. This part is well explained in Fusion Developer's Guide - 41.2.4 How to Programmatically Set Configuration Properties.
In this example, I'm trying to make use of this custom EnvInfoProvider which may get engaged whenever run time needs configuration properties for an Application Module. You may also need to keep jbo.ampool.dynamicjdbccredentials=true(default is true) to enable additional pooling lifecycle events to allow developer-written code to change the db credential.
The custom EnvInfoProvider used in this example may look like as shown in the following picture. You can see that the DynamicEnvInfoProvider::getInfo(...) overrides the default configuration property for Configuration.JDBC_DS_NAME(JDBC DataSource) using value from a session variable.
public class DynamicEnvInfoProvider implements EnvInfoProvider {
public Object getInfo(String infoType, Object env) {
if (EnvInfoProvider.INFO_TYPE_JDBC_PROPERTIES.equals(infoType)) {
Map session = ADFContext.getCurrent().getSessionScope();
Object dsName = session.get(Configuration.JDBC_DS_NAME);
if (dsName != null) {
if (((Hashtable)env).containsKey(Configuration.JDBC_DS_NAME)) {
((Hashtable)env).put(Configuration.JDBC_DS_NAME,
(String)dsName);
}
}
}
return null;
}
Note
When you enable dynamic credentials (jbo.ampool.dynamicjdbccredentials) the AM JDBC credentials will be updated whenever a new DataControl is constructed (new AM handle is created). The credentials will NOT be updated at the begin of each request in a stateful session, even though the AM is released at the end of each request.
Configuring a custom EnvInfoProvider for AM
There are two possible approaches for hooking your custom EnvInfoProvider with AM.
Approach 1 - Using custom session cookie factory class
a) Implement a custom session cookie factory class to set the custom EnvInfoProvider on the SessionCookie instance. Runtime will check for overridden EnvInfoProvider on the session cookie whenever JDBC data source needs to be created.
@Override
public SessionCookie createSessionCookie(String applicationId,
String sessionId,
ApplicationPool pool,
Properties properties) {
SessionCookie cookie =
super.createSessionCookie(applicationId, sessionId, pool,
properties);
EnvInfoProvider provider = new DynamicEnvInfoProvider();
cookie.setEnvInfoProvider(provider);
return cookie;
}
b)Configure AM to use the custom session cookie factory class The following class diagram depicts the runtime engagement between the classes.
Approach 2 - Using Application Module configuration parameter - jbo.envinfoprovider
Configure 'jbo.envinfoprovider' to use custom EnvInfoProvider class using the AM configuration editor as shown in the following screen shot. Well, this seems to be more straight forward and much simpler compared to Approach 1.
The above action may update the bc4j.xcfg file as shown below.
Please note that, you may face some weird error at design time if you try modifying this property using JDeveloper 11.1.1.4.0 release. In case if the editor errors out while manipulating this property, then please follow the Approach 1(though you may need to add a couple of 'infrastructural' classes)
<?xml version = '1.0' encoding = 'UTF-8'?>
<BC4JConfig version="11.1" xmlns="http://xmlns.oracle.com/bc4j/configuration">
<AppModuleConfigBag ApplicationName="model.AppModule">
<AppModuleConfig DeployPlatform="LOCAL" RELEASE_MODE="Stateless" jbo.project="model.Model" name="AppModuleLocal" ApplicationName="model.AppModule">
<AM-Pooling jbo.doconnectionpooling="true" />
<Database jbo.locking.mode="optimistic"/>
<Security AppModuleJndiName="model.AppModule"/>
<Custom JDBCDataSource="java:comp/env/jdbc/HRDS" jbo.envinfoprovider="binding.extension.DynamicEnvInfoProvider"/>
</AppModuleConfig>
</AppModuleConfigBag>
</BC4JConfig>
Download
You can download the sample workspace from here.
[Runs with Oracle JDeveloper 11g R1 PS3 + HR Schema]
How to run this sample?
The 'CoreBindingRuntime' project in the example workspace contains custom implementations for EnvInfoProvider and HttpSessionCookieFactory classes. Take a look at this project to see the implementations.
1. To run this example you may need to configure a JDBC Data Source (pointing to HR schema) in your weblogic server. You can do this using weblogic admin console.
2. Run the entry.jspx, key in the JNDI name of the JDBC data source(refer step 1) and click on command button
3. You can see the data source what you keyed at step 2 is used by the next page to execute the view object.
Learn More ...
There are a lot more points like this. If you are curious to learn the internals of the ADF Business Components and ADF Binding Layer, the following book is for you - Oracle ADF Real World Developer’s Guide.
More details about this book can be found in this post- http://jobinesh.blogspot.in/2012/07/pre-order-your-copy-of-oracle-adf-real.html
