Complete Contents
Introduction
Chapter 1 About Netscape Application Server Extensions
Chapter 2 About the Netscape Extension Builder
Chapter 3 Introduction to Netscape's Interface Definition Language
Chapter 4 Designing a Netscape Extension
Chapter 5 Generating Output Files
Chapter 6 Completing Method Stubs
Chapter 7 Using Template Streaming
Chapter 8 Managing State and Session Information
Chapter 9 Using Object Pools
Chapter 10 Compiling the Extension Source Code
Chapter 11 Deploying and Managing a Netscape Extension
Chapter 12 Example Extension: HelloWorld
Appendix A C++ Helper Functions
Appendix B Java Helper Static Methods
Appendix C Java Class Decorations
Appendix D Reserved Words
Appendix E The ConnManager.cpp File
Glossary
Previous Next Contents Index


Using Object Pools

This chapter describes object pooling, a solution to potential limited-resource issues, including bottlenecks that occur when there are not enough resources to meet clients' demands.

The following topics are included in this chapter:


Introduction to Object Pooling
Object pooling solves potential limited-resource issues. Limited resources can cause performance bottlenecks when there are not enough resources to meet clients' demands. For example, connections to networked resources, such as databases, require non-trivial amounts of time to create and destroy. Often, in high-throughput applications, client objects must wait for a connection object to become available, creating a bottleneck in the flow of the application.

With object pooling, many clients can share a limited resource such as a connection, using it only when they need it. In this way, the performance cost of creating and destroying the resource is reduced. This benefit applies to any client of the pool-enabled extension, whether the calling client is an application or another extension.

Summary of Object Pooling Tasks
To enable object pooling, extension writers and server administrators work together as follows:

Key Concepts
Object pooling involves the following key concepts:

Object Pool
An object pool is a set of limited resources, such as connections, that can be reserved for use by clients and then returned to the pool (for probable reuse) when the object is no longer needed. Reserving and returning pooled objects avoids the overhead of separately creating and destroying an object each time a client requests it. Multiple object pools can be used. For example, one object pool might contain database connection objects, and another pool might contain CICS connection objects.

Virtual and Physical Objects
Without object pooling, whenever a client of an extension (typically an application) requests an object, a physical object is created and destroyed when no longer needed.

By contrast, when an extension uses object pooling, the application's request for a poolable object generates a virtual object instead. The virtual object supports all the methods of the requested object, but the application sees only the virtual object.

When an application calls an interface method from the virtual object, the virtual object's implementation requests a physical object from the pool and delegates the request to the physical object. When the request is complete, the extension returns the physical object to the Object Pool Manager for use by other virtual objects.

Client
In the context of object pooling, a client is the code that calls into the extension. The client is typically an application but can also be another extension. The extension requests objects, and the Object Pool Manager makes callbacks to the extension to determine how to fulfill the request.

Object Pool Manager
The Object Pool Manager is a service of Netscape Application Server. In response to clients' requests for objects, the Object Pool Manager controls one or more pools by reserving and releasing the objects in the pool. The Object Pool Manager performs the following tasks:


Process Overview for Object Pooling
The following figure shows the interrelationship between a pool-enabled extension and the key components of object pooling:



  1. The client of an extension calls an interface method on the virtual object.
  2. The virtual object's implementation reserves a matching physical object from a named pool.
  3. The method call is delegated to the physical object.
  4. When the method call is completed, the physical object is returned to the appropriate pool for use by other virtual objects. The Object Pool Manager uses a timer thread that periodically releases unused physical objects after a timeout.
For a more detailed description of object pooling processes, see the following sections:


Example of Object Pooling
In the Netscape Extension Builder sample\poolsample directory is an extension named PoolSampleExt, built in C++ with a Java Access Layer. Many topics in this section of Developer's Guide refer to this sample extension. To better understand the concepts and tasks presented, you might want to open the sample extension while reading about object pooling.

To open PoolSampleExt

  1. Start Netscape Extension Builder Designer.
  2. From the File menu, open the poolsample.gxp project file.
  3. After you expand some of the nodes in the tree view, a window similar to the following appears:
About PoolSampleExt
The PoolSampleExt extension demonstrates the use of object pooling. The extension implements a "dummy" SQL execution service. In other words, no backend SQL engine exists, and the results returned are just an echo of the SQL provided to the connection.

Based on user input, the IConnManager interface can be asked to create either of two types of connections to the back-end data source: non-transactional or transactional. All connections are returned as an IFakeConnection object. Given some SQL, a connection can be asked to create a result set, which keeps a reference to the parent connection. The result set can be asked to return the SQL execution result in the form of a string.

About the Application
Using an HTML file, poolsample.html, users provide input to the application whose functionality is extended by PoolSampleExt. The application accepts the following parameters:

The application creates the specified number and type of connections. It then queries the connections for their associated physical connection IDs, and returns the IDs. These IDs appear in the first section of the application's response page.

For each connection the application creates, it also creates a result set with the given SQL, executes the GetResult( ) method from each result set, and displays the results. Each result is a string containing the connection ID of the associated physical connection. The results appear in the second section of the application's response page.


Inside a Pool-Enabled Extension
This section describes the interactions within an extension, using PoolSampleExt as an example. Two main process flows are described:

Creating a Connection
As shown in the following figure, creating a connection involves this process:

  1. An application calls CreateConnection( ), a method of the ConnManager class. ConnManager is defined by the extension programmer.
  2. CreateConnection( ) acts on _ConnManager, a runtime layer object that corresponds to the ConnManager class.
  3. Using the same parameters as CreateConnection( ), _ConnManager calls CreateConnectionIntrospection( ) on ConnManager.
  4. ConnManager creates an introspection object, CInfo, which encapsulates the method parameters from CreateConnection( ). For more information, see The Introspection Interface.
  5. ConnManager passes CInfo back to the Netscape Extension Builder Runtime Layer as an interface, IInfo. IInfo is the introspection interface that is implemented by CInfo and Connection.
  6. The Netscape Extension Builder Runtime Layer creates a virtual connection object, _Connection, which contains the introspection object, CInfo.
  7. The Netscape Extension Builder Runtime Layer passes _Connection back to the application.


Calling a Method on a Virtual Connection
As shown in the following figure, calling a method on a virtual connection involves this process:

  1. The application calls CreateResultSet( ) on the virtual object, _Connection.
  2. The virtual object makes a reserve request, asking the Object Pool Manager to reserve a physical connection object that matches the virtual connection's introspection object, CInfo.
  3. The Object Pool Manager makes callbacks to the object evaluation interface in the stub-file component of the extension. For more information, see The Object Evaluation Interface.
  4. Based on the callbacks, the Object Pool Manager passes back a matching physical object. In other words, the virtual object binds to a physical object.
  5. The virtual connection delegates the CreateResultSet( ) method call to the physical connection, and a result set is created.
  6. After the method call is finished, the virtual connection returns the physical connection to the Object Pool Manager. In other words, the binding between virtual and physical object is broken.
  7. The virtual connection object returns results to the application.


The Introspection Interface
In Netscape Extension Builder Designer, suppose you decorate a method to be a pooled-object creation method. In PoolSampleExt for example, CreateConnection( ) has its Pooled Object Creation decoration set to Yes.

When you set this decoration, subsequent code generation produces two related method stubs: one for the normal creation method, and a "twin" stub known as the create-introspection method. The twin method has a naming scheme of

<method>Introspection()

For example:

CreateConnectionIntrospection()

In addition to filling out the normal creation method, you fill out the create-introspection method, whose purpose is to return an introspection object.

An introspection object encapsulates the information that is used as the basis for matching by the Object Pool Manager, and the introspection interface provides access to this information.

An introspection interface is one whose methods are used to query attributes of virtual or physical objects. This interface is implemented by the introspection object.

You define an introspection interface in Netscape Extension Builder Designer. Then, when you set a coclass's Poolable Object decoration, you are also required to specify this coclass's introspection interface. For more information on specifying the introspection interface, see Designating Objects That Can Be Pooled.

The Object Evaluation Interface
The object evaluation interface provides methods to help the Object Pool Manager reserve objects and return them to a pool. This Netscape Application Server-defined interface is named IGXObjectEvaluation in C++ extensions, or IJavaObjectEvaluation in Java extensions.

Each class that contains pooled-object creation methods will implement the object evaluation interface. Therefore, each class's corresponding stub file contains the object evaluation interface and its method stubs. For example, PoolSampleExt has a ConnManager class for creating pooled objects, so the ConnManager.cpp file is where you would complete stubs for the IGXObjectEvaluation interface.

You never call these methods directly. Instead, the Object Pool Manager makes callbacks to your extension classes to obtain specific data. You decide how the Object Pool Manager evaluates this data when you fill out the method stubs, supplying appropriate return values for given input conditions.

The object evaluation interface defines the methods as shown in the following table. The C++ versions are listed. The Java versions are equivalent, but their names begin with a lowercase letter.

Method
Description
MatchObject( )
Determines whether a virtual object matches a physical object from a specified pool.
CreateObject( )
For a given virtual object, creates a matching physical object in a specified pool.
StealObject( )
Determines whether a physical object is eligible to be replaced.
ReleaseObject( )
Destroys a physical object in a specified pool.
InitObject( )
Marks a physical object as reserved.
UninitObject( )
Marks a physical object as returned to the pool (unreserved).
GetHint( )
Provides a hint string that may improve performance of the MatchObject( ) method.

For more information on syntax and usage of the object evaluation methods, see Completing Stubs for Object Evaluation Methods.


Inside the Object Pool Manager
When an extension makes a request to reserve an object, the Object Pool Manager processes the request through the following possible phases:

The following flowchart and the next several sections describe the lifetime of a request received by the Object Pool Manager:



Matching a Pooled Object
A client makes a request of a virtual object. The extension communicates with the Object Pool Manager to bind the virtual object to a matching physical object. The virtual object then repeats the client's request, making this same request of the matched physical object.

If a match is found (if MatchObject( ) returns TRUE), then the Object Pool Manager reserves the matching physical object and sends it back to the requesting extension. If no matching object is found (if MatchObject( ) returns FALSE), then the Object Pool Manager proceeds to the next phase of processing logic—attempting to create a physical object.

Creating a Pooled Object
If no matching object is found, the Object Pool Manager checks its MaxPoolSize variable before trying to create a physical object. MaxPoolSize determines the maximum number of objects a pool can contain. This variable is set in the registry by the server administrator.

If the number of objects in the pool is less than MaxPoolSize, then the pool is allowed to grow. As a result, the Object Pool Manager calls the CreateObject( ) method. A successful call returns a physical object to the requesting client. An unsuccessful call indicates that a critical resource is unavailable. For example, if an application requests a database connection but the database server is down, then the call to CreateObject( ) would fail, and a FAILURE state would be returned immediately.

Replacing a Pooled Object
If an object pool is at the limit set by MaxPoolSize, then the pool is considered full. As a result, instead of trying to create an object, the Object Pool Manager attempts to replace a non-matching object with a physical object that matches the one requested.

Only unreserved objects can be replaced, so the Object Pool Manager first checks whether any objects are free. Assuming there are unreserved objects, the Object Pool Manager next calls the StealObject( ) method to determine which object to replace.

The Object Pool Manager calls the ReleaseObject( ) method to destroy the object to be replaced. As a result, the pool now contains one slot to fill, and the CreateObject( ) method is immediately called.

Queuing a Request
The fourth phase of processing occurs under the following conditions: if no matches are found, if the pool is full, and if none of the objects is free to be replaced. Under these conditions, the Object Pool Manager queues the request. The request waits until an object is returned to the pool. Pooled objects are returned to their originating pool when a client is done using them.

If the waiting period is within a maximum allowable idle time, then the request processing starts over from the beginning, with an attempt to match the newly returned object. The maximum allowable idle time is configurable through the MaxWait variable in the registry.

Returning a FAILURE State
If the request is queued for longer than the MaxWait time, then the request finally fails. Frequent request failures may indicate a need for the server administrator to review an object pool's configuration settings.


Adding Decorations for Object Pooling
Just as you do for other decorations, use Netscape Extension Builder Designer to add decorations for object pooling. The order in which you add decorations does not matter. However, there are different sets of decorations you must specify, depending on what you want to do.

Object pooling decorations can be categorized according to the following tasks:

Details of the preceding tasks are based on PoolSampleExt, whose project file is poolsample.gxp.

Creating Pooled Objects
To create pooled objects, specify the following decorations:

Pooled Object Creation
You set the Pooled Object Creation decoration at the method level. A value of Yes indicates that this method creates a pooled object through its Out parameter. For example, in the connService module, the IConnManager interface provides three creation methods. Note the values for each method's Pooled Object Creation decoration:

Method
Pooled Object Creation Value
CreateConnection( )
Yes
CreateTxConnection( )
Yes
CreateNonPooledConnection( )
No

The CreateConnection( ) method is used to create a non-transactional connection, and the CreateTxConnection( ) method is used to create a transactional connection. In both cases, the object created is allocated from a pool. However, the CreateNonPooledConnection( ) method, creates a non-pooled, non-transactional connection.

When Pooled Object Creation is set to its default value of No, a corresponding default set of decorations appears for the method's Out parameter. For example, the decorations on the Out parameter of CreateNonPooledConnection( ) appear as follows:

By contrast, when Pooled Object Creation is set to Yes, four additional decorations become available to the method's Out parameter. For example, the decorations on the Out parameter of CreateConnection( ) appear as follows:

Compare the Out parameter decorations for CreateConnection( ) and CreateTxConnection( ):

Decoration
Value in CreateConnection( )
Value in CreateTxConnection( )
C++ Class
Connection
TxConnection
Java Class
Connection
TxConnection
Pooled Object Name
CONNECTION
CONNECTION
Object Pool Name
CONN_POOL
TXCONN_POOL
Object Pool Config
POOLSAMPLE
POOLSAMPLE
Keep Pooled Object
No
Yes

CreateConnection( ) creates a Connection object allocated from a pool named CONN_POOL, whereas CreateTxConnection( ) creates a TxConnection object allocated from a pool named TXCONN_POOL.

Another difference appears in the Keep Pooled Object decoration. This decoration affects the lifetime of a pooled object and is described in Changing a Pooled Object's Lifetime. The next three sections describe Pooled Object Name, Object Pool Name, and Object Pool Config.

Pooled Object Name
The Pooled Object Name decoration is an arbitrary name you assign to the pooled object you want to create. The Object Pool Manager uses this name to track objects as they are passed from place to place in the object pooling request flow.

The example uses a value of CONNECTION as a convenient indication that the object is a connection. However, the value is not indicating the Connection class itself. Note that CONNECTION is also used as the name for TxConnection objects. Even though CONNECTION is created by both methods, the created objects are allocated from different pools. As a result, the Object Pool Manager can distinguish Connection objects and TxConnection objects.

The Pooled Object Name decoration is required if an Object Pool Name is specified.

Object Pool Name
The Object Pool Name decoration determines which pool will contain the objects. Based on the example, the Object Pool Manager will be managing two pools: CONN_POOL will contain connection objects; TXCONN_POOL will contain transactional connection objects.

In general, the number of pools that the Object Pool Manager controls at any one time is determined by the number of unique values for the Object Pool Name decoration, in all extensions running on the same server. If the specified pool does not exist, it is created the first time an object is requested from this pool.

One reason for using different pools is to allow the Object Pool Manager to evaluate matches differently. For example, you might want to have more restrictive matching criteria for TxConnection objects. If so, you would implement the MatchObject( ) method to check for a pool name of TXCONN_POOL, and use different programming logic depending on the pool name. Similarly, you can implement CreateObject( ) to create a TxConnection object based on the pool name.

Another reason for using different pools is to manage them differently. For example, the Keep Pooled Object decoration is No for objects from the CONN_POOL, but is Yes for objects from TXCONN_POOL.

Object Pool Config
The Object Pool Config decoration is the configuration key in the Netscape Application Server registry. For example, both CONN_POOL and TXCONN_POOL use the same configuration key, POOLSAMPLE. If the value is null, the extension uses Object Pool Name as the default value for the configuration key.

Typically, the server administrator assigns a key name to configure the server for optimal performance under object pooling conditions. Different configurations can be created depending on server resources. Check with the server administrator for the value to enter for the Object Pool Config decoration.

Designating Objects That Can Be Pooled
To designate objects that can be pooled, specify the following decorations:

You set both of these decorations on a coclass. For example, the decorations on the Connection coclass appear as shown in the following figure:

Poolable Object
If you want clients to be able to share an object, set the Poolable Object decoration to Yes. Just because an object can be pooled does not necessarily mean that the object always will be pooled. For example, CreateNonPooledConnection( ) is not decorated as an pooled-object creation method; therefore, the Connection objects it creates are not pooled.

Introspection Interface
Setting Poolable Object to Yes causes another decoration to appear just below it: Introspection Interface. The value you specify must be an interface you have defined in your extension. Also, the poolable coclass, Connection, must implement this interface.

In PoolSampleExt, the introspection interface is set to IInfo. This means that IInfo will be used to encapsulate data into a virtual object. The Object Pool Manager will use this data from the virtual object and will either find a matching physical object or create one if needed. In PoolSampleExt, the IInfo interface defines methods that will return a user ID, password, and some flags.

Changing a Pooled Object's Lifetime
To change the lifetime of a pooled object, specify either of the following decorations:

Keep Pooled Object
The Keep Pooled Object decoration determines how long to keep a virtual object bound to a physical object. The default value, No, causes the binding to last only as long as a method call on the pooled object. In other words, successive method calls on the same virtual object are not guaranteed to bind to the same physical object. A value of No will also produce better interleaved use of the pooled object, because it is held for shorter periods.

By contrast, setting Keep Pooled Object to Yes extends the binding to the lifetime of the virtual object, thereby ensuring that successive method calls use the same physical object. This is useful in the case of the CreateTxConnection( ) method, because the resource being requested is a transactional connection, so preserving the session context is important.

You can set Keep Pooled Object in either of two places:

Note that Keep Pooled Object is set to Yes for CreateTxConnection( ) but is set to No for CreateConnection( ). This difference can be seen in the first section of the application's response page:

Pooled No Reuse
Use the Pooled No Reuse decoration on the method of a pooled object. By default, Pooled No Reuse is set to No. This setting means that after a physical object is returned to the Object Pool Manager, the physical object is available for reuse by other virtual objects.

In some cases, a method call on a pooled object changes the state of this object so it becomes unusable. When this happens, the physical object should not be reused by other virtual objects.

To ensure that such physical objects are not reused, set the Pooled No Reuse decoration to Yes on any method that might make a physical object unusable for future method calls. A setting of Yes causes a physical object to be destroyed when it is returned to the Object Pool Manager.

Passing a Pooled Object
When passing a pooled object, specify the following decorations:

Although these decorations affect the lifetime of a pooled object, they are used particularly when passing pooled objects. For example, suppose a pooled object, Connection, passes itself to a ResultSet object. By default, the ResultSet will try to use the pooled Connection, but the Object Pool Manager may have already given away this physical object to another request.

Instead, to preserve the pooled object for use by ResultSet, it's necessary to bind the reservation lifetime of the pooled object to the lifetime of the ResultSet object. In other words, as long as the ResultSet object exists, the pooled Connection that it uses must not be returned to its pool. You specify the necessary binding by setting Uses Pooled Object and Pooled In Parameter.

A pooled object may be passed around in any of the following ways:

How Pooled Object Is Passed
Decorations to Set
From the called object to an Out parameter.
Uses Pooled Object
(on Out parameter)

From an In parameter to the called object.
Uses Pooled Object, Pooled In Parameter (on a method)
From an In parameter to an Out parameter.
Uses Pooled Object, Pooled In Parameter (on Out parameter)

The next three sections describe these situations in detail. The most common case is the first one, passing from the called object to an Out parameter. But you may find use for any of the three situations, depending on how you design the extension. Note that you specify Pooled In Parameter only when Uses Pooled Object is also specified.

From Called Object to Out Parameter
The following figure represents the case of passing a pooled object from the called object to an Out parameter:



In this case, specify the Uses Pooled Object decoration on the Out parameter.

For example, in IFakeConnection, the CreateResultSet( ) method creates a ResultSet object, which keeps a reference to the IFakeConnection. Since the ResultSet object intends to use the IFakeConnection, the associated physical connection must not be returned to its pool. The Uses Pooled Object decoration prevents the physical connection from being returned to its pool, for the lifetime of the ResultSet object.

The Out parameter settings for CreateResultSet( ) are shown in the following figure:

Note that you specify CONNECTION as the value for Uses Pooled Object. This corresponds to the arbitrary name you assigned to the IFakeConnection object when you decorated the CreateConnection( ) method. In CreateConnection( ), you previously set the Out parameter's Pooled Object Name to CONNECTION:

From In Parameter to Called Object
The following figure represents the case of passing a pooled object from an In parameter to the called object:



In this case, specify both Pooled In Parameter and Uses Pooled Object on the method.

For example, suppose Attach2Conn( ) is a method that uses a pooled Connection object. If an Attach2Conn( ) method call is made on a ResultSet object, then you want to prevent the pooled Connection object from being returned to its pool, for the lifetime of the ResultSet object. To do so, set the decorations on Attach2Conn( ). In the example, you might set Pooled In Parameter to ppConn, and Uses Pooled Object to CONNECTION.

From In Parameter to Out Parameter
The following figure represents the case of passing a pooled object from an In parameter to an Out parameter:



In this case, specify both Pooled In Parameter and Uses Pooled Object on the method's Out parameter.

For example, suppose a CreateResultSet( ) method call is made on a ConnManager object. In this case, a pooled object is being passed in, some processing occurs, and the pooled object is passed out again. To prevent the pooled object from being returned to its pool, for the lifetime of the Out parameter, set the decorations on the Out parameter of CreateResultSet( ). In the example, you might set Pooled In Parameter to ppConn, and Uses Pooled Object to CONNECTION.


Completing Stubs for Pooled-Object Creation Methods
In PoolSampleExt, the connService service module contains the ConnManager coclass. Therefore, after successful code generation, the ConnManager coclass is represented in source code by the following file:

poolsample\cpp\connService\ConnManager.cpp

ConnManager implements the IConnManager interface, which in turn has three creation methods. Each method has a corresponding stub to be completed, which is found in ConnManager.cpp. The following code fragment shows the completed stub for the CreateConnection( ) method:

// Stub method bodies for interface: IConnManager

HRESULT

ConnManager::CreateConnection(

/* [in] */ unsigned long uid,

/* [in] */ LPSTR passwd,

/* [in] */ unsigned long flags,

/* [out] */ IFakeConnection **ppConn)

{

HRESULT hr=GXE_SUCCESS;

//***

//*** Provide your implementation here

//*** and remove the GXASSERT below

//***

*ppConn = new Connection(this, uid, passwd, flags);

return hr;

}

However, in addition to a method stub for CreateConnection( ), there is also a stub for a "twin method" called CreateConnectionIntrospection( ). The completed stub is shown in the following code fragment:

HRESULT

ConnManager::CreateConnectionIntrospection(

/* [in] */ unsigned long uid,

/* [in] */ LPSTR passwd,

/* [in] */ unsigned long flags,

/* [out] */ IInfo **ppConn)

{

HRESULT hr=GXE_SUCCESS;

//***

//*** Provide your implementation here

//*** and remove the GXASSERT below

//***

*ppConn = new Info(uid, passwd, flags);

return hr;

}

This twin method, known as a create-introspection method, appears because the Pooled Object Creation decoration is set to Yes for the CreateConnection( ) method. The purpose of a create-introspection method is to create an introspection object, which encapsulates the data that the Object Pool Manager uses to match a physical object.

Note how CreateConnectionIntrospection( ) returns an introspection object:

/* [out] */ IInfo **ppConn)

This object must implement the introspection interface, which was set to IInfo in Netscape Extension Builder Designer.

The other pooled object creation method, CreateTxConnection( ), has its own introspection method, CreateTxConnectionIntrospection( ). For any method whose Pooled Object Creation decoration is set to Yes, a twin method stub is generated using the following naming scheme:

<method>Introspection()


Completing Stubs for Object Evaluation Methods
For any class containing pooled-object creation methods, a stub file is generated that contains the object evaluation interface and its methods. The Object Pool Manager makes callbacks to these methods to determine criteria for matching and creating objects.

You must complete the method stubs in this interface, which is named IGXObjectEvaluation in C++ extensions or IJavaObjectEvaluation in Java extensions. For example, in PoolSampleExt, the object evaluation method stubs are found in ConnManager.cpp.

Most or all of the object evaluation methods use the following parameters:

poolName
The name of an object pool. poolName is needed because a class may create pooled objects from more than one pool, and each pool may contain different types of objects. However, the methods in the object evaluation interface can be called for any pool. You may want to use different decision logic depending on which pool a request comes from.
pVirtual
A pointer to a virtual object.
pPhysical
A pointer to a physical object.

Implementing MatchObject( )
The Object Pool Manager makes a callback to MatchObject( ) to ask if a given physical object matches a given virtual object. Given these two objects, you determine whether they are considered a match, and you set the return value accordingly to TRUE or FALSE.

C++ Example
In PoolSampleExt, MatchObject( ) is implemented in ConnManager.cpp as shown in the following code. The matching criteria differ for TXCONN_POOL, which contains transactional connection objects created by CreateTxConnection( ).

// Stub method bodies for interface: IGXObjectEvaluation

HRESULT

ConnManager::MatchObject(

/* [in] */ LPSTR poolName,

/* [in] */ IGXObject *pVirtual,

/* [in] */ IGXObject *pPhysical,

/* [out] */ BOOL *pMatches)

{

HRESULT hr=GXE_SUCCESS;

//***

//*** Provide your implementation here

//*** and remove the GXASSERT below

//***

// Depending on poolName, determine if the objects match:

// Navigate to the introspection interface of the

// virtual & physical objects, get their attributes,

// and see if they match.

// CONN_POOL: match on userid & passwd

// TXCONN_POOL: match on userid, passwd AND flags

// (match criteria is stricter than CONN_POOL)

if (!strcmp(poolName, "CONN_POOL"))

{

*pMatches = FALSE;

IInfo* pV = NULL;

IInfo* pP = NULL;

// Navigate to IInfo interfaces

if((((hr=pVirtual->QueryInterface(IID_IInfo,

(LPVOID*)&pV))==GXE_SUCCESS)&&(pV))

&&(((hr=pPhysical->QueryInterface(IID_IInfo,

(LPVOID*)&pP))==GXE_SUCCESS)&&(pP)))

{

ULONG PUid = 0;

ULONG VUid = 0;

char PPasswd[256];

char VPasswd[256];

// Get uid, passwd for both virtual

// & physical objects

if(hr==GXE_SUCCESS)

hr=pV->GetUid(&VUid);

if(hr==GXE_SUCCESS)

hr=pV->GetPasswd(VPasswd, 256);

if(hr==GXE_SUCCESS)

hr=pP->GetUid(&PUid);

if(hr==GXE_SUCCESS)

hr=pP->GetPasswd(PPasswd, 256);

// Check if userid & password match

if ((hr==GXE_SUCCESS)

&& (PUid==VUid)

&& (!strcmp(PPasswd, VPasswd)))

*pMatches = TRUE;

}

// Release interfaces

if (pP)

pP->Release();

if (pV)

pV->Release();

}

else // TXCONN_POOL

...

Implementing CreateObject( )
The Object Pool Manager makes a callback to CreateObject( ) to ask you to create a physical object that matches the given virtual object.

This callback may occur for two reasons:

If CreateObject( ) fails to create a physical object, it means a critical resource is unavailable. As a result, the Object Pool Manager will not queue the associated request but will return a FAILURE status immediately.

Note the Out parameter for CreateObject( ):

/* [out] */ IGXPoolObject **ppPhysical)

The previous line of code creates an instance of a coclass that is marked as poolable. This coclass implements the IGXPoolObject interface, which is automatically code-generated for you.

C++ Example
In PoolSampleExt, CreateObject( ) is implemented in ConnManager.cpp as shown in the following code. The creation logic differs depending on the pool name.

HRESULT

ConnManager::CreateObject(

/* [in] */ LPSTR poolName,

/* [in] */ IGXObject *pVirtual,

/* [out] */ IGXPoolObject **ppPhysical)

{

HRESULT hr=GXE_SUCCESS;

//***

//*** Provide your implementation here

//*** and remove the GXASSERT below

//***

// Depending on the poolName, navigate to the

// introspection interface of the virtual object,

// get the encapsulated attributes,

// and create the appropriate physical object with the

// same attributes.

if (!strcmp(poolName, "CONN_POOL"))

{

IInfo* pV = NULL;

IFakeConnection* pConn = NULL;

ULONG uid = 0;

ULONG flags = 0;

char passwd[256];

// Navigate to IInfo interface

if(((hr=pVirtual->QueryInterface(IID_IInfo,

(LPVOID*)&pV))==GXE_SUCCESS)&&(pV))

{

// Get the uid, passwd, flags

if(hr==GXE_SUCCESS)

hr=pV->GetUid(&uid);

if(hr==GXE_SUCCESS)

hr=pV->GetPasswd(passwd, 256);

if(hr==GXE_SUCCESS)

hr=pV->GetFlags(&flags);

}

// Create a matching Connection object.

if (hr==GXE_SUCCESS)

{

hr = CreateConnection(uid, passwd, flags, &pConn);

// QueryInterface to IGXPoolObject

if((hr==GXE_SUCCESS)&& pConn)

hr=pConn->QueryInterface(IID_IGXPoolObject,

(LPVOID*)ppPhysical);

}

// Release interfaces

if (pV)

pV->Release();

if (pConn)

pConn->Release();

}

else // TXCONN_POOL

...

Implementing StealObject( )
The Object Pool Manager makes a callback to this method to ask if a given physical object can be destroyed. Destroying the object makes room in the pool to create another object that matches a given virtual object. Set the return value to TRUE or FALSE depending on the physical object to be replaced and the virtual object to be reserved.

In most cases, you may replace any physical object, so you should return TRUE. In rare cases, the object may be an important resource that you want to prevent from being replaced. Return FALSE in this case. Returning FALSE does not guarantee that the object will never be destroyed. Instead, a value of FALSE effectively raises that object's priority. The Object Pool Manager will pass over this object when searching for objects to destroy.

If you return FALSE, the request will probably be queued until another object is returned to the pool.

C++ Example
In PoolSampleExt, StealObject( ) is implemented in ConnManager.cpp as shown in the following code. The implementation means that any object is equally eligible to be replaced.

HRESULT

ConnManager::StealObject(

/* [in] */ LPSTR poolName,

/* [in] */ IGXObject *pVirtual,

/* [in] */ IGXObject *pPhysical,

/* [out] */ BOOL *pCanSteal)

{

HRESULT hr=GXE_SUCCESS;

//***

//*** Provide your implementation here

//*** and remove the GXASSERT below

//***

// Allow any connection to be replaced.

*pCanSteal = TRUE;

return hr;

}

Implementing ReleaseObject( )
The Object Pool Manager makes a callback to ReleaseObject( ) to ask you to dispose of any resource a physical object might be holding. The physical object will never be used again. This callback may occur if an object needs to be created but the pool is at its maximum size.

However, do not use ReleaseObject( ) to actually destroy the object. The object is automatically destroyed like any other COM object, when its reference count drops to zero.

For pooled objects, use ReleaseObject( ) for time-consuming actions such as closing network connections. If the destructor is used for time-consuming tasks instead of ReleaseObject( ), other requesting threads will be blocked.

It is recommended that you isolate time-consuming actions in a separate method of the physical object. You can use a state flag to ensure that the method executes its logic. A non-pooled instance of the object can then call this logic from the destructor, and a pooled instance can call the logic from ReleaseObject( ).

C++ Example
In PoolSampleExt, ReleaseObject( ) is implemented in ConnManager.cpp as follows. The reason parameter does nothing but is reserved for future use.

HRESULT

ConnManager::ReleaseObject(

/* [in] */ LPSTR poolName,

/* [in] */ IGXObject *pPhysical,

/* [in] */ unsigned long reason)

{

HRESULT hr=GXE_SUCCESS;

//***

//*** Provide your implementation here

//*** and remove the GXASSERT below

//***

// Would have closed any backend connection here.

// Nothing to do in this dummy implementation.

return hr;

}

Implementing InitObject( )
The Object Pool Manager makes a callback to InitObject( ) whenever the given physical object is reserved against the given virtual object; that is, after a successful match, creation, or replacement. Use InitObject( ) to make any initializations on the physical object that are specific to the given virtual object.

For example, suppose you have a connection object. For this object to match exactly with a given virtual object, both the userid/password and any connection settings must match. If you assume that allocating a network connection is time consuming, it is more efficient to do so in the object constructor or in the CreateObject( ) method. In that case, you would return TRUE from MatchObject( ) as long as the userid/password match.

By contrast, use InitObject( ) to initialize the settings that take little processing time. This breakup of actions will ensure maximum pooling efficiency.

C++ Example
In PoolSampleExt, InitObject( ) is implemented in ConnManager.cpp as follows.

HRESULT

ConnManager::InitObject(

/* [in] */ LPSTR poolName,

/* [in] */ IGXObject *pVirtual,

/* [in] */ IGXObject *pPhysical)

{

HRESULT hr=GXE_SUCCESS;

//***

//*** Provide your implementation here

//*** and remove the GXASSERT below

//***

// Remember: the match criteria for objects in

// CONN_POOL did not include flag settings.

// We therefore need to restore the flag settings

// of the physical object, to match those of the

// virtual object.

// For CONN_POOL objects, do flag settings here.

if (!strcmp(poolName, "CONN_POOL"))

{

// Get to IInfo interface

IInfo* pV = NULL;

if(((hr=pVirtual->QueryInterface(IID_IInfo,

(LPVOID*)&pV))==GXE_SUCCESS)&&(pV))

{

ULONG flags = 0;

hr=pV->GetFlags(&flags);

// Get Connection implementation

IFakeConnection* pIConn=NULL;

if(((hr=pPhysical->QueryInterface

(IID_IFakeConnection,(LPVOID*)&pIConn))

==GXE_SUCCESS)&&(pIConn))

{

// Set flags

pIConn->SetFlags(flags);

}

}

}

return hr;

}

Implementing UninitObject( )
The Object Pool Manager makes a callback to UninitObject( ) whenever the given physical object is returned to the given pool. Use this method as a complement to InitObject( ). Do not use UninitObject( ) nor the object destructor for time-consuming actions such as closing network connections; use ReleaseObject( ) instead.

C++ Example
In PoolSampleExt, UninitObject( ) is implemented in ConnManager.cpp as follows.

HRESULT

ConnManager::UninitObject(

/* [in] */ LPSTR poolName,

/* [in] */ IGXObject *pPhysical)

{

HRESULT hr=GXE_SUCCESS;

//***

//*** Provide your implementation here

//*** and remove the GXASSERT below

//***

// Nothing to do.

return hr;

}

Implementing GetHint( )
The Object Pool Manager makes a callback to GetHint( ) to ask for a hint string for the given virtual object. This hint string is used to group objects in the pool, to limit MatchObject( ) searches to this group. Using GetHint( ) may improve performance if the MatchObject( ) method is time-consuming. In most cases, however, return an empty string.

C++ Example
In PoolSampleExt, GetHint( ) is implemented in ConnManager.cpp as shown in the following code:

HRESULT

ConnManager::GetHint(

/* [in] */ LPSTR poolName,

/* [in] */ IGXObject *pVirtual,

/* [out] */ LPSTR hint,

/* [in] */ unsigned long Size)

{

HRESULT hr=GXE_SUCCESS;

//***

//*** Provide your implementation here

//*** and remove the GXASSERT below

//***

// Don't want to provide any hint.

strcpy(hint, "");

return hr;

}


Reference List of Object Pooling Decorations
You add decorations for object pooling in coclasses, methods, and Out parameters.

Coclass Decorations
Add decorations on a coclass if it represents objects that are pooled.

Decoration
Description
Poolable Object
Specifies whether this object can be pooled. Pooled objects are shared between clients so as to minimize the time clients wait to be served. This option is useful for objects that are linked to limited and costly resources, such as data connections.
Introspection Interface
Only available when Poolable Object is set to Yes. This decoration specifies the interface that provides the methods used to query the virtual object. This is an interface you have defined in the extension, and the poolable coclass must implement this interface.

Method Decorations
The following decorations are available in all methods:

Decoration
Description
Uses Pooled Object
Indicates that when this method is called, a pooled object is retrieved from an In parameter. Specify an arbitrary name for the pooled object. Use this decoration to extend the reservation lifetime of pooled objects that are passed to other objects.
Pooled In Parameter
Enter the name of the In parameter that holds the pooled object. The In parameter may be the pooled coclass or any other downstream coclass that has previously grabbed the pooled object. This decoration is required if the Uses Pooled Object decoration is set.
Pooled Object Creation
Defines this method as one that creates a pooled object through its Out parameter. Setting this decoration makes additional decorations available on its Out parameter.

The following method decorations appear only within coclasses that are decorated as poolable objects:

Decoration
Description
Keep Pooled Object
Once this method is called, this decoration specifies whether the virtual object will keep the real object reserved (not allowing other matches) for the life of the virtual object. Establishes a persistent binding between the virtual object and the real object.
Pooled No Reuse
Once this method is called, this decoration specifies the reserved object will be destroyed when the virtual object returns it to the object pool. This is useful if a method is known to have side-effects on a pooled resource.

Out Parameter Decorations
The following Out parameter decorations can be set in any method:

Decoration
Description
Uses Pooled Object
Indicates that when this method is called, this Out parameter retrieves a pooled object. If this Out parameter is also decorated with a Pooled In Parameter, then this Out parameter retrieves the pooled object from the specified In parameter.
If this Out parameter is not decorated with a Pooled In Parameter, then this Out parameter retrieves the pooled object from the called object.
Use this decoration to extend the reservation lifetime of pooled objects that are passed to other objects.
Pooled In Parameter
Enter the name of the In parameter that holds the pooled object. The In parameter may be the pooled coclass or any other downstream coclass that has previously grabbed the pooled object. This decoration is optional and supports the Uses Pooled Object decoration.

The following Out parameter decorations are available only in methods that are decorated as pooled object creation methods:

Decoration
Description
Pooled Object Name
Name of the pooled object that is being created. This decoration is required if the Object Pool Name is specified.
Object Pool Name
Name of the pool that will contain objects being pooled. This decoration is required if the Pooled Object Name is specified.
Object Pool Config
Configuration key for this pool in the Netscape Application Server registry. If null, the extension uses Object Pool Name as the default value for the configuration key.
Keep Pooled Object
If set to No, the virtual object binds to a physical object only for the duration of a method call on the virtual object.
If set to Yes, the virtual object created binds itself immediately to a physical object and reserves the physical object for the life of the virtual object. A setting of Yes is useful when you want to preserve session context.

 

Copyright © 2000 Sun Microsystems, Inc. Some preexisting portions Copyright © 2000 Netscape Communications Corp. All rights reserved.