Oracle® Application Development Framework Developer's Guide For Forms/4GL Developers 10g Release 3 (10.1.3.0) Part Number B25947-02 |
|
|
View PDF |
This chapter describes how ADF Business Components application module pools work and how you can tune the pools to optimize application performance.
This chapter includes the following sections:
Section 29.2, "Lifecycle of a Web Page Request Using Oracle ADF and JSF"
Section 29.8, "How Database and Application Module Pools Cooperate"
Section 29.9, "Database User State and Pooling Considerations"
An application module pool is a collection application module instances of the same type. For example, the SRDemo application has one or more instances of the SRService application module in it, based on the number of users that are visiting the site. This pool of application module instances is shared by multiple browser clients whose typical "think time" between submitting web pages allows optimizing the number of application module components to be effectively smaller than the total number of active users working on the system. That is, twenty users visiting the web site from their browser might be able to be serviced by 5 or 10 application module instances instead of having as many application module instances as you have browser users.
Application module components can be used to support web application scenarios that are completely stateless, or they can be used to support a unit of work that spans multiple browser pages. As a performance optimization, when an instance of an application module is returned to the pool in "managed state" mode, the pool keeps track that the application module is referenced by that particular session. The application module instance is still in the pool and available for use, but it would prefer to be used by the same session that was using it last time because maintaining this so-called "session affinity" improves performance.
So, at any one moment in time, the instances of application modules in the pool are logically partitioned into three groups, reflecting their state:
Unconditionally available for use
Available for use, but referenced for session affinity reuse by an active user session
Unavailable, inasmuch as it's currently in use (at that very moment) by some thread in the web container.
Section 29.3, "Understanding Configuration Property Scopes" describes the application module pool configuration parameters and how they affect the behavior of the pool.
Figure 29-1 shows a sequence diagram of the lifecycle of a web page request using JSF and Oracle ADF in tandem.
As shown in the figure, the basic flow of processing happens as follows:
A web request for http://yourserver/yourapp/faces/some.jsp
arrives from the client to the application server
The ADFBindingFilter
finds the ADF binding context in the HTTP session, and if not yet present, initializes it for the first time.
During binding context initialization, the ADFBindingFilter
:
Consults the servlet context initialization parameter named CpxFileName
and appends the *.cpx
file extension to its value to determine the name of the binding context metadata file. By default the parameter value will be "DataBindings
", so it will look for a file named DataBindings.cpx
.
Reads the binding context metadata file to discover the data control definitions, the page definition file names used to instantiate binding containers at runtime, and the page map that relates a JSP page to its page definition file.
Constructs an instance of each Data Control, and a reference to each BindingContainer. The contents of each binding container are loaded lazily the first time they are used by a page.
The ADFBindingFilter
invokes the beginRequest()
method on each data control participating in the request. This gives every data control a notification at the start of every request where they can perform any necessary setup.
An application module data control uses the beginRequest
notification to acquire an instance of the application module from the application module pool.
The JSF Lifecycle
class, which is responsible for orchestrating the standard processing phases of each request, notifies the ADFPhaseListener
class during each phase of the lifecycle so that it can perform custom processing to coordinate the JSF lifecycle with the Oracle ADF Model data binding layer.
Note:
TheFacesServlet
(in javax.faces.webapp
) is configured in the web.xml
file of a JSF application and is responsible for initially creating the JSF Lifecycle
class (in javax.faces.lifecycle
) to handle each request. However, since it is the Lifecycle
class that does all the interesting work, the FacesServlet is not shown in the diagram.The ADFPhaseListener
creates an ADF PageLifecycle
object to handle each request and delegates appropriate before/after phase methods to corresponding methods in the ADF PageLifecycle
class as shown in Figure 29-2. If the appropriate binding container for the page has never been used before during the user's session, it is created.
The JSF Lifecycle
forwards control to the page to be rendered.
The UI components on the page access value bindings and iterator bindings in the page's binding container and render the formatted output to appear in the browser.
The ADFBindingFilter
invokes the endRequest()
method on each data control participating in the request. This gives every data control a notification at the end of every request where they can perform any necessary resource cleanup.
An application module data control uses the endRequest
notification to release the instance of the application module back to the application module pool.
The user sees the resulting page in the browser.
Each runtime configuration property used by ADF Business Components has a scope. The scope of each property indicates at what level the property's value is evaluated and whether its value is effectively shared (i.e. static) in a single Java VM, or not. The ADF Business Components PropertyManager
class is the registry of all supported properties. It defines the property names, their default values, and their scope. This class contains a main()
method so that you can run the class from the command line to see a list of all the configuration property information.
Assuming JDEVHOME is the JDeveloper 10g installation directory, to see this list of settings for reference, do the following:
$ java -cp JDEVHOME/BC4J/lib/bc4jmt.jar oracle.jbo.common.PropertyManager
Issuing this comman will send all of the ADF Business Components configuration properties to the console. It also lists a handy reference about the different levels at which you can set configuration property values and remind you of the precedence order these levels have:
--------------------------------------------------------------- Properties loaded from following sources, in order: 1. Client environment [Provided programmatically or declaratively in bc4j.xcfg] 2. Applet tags 3. -D flags (appear in System.properties) 4. bc4j.properties file (in current directory) 5. /oracle/jbo/BC4J.properties resource 6. /oracle/jbo/commom.jboserver.properties resource 7. /oracle/jbo/common.Diagnostic.properties resource 8. System defined default ---------------------------------------------------------------
You'll see each property is listed with one of the following scopes:
MetaObjectManager
Properties at this scope are initialized once per Java VM when the ADF PropertyManager is first initialized.
SessionImpl
Properties at this scope are initialized once per invocation of ApplicationModule.prepareSession()
.
Configuration
Properties at this scope are initialized when the ApplicationModule pool is first created and the application module's configuration is read the first time.
Diagnostic
Properties at this scope are specific to the built-in ADF Business Components diagnostic facility.
At each of these scopes, the layered value resolution described above is performed when the properties are initialized. Whenever property values are initialized, if you have specified them in the Client Environment (level 1 in the resolution order) the values will take precedence over values specified as System parameters (level 3 in the resolution order).
The Client Environment is a hashtable of name/value pairs that you can either programatically populate, or which will be automatically populated for you by the Configuration
object when loaded, with the name/value pairs it contains in its entry in the bc4j.xcfg
file. The implication of this is that for any properties scoped at MetaObjectManager level, the most reliable way to ensure that all of your application modules use the same default value for those properties is to do both of the following:
Make sure the property value does not appear in any of your application module's bc4j.xcfg
file configuration name/value pair entries.
Set the property value using a Java system property in your runtime environment.
If, instead, you leave any MetaObjectManager-scoped properties in your bc4j.xcfg
files, you will have the undesirable behavior that they will take on the value specified in the configuration of the first application module whose pool gets created after the Java VM starts up.
You control the runtime behavior of an application module pool by setting appropriate configuration parameters. You can set these declaratively in an application module configuration, supply them as Java System parameters, or set them programmatically at runtime.
The Pooling and Scalability tab of the Configuration Editor shown in Figure 29-3 is used for seeing and setting parameters.
The values that you supply through the Configuration Manager are saved in an XML file named bc4j.xcfg
in the ./common subdirectory relative to the application module's XML component definition. All of the configurations for all of the application modules in a single Java package are saved in that same file.
For example, if you look at the bc4j.xcfg
file in the ./oracle/srdemo/model/common
directory of the SRDemo application's DataModel
project, you will see the two named configurations for its SRService
application module, as shown in Example 29-1. The SRServiceLocalTesting
configuration uses JDBC URL connections for use by the SRDemo application's JUnit tests and by the Business Components Browser. The SRServiceLocal
uses JDBC Datasource names and is used by the web application.
Example 29-1 Configuration Settings for the SRService Application Module
<BC4JConfig> <AppModuleConfigBag> <AppModuleConfig name="SRServiceLocal"> <DeployPlatform>LOCAL</DeployPlatform> <JDBCDataSource>java:comp/env/jdbc/SRDemoDS</JDBCDataSource> <jbo.project>DataModel</jbo.project> <jbo.locking.mode>optimistic</jbo.locking.mode> <AppModuleJndiName>oracle.srdemo.model.SRService</AppModuleJndiName> <jbo.security.enforce>Must</jbo.security.enforce> <ApplicationName>oracle.srdemo.model.SRService</ApplicationName> <jbo.server.internal_connection >java:comp/env/jdbc/SRDemoCoreDS</jbo.server.internal_connection> </AppModuleConfig> <AppModuleConfig name="SRServiceLocalTesting"> <DeployPlatform>LOCAL</DeployPlatform> <JDBCName>SRDemo</JDBCName> <jbo.project>DataModel</jbo.project> <AppModuleJndiName>oracle.srdemo.model.SRService</AppModuleJndiName> <jbo.locking.mode>optimistic</jbo.locking.mode> <jbo.security.enforce>Must</jbo.security.enforce> <ApplicationName>oracle.srdemo.model.SRService</ApplicationName> </AppModuleConfig> </AppModuleConfigBag> <ConnectionDefinition name="SRDemo"> <ENTRY name="JDBC_PORT" value="1521"/> <ENTRY name="ConnectionType" value="JDBC"/> <ENTRY name="HOSTNAME" value="localhost"/> <ENTRY name="DeployPassword" value="true"/> <ENTRY name="user" value="srdemo"/> <ENTRY name="ConnectionName" value="SRDemo"/> <ENTRY name="SID" value="XE"/> <ENTRY name="password"> <![CDATA[{904}05708016F4BB90FC04CFE36B6C9D2BDFE5]]> </ENTRY> <ENTRY name="JdbcDriver" value="oracle.jdbc.OracleDriver"/> <ENTRY name="ORACLE_JDBC_TYPE" value="thin"/> <ENTRY name="DeployPassword" value="true"/> </ConnectionDefinition> </BC4JConfig>
Note that child elements of the AppModuleConfig tag appear with tag names matching their property values. It's also important to understand that if a property is currently set to its runtime default value, then the Configuration Manager does not write the entry to the bc4j.xcfg
file.
As an alternative to specifying configuration properties in the bc4j.xcfg
file, you can also set Java VM system parameters with the same property names. These system parameters will be used only if a corresponding property does not exist in the relevant bc4j.xcfg
file for the application module in question. In other words, configuration parameters that appear in the application module configuration take precedence over parameters of the same name supplied as Java system parameters.
You typically set Java system parameters using the -D
command line flag to the Java VM like this:
java -Dproperty=value -jar yourserver.jar
Alternatively, your J2EE container probably has a section in its own configuration files where Java system parameters can be specified for use at J2EE container startup time.
Many customers adopt the best practice technique of supplying site-specific default values for ADF configuration parameters as Java system parameters and then make sure that their bc4j.xcfg
files do not include references to these parameters unless an application-module-specific exception to these global default values is required.
Using OC4J you can specify these parameters either as -D
Java system parameters on the command line that starts OC4J, or provide them — one per line — in the oc4j.properties
file and add the -properties oc4j.properties
command line flag to OC4J at startup.
Caution:
The values of Idle Instance Timeout, Pool Polling Interval settings for both the Application Pool and the database Connection Pool are displayed and edited in this dialog as a number of seconds, but are saved to the configuration file in milliseconds. If you provide a value for any of these four parameters as a Java System parameter — or if you hand-edit thebc4j.xcfg
file — make sure to provide these time interval values in milliseconds!You can set configuration properties programmatically by creating a Java class that implements the EnvInfoProvider
interface in the oracle.jbo.common.ampool
package. In your class, you override the getInfo()
method and call put()
to put values into the environment Hashtable passed in as shown in Example 29-2
Example 29-2 Setting Environment Properties with a Custom EnvInfoProvider
package devguide.advanced.customenv.view; import java.util.Hashtable; import oracle.jbo.common.ampool.EnvInfoProvider; /** * Custom EnvInfoProvider implementation to set * environment properties programmatically */ public class CustomEnvInfoProvider implements EnvInfoProvider { /** * Overridden framework method to set custom values in the * environment hashtable. * * @param string - ignore * @param environment Hashtable of config parameters * @return null - not used */ public Object getInfo(String string, Object environment) { Hashtable envHashtable = (Hashtable)environment; envHashtable.put("some.property.name","some value"); return null; } /* Required to implement EnvInfoProvider */ public void modifyInitialContext(Object object) {} /* Required to implement EnvInfoProvider */ public int getNumOfRetries() {return 0;} }
When creating an application module for a stateless or command-line-client, with the createRootApplicationModule()
method of the Configuration
class, you can pass the custom EnvInfoProvider as the optional second argument. In order to use a custom EnvInfoProvider in an ADF web-based application, you need to implement a custom session cookie factory class as shown in Example 29-3. To use your custom session cookie factory, set the jbo.ampool.sessioncookiefactoryclass
configuration property to the fully-qualified name of your custom session cookie factory class.
Example 29-3 Custom SessionCookieFactory to Install a Custom EnvInfoProvider
package devguide.advanced.customenv.view; import java.util.Properties; import oracle.jbo.common.ampool.ApplicationPool; import oracle.jbo.common.ampool.EnvInfoProvider; import oracle.jbo.common.ampool.SessionCookie; import oracle.jbo.http.HttpSessionCookieFactory; /** * Example of custom http session cookie factory * to install a custom EnvInfoProvider implementation * for an ADF web-based application. */ public class CustomHttpSessionCookieFactory extends HttpSessionCookieFactory { public SessionCookie createSessionCookie(String appId, String sessionId, ApplicationPool pool, Properties props) { SessionCookie cookie = super.createSessionCookie(appId, sessionId,pool, props); EnvInfoProvider envInfoProv = new CustomEnvInfoProvider(); cookie.setEnvInfoProvider(envInfoProv); return cookie; } }
There are two kinds of pools in use when running a typical ADF web application, Application Module pools and database connection pools. It's important to understand how many of each kind of pool your application will create.
Application Module components can be used at runtime in two ways:
As an application module the client accesses directly
As a reusable component aggregated (or "nested") inside of another application module instance
When a client accesses it directly, an application module is called a root application module. Clients access nested application modules indirectly as a part of their containing application module instance. It's possible, but not common, to use the same application module at runtime in both ways. The important point is that ADF only creates an application module pool for a root application module.
The basic rule is that one application module pool is created for each root application module used by an ADF web application in each Java VM where a root application module of that type is used by the ADF controller layer.
ADF web applications always use a database connection pool, but which one they use for your application modules depends on how they define their connection:
JDBC URL (e.g. jdbc:oracle:thin:@penguin:1521:ORCL
)
JNDI Name for a Datasource (e.g. java:comp/env/jdbc/YourConnectionDS
)
If you supply a JDBC URL connection while configuring your application module — which happens when you select a JDeveloper named connection which encapsulates the JDBC URL and username information — then the ADF database connection pool will be used for managing the connection pool.
If you supply the JNDI name of a JDBC Datasource then the ADF database connection pool will not be used and the configuration parameters described below relating to the ADF database connection pool are not relevant.
Note:
To configure the database connection pool for JDBC Datasources looked-up by JNDI from your J2EE Web and/or EJB container, consult the documentation for your J2EE container to understand the pooling configuration options and how to set them.When using ADF database connection pooling, you have the following basic rule: One database connection pool is created for each unique <JDBCURL,Username> pair, in each Java VM where a <JDBCURL,Username> connection is requested by a root application used by the ADF controller layer.
Section 29.5.3.1, "Single Oracle Application Server Instance, Single OC4J Container, Single JVM" and Section 29.5.3.2, "Multiple Oracle Application Server Instances, Single OC4J Container, Multiple JVMs" illustrate how application module pools and connection pools are created in different scenarios. Both of these sections make the following assumptions:
Your web application makes use of two application modules HRModule
and PayablesModule
.
You have a CommonLOVModule
containing a set of commonly used view objects to support list-of-values in your application, and that both HRModule
and PayablesModule
aggregate a nested instance of CommonLOVModule
to access the common LOV view objects it contains.
You have configured both HRModule
and PayablesModule
to use the same JDeveloper connection definition named appuser
.
In both HRModule
and PayablesModule
you have configured jbo.passivationstore=database
(the default) and configured the ADF "internal connection" (jbo.server.internal_connection
) used for state management persistence to have the value of a fully-qualified JDBC URL that points to a different username than the appuser
connection does.
Consider how many pools of which kinds are created for this application in both a single JVM and multiple JVM runtime scenario.
If you deploy this application to a single Oracle Application Server instance, configured with a single OC4J container having a single Java VM, there is only a single Java VM available to service the web requests coming from your application users.
Assuming that all the users are making use of web pages that access both the HRModule
and the PayablesModule
, this will give:
One application module pool for the HRModule
root application module
One application module pool for the PayablesModule
root application module
One DB connection pool for the appuser
connection
One DB connection pool for the JDBC URL supplied for the internal connection for state management.
This gives a total of two application module pools and two database pools in this single Java VM.
Note:
There is no separate application module pool for the nested instances of the reusableCommonLOVModule
. Instances of CommonLOVModule are wrapped by instances of HRModule
and PayablesModule
in their respective application module pools.Next consider a deployment environment involving multiple Java VMs. Assume that you have installed Oracle Application Server 10g (version 9.0.4) onto two different physical machines, with a hardware load-balancer in front of it. On each of these two machines, imagine that the Oracle Application Server instance is configured to have one OC4J container with two JVMs. As users of your application access the application, their requests are shared across these two Oracle Application Server instances, and within each Oracle Application Server instance, across the two JVMs that its OC4J container has available.
Again assuming that all the users are making use of web pages that access both the HRModule
and the PayablesModule
, this will give:
Four application module pools for HRModule
, one in each of four JVMs.
(1 HRModule
root application module) x (2 Oracle Application Server Instances) x (2 OC4J JVMs each)
Four application module pools for PayablesModule
, one in each of four JVMs.
(1 PayablesModule
root application module) x (2 Oracle Application Server Instances) x (2 OC4J JVMs each)
Four DB connection pools for appuser
, one in each of four JVMs.
(1 appuser
DB connection pool) x (2 Oracle Application Server Instances) x (2 OC4J JVMs each)
Four DB connection pools for the internal connection JDBC URL, one in each of four JVMs.
(1 internal connection JDBC URL DB connection pool) x (2 Oracle Application Server Instances) x (2 OC4J JVMs each)
This gives a total of eight application module pools and eight DB connection pools spread across four JVMs.
As you begin to explore the configuration parameters for the application module pools in Section 29.6, "Application Module Pool Parameters", keep in mind that the parameters apply to a given application module pool for a given application module in a single JVM.
As the load balancing spreads user request across the multiple JVMs where ADF is running, each individual application module pool in each JVM will have to support one N
th of the user load — where N
is number of JVMs available to service those user requests. The appropriate values of the application module and DB connection pools need to be set with the number of Java VMs in mind.
The application module pool configuration parameters fall into three logical categories relating to pool behavior, pool sizing, and pool cleanup behavior.
Table 29-2 lists the application module configuration parameters that affect the behavior of the application module pool.
Table 29-1 Application Module Pool Behavior Configuration Parameters
Pool Configuration Parameter | Description |
---|---|
Failover Transaction State Upon Managed Release ( |
Enables eager passivation of pending transaction state each time an application module is released to the pool in "Managed State" mode. See Section 28.2.3, "How Passivation Changes When Optional Failover Mode is Enabled" for more information. This feature is disabled by default ( |
Disconnect Application Module Upon Release ( |
Forces the application module pool to release the JDBC connection used each time the application module is released to the pool. See Section 29.8, "How Database and Application Module Pools Cooperate" for more information. This feature is disabled by default ( |
Support Dynamic JDBC Credentials ( |
Enables additional pooling lifecycle events to allow developer-written code to change the database credentials (username/password) each time a new user session begins to use the application module. This feature is enabled by default ( |
Reset Non-Transactional State Upon Unmanaged Release ( |
Forces the application module to reset any non-transactional state like view object runtime settings, JDBC prepared statements, bind variable values, etc. when the application module is released to the pool in unmanaged or "stateless" mode. This feature is enabled by default ( |
Enable Application Module Pooling ( |
Enables the application module pooling facility. See Section 28.8, "Testing to Ensure Your Application Module is Activation-Safe" for more information on when Oracle recommends to disable this feature as a routine part of your application testing. This feature is enabled by default ( |
Table 29-2 lists the application module configuration parameters that affect the sizing of the application module pool.
Table 29-2 Application Module Pool Sizing Configuration Parameters
Pool Configuration Parameter | Description |
---|---|
Initial Pool Size ( |
The number of application module instances to created when the pool is initialized. The default is |
Maximum Pool Size ( |
The maximum number of application module instances that the pool can allocate. The pool will never create more application module instances than this limit imposes. The default is |
Referenced Pool Size ( |
The maximum number of application module instances in the pool that attempt to preserve session affinity for the next request made by the session which used them last before releasing them to the pool in managed-state mode. The referenced pool size should always be less than or equal to the maximum pool size. The default is to allow |
Maximum Instance Time to Live ( |
The number of milliseconds after which to consider an application module instance in the pool as a candidate for removal during the next resource cleanup regardless of whether it would bring the number of instances in the pool below minavailablesize. The default is 3600000 milliseconds of total time to live (which is 3600 seconds, or one hour) |
A single "application module pool monitor" per Java VM runs in a background thread and wakes up every so often to do resource reclamation. Table 29-3 lists the parameters that affect how resources are reclaimed when the pool monitor does one of its resource cleanup passes.
Note:
Since there is only a single application monitor pool monitor per Java VM, the value that will effectively be used for the application module pool monitor polling interval will be the value found in the application module configuration read by the first application module pool that gets created. To make sure this value is set in a predictable way, it is best practice to set all application modules to use the same Pool Polling Interval value.Table 29-3 Application Module Resource Management Configuration Parameters
Pool Configuration Parameter | Description |
---|---|
Pool Polling Interval ( |
The length of time in milliseconds between pool resource cleanup. While the number of application module instances in the pool will never exceed the maximum pool size, available instances which are candidates for getting removed from the pool do not get "cleaned up" until the next time the application module pool monitor wakes up to do its job. The default is to have the application module pool monitor wake up every |
Maximum Available Size ( |
The ideal maximum number of application module instances in the pool when not under abnormal load. When the pool monitor wakes up to do resource cleanup, it will try to remove available application module instances to bring the total number of available instances down to this ideal maximum. Instances that have been not been used for a period longer than the idle instance time-out will always get cleaned up at this time, then additional available instances will be removed if necessary to bring the number of available instances down to this size. The default maximum available size is |
Minimum Available Size ( |
The minimum number of available application module instances that the pool monitor should leave in the pool during a resource cleanup operation. Set to zero ( The default is |
Idle Instance Timeout ( |
The number of milliseconds after which to consider an inactive application module instance in the pool as a candidate for removal during the next resource cleanup. The default is 600000 milliseconds of idle time (which is 600 seconds, or ten minutes). |
Maximum Instance Time to Live ( |
The number of milliseconds after which to consider an connection instance in the pool as a candidate for removal during the next resource cleanup regardless of whether it would bring the number of instances in the pool below minavailablesize. The default is 3600000 milliseconds of total time to live (which is 3600 seconds, or one hour) |
If you are using a JDBC URL for your connection information so that the ADF database connection pool is used, then configuration parameters listed in Table 29-4 can be used to tune the behavior of the database connection pool. A single "database connection pool monitor" per Java VM runs in a background thread and wakes up every so often to do resource reclamation. The parameters in Table 29-3 include the ones that affect how resources are reclaimed when the pool monitor does one of its resource cleanup passes.
Note:
The configuration parameters for database connection pooling have MetaObjectManager scope (described in Section 29.3, "Understanding Configuration Property Scopes" earlier). This means their settings are global and will be set once when the first application module pool in your application is created. To insure the most predictable behavior, Oracle recommends leaving the values of these parameters in the Connection Pooling section of the Pooling and Scalability tab at their default values — so that no entry for them is written into thebc4j.xcfg
file — and to instead set the desired values for the database connection pooling tuning parameters as Java System Parameters in your J2EE container.Table 29-4 Database Connection Pool Parameters
Pool Configuration Parameter | Description |
---|---|
Initial Pool Size ( |
The number of JDBC connection instances to created when the pool is initialized The default is an initial size of |
Maximum Pool Size ( |
The maximum number of JDBC connection instances that the pool can allocate. The pool will never create more JDBC connections than this imposes. The default is |
Pool Polling Interval ( |
The length of time in milliseconds between pool resource cleanup. While the number of JDBC connection instances in the pool will never exceed the maximum pool size, available instances which are candidates for getting removed from the pool do not get "cleaned up" until the next time the JDBC connection pool monitor wakes up to do its job. The default is |
Maximum Available Size ( |
The ideal maximum number of JDBC connection instances in the pool when not under abnormal load. When the pool monitor wakes up to do resource cleanup, it will try to remove available JDBC connection instances to bring the total number of available instances down to this ideal maximum. Instances that have been not been used for a period longer than the idle instance time-out will always get cleaned up at this time, then additional available instances will be removed if necessary to bring the number of available instances down to this size. The default is an ideal maximum of |
Minimum Available Size ( |
The minimum number of available JDBC connection instances that the pool monitor should leave in the pool during a resource cleanup operation. Set to zero ( The default is to not let the minimum available size drop below |
Idle Instance Timeout ( |
The number of seconds after which to consider an inactive JDBC connection instance in the pool as a candidate for removal during the next resource cleanup. The default is |
Notice that since the database connection pool does not implement the heuristic of session affinity, there is no configuration parameter for the database connection pool which controls the referenced pool size.
You should take care not to configure the jbo.ampool.monitorsleepinterval
(for the application module pools) or the jbo.poolmonitorsleepinterval
(for the DB pools) to be too short of a time period because the chance exists — with a large number of application module pools to cleanup — that your next pool monitor "wakeup" might occur while your previous cleanup-cycle is still going on. The default of 10 minutes (600000
milliseconds) is reasonable. Setting it to something like 10 seconds (10000
milliseconds) might cause trouble.
How ADF application module pools use the database connection pool depends on the setting of the jbo.doconnectionpooling
application module configuration parameter. In the Configuration Manager panel that you see in Figure 29-3, you set this parameter using the checkbox labelled Disconnect Application Module Upon Release.
Note:
The notion of disconnecting the application module upon release to the pool better captures what the actual feature is doing than the related configuration parameter name (jbo.doconnectionpooling
) does. The setting of jbo.doconnectionpooling=false
does not mean that there is no database connection pooling happening. What it means is that the application module is not disconnected from its JDBC connection upon check in back to the application module pool.If the default setting of jbo.doconnectionpooling=false
is used, then when an application module instance is created in any pool it acquires a JDBC connection from the appropriate connection pool (based on the JDBC URL in the ADF case, or from the underlying JDBC data source implementation's pool in the case of a JNDI data source name). That application module instance holds onto the JDBC connection object that it acquired from the pool until the application module instance is removed from the application module pool. During its lifetime, that application module instance may service many different users, and ADF worries about issuing rollbacks on the database connection so that different users don't end up getting pending database state confused. By holding onto the JDBC connection, it allows each application module instance to keep its JDBC PreparedStatements's open and usable across subsequent accesses by clients, thereby providing the best performance.
If jbo.doconnectionpooling=true
, then each time a user session finishes using an application module (typically at the end of each HTTP request), the application module instance disassociates itself with the JDBC connection it was using on that request and it returns it to the JDBC connection pool. The next time that application module instance is used by a user session, it will reacquire a JDBC connection from the JDBC connection pool and use it for the span of time that application module is checked out of the application module pool (again, typically the span of one HTTP request). Since the application module instance "unplugs" itself from the JDBC connection object used to create the PreparedStatements it might have used during the servicing of the current HTTP request, those PreparedStatements are no longer usable on the next HTTP request because they are only valid in the context of the Connection object in which they were created. So, when using the connection pooling mode turned on like this, the trade-off is slightly more JDBC overhead setup each time, in return for using a smaller number of overall database connections.
The key difference is seen when many application module pools are all using the same underlying database user for their application connection.
If 50 different application module pools each have even just a single application module instance in them, with jbo.doconnectionpooling=false
there will be 50 JDBC application connections in use. If the application module pooling parameters are set such that the application module pools are allowed to shrink to 0
instances after an appropriate instance idle timeout by setting jbo.ampool.minavailablesize=0
, then when the application module is removed from its pool, it will put back the connection its holding onto.
In contrast, if 50 different application module pools each have a single application module instance and jbo.doconnectionpooling=true
, then the amount of JDBC connections in use will depend on how many of those application modules are simultaneously being used by different clients. If an application module instance is in the pool and is not currently being used by a user session, then with jbo.doconnectionpooling=true
it will have released its JDBC connection back to the connection pool and while the application module instance is sitting there waiting for either another user to need it again, or to eventually be cleaned up by the application module pool monitor, it will not be "hanging on" to a JDBC connection.
For highest performance, Oracle recommends not disconnecting the application module instance from its database connection on each check in to the application module pool. Accordingly, the default setting of the jbo.doconnectionpooling
configuration parameter is false
. The pooling of application module instances is already an effective way to optimize resource usage, and there are runtime efficiencies that Oracle ADF can gain if you do not have to disconnect application module instances from their associated JDBC connection after each release to the pool. Effectively, by pooling the application modules which are related one-to-one with a JDBC connection, you are already achieving a pooling of database connections that is optimal for most web applications.
In contrast to Oracle's default recommendation, one situation in which it might be opportune to use database connection pooling is when you have a large number of application module pools all needing to use database connections from the same underlying application user at the database level. In this case, the many application module pools can perhaps economize on the total overall database sessions by sharing a single, underlying database connection pool of JDBC connections, albeit at a loss of efficiency of each one. This choice would be favored only if total overall database sessions is of maximum priority.
Sometimes you may need to invoke stored procedures to initialize database state related to the current user's session. The correct place to perform this initialization is in an overridden prepareSession()
method of your application module.
The default setting for jbo.doconnectionpooling
is false
. This means the application module instance hangs onto its JDBC connection while it's in the application module pool. This is the most efficient setting because the application module can keep its JDBC prepared statements open across application module checkouts/checkins.The application module instance will trigger its prepareSession()
method each time a new user session begins using it.
If you set jbo.doconnectionpooling
to true
, then on each checkout of an application module from the pool, that application module pool will acquire a JDBC connection from the database connection pool and use it during the span of the current request. At the end of the request when the application module is released back to the application module pool, that application module pool releases the JDBC connection it was using back to the database connection pool.
It follows that with jbo.doconnectionpooling
set to true
the application module instance in the pool may have a completely different JDBC connection each time you check it out of the pool. In this situation, the prepareSession()
method will fire each time the application module is checked out of the pool to give you a chance to reinitialize the database state.
The SRDemo application includes a simple example of setting database state on a per-user basis. It uses the following PL/SQL package to set and get a package-level variable that holds the name of the currently authenticated web application user.
Example 29-4 SRDemo CONTEXT_PKG PL/SQL Package
create or replace package context_pkg as procedure set_app_user_name(username varchar2); function app_user_name return varchar2; end context_pkg;
The WHERE clause of the ServiceHistories
view object in the demo references the context_pkg.app_user_name
function to illustrate how your application queries might reference the per-user state.
Note:
In practice, you will typically create a databaseCONTEXT
namespace, associate a PL/SQL procedure with it, and then use the SYS_CONTEXT()
SQL function to reference values from the context. however the simple PL/SQL package above was enough to illustrate the mechanics involved in setting and referencing the user state without further complicating the installation of the SRDemo application, so the demo's authors chose this simpler approach to keep the demo more straightforward.The SRApplicationModuleImpl
framework extension class in the FrameworkExtensions
project includes a callStoredProcedure()
helper method similar to the ones in Section 25.5.2, "Invoking Stored Procedure with Only IN Arguments". The SRServiceImpl
application module class extends this class and defines the setCurrentUserInPLSQLPackage()
helper method shown in Example 29-5 that uses the callStoredProcedure()
method to invoke context_pkg.set_app_user_name()
stored procedure, passing the value of the currently authenticated user as a parameter value.
Example 29-5 Method to Call Context_Pkg.Set_App_User_Name Stored Procedure
// In SRServiceImpl.java public void setCurrentUserInPLSQLPackage() { String user = getUserPrincipalName(); callStoredProcedure("context_pkg.set_app_user_name(?)",new Object[]{user}); }
With this helper method in place, the SRServiceImpl
class then overrides the prepareSession()
method as shown in Example 29-6.
Example 29-6 Overridden afterConnect() and prepareSession() to Set Database State
// In SRServiceImpl.java
protected void prepareSession(Session session) {
super.prepareSession(session);
getLoggedInUser().retrieveUserInfoForAuthenticatedUser();
setUserIdIntoUserDataHashtable();
setCurrentUserInPLSQLPackage();
}