|
|||||||||
PREV PACKAGE NEXT PACKAGE | FRAMES NO FRAMES |
This package contains generic components for the IdM Connection Framework.
See:
Description
Interface Summary | |
---|---|
ConnectionDelegate | This interface defines methods that need to be supported by connection delegates. |
ConnectionListener | This interface specifies the method needed to be implemented by connection listeners. |
Class Summary | |
---|---|
Connection | This class represents connections and various information that can be collected about connections in this framework. |
Connection.CountInfo | This class maintains connection count information. |
Connection.Match | This class facilitates connection matching. |
Connection.Operation | This class defines common connection operations. |
Connection.Operation.CountInfo | This class maintains connection operation count information. |
Connection.Operation.FailSafe | This class maintains fail-safe levels for connection operations. |
Connection.Operation.Intrinsic | This class defines intrinsic connection operations. |
Connection.Parameter | This class defines commonly used connection parameters. |
Connection.Parameter.Intrinsic | This class defines intrinsic connection parameters. |
Connection.Status | This class defines common connection statuses. |
ConnectionEvent | This class represents a connection event. |
ConnectionEvent.CountInfo | This class maintains connection event count information. |
ConnectionGroup | This class implements the connection group. |
ConnectionLogger | This class logs connections events into memory and to the specified destination. |
ConnectionLogger.Operator | This class defines connection logger operators. |
ConnectionManager | This is an abstract superclass for all connection mamagers. |
ConnectionPool | This class implements the connection pool. |
Exception Summary | |
---|---|
ConnectionException | This class represents connection exceptions. |
This package contains generic components for the IdM Connection Framework.
Author: Adam Victor
This document describes the Identity Management Connection Framework.
The following sections outline the high level feature of the IdM Connection Framework.
The framework allows for a very simple (homogeneous) to a very complex (heterogeneous) configuration.
The simplest configuration involves homogeneous connection usage from a single connection host. In this mode, the following features are available.
Connections can be captured from and released into the pool. When a connection is captured, it is still managed by the connection pool. The connection pool enforces a capture timeout, meaning that any connection that is not released back into the pool within the specified timeout will be invalidated and closed. Captured connections should be released back into the pool.
Connections can be removed from and returned to the pool. When a connection is removed, it is no longer managed by the pool. The user is free to use the connection for as long as needed. Removed connections need not be returned back to the pool.
If it is possible to proxy connections on behalf of different users, rather than reestablish a new one for each different user identity, the connection framework provides for hooks to take advantage of this feature. The connection pool observes the proxy timeout, and a connection will be available to be proxied to a different user identity only after the proxy timeout has been reached. This feature will prevent proxy thrashing under have usage.
A captured or removed connection can be validated upon a user's request. If the validation attempt is not successful, the connection will be automatically invalidated and closed.
The connection pool validates connections on a regular basis. The validate timeout is observed by the pool, and a connection will not be revalidated until its validate timeout has been reached.
A captured or removed connection can be invalidated upon a user's request. All invalidated connections are automatically closed.
The connection pool can invalidate connections randomly, as defined by the "random invalidation" property. The connections are randomly invalidated at the inverse rate specified by this property, to simulate failures that may occur in real productions systems.
The framework traces all connection operations. This includes operation parameter and stack tracing. The stack tracing can be tuned off or on the pool level. Parameter tracing is always on. These features ease debugging of connection usage within the framework.
The framework keeps track of connection operation metrics. This feature simplifies integration with Enterprise Manager agents.
The framework allows fail-safe operation by setting fail-safe levels for each connection delegate. Implementations of connection delegates will attempt repeating any given operation as many times as specified by the fail-safe level.
The framework has intrinsic ability to detect connection leaks if the connections are captured, and never released back into the pool. If the connections are removed, they need not be returned to the pool, and connection leak detection is not available in that case.
The framework has intrinsic ability to enforce connection integrity. When users capture or remove connections from the pool, they may alter the connection in a way that may make it unusable for further requests. The connection pool provides a mechanism to check for connection integrity upon release and return operations to make sure all connections in the pool remain usable for further requests.
A more complex configuration involves a heterogeneous connection usage of different connection types from multiple connection hosts. In this mode, the following features are also available.
If any of the multiple connection hosts become unavailable, the framework will automatically use another connection host to create new connections. The order in which connection hosts are selected depends on their priorities and loads.
The following priority modes are available:
Each connection host is load balanced depending on the load. A weight can be associated with each connection host so that hosts with a heavier weight will be used more often to serve connection operations. The load is calculated based on this formula:
load = (open count - close count) / weight
The following priority modes are available:
If preemptive validation is turned on, a connection will be validated upon capture or removal. If the connection validation fails, the connection will be invalidated and closed, and another connection from an alternate connection host will be used. Depending on the preemptive validation retry rate, this process will be repeated until all available connection hosts have been tried or the preemptive validation retry rate has been reached.
Connections can be used in a sticky fashion, meaning once a connection request has been delegated to a particular connection host, the same connection host will be used for all subsequent connection operations as long as the same connection sticker has been specified. This ensures consistent end user experience with respect to the data coming from the connection host. As long as the same sticker is used for a given user session, all connection requests for that session will be forwarded to the same connection host, and data inconsistency due to replication delays and other reasons can be avoided.
The heterogeneous feature of the connection framework allows for multiple connection types in the same connection pool, for example the pool can be set up to contain both LDAP and SQL connections, or LDAP connections via SSL and Non-SSL protocols. The major benefit of this feature is the ability to group different connection types with each other. For example, if a user gets an LDAP connection from the pool that is coming from connection host A, then the pool can be set up in such a way that the same user will also get a SQL connection from the same connection host, as long as the same connection sticker has been specified.
The two use cases shown there represent one of the simplest and one of the complex ways in which the framework can be used.
The simple use case presented here shows how to set up a ConnectionPool for LDAP connections. Sample code is below:
// Specify the environment for the LDAP context manager. Map environment = new HashMap(); environment.put(LdapContext.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); environment.put(LdapContext.PROVIDER_URL, "ldap://<host>:<port>"); // Create the connection pool. ConnectionPool pool = new ConnectionPool(new LdapConnectionManager(new LdapContextManager(environment, null))); // Schedule the monitor for the pool. pool.getMonitor().schedule(); // Specify the desired parameters for the connection to be captured from the pool. Map parameters = new HashMap(); parameters.put(Connection.Parameter.TYPE, LdapConnection.TYPE); parameters.put(Connection.Parameter.PRINCIPAL, "..."); parameters.put(Connection.Parameter.CREDENTIALS, "..."); // Capture an LDAP connection from the pool. LdapConnection connection = (LdapConnection)pool.captureConnection(parameters); // Get LDAP context from the captured connection. LdapContext context = connection.getLdapContext(); // Use the LDAP context as desired, but do not alter its environment ever! // If you need an LDAP context with a different environment, capture another // connection from the pool and specify the desired connection parameters. // If the LDAP context environment is altered, pool will reject the connection. // When finished using the connection, release the connection into the pool. pool.releaseConnection(connection, null);
Note: Each LdapContext that comes from the IdM Connection Framework will contain the following environment property, so you can get back the LdapConnection:
// Get LdapConnection reference from LdapContext. LdapConnection connection = (LdapConnection)context.getEnvironment().get(Connection.Parameter.REFERENCE);
The complex use case presented here shows how to set up a ConnectionPool for LDAP & SQL connections, and configure it to use multiple hosts to achieve load balancing and fail-over. A connection logger is added as the connection listener for logging and tracing of connection operations.
// Specify the environment for the first LDAP context manager. Map environment1 = new HashMap(); environment1.put(LdapContext.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); environment1.put(LdapContext.PROVIDER_URL, "ldap://<host1>:<port1>"); // Specify the environment for the second LDAP context manager. Map environment2 = new HashMap(); environment2.put(LdapContext.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); environment2.put(LdapContext.PROVIDER_URL, "ldap://<host2>:<port2>"); // Create an array of connection delegates for the connection pool. ConnectionDelegate[] delegates = new ConnectionDelegate[] { new LdapConnectionManager(new LdapContextManager(environment1, null)), new LdapConnectionManager(new LdapContextManager(environment2, null)), new SqlConnectionManager(...), new SqlConnectionManager(...) }; // Create the connection pool with initial size of 100. ConnectionPool pool = new ConnectionPool(delegates, 100); // Create the connection logger. ConnectionLogger logger = new ConnectionLogger("ConnectionLogger.xml"); // Add the connection logger as a connection listener to the pool. pool.addConnectionListener(logger); // Schedule the monitor for the pool. pool.getMonitor().schedule(); // Specify the desired parameters for the connection to be captured from the pool. Map parameters = new HashMap(); parameters.put(Connection.Parameter.TYPE, LdapConnection.TYPE); parameters.put(Connection.Parameter.PRINCIPAL, "..."); parameters.put(Connection.Parameter.CREDENTIALS, "..."); // Capture an LDAP connection from the pool. LdapConnection connection = (LdapConnection)pool.captureConnection(parameters); // Get LDAP context from the captured connection. LdapContext context = connection.getLdapContext(); // Use the LDAP context as desired, but do not alter its environment ever! // If you need an LDAP context with a different environment, capture another // connection from the pool and specify the desired connection parameters. // If the LDAP context environment is altered, pool will reject the connection. // When finished using the connection, release the connection into the pool. pool.releaseConnection(connection, null);
Note: Each LdapContext that comes from the IdM Connection Framework will contain the following environment property, so you can get back the LdapConnection:
// Get LdapConnection reference from LdapContext. LdapConnection connection = (LdapConnection)context.getEnvironment().get(Connection.Parameter.REFERENCE);
The following sections show a few common use case scenarios. For all of the scenarios, the following assumptions apply:
The following code snippet applies to each use case:
// Specify the environment for each connection host. Map environmentA = ...; Map environmentB = ...; Map environmentC = ...; Map environmentD = ...; // Create a connection delegate for each connection host. ConnectionDelegate delegateA = new LdapConnectionManager(new LdapContextManager(environmentA, null)); ConnectionDelegate delegateB = new LdapConnectionManager(new LdapContextManager(environmentB, null)); ConnectionDelegate delegateC = new LdapConnectionManager(new LdapContextManager(environmentC, null)); ConnectionDelegate delegateD = new LdapConnectionManager(new LdapContextManager(environmentD, null)); // Create the connection pool. ConnectionPool pool = new ConnectionPool(); // Add each connection delegate to the pool. pool.addConnectionDelegate(delegateA); pool.addConnectionDelegate(delegateB); pool.addConnectionDelegate(delegateC); pool.addConnectionDelegate(delegateD); // Schedule the pool monitor at the default interval. pool.getMonitor().schedule(); // The pool is now set up and ready for use.
Fail-over is the most important high availability feature in this framework. Fail-over allows a user of the connection framework to open connections from a number of connection hosts seamlessly event if some or most of the connection hosts become unavailable. Fail-over is associated with open connection operations only. Once a connection has been opened, there are other mechanisms in the framework to ensure its validity, however fail-over is associated only with opening connections.
Load balancing is the next most important high availability feature. Load balancing allows a user of the connection framework to use connections from a number of connection hosts in such a manner that the connection load is balanced. Load balancing is associated with open and close connection operations only.
Fail-over and load balancing are related and can be used together or separately. In order to support different ways in which these two features can be used, the following configuration parameters are available for each connection delegate:
The default priority of a connection delegate is 0, the default weight is 1, and the default limit is Integer.MAX_VALUE.
Suppose the connection hosts are to be used in the following manner:
In this scenario both fail-over and load balancing are present. No modifications to the code shown in the 3.3 section are required. The prerequisite for his scenario is that all connection delegates have the same priority, which is the default setup. If you want to explicitly assign the same priority to each connection delegate, use the code below.
// Give each delegate the same priority. synchronized (pool) { delegateA.setPriority(0); delegateB.setPriority(0); delegateC.setPriority(0); delegateD.setPriority(0); }
In the scenario from above, the load will be distributed equally among all hosts. Now suppose you want to distribute the load in the following manner:
Such distributions of connection usage are achieved by setting the weight parameter for each connection delegate, and the following code snippet shows how this can be done.
// Give each delegate a desired weight. synchronized (pool) { delegateA.setWeight(.60); delegateB.setWeight(.20); delegateC.setWeight(.10); delegateD.setWeight(.10); }
That is all; now the connection delegates will be used in the order of their ascending loads, which are adjusted for the specified weight using the following formula:
load = (open count - close count) / weight
Suppose the connection hosts are to be used in the following manner:
In this scenario fail-over is present but there is no load balancing; the hosts are always used in a predetermined order no matter how loaded they are. To achieve this behavior, a user of the connection framework needs to give a unique priority to each connection delegate, reflecting the order in which the delegates are to be selected when opening connections.
The following code snippet achieves this behavior:
// Give each delegate the desired priority. synchronized (pool) { delegateA.setPriority(4); delegateB.setPriority(3); delegateC.setPriority(2); delegateD.setPriority(1); }
Now suppose you want to limit the number of connections on each host in the following manner:
Such limits of connection usage are achieved by setting the limit parameter for each connection delegate, and the following code snippet shows how this can be done.
// Give each delegate a desired limit. synchronized (pool) { delegateA.setLimit(1000); delegateB.setLimit(500); delegateC.setLimit(250); delegateD.setLimit(250); }
That is all; now the connection delegates will be used in the order of their descending priorities up to the specified limit. No load balancing will be performed, since all hosts have a unique priority. The limit is enforced according to the following formula:
limit > open count - close count
Suppose the connection hosts are to be used in the following manner:
In this scenario both fail-over and load balancing are present, however fail-over and load balancing are used selectively. Hosts A and B have a higher priority than hosts C and D, and only if hosts A and B are not available hosts C or D will be used. To achieve this behavior, a user of the connection framework needs to give a higher priority to hosts A and B, and a lower priority to hosts C and D, reflecting the order in which the delegates are to be selected when opening connections. However, since the load is balanced between hosts A and B or C and D, the hosts that participate in load balancing must have the same priority.
The following code snippet achieves this behavior:
// Give each delegate the desired priority. synchronized (pool) { delegateA.setPriority(2); delegateB.setPriority(2); delegateC.setPriority(1); delegateD.setPriority(1); }
In the scenario from above, the load will be distributed equally among hosts A and B or C and D. Now suppose you want to distribute the load in the following manner:
Such distributions of connection usage are achieved by setting the weight parameter for each connection delegate, and the following code snippet shows how this can be done.
// Give each delegate a desired weight. synchronized (pool) { delegateA.setWeight(.75); delegateB.setWeight(.25); delegateC.setWeight(.60); delegateD.setWeight(.40); }
That is all; now the connection delegates will be used in the order of their descending priorities first, then the order of their ascending loads, which are adjusted for the specified weight using the following formula:
load = (open count - close count) / weight
Another important aspect of high availability is the ability to perform seamlessly in a network environment that involves firewalls and proxies. The common problem with firewalls and proxies is that the idle connections often get dropped without the knowledge of the application that is using them. Since connection pools cache connections, chances of getting a connection from the pool what has been dropped by the firewall or a proxy are high. In order to solve this problem, this connection framework provides two mechanisms that can be used separately or together.
For both use cases in this section, we suppose there is a firewall or a proxy between the connection pool host and the connection hosts. The firewall or proxy will automatically drop connections that have not been used for 1 hour, and attempting to use any connection that has been idle for over 1 hour will result in a communication failure.
If a pool monitor is run on a given schedule, as shown in the 3.3 code snippet, it will enforce the connection idle timeout. Idle connections will automatically be closed, and if the minimum pool size if greater then 0, a new one will be opened to replace it.
A connection is considered to be idle between an open/release/return operation occurrence and a capture/remove/close operation occurrence. Note that proxy/validate/ invalidate operations do not affect connections' idle phase.
The pool allows a user to specify an idle timeout for all connections in the pool, as follows:
// Specify idle timeout for all connections in the pool to 45 minutes. pool.setIdleTimeout(45 * 60 * 1000);
This simple code shows how you can change the idle timeout to match the timeout enforced by the firewall or proxy. The pool idle timeout should be less than the firewall or proxy timeout minus the pool monitor interval to guarantee connection validity:
idle timeout < firewall or proxy timeout - pool monitor interval
If a pool monitor is run on a given schedule, as shown in the 3.3 code snippet, it will also validate connections with the frequency specified by the validate timeout. Connections that have not been validated since they were opened, or that have been validated longer than the validate timeout will be re-validated. This mechanism can be used to keep connections alive and prevent the firewall or proxy from dropping unused connections.
The pool allows a user to specify a validate timeout for all connections in the pool, as follows:
// Specify validate timeout for all connections in the pool to 20 minutes. pool.setValidateTimeout(20 * 60 * 1000);
This simple code shows how you can change the validate timeout to be less than the timeout enforced by the firewall or proxy. The pool validate timeout should be less than the firewall or proxy timeout minus the pool monitor interval to guarantee connection validity:
validate timeout < firewall or proxy timeout - pool monitor interval
So far we examined fail-over as a mechanism for ensuring connection validity. However, since fail-over is only involved in opening new connections, there is still the question of connection validity during the connection lifecycle. The connection pool provides a number of options for managing connection validity during the connection lifecycle.
The default pool setup, assuming the pool monitor is run on a given schedule, as shown in the 3.3 section, will guarantee connection validity most of the time, with a window of potential connection failure. This window is guaranteed to be less than or equal to the validate timeout of the pool. For example, if a host goes down, the pool will always re-validate each connection within the validate timeout. Hover, from the moment the host goes down till a connection is re-validated, the user may still get a bad connection from the pool. By default this time window is 15 minutes, and that may be changed depending on the deployment environment's needs.
It is possible to configure the pool to preemptively validate each connection upon connection capture or removal. This will guarantee validity of each connection at any given time, but there is a cost to this feature. Turning on preemptive validation will increase connection network traffic. In the worst-case scenario, this will at most double the connection network traffic. In a real world scenario, the impact should be less costly, since multiple connection operations are usually performed per each connection capture or removal.
The following code snippet shows how to turn on preemptive validation:
// Turn on preemptive validation. pool.setPreemptiveValidation(1);
If preemptive validation rate is set to 1, the pool will attempt to validate a connection once. If the connection is invalid, it will select an alternative host to obtain another connection. This will guarantee validity of connections if at most 1 host goes down. If the user wants to guarantee validity of connections if at most 2 hosts go down, the preemptive validation rate needs to be set to 2. If a user wants to guarantee connection validity no matter how many hosts go down (assuming at least one is still available to serve the request) the preemptive validation rate needs to be set to the exhaustive setting, as follows:
// Turn on exhaustive preemptive validation. pool.setPreemptiveValidation(ConnectionPool.EXHAUSTIVE_PREEMPTIVE_VALIDATION);
So far we have examined how to deal with unpredictable changing network conditions with minimal involvement and configuration. There is another class of changing network conditions which are predictable, and the administrators can dynamically change the pool configuration in order to anticipate planned changes in the network conditions.
If a given host is planned for a downtime, it can be explicitly removed from the pool as follows:
// Remove delegate A from the pool. pool.removeConnectionDelegate(delegateA);
This will automatically close all idle connections from host A immediately, while the busy connections will be closed as they are released or returned back into the pool.
When a given host comes up again and is ready to serve requests, it can be explicitly added back to the pool as follows:
// Add delegate A back to the pool. pool.addConnectionDelegate(delegateA);
This will automatically make host A available to open new connections are they are requested from the pool.
Since upgrades are planned, they can easily be managed by removing and adding hosts from the and back to the pool.
// Remove delegate A from the pool. pool.removeConnectionDelegate(delegateA);
Perform the upgrade as desired.
// Add delegate A back to the pool. pool.addConnectionDelegate(delegateA);
Done.
Rolling upgrades are planned, however, it may be too involved to coordinate the application availability and host upgrade order manually. Since rolling upgrades are usually done during a low traffic period, it is recommended to turn on preemptive validation at the beginning of the rolling upgrade, and turn it off when all hosts have been upgraded.
// Turn on preemptive validation. pool.setPreemptiveValidation(1);
Upgrade all desired hosts one by one.
// Turn off preemptive validation. pool.setPreemptiveValidation(0);
Done.
In mission critical deployments when connection validity is an absolute requirement, preemptive validation must be turned on at the exhaustive rate, and the network can compensate for the performance cost in hardware.
// Turn on exhaustive preemptive validation. pool.setPreemptiveValidation(ConnectionPool.EXHAUSTIVE_PREEMPTIVE_VALIDATION);
Connections will always be valid when captured or removed from the pool.
Note: Even though a connection is valid at the very moment it is captured or removed from the pool, it may become invalid in the time period between the connection capture or removal and actual connection usage. Applications still need to implement their own fail-safe algorithms to deals with such scenarios, however unlikely they may or may not be.
When users change their passwords, and the system employs connection pooling, we have an interesting situation. The pool may contain connections that were authenticated with the old password, and as long as such a connection is available in the pool, a user may be able to access the connection via the old password. In order to remedy this problem, the framework observes a connection open timeout, and all connections that have been open longer than the specified timeout will be automatically closed. This timeout is by default 1 hour, and it can be changed depending on deployment needs. When a user changes their password, they may be able to use the old and the new password within the specified timeout, after this timeout has been exceeded, only the new password will work.
// Specify open timeout for all connections in the pool to 2 hours. pool.setOpenTimeout(2 * 60 * 60 * 1000);
Now, when a user changes their password, the old password may still work up to 2 hours after the password change.
In some cases networks may be flaky and unpredictable, and for example, establishing a connection may be repeated more than once to achieve a successful outcome. For such scenarios, the framework provides fail-safe operation, which can be configured on the connection delegate level.
For example, to configure a connection delegate to attempt repeating the open operation once, use the following code:
// Set the fail-safe level for open operation to 1. synchronized (pool) { delegate.getConnectionOperationFailSafe().setLevel(Connection.Operation.OPEN, 1); }
Now the open operation will be repeated once after initial operation failure.
Connection stickiness and grouping are features that improve data consistency in a heterogeneous environment where data may be coming from a variety of different sources that may or may not be synchronized.
Connection stickers are maintained on the connection group level. By default each connection delegate representing a connection host is placed in its own group. This can be changed so that multiple connection delegates reside in the same connection group if they refer to the same source-of-truth and need to be used together and/or interchangeably.
To insure data consistency by getting a connection from the same connection host whenever possible, simply specify the STICKER parameter when capturing or removing connections.
As long as the STICKER is the same, you will be guaranteed the connection from the same host, or groups of hosts, as described in the section on grouping.
Example:
String sticker = "<something like session or user id>"; // Specify the desired parameters for the connection to be captured from the pool. Map parameters = new HashMap(); parameters.put(Connection.Parameter.TYPE, LdapConnection.TYPE); parameters.put(Connection.Parameter.STICKER, sticker); parameters.put(Connection.Parameter.PRINCIPAL, "..."); parameters.put(Connection.Parameter.CREDENTIALS, "..."); // Capture the connection from the pool. LdapConnection connection = (LdapConnection)pool.captureConnection(parameters);
If the captureConnection(parameters) call fails, that means the host for the current sticker has become unavailable.
If the caller can work with a different host, the following code can be used to retry capturing the connection after removing the sticker.
// Remove the current sticker from the pool. pool.removeSticker(sticker); // Once again, capture the connection from the pool. LdapConnection connection = (LdapConnection)pool.captureConnection(parameters);
Connection groups are used to associate related connection delegates that refer to the same source-of-truth. Typically all connection delegates that need to be used in tandem or can be used interchangeably with respect to the source-of-truth are grouped together into the same connection group. Connection stickers are maintained on the group level, and if you specify the same sticker, you will be guaranteed a connection from the same connection group.
The following example shows how to group together SSL and non-SSL LDAP connection delegates that refer to the same connection host.
// Specify the environment for each connection host. Map environmentA = ...; // Points to host A using non-SSL protocol. Map environmentAssl = ...; // Points to host A using SSL protocol. Map environmentB = ...; // Points to host B using non-SSL protocol. Map environmentBssl = ...; // Points to host B using SSL protocol. // Create a connection delegate for each connection host. ConnectionDelegate delegateA = new LdapConnectionManager(new LdapContextManager(environmentA, null)); ConnectionDelegate delegateAssl = new LdapConnectionManager(new LdapContextManager(environmentAssl, null)); ConnectionDelegate delegateB = new LdapConnectionManager(new LdapContextManager(environmentB, null)); ConnectionDelegate delegateBssl = new LdapConnectionManager(new LdapContextManager(environmentBssl, null)); // Create connection groups for hosts A and B. ConnectionGroup groupA = new ConnectionGroup(); ConnectionGroup groupB = new ConnectionGroup(); // Group delegates that point to host A together. groupA.addConnectionDelegate(delegateA); groupA.addConnectionDelegate(delegateAssl); // Group delegates that point to host B together. groupB.addConnectionDelegate(delegateB); groupB.addConnectionDelegate(delegateBssl); // Create the connection pool. ConnectionPool pool = new ConnectionPool(); // Add each connection group to the pool. pool.addConnectionGroup(groupA); pool.addConnectionGroup(groupB); // Schedule the pool monitor at the default interval. pool.getMonitor().schedule(); // The pool is now set up and ready for use.
Now when you request a connection from the pool using a consistent STICKER, you will always get connections from the same group, either SSL or non-SSL depending on the supplied connection parameters.
In order to detect connection leaks, the pool sends connection events to the connection listeners. One implementation of the ConnectionListener interface is provided by the ConnectionLogger. The connection logger will log all connection events in XML format. Use the following code to add a connection logger as a connection listener to the connection pool:
// Create a connection logger. ConnectionLogger logger = new ConnectionLogger("Connection.log"); // Add the logger to the pool. pool.addConnectionListener(logger);
You will soon notice that every connection event gets logged in the example above. This can be quite voluminous, but fortunately there is a way to filter out more interesting events. To do this, set the status filter for the logger to look for FAILURE status and the operation filter to look for INVALIDATE operation, and set the operator to OR.
// Create the status filter. Set statusFilter = new HashSet(); statusFilter.add(Connection.Status.FAILURE); // Create the operation filter. Set operationFilter = new HashSet(); operationFilter.add(Connection.Operation.INVALIDATE); // Set the operator and filters for the logger. logger.setOperator(ConnectionLogger.Operator.OR); logger.setStatusFilter(statusFilter); logger.setOperationFilter(operationFilter);
Now only events whose status if FAILURE or whose operation is INVALIDATE will be logged. The connection leaks will show as events whose operation is INVALIDATE, and the Connection.Parameter.Intrinsic.CAUSE will be a ConnectionException with the "connection leaked" message. One may simply grep for the "connection leaked" message in the log to find these events. Once the leaked connection event is found, take a look at the <StackTrace> tag inside the <CaptureInfo> tag. This will tell you exactly where in your code the connection leak occurred, i.e. where the connection was captured but never released. Naturally, stack tracing has to be turned on for this feature.
In order for the leaked connection events to be generated, you must schedule the connection pool monitor, and finalize the pool before exiting the application.
// Schedule the pool monitor at the default interval. pool.getMonitor().schedule(); . . . // Finalize the pool before exiting the application. pool.finalize();
The overarching design pattern used to implement IdM Connection Framework is "flyweight" as identified by the GoF. There are a number of design patterns and principles used within the framework and are listed below.
The IdM Connection Framework consists of abstract components (found in the oracle.idm.connection package) that represent abstractions defined by the framework. These abstractions are:
Furthermore, users of the IdM Connection Framework will also find specific components (found in the oracle.idm.connection sub-packages) that represent specifications of the framework. These specifications are:
By splitting the design into abstract and specific components, a number of useful design patterns become available to manage the complexity and maximize component reuse. These principals are outlined below:
Users of the IdM Connection Framework will find that all specific components in the framework are derived from the abstract components. This maximizes component reuse and improves consistency between different implementations.
For example, the LdapConnectionManager extends the abstract ConnectionManager, and so does the SqlConnectionManager. Not only is the code base largely the same for both of these connection managers, event though the underlying protocol is completely different, but also the way these managers interact with the framework is also largely the same.
Derivation is achieved via the Java class inheritance mechanism.
Whenever possible, common behaviors are isolated into a "mediator" pattern as defined by the GoF. The example of a mediator in the IdM Connection Framework is the connection delegate. Connection delegates are delegated requests to manage connections on behalf of the connection pool.
Delegation is achieved via Java interfaces. Implementations of the ConnectionDelegate interface are called connection managers, such as LdapConnectionManager or SqlConnectionManager.
The delegation pattern allows for creation of "template methods" as defined by GoF. This pattern identifies the high level steps that are involved in managing connections, for example, but leaves the actual implementations of these steps to the classes that represent specific connection implementations.
Factories are used to create connection objects within the IdM Connection Framework. The factories are used in the "factory method" pattern as defined by GoF, where the connection delegates are in charge of deciding which specific connections are created for the connection pool.
Orthogonal to the components deeply involved in the management of connections within the framework, there are also detached observers of the system that are notified of the system changes using the "observer" pattern as defined by the GoF.
Observers are implemented using the standard Java Beans events and listeners conventions.
This framework relies heavily on the Java Collections framework to simplify the code and maintain a high level or readability and maintainability. Users of the IdM Connection Framework should be familiar with the Java Collection framework, and common patterns such as Sets, Maps, Lists, Iterators, etc.
The final GoF pattern I want to mention here is "flyweight". The implementation of this pattern in the IdM Connection Framework is the ConnectionPool. The connection pool maintains a collection of connections on behalf of the user and optimizes creation of connections, balances the load between different connection delegates, manages fail-over should a connection delegate be unable to respond, and check for connection validity throughout the connection lifecycle.
Connections are the foundation of the IdM Connection Framework. The framework provides a base implementation of the connection object that needs to be extended by each specific implementation.
The connection object is a wrapper that will contain the actual connection provided by the specific implementation, and a number of structures that monitor connection usage, control connection behavior, and record connection metrics.
Connection operations that are performed by the connection pool are high level and provide a sufficient and necessary abstraction for a complete connection lifecycle management. There are 9 operations identified by the framework and they are outlined in the sections below.
Each operation is associated with an inner class of the connection object that extends the OperationInfo class. This class provides information about the connection state and metrics associated with any given connection operation.
The following is the summary of common methods found in the OperationInfo class:
Connection.OperationInfo class | |
---|---|
Method | Description |
String getOperation() |
Returns the operation, as defined by the Connection.Operation class. |
Map getParameters() |
Returns parameters of the last operation occurrence. |
StackTrace[] getStackTrace() |
Returns stack trace of the last operation occurrence. |
Collection getMessages() |
Returns messages associated with the last operation occurrence. |
Collection getLocalizedMessages() |
Returns localized messages associated with the last operation occurrence. |
Methods inherited from PredicateInfo class. | |
int getCount() |
Returns the count of the operation occurrences. |
long getTimeStamp() |
Returns the time stamp of the last operation occurrence. |
long getDuration() |
Returns the duration since the last operation occurrence. |
Record getRecord() |
Returns the recorded metrics for occurrences of this operation. |
Note: Calling the getOperationInfo() method on the Connection class or subclasses will always return the last operation performed on the connection.
The framework assumes that each connection is opened before it can be used. If this is not the case, the open operation can simply be a no-op. However, the open operation needs to at least create the connection object of any given implementation, as it is associated with the factory methods in implementation specific connection managers.
Open operation is associated with a timeout, and a connection that has been open longer than the specified timeout will be automatically closed by the pool monitor. This mechanism makes sure that all connections in the pool have been authenticated within the specified open timeout, which is important when users change passwords, and the system must limit the time period the old password could still be used, thus the open timeout.
Connection.OpenInfo class | |
---|---|
Method | Description |
boolean isOpened() |
Returns true if the connection is opened. |
long getTimeout() |
Returns the open operation timeout. If the value is UNKNOWN the connection pool setting will be used. |
void setTimeout(long timeout) |
Sets the open operation timeout. If the value is UNKNOWN the connection pool setting will be used. |
void resetTimeout() |
Resets the open operation timeout to UNKNOWN, defaulting it to the connection pool setting. |
boolean hasTimedout() |
Returns true if the open operation has timedout. |
Methods inherited from OperationInfo class. | |
String getOperation() |
Returns Connection.Operation.OPEN. |
Map getParameters() |
Returns parameters of the last open operation occurrence. |
StackTrace[] getStackTrace() |
Returns stack trace of the last open operation occurrence. |
Collection getMessages() |
Returns messages associated with the last open operation occurrence. |
Collection getLocalizedMessages() |
Returns localized messages associated with the last open operation occurrence. |
Methods inherited from PredicateInfo class. | |
int getCount() |
Returns the count of the open operation occurrences. |
long getTimeStamp() |
Returns the time stamp of the last open operation occurrence. |
long getDuration() |
Returns the duration since the last open operation occurrence. |
Record getRecord() |
Returns the recorded metrics for occurrences of the open operation. |
Note: Calling the getOpenInfo() method on the Connection class or subclasses will always return the last open operation performed on the connection.
The framework assumes that each connection is closed after it is no longer needed. If this is not the case, the close operation can simply be a no-op. The close operation needs to release resources associated with an open connection that will no longer be used.
Connection.CloseInfo class | |
---|---|
Method | Description |
boolean isClosed() |
Returns true if the connection is closed. |
Methods inherited from OperationInfo class. | |
String getOperation() |
Returns Connection.Operation.CLOSE. |
Map getParameters() |
Returns parameters of the last close operation occurrence. |
StackTrace[] getStackTrace() |
Returns stack trace of the last close operation occurrence. |
Collection getMessages() |
Returns messages associated with the last close operation occurrence. |
Collection getLocalizedMessages() |
Returns localized messages associated with the last close operation occurrence. |
Methods inherited from PredicateInfo class. | |
int getCount() |
Returns the count of the close operation occurrences. |
long getTimeStamp() |
Returns the time stamp of the last close operation occurrence. |
long getDuration() |
Returns the duration since the last close operation occurrence. |
Record getRecord() |
Returns the recorded metrics for occurrences of the close operation. |
Note: Calling the getCloseInfo() method on the Connection class or subclasses will always return the last close operation performed on the connection.
If a given connection implementation can change the identity of a connection without opening a new connection, this framework can take advantage of this feature. The proxy operation is associated with the act of changing the connection identity on behalf of a different user.
Proxy operation is associated with a timeout, and a connection will be eligible for re-proxying only after the proxy timeout has been reached. This will prevent proxy thrashing when the connection pool is under heavy usage. The proxy timeout can be set on the pool level, or on individual connections.
Connection.ProxyInfo class | |
---|---|
Method | Description |
boolean isProxied() |
Returns true if the connection has been proxied at least once. |
long getTimeout() |
Returns the proxy operation timeout. If the value is UNKNOWN the connection pool setting will be used. |
void setTimeout(long timeout) |
Sets the proxy operation timeout. If the value is UNKNOWN the connection pool setting will be used. |
void resetTimeout() |
Resets the proxy operation timeout to UNKNOWN, defaulting it to the connection pool setting. |
boolean hasTimedout() |
Returns true if the proxy operation has timedout. |
long getCompositeDuration() |
Returns the composite duration since the last open or proxy operation. |
boolean isExpected() |
Returns true if the connection proxying is expected. |
Methods inherited from OperationInfo class. | |
String getOperation() |
Returns Connection.Operation.PROXY. |
Map getParameters() |
Returns parameters of the last proxy operation occurrence. |
StackTrace[] getStackTrace() |
Returns stack trace of the last proxy operation occurrence. |
Collection getMessages() |
Returns messages associated with the last proxy operation occurrence. |
Collection getLocalizedMessages() |
Returns localized messages associated with the last proxy operation occurrence. |
Methods inherited from PredicateInfo class. | |
int getCount() |
Returns the count of the proxy operation occurrences. |
long getTimeStamp() |
Returns the time stamp of the last proxy operation occurrence. |
long getDuration() |
Returns the duration since the last proxy operation occurrence. |
Record getRecord() |
Returns the recorded metrics for occurrences of the proxy operation. |
Note: Calling the getProxyInfo() method on the Connection class or subclasses will always return the last proxy operation performed on the connection.
Connections can be captured from the pool. This operation usually does not involve any actions on behalf of the implementation, other than optionally saving the connection state upon capture in order to make sure the connection has not be altered in a way that would cause undesirable side-effects upon release.
After a connection is captured, it is still managed by the connection pool. The pool will expire each connection that has been capture for too long. Thus the capture operation has a timeout specifying how long capture is expected to endure. The capture timeout can be set on the pool level, or on the individual connections.
Connection.CaptureInfo class | |
---|---|
Method | Description |
boolean isCaptured() |
Returns true if the connection is captured. |
long getTimeout() |
Returns the capture operation timeout. If the value is UNKNOWN the connection pool setting will be used. |
void setTimeout(long timeout) |
Sets the capture operation timeout. If the value is UNKNOWN the connection pool setting will be used. |
void resetTimeout() |
Resets the capture operation timeout to UNKNOWN, defaulting it to the connection pool setting. |
boolean hasTimedout() |
Returns true if the capture operation has timedout. |
Methods inherited from OperationInfo class. | |
String getOperation() |
Returns Connection.Operation.CAPTURE. |
Map getParameters() |
Returns parameters of the last capture operation occurrence. |
StackTrace[] getStackTrace() |
Returns stack trace of the last capture operation occurrence. |
Collection getMessages() |
Returns messages associated with the last capture operation occurrence. |
Collection getLocalizedMessages() |
Returns localized messages associated with the last capture operation occurrence. |
Methods inherited from PredicateInfo class. | |
int getCount() |
Returns the count of the capture operation occurrences. |
long getTimeStamp() |
Returns the time stamp of the last capture operation occurrence. |
long getDuration() |
Returns the duration since the last capture operation occurrence. |
Record getRecord() |
Returns the recorded metrics for occurrences of the capture operation. |
Note: Calling the getCaptureInfo() method on the Connection class or subclasses will always return the last capture operation performed on the connection.
Connections that were captured need to be released back into the pool. This operation usually does not involve any actions on behalf of the implementation, other than optionally checking the connection state to make sure the connection has not be altered in a way that would cause undesirable side-effects.
Connection.ReleaseInfo class | |
---|---|
Method | Description |
boolean isReleased() |
Returns true if the connection is released. |
Methods inherited from OperationInfo class. | |
String getOperation() |
Returns Connection.Operation.RELEASE. |
Map getParameters() |
Returns parameters of the last release operation occurrence. |
StackTrace[] getStackTrace() |
Returns stack trace of the last release operation occurrence. |
Collection getMessages() |
Returns messages associated with the last release operation occurrence. |
Collection getLocalizedMessages() |
Returns localized messages associated with the last release operation occurrence. |
Methods inherited from PredicateInfo class. | |
int getCount() |
Returns the count of the release operation occurrences. |
long getTimeStamp() |
Returns the time stamp of the last release operation occurrence. |
long getDuration() |
Returns the duration since the last release operation occurrence. |
Record getRecord() |
Returns the recorded metrics for occurrences of the release operation. |
Note: Calling the getReleaseInfo() method on the Connection class or subclasses will always return the last release operation performed on the connection.
Connections can be removed from the pool. This operation usually does not involve any actions on behalf of the implementation, other than optionally saving the connection state upon removal in order to make sure the connection has not be altered in a way that would cause undesirable side-effects upon return.
When a connection is removed, it is no longer managed by the pool, and can be used for as long as desired, and does not need to be returned back to the pool. When acquiring the connections via the remove operation, the connection pool acts merely as a connection factory, which performs fail-over, load balancing, and preemptive validation. However, since the connection is not under pool management after it has been removed, connection lifecycle features of the pool are not available.
Connection.RemoveInfo class | |
---|---|
Method | Description |
boolean isRemoved() |
Returns true if the connection is removed. |
Methods inherited from OperationInfo class. | |
String getOperation() |
Returns Connection.Operation.REMOVE. |
Map getParameters() |
Returns parameters of the last remove operation occurrence. |
StackTrace[] getStackTrace() |
Returns stack trace of the last remove operation occurrence. |
Collection getMessages() |
Returns messages associated with the last remove operation occurrence. |
Collection getLocalizedMessages() |
Returns localized messages associated with the last remove operation occurrence. |
Methods inherited from PredicateInfo class. | |
int getCount() |
Returns the count of the remove operation occurrences. |
long getTimeStamp() |
Returns the time stamp of the last remove operation occurrence. |
long getDuration() |
Returns the duration since the last remove operation occurrence. |
Record getRecord() |
Returns the recorded metrics for occurrences of the remove operation. |
Note: Calling the getRemoveInfo() method on the Connection class or subclasses will always return the last remove operation performed on the connection.
Connections that were removed may be returned back to the pool. This operation usually does not involve any actions on behalf of the implementation, other than optionally checking the connection state to make sure the connection has not be altered in a way that would cause undesirable side-effects.
The pool may not take back the removed connection if it is already full. In that case the connection will simply be closed upon its return.
Connection.ReturnInfo class | |
---|---|
Method | Description |
boolean isReturned() |
Returns true if the connection is returned. |
Methods inherited from OperationInfo class. | |
String getOperation() |
Returns Connection.Operation.RETURN. |
Map getParameters() |
Returns parameters of the last return operation occurrence. |
StackTrace[] getStackTrace() |
Returns stack trace of the last return operation occurrence. |
Collection getMessages() |
Returns messages associated with the last return operation occurrence. |
Collection getLocalizedMessages() |
Returns localized messages associated with the last return operation occurrence. |
Methods inherited from PredicateInfo class. | |
int getCount() |
Returns the count of the return operation occurrences. |
long getTimeStamp() |
Returns the time stamp of the last return operation occurrence. |
long getDuration() |
Returns the duration since the last return operation occurrence. |
Record getRecord() |
Returns the recorded metrics for occurrences of the return operation. |
Note: Calling the getReturnInfo() method on the Connection class or subclasses will always return the last return operation performed on the connection.
Validate operations is usually the simples and cheapest operation you can perform on a connection in order to establish connection validity. Implementations that want to take advantage of the validation features of the connection pool should implement this operation.
Connection validation is performed on a schedule, and so the validate operation has a timeout specifying how long a connection is assumed to be valid after it has been validated. Once the timeout is exceeded, the connection will be automatically re-validated. The validate timeout can be set on the pool level, or on the individual connections.
Note: Preemptive validation will always revalidate a connection upon it capture or removal (except for connection that were just opened to fulfill the given request; just opened connections are assumed to be valid.)
Connection.ValidateInfo class | |
---|---|
Method | Description |
boolean isValidated() |
Returns true if the connection is validated. |
long getTimeout() |
Returns the validate operation timeout. If the value is UNKNOWN the connection pool setting will be used. |
void setTimeout(long timeout) |
Sets the validate operation timeout. If the value is UNKNOWN the connection pool setting will be used. |
void resetTimeout() |
Resets the validate operation timeout to UNKNOWN, defaulting it to the connection pool setting. |
boolean hasTimedout() |
Returns true if the validate operation has timedout. |
long getCompositeDuration() |
Returns the composite duration since the last open, proxy or validate operation. |
boolean isExpected() |
Returns true if the connection validation is expected. |
Methods inherited from OperationInfo class. | |
String getOperation() |
Returns Connection.Operation.VALIDATE. |
Map getParameters() |
Returns parameters of the last validate operation occurrence. |
StackTrace[] getStackTrace() |
Returns stack trace of the last validate operation occurrence. |
Collection getMessages() |
Returns messages associated with the last validate operation occurrence. |
Collection getLocalizedMessages() |
Returns localized messages associated with the last validate operation occurrence. |
Methods inherited from PredicateInfo class. | |
int getCount() |
Returns the count of the validate operation occurrences. |
long getTimeStamp() |
Returns the time stamp of the last validate operation occurrence. |
long getDuration() |
Returns the duration since the last validate operation occurrence. |
Record getRecord() |
Returns the recorded metrics for occurrences of the validate operation. |
Note: Calling the getValidateInfo() method on the Connection class or subclasses will always return the last validate operation performed on the connection.
Connections can be invalidated for a number of reasons that cause failures during connection pool operation or explicitly via the user of the pool. This operation usually does not involve any actions on behalf of the implementation. All invalidated connections will be automatically closed.
Connection.InvalidateInfo class | |
---|---|
Method | Description |
boolean isInvalidated() |
Returns true if the connection is invalidated. |
Methods inherited from OperationInfo class. | |
String getOperation() |
Returns Connection.Operation.INVALIDATE. |
Map getParameters() |
Returns parameters of the last invalidate operation occurrence. |
StackTrace[] getStackTrace() |
Returns stack trace of the last invalidate operation occurrence. |
Collection getMessages() |
Returns messages associated with the last invalidate operation occurrence. |
Collection getLocalizedMessages() |
Returns localized messages associated with the last invalidate operation occurrence. |
Methods inherited from PredicateInfo class. | |
int getCount() |
Returns the count of the invalidate operation occurrences. |
long getTimeStamp() |
Returns the time stamp of the last invalidate operation occurrence. |
long getDuration() |
Returns the duration since the last invalidate operation occurrence. |
Record getRecord() |
Returns the recorded metrics for occurrences of the invalidate operation. |
Note: Calling the getInvalidateInfo() method on the Connection class or subclasses will always return the last invalidate operation performed on the connection.
The following is the summary of metrics recorded for each operation, and the methods found in the Record class.
Record class | |
---|---|
Method | Description |
int getCount() |
Returns the recorded count of operation occurrences thus far. |
long getTotal() |
Returns the recorded total duration of operation occurrences thus far. |
long getAverage() |
Returns the recorded average duration of operation occurrences thus far. |
long getMinimum() |
Returns the recorded minimum duration of operation occurrences thus far. |
long getMaximum() |
Returns the recorded maximum duration of operation occurrences thus far. |
long getGamut() |
Returns the recorded duration gamut of operation occurrences thus far. |
Note: As you can see there are 2 versions of the getCount() method, one in the PredicateInfo class, and another in the Record class. The one in the PredicateInfo class represents the number of operation occurrences, including the current operation that may be occurring at the moment. The one in the Record class represents the number of recorded operation occurrences, and since the metrics cannot be recorded until the operation has completed, it will lag by one behind the one in the PredicateInfo class if the given operation is occurring at that moment.
At a level even higher than connection operations, this framework observes busy and idle connection phases.
A connection is in a busy phase between capture/remove operation occurrence and release/return/close operation occurrence. Busy connections are not eligible for connection pool operations.
Connection.BusyInfo class | |
---|---|
Method | Description |
boolean isBusy() |
Returns true if the connection is busy. |
Methods inherited from PredicateInfo class. | |
int getCount() |
Returns the count of the busy phase occurrences. |
long getTimeStamp() |
Returns the time stamp of the last busy phase occurrence. |
long getDuration() |
Returns the duration since the last busy phase occurrence. |
Record getRecord() |
Returns the recorded metrics for occurrences of the busy phase. |
Note: Calling the getBusyInfo() method on the Connection class or subclasses will always return the last busy phase of the connection.
A connection is in an idle phase between open/release/return operation occurrence and a capture/remove/close operation occurrence. Note that proxy/validate/invalidate operations do not affect connections' idle phase. Idle connections are eligible for connection pool operations.
In order to be able to close idle connections after a certain period of time, connections' idle phase is associated with the idle timeout. Once the timeout is exceeded, the connection will be automatically closed. The idle timeout can be set on the pool level, or on the individual connections.
Connection.IdleInfo class | |
---|---|
Method | Description |
boolean isIdle() |
Returns true if the connection is idle. |
long getTimeout() |
Returns the idle phase timeout. If the value is UNKNOWN the connection pool setting will be used. |
void setTimeout(long timeout) |
Sets the idle phase timeout. If the value is UNKNOWN the connection pool setting will be used. |
void resetTimeout() |
Resets the idle phase timeout to UNKNOWN, defaulting it to the connection pool setting. |
boolean hasTimedout() |
Returns true if the idle phase has timedout. |
Methods inherited from PredicateInfo class. | |
int getCount() |
Returns the count of the idle phase occurrences. |
long getTimeStamp() |
Returns the time stamp of the last idle phase occurrence. |
long getDuration() |
Returns the duration since the last idle phase occurrence. |
Record getRecord() |
Returns the recorded metrics for occurrences of the idle phase. |
Note: Calling the getIdleInfo() method on the Connection class or subclasses will always return the last idle phase of the connection.
The following is the summary of metrics recorded for each phase, and the methods found in the Record class.
Record class | |
---|---|
Method | Description |
int getCount() |
Returns the recorded count of phase occurrences thus far. |
long getTotal() |
Returns the recorded total duration of phase occurrences thus far. |
long getAverage() |
Returns the recorded average duration of phase occurrences thus far. |
long getMinimum() |
Returns the recorded minimum duration of phase occurrences thus far. |
long getMaximum() |
Returns the recorded maximum duration of phase occurrences thus far. |
long getGamut() |
Returns the recorded duration gamut of phase occurrences thus far. |
Note: As you can see there are 2 versions of the getCount() method, one in the PredicateInfo class, and another in the Record class. The one in the PredicateInfo class represents the number of phase occurrences, including the current phase that may be occurring at the moment. The one in the Record class represents the number of recorded phase occurrences, and since the metrics cannot be recorded until the phase has completed, it will lag by one behind the one in the PredicateInfo class if the given phase is occurring at that moment.
Connection matching is done via the matchConnection(Connection connection, Map parameters) method. This method returns connection match heuristic.
If the connection should be ignored, this method returns 0. ConnectionPool will ignore all connections whose match is 0.
If the connection is a match, returns a number greater than 0. ConnectionPool will choose the connection with the highest positive number for the final best match.
If the connection is not a match, returns a number less than 0. ConnectionPool will choose the connection with the lowest negative number for the final worst match.
If best match is not available, and the pool cannot open a new connection because it is full, then the worst match may be closed in order to create room for a new connection.
This method is called from the ConnectionPool.
Note: Connection delegates should not check for reached limit, this should be left to the pool.
Note: Connection delegates should not enforce operation timeouts; this should be left to the pool.
Note: Connection delegates should not check for altered connections, this should be left to the pool.
The following figure shows the connection-matching algorithm implemented by the base connection manager. The connection matching is done using the "template method" design pattern. The methods listed below need to be implemented by the extending connection managers to give meaning to the algorithm logic:
Connection managers that extend the base connection manager implementation can also override the matchConnection(Connection connection, Map parameters) method and replace this algorithm with a different one if it better suites the needs of that particular implementation.
The default preemptive validation retry rate is 0, meaning no connections will be preemptively validated upon capture or removal.
These connection pool methods are used to get and set the preemptive validation retry rate:
int pool.getPreemptiveValidation()
void pool.setPreemptiveValidation(int)
The default random invalidation inverse rate is 1/0, meaning no connections will be randomly invalidated by the connection pool monitor.
These connection pool methods are used to get and set the random invalidation inverse rate:
int pool.getRandomInalidation()
void pool.setRandomInalidation(int)
To invalidate every connection, set the random invalidation inverse rate to 1, meaning every 1/1 connection will be invalidated.
To invalidate every 1000th connection, set the random invalidation inverse rate to 1000, meaning every 1/1000 connection will be invalidated.
The following timeouts allow fine-tuning of connection pool performance.
The amount of time a connection can remain open, default is 1 hour.
Connections whose open duration exceeds this timeout will be closed.
These connection pool methods are used to get and set the open timeout:
long pool.getOpenTimeout()
void pool.setOpenTimeout(long)
This timeout can be get and set on individual connections as well using these methods:
long connection.getOpenInfo().getTimeout()
void connection.getOpenInfo().setTimeout(long)
At the end of the open operation episode, the timeout will be reset to default, which is defined on the pool level.
The amount of time allowed between proxy connection operations, default is 5 minutes.
Connections whose proxy duration exceeds this timeout will be available for reproxing.
These connection pool methods are used to get and set the proxy timeout:
long pool.getProxyTimeout()
void pool.setProxyTimeout(long)
This timeout can be get and set on individual connections as well using these methods:
long connection.getProxyInfo().getTimeout()
void connection.getProxyInfo().setTimeout(long)
At the end of the proxy operation episode, the timeout will be reset to default, which is defined on the pool level.
The amount of time allowed from the capture connection operation to the release connection operation, default is 10 minutes.
Connections whose capture duration exceeds this timeout will be invalidated.
These connection pool methods are used to get and set the capture timeout:
long pool.getCaptureTimeout()
void pool.setCaptureTimeout(long)
This timeout can be get and set on individual connections as well using these methods:
long connection.getCaptureInfo().getTimeout()
void connection.getCaptureInfo().setTimeout(long)
At the end of the capture operation episode, the timeout will be reset to default, which is defined on the pool level.
The amount of time allowed between validate connection operations, default is 15 minutes.
Connections whose validate duration exceeds this timeout will be revalidated.
These connection pool methods are used to get and set the validate timeout:
long pool.getValidateTimeout()
void pool.setValidateTimeout(long)
This timeout can be get and set on individual connections as well using these methods:
long connection.getValidateInfo().getTimeout()
void connection.getValidateInfo().setTimeout(long)
At the end of the validate operation episode, the timeout will be reset to default, which is defined on the pool level.
The amount of idle time allowed before the close connection operation, default is 30 minutes.
Connections whose idle duration exceeds this timeout will be closed.
These connection pool methods are used to get and set the idle timeout:
long pool.getIdleTimeout()
void pool.setIdleTimeout(long)
This timeout can be get and set on individual connections as well using these methods:
long connection.getIdleInfo().getTimeout()
void connection.getIdleInfo().setTimeout(long)
At the end of the idle phase episode, the timeout will be reset to default, which is defined on the pool level.
The amount of time allowed before sticker removal, default is 45 minutes.
Stickers that have not been used longer than this timeout will be removed.
These connection pool methods are used to get and set the sticker timeout:
long pool.getStickerTimeout()
void pool.setStickerTimeout(long)
The amount of time to sleep after a connection operation, default is 0 milliseconds.
This is useful for debugging and simulating slow network traffic scenarios.
These connection pool methods are used to get and set the sleep timeout:
long pool.getSleepTimeout()
void pool.setSleepTimeout(long)
The connection pool monitor observes busy and idle phases.
A connection pool monitor is in a busy phase while monitoring connections.
ConnectionPool.Monitor.BusyInfo class | |
---|---|
Method | Description |
Boolean isBusy() |
Returns true if the connection pool monitor is busy. |
Methods inherited from PredicateInfo class. | |
int getCount() |
Returns the count of the busy phase occurrences. |
long getTimeStamp() |
Returns the time stamp of the last busy phase occurrence. |
long getDuration() |
Returns the duration since the last busy phase occurrence. |
Record getRecord() |
Returns the recorded metrics for occurrences of the busy phase. |
Note: Calling the getBusyInfo() method on the ConnectionPool.Monitor class or subclasses will always return the last busy phase of the connection pool monitor.
A connection pool monitor is in an idle phase while waiting for the next execution.
ConnectionPool.Monitor.IdleInfo class | |
---|---|
Method | Description |
Boolean isIdle() |
Returns true if the connection pool monitor is idle. |
Methods inherited from PredicateInfo class. | |
int getCount() |
Returns the count of the idle phase occurrences. |
long getTimeStamp() |
Returns the time stamp of the last idle phase occurrence. |
long getDuration() |
Returns the duration since the last idle phase occurrence. |
Record getRecord() |
Returns the recorded metrics for occurrences of the idle phase. |
Note: Calling the getIdleInfo() method on the ConnectionPool.Monitor class or subclasses will always return the last idle phase of the connection pool monitor.
The following is the summary of metrics recorded for each phase, and the methods found in the Record class.
Record class | |
---|---|
Method | Description |
int getCount() |
Returns the recorded count of phase occurrences thus far. |
long getTotal() |
Returns the recorded total duration of phase occurrences thus far. |
long getAverage() |
Returns the recorded average duration of phase occurrences thus far. |
long getMinimum() |
Returns the recorded minimum duration of phase occurrences thus far. |
long getMaximum() |
Returns the recorded maximum duration of phase occurrences thus far. |
long getGamut() |
Returns the recorded duration gamut of phase occurrences thus far. |
Note: As you can see there are 2 versions of the getCount() method, one in the PredicateInfo class, and another in the Record class. The one in the PredicateInfo class represents the number of phase occurrences, including the current phase that may be occurring at the moment. The one in the Record class represents the number of recorded phase occurrences, and since the metrics cannot be recorded until the phase has completed, it will lag by one behind the one in the PredicateInfo class if the given phase is occurring at that moment.
This framework ignores all exceptions reported during connection usage and processing except for ConnectionExceptions. This means that all other exceptions will be propagated to the calling APIs. Implementers of the IdM Connection Framework components need to wrap all exceptions that need to be handled by the framework with a ConnectionException and specify the original exception via the cause property.
This section covers different implementations of the framework components. First we look at how a new implementation can be added to the framework, and then we look at the existing implementations and some interesting solutions employed by the same.
Adding a new implementation to the framework is fairly easy. A new implementation can be implemented by adding a new package to the framework, and adding at least 2 new classes to that package.
Each new implementation should reside in its own package. If you want the new implementation to be distributed with the framework itself, it should reside in the oracle.idm.connection.* namespace.
The name of the new package should be the same as the new connection type you are adding to the framework. In our example, we shall call the new connection type NEW.
So, to add a new implementation, create a package named:
oracle.idm.connection.new
Under this package, create the following new classes:
NewConnection extends Connection
NewConnectionManager extends ConnectionManager
First, define the connection type in the NewConnection class, as follows:
/** * Use for NEW connection type parameter value. */ public static final String TYPE = "new"; // See Connection for comments. public String getType() { return TYPE; }
Next, you will need to add a Java Bean property to reference the actual connection this class will be wrapped around. The type of this member field is the class defined by the API that creates the actual connection object.
// The actual connection. ActualConnection actualConnection = null; /** * Returns the actual connection. */ public ActualConnection getActualConnection() { return actualConnection; } /** * Sets the actual connection. */ protected void setActualConnection(ActualConnection actualConnection) { this.actualConnection = actualConnection; }
Note that the setter for the actual connection must not be public, it should be accessible only to the NewConnectionManager class and possibly the extending classes.
Next, you will need to override the clone method to null out the actualConnection property. Connections are cloned when sent in events or for analysis, and the actual connection property should not be available in those contexts. However, you can extract interesting information about the actual connection when cloning and add it to the new connection class as various Java Bean properties.
/** * Cloned NEW connections will not contain a reference to the actual connection. *
* Connections are cloned when referenced in connection events. */ public Object clone() throws CloneNotSupportedException { NewConnection clone = (NewConnection)super.clone(); clone.actualConnection = null; return clone; }
Finally, do not forget to set the proper tag name for the NewConnection class in its constructor for XML printing support:
/** * Creates an NEW connection. */ protected NewConnection(NewConnectionManager manager, Map parameters) { super(manager, parameters); tag = "NewConnection"; }
Note that the NewConnection constructor should never be public, connections are created only via the connection managers' openConnection(Map parameters) factory method.
First, define the connection manager type in the NewConnectionManager class, as follows:
// See ConnectionDelegate for comments. public String getType() { return NewConnection.TYPE; }
Connection manager type should always match the type of the connection it will manage.
Next, we need to provide for a way to configure the new connection manager to communicate with a particular connection server. Typically this is done via a map of configuration parameters passed to the constructor, as follows:
// The configuration. Map configuration; /** * Returns the configuration. */ public Map getConfiguration() { return configuration; } /** * Sets the configuration. */ protected void setConfiguration(Map configuration) { this.configuration = configuration; }
Finally, do not forget to set the proper tag name for the NewConnectionManager class in its constructor for XML printing support:
/** * Constructor for the NEW connection manager. */ public NewConnectionManager(Map configuration) { super(); if (configuration != null) configuration = Collections.unmodifiableMap(configuration); setConfiguration(configuration); tag = "NewConnectionManager"; }
In order to implement the basic operational support, the following connection operations must be implemented:
This is achieved by supplying the openConnection() and closeConnection() methods in the NewConnectionManager class.
First, implement the openConnection(Map parameters) factory method. This method must create a new connection, open and populate the actual connection property of the NewConnection class.
If possible, it is highly recommended to save a reference to the NEW connection object that wraps the actual connection object inside the actual connection. Users will often unwrap the NEW connection to extract the actual connection, and pass only the actual connection to their methods. Later on they will realize they need the wrapper in order to set desired timeouts, for example. If you provide a way to get back the NEW connection from the actual connection, you will save them a lot of trouble and make your implementation a lot more usable.
Try to use the predefined connection parameters to specify the identity of the connection you are about to open. In particular use the Connection.Parameter.PRINCIPAL for username type of parameters, and Connection.Parameter.CREDENTIALS for password type of parameters.
// See ConnectionDelegate for comments. public Connection openConnection(Map parameters) throws ConnectionException { checkParameters(parameters, Connection.Operation.OPEN); // Create a NEW connection. NewConnection newConnection = new NewConnection(this, parameters); // Get the desired principal and credentials parameters. String principal = (String)parameters.get(Connection.Parameter.PRINCIPAL); String credentials = (String)parameters.get(Connection.Parameter.CREDENTIALS); try { // Call the actual API to open the actual connection. ActualConnection actualConnection = new ActualConnection(configuration, principal, credentials); // Populate the NEW connection with the actual connection. newConnection.setActualConnection(actualConnection); // Reference the NEW connection from the actual connection. actualConnection.setAttribute(Connection.Parameter.REFERENCE, newConnection); } catch (ActualConnectionException ace) { throw new ConnectionException("cannot open actual connection", getType(), Connection.Operation.OPEN, cloneParameters(parameters), newConnection, ace); } // Call super to record open operation. super.openConnection(connection, parameters); // Return the opened connection. return connection; }
Do not forget to call the super class' openConnection(Connection connection, Map parameters) method to record the open operation. The framework will not function without this step.
Next, implement the closeConnection(Connection connection, Map parameters) method. This method must close and null out the actual connection property of the NewConnection class.
// See ConnectionDelegate for comments. public void closeConnection(Connection connection, Map parameters) throws ConnectionException { checkConnection(connection, Connection.Operation.CLOSE); checkParameters(parameters, Connection.Operation.CLOSE); NewConnection newConnection = (NewConnection)connection; ActualConnection actualConnection = newConnection.getActualConnection(); try { // Call the actual API to close the actual connection. actualConnection.close(); } catch (ActualConnectionException ace) { throw new ConnectionException("cannot close actual connection", getType(), Connection.Operation.CLOSE, cloneParameters(parameters), connection, ace); } finally { newConnection.setActualConnection(null); } // Call super to record close operation. super.closeConnection(connection, parameters); }
Do not forget to call the super class' closeConnection(Connection connection, Map parameters) method to record the close operation. The framework will not function without this step.
Next step is optional; to give more control over the connection operations, each operation is guarded by a separate method, in the case of open and close operations, these methods are canOpenConnection(Map parameters) and canCloseConnection(Connection connection, Map parameters). The connection pool will invoke these methods and check the return value before proceeding with the operation. If these methods return false, the pool will look for an alternate way of performing the operation or give up, depending on the context of the operation. You can implement these methods to do further parameter matching, such as selecting a desired connection protocol or authentication mode, see the section on Connection Subtype Support for more information.
Finally, if you do not plan to implement proxying and validating support, you must override the default settings for these modes to false and disable the corresponding property setters, as follows:
/** * Constructor for the NEW connection manager. */ public NewConnectionManager() { super(); super.setProxying(false); super.setValidating(false); tag = "NewConnectionManager"; } /** * This operation is not supported, NEW connection manager is not proxying. */ public void setProxying(boolean proxying) throws UnsupportedOperationException { throw new UnsupportedOperationException(); } /** * This operation is not supported, NEW connection manager is not validating. */ public void setValidating(boolean proxying) throws UnsupportedOperationException { throw new UnsupportedOperationException(); }
Note: If you do not implement validation, all validation related connection pool features will be unavailable.
You may want to override the finalize() method in the NewConnection class to close the actual connection if that has not already happened.
/** * Finalizes the NEW connection. */ public void finalize() throws Throwable { super.finalize(); // Call super to close the connection properly. if (actualConnection != null) // If still open, close the connection explicitly. try { actualConnection.close(); } catch(Throwable t) { getLogger().log(Level.SEVERE, "cannot close actual connection", t); } finally { actualConnection = null; } }
In order to enable the pool to match connections for connection capture and removal, you must implement the isMatchingConnection(Connection connection, Map parameters) method in the NewConnectionManager class. After this point you new implementation will have enough support to be used in your applications.
In order to implement connection matching, the isMatchingConnection(Connection connection, Map parameters) method must check if the connection matches the specified parameters. Here is a sample implementation:
// See ConnectionDelegate for comments. public boolean isMatchingConnection(Connection connection, Map parameters) throws ConnectionException { if (!super.isMatchingConnection(connection, parameters)) return false; NewConnection newConnection = (NewConnection)connection; ActualConnection actualConnection = newConnection.getActualConnection(); // Get the desired principal and credentials parameters. String principal = (String)parameters.get(Connection.Parameter.PRINCIPAL); String credentials = (String)parameters.get(Connection.Parameter.CREDENTIALS); try { // Match connection and parameters. if (!principal.equals(actualConnection.getPrincipal()) return false; if (!credentials.equals(actualConnection.getCrededntials()) return false; return true; } catch (ActualConnectionException ace) { throw new ConnectionException("cannot determine if actual connection is matching", getType(), null, cloneParameters(parameters), connection, ace); } }
Note: After this step, you should be able to use the new implementation in your applications. This is the minimal support level required for a functioning implementation.
If you have gotten this far, your new implementation is already functioning for basic open and close operations. This is possible because all other operations have enough support build into the abstract connection manager class. You can override any of the operation methods to implement additional steps that your implementation may choose to perform for each operation. Some examples of how this is achieved can be found in the following sections on Connection Integrity Support, Proxy Operation Support, and Validate Operation Support.
As you override the default operation methods from the abstract connection manager, always remember to call super.<operation>Connection(...) method at the end to record the successful operation that was just performed. The framework will not function properly if you fail to do this. (However, if an exception happened and the operation was not performed successfully, wrap the exception with the ConnectionException class and throw it - do not call super.<operation>Connection(...) method in this case.)
It is possible to discriminate amongst different connection delegates based on other than the type property. This is achieved by implementing the isMatchingParameters(Map parameters) method of the connection delegate interface. This method will be called by the connection pool on every connection delegate before selecting it to fulfill a particular connection request. If the method returns false, a different connection delegate will be used. This mechanism can be used to implement connection subtypes, based on any arbitrary parameters, such as protocol or authentication, for example.
The convention we follow is to ignore a parameter if it was not specified, meaning that if a user does not specify a particular parameter, then any connection delegate that matches other specified parameters should be selected, regardless of the unspecified parameter.
In order to implement the isMatchingParameters(Map parameters) method, simply call super and check for additional parameters that may be relevant to the new connection manager. Here is an example that implements a connection subtype based on the protocol:
// See ConnectionDelegate for comments. public final boolean isMatchingParameters(Map parameters) { if (!super.isMatchingParameters(parameters)) return false; if (parameters == null) return true; // Match the specified and configured protocol parameter. if (parameters.containsKey(Connection.Parameter.PROTOCOL)) { String specified = parameters.get(Connection.Parameter.PROTOCOL); String configured = configuration.get(ActualConnection.Parameter.PROTOCOL); if (!specified.equals(configured)) return false; } // Everything matches. return true; }
This method will by default be called from each can<operation>Connection(...) method in the abstract connection manager code. You can also extend each operation specific method if you need to perform more operation specific checks. If you do so, remember to always call the super class' version of the method you are overriding in order to make sure the framework does all necessary bookkeeping.
A robust implementation may want to check connection integrity between capture/release and remove/return operation events. The idea is to make sure the user did not modify the connection in a way that will confuse the framework and cause undesirable side effects. This can be done in two steps. The connection class needs to record the relevant connection state when the connection is captured or removed, and the connection manager needs to implement the isAlteredConnection(...) method to determine if the relevant state has been changed.
In the new connection class, we define a recorded state property, and override methods to record and unrecord the relevant state as follows:
// Recorded state of this connection. Map recordedState = null; /** * Getter for the recorded state. */ protected Map getRecordedState() { return recordedState; } /** * Records state, called upon capture and remove operations. */ protected void recordState() throws ConnectionException { super.recordState(); if (actualConnection == null) recordedState = null; else { // Record actual connection state. try { recordedState = new HashMap(actualConnection.getState()); } catch (ActualConnectionException ace) { throw new ConnectionException("cannot record actual connection state", getType(), null, this, ace); } } } /** * Unrecords state, called upon release and return operations. */ protected void unrecordState() throws ConnectionException { super.unrecordState(); recordedState = null; }
The recordState() method will be automatically called upon capture and remove operations, while the unrecordState() method will be automatically called upon the release and return operations.
Finally, do not forget to null out the recorded state property when cloning a connection:
/** * Cloned NEW connections will not contain a reference to the actual connection. *
* Connections are cloned when referenced in connection events. */ public Object clone() throws CloneNotSupportedException { NewConnection clone = (NewConnection)super.clone(); clone.actualConnection = null; clone.recordedState = null; return clone; }
Now that the relevant state has been recorded by the connection object upon capture and remove operations, the connection manager can implement the isAlteredConnection(...) method:
// See ConnectionDelegate for comments. public boolean isAlteredConnection(Connection connection, Map parameters) throws ConnectionException { if (super.isAlteredConnection(connection, parameters)) return true; NewConnection newConnection = (NewConnection)connection; ActualConnection actualConnection = newConnection.getActualConnection(); try { // Compare the actual connection state with the recorded state. return !actualConnection.getState().equals(newConnection.getRecordedState()); } catch (ActualConnectionException ace) { throw new ConnectionException("cannot determine if actual connection is altered", getType(), null, cloneParameters(parameters), connection, ace); } }
This method will automatically get called from the connection pool upon release and return operations to check for connection integrity.
In order to support the proxy operation, you must implement the proxyConnection() method in the new connection manager. This method reestablishes a connection on behalf of a different user without opening a new one.
Implement the proxy operation, as follows:
// See ConnectionDelegate for comments. public void proxyConnection(Connection connection, Map parameters) throws ConnectionException { checkConnection(connection, Connection.Operation.PROXY); checkParameters(parameters, Connection.Operation.PROXY); NewConnection newConnection = (NewConnection)connection; ActualConnection actualConnection = newConnection.getActualConnection(); // Get the desired principal and credentials parameters. String principal = (String)parameters.get(Connection.Parameter.PRINCIPAL); String credentials = (String)parameters.get(Connection.Parameter.CREDENTIALS); try { // Call the actual API to proxy the actual connection. actualConnection.reconnect(principal, credentials); } catch (ActualConnectionException ace) { throw new ConnectionException("cannot proxy actual connection", getType(), Connection.Operation.PROXY, cloneParameters(parameters), connection, ace); } // Call super record proxy operation. super.proxyConnection(connection, parameters); }
Remember to enable proxying support by removing the disabled setProxying(...) method if you added it earlier as suggested in one of the previous sections. The default proxying mode of a proxying connection manager should be true, so remove this setting from the constructor if you were setting it to false.
In order to support the validate operation, you must implement the validateConnection() method in the new connection manager. This method performs a simple operation that can be used to establish actual connection validity.
Implement the validate operation, as follows:
// See ConnectionDelegate for comments. public void validateConnection(Connection connection, Map parameters) throws ConnectionException { checkConnection(connection, Connection.Operation.VALIDATE); checkParameters(parameters, Connection.Operation.VALIDATE); NewConnection newConnection = (NewConnection)connection; ActualConnection actualConnection = newConnection.getActualConnection(); try { // Call the actual API to validate the actual connection. actualConnection.simpleOperation(); } catch (ActualConnectionException ace) { throw new ConnectionException("cannot validate actual connection", getType(), Connection.Operation.VALIDATE, cloneParameters(parameters), connection, ace); } // Call super record validate operation. super.validateConnection(connection, parameters); }
Remember to enable validating support by removing the disabled setValidating(...) method if you added it earlier as suggested in one of the previous sections. The default validating mode of a validating connection manager should be true, so remove this setting from the constructor if you were setting it to false.
All framework components are printable in XML format using the XmlPrintWriter as defined in the oracle.idm.io package. In order to print the new properties added to the new connection and new connection manager classes, all you have to do is override the xprintBody() method.
Override the xprintBody() method to print new connection properties, as follows:
protected void xprintBody(XmlPrintWriter out) { super.xprintBody(out); out.xprint(actualConnection, "ActualConnection"); }
Override the xprintBody() method to print new connection manager properties, as follows:
protected void xprintBody(XmlPrintWriter out) { super.xprintBody(out); out.xprint(configuration, "Configuration"); }
This framework uses the standard Java logging mechanism, as implemented by the java.util.logging package. All connection manager operation methods will log a single event, this will happen when you call super.<operation>Connection(...) methods within your own connection manager. If you want to log more events, you can do the following inside either the NewConnection or NewConnectionManager class:
getLogger().log(...);
Check documentation on standard Java logging and the java.util.logging package for more information.
If you wish to support fail-safe operation, you need to augment the operations explained in this section. For each operation (we will use open operation in the examples), first get the fail-safe level configured for that operation, as follows:
int failSafeLevel = getConnectionOperationFailSafe().getLevel(Connection.Operation.OPEN);
Then wrap each operation with a bit of logic that will repeat the operation as many times as specified by the fail-safe level after the initial failure, as follows:
ActualConnection actualConnection = null; while (failSafeLevel >= 0) try { // Open the actual connection. actualConnection = new ActualConnection(configuration, principal, credentials); break; } catch (ActualConnectionException ace) { if (failSafeLevel == 0) throw new ConnectionException("cannot open actual connection", getType(), Connection.Operation.OPEN, cloneParameters(parameters), newConnection, ace); failSafeLevel--; continue; }
The LDAP implementation can be found in the oracle.idm.connection.ldap package.
Note: Each LdapContext that comes from the LDAP connection manager will contain the following environment property, so you can get back the LdapConnection:
LdapConnection connection = (LdapConnection)context.getEnvironment().get(Connection.Parameter.REFERENCE);
LDAP context managers should behave as follows for consistency:
All IdM Connection Framework objects are printable using XML format; here is an example of how to print IdM Connection Framework objects:
ConnectionPool pool = ... ConnectionLogger logger = ...; Connection connection = ...; ConnectionEvent event = ...; // Create an XML Print Writer from the oracle.idm.io package. XmlPrintWriter out = new XmlPrintWriter(System.out); out.xprint(pool); // Prints the pool as an XML element. out.xprint(logger); // Prints the logger as an XML element. out.xprint(connection); // Prints the connection as an XML element. out.xprint(event); // Prints the event as an XML element. etc.
The IdM Connection Framework provides a GUI component for monitoring connections.
The ConnectionMonitor can be found in the oracle.idm.connection.util package.
To launch the connection monitor, simply insert the following line:
ConnectionMonitor.launch(pool);
Where pool
is the connection pool to be monitored.
The following GUI will launch automatically:
|
|||||||||
PREV PACKAGE NEXT PACKAGE | FRAMES NO FRAMES |