Skip Headers
Oracle® Application Server Containers for J2EE Services Guide
10g Release 2 (10.1.2) for Windows or UNIX
B14012-02
  Go To Documentation Library
Home
Go To Product List
Solution Area
Go To Table Of Contents
Contents
Go To Index
Index

Previous
Previous
Next
Next
 

9 Java Object Cache

This chapter describes the Oracle Application Server Containers for J2EE (OC4J) Java Object Cache, including its architecture and programming features. This chapter covers the following topics:

Java Object Cache Concepts

Oracle Application Server 10g offers the Java Object Cache to help e-businesses manage Web site performance issues for dynamically generated content. The Java Object Cache improves the performance, scalability, and availability of Web sites running on Oracle Application Server 10g.

By storing frequently accessed or expensive-to-create objects in memory or on disk, the Java Object Cache eliminates the need to repeatedly create and load information within a Java program. The Java Object Cache retrieves content faster and greatly reduces the load on application servers.

The Oracle Application Server 10g cache architecture includes the following cache components:

Java Object Cache Basic Architecture

Figure 9-1 shows the basic architecture for the Java Object Cache. The cache delivers information to a user process. The process could be a servlet application that generates HTML pages, or any other Java application.

The Java Object Cache is an in-process, process-wide caching service for general application use. That is, objects are cached within the process memory space, and the Java Object Cache is a single service that is shared by all threads running in the process, in contrast to a service that runs in another process. The Java Object Cache can manage any Java object. To facilitate sharing of cached objects, all objects within the cache are accessed by name. The caching service does not impose a structure on objects being cached. The name, structure, type, and original source of the object are all defined by the application.

To maximize system resources, all objects within the cache are shared. However, access to cached objects is not serialized by access locks, allowing for a high level of concurrent access. When an object is invalidated or updated, the invalid version of the object remains in the cache as long as there are references to that particular version of the object. It is thus possible to have multiple versions of an object in the cache at the same time; however, there is never more than one valid version of the object. The old or invalid versions of an object are visible only to applications that had references to the version before it was invalidated. If an object is updated, a new copy of the object is created in the cache, and the old version is marked as invalid.

Objects are loaded into the cache with a user-provided CacheLoader object. This loader object is called by the Java Object Cache when a user application requests an object from the cache and it is not already present. Figure 9-1 is a graphical representation of the architecture. The application interacts with the cache to retrieve objects, and the cache interacts through the CacheLoader with the data source. This process gives a clean division between object creation and object use.

Figure 9-1 Java Object Cache Basic Architecture

Java Object Cache architecture.
Description of the illustration O_1034.gif

Distributed Object Management

The Java Object Cache can be used in an environment in which multiple Java processes are running the same application or working on behalf of the same application. In this environment, it is useful to have identical objects cached in different processes. For simplicity, availability and performance, the Java Object Cache is specific to each process. There is no centralized control of which objects are loaded into a process. However, the Java Object Cache coordinates object updating and invalidation between processes. If an object is updated or invalidated in one process, then it is also updated or invalidated in all other associated processes. This distributed management allows a system of processes to stay synchronized without the overhead of centralized control.

Figure 9-2 is a graphical representation of the following:

  • How the application interacts with the Java Object Cache to retrieve objects

  • How the Java Object Cache interacts with the data source

  • How the caches of the Java Object Cache coordinate cache events through the cache messaging system

Figure 9-2 Java Object Cache Distributed Architecture

Java Object Cache distributed architecture
Description of the illustration O_1033.gif

How the Java Object Cache Works

The Java Object Cache manages Java objects within a process, across processes, and on a local disk. The Java Object Cache provides a powerful, flexible, and easy-to-use service that significantly improves Java performance by managing local copies of Java objects. There are very few restrictions on the types of Java objects that can be cached or on the original source of the objects. Programmers use the Java Object Cache to manage objects that, without cache access, are expensive to retrieve or to create.

The Java Object Cache is easy to integrate into new and existing applications. Objects can be loaded into the object cache, using a user-defined object, the CacheLoader, and can be accessed through a CacheAccess object. The CacheAccess object supports local and distributed object management. Most of the functionality of the Java Object Cache does not require administration or configuration. Advanced features support configuration using administration APIs in the Cache class. Administration includes setting configuration options, such as naming local disk space or defining network ports. The administration features allow applications to fully integrate the Java Object Cache.

Each cached Java object has a set of associated attributes that control how the object is loaded into the cache, where the object is stored, and how the object is invalidated. Cached objects are invalidated based on time or an explicit request. (Notification can be provided when the object is invalidated.) Objects can be invalidated by group or individually.

Figure 9-3 illustrates the basic Java Object Cache APIs. Figure 9-3 does not show distributed cache management.

Figure 9-3 Java Object Cache Basic APIs

This figure illustrates the basic Java Object Cache APIs.
Description of the illustration O_1032.gif

Cache Organization

The Java Object Cache is organized as follows:

  • Cache Environment. The cache environment includes cache regions, subregions, groups, and attributes. Cache regions, subregions, and groups associate objects and collections of objects. Attributes are associated with cache regions, subregions, groups, and individual objects. Attributes affect how the Java Object Cache manages objects.

  • Cache Object Types. The cache object types include memory objects, disk objects, pooled objects, and StreamAccess objects.

Table 9-1 contains a summary of the constructs in the cache environment and the cache object types.

Table 9-1 Cache Organizational Construct

Cache Construct Description
Attributes Functionality associated with cache regions, groups, and individual objects. Attributes affect how the Java Object Cache manages objects.
Cache region An organizational name space for holding collections of cache objects within the Java Object Cache.
Cache subregion An organizational name space for holding collections of cache objects within a parent region, subregion, or group.
Cache group An organizational construct used to define an association between objects. The objects within a region can be invalidated as a group. Common attributes can be associated with objects within a group.
Memory object An object that is stored and accessed from memory.
Disk object An object that is stored and accessed from disk.
Pooled object A set of identical objects that the Java Object Cache manages. The objects are checked out of the pool, used, and then returned.
StreamAccess object An object that is loaded using a Java OutputStream and accessed using a Java InputStream. The object is accessed from memory or disk, depending on the size of the object and the cache capacity.

Java Object Cache Features

The Java Object Cache provides the following features:

  • Objects can be updated or invalidated

  • Objects can be invalidated either explicitly, or with an attribute specifying the expiration time or the idle time

  • Objects can be coordinated between processes

  • Object loading and creation can be automatic

  • Object loading can be coordinated between processes

  • Objects can be associated in cache regions or groups with similar characteristics

  • Cache event notification provides for event handling and special processing

  • Cache management attributes can be specified for each object or applied to cache regions or groups

Java Object Cache Object Types

This section describes the object types that the Java Object Cache manages:

Memory Objects

Memory objects are Java objects that the Java Object Cache manages. Memory objects are stored in the Java virtual machine (JVM) heap space as Java objects. Memory objects can hold HTML pages, the results of a database query, or any information that can be stored as a Java object.

Memory objects are usually loaded into the Java Object Cache with an application-supplied loader. The source of the memory object can be external (for example, using data in a table on the Oracle9i Database Server). The application supplied loader accesses the source and either creates or updates the memory object. Without the Java Object Cache, the application would be responsible for accessing the source directly, rather than using the loader.

You can update a memory object by obtaining a private copy of the memory object, applying the changes to the copy, and then placing the updated object back in the cache (using the CacheAccess.replace() method). This replaces the original memory object.

The CacheAccess.defineObject() method associates attributes with an object. If attributes are not defined, then the object inherits the default attributes from its associated region, subregion, or group.

An application can request that a memory object be spooled to a local disk (using the SPOOL attribute). Setting this attribute allows the Java Object Cache to handle memory objects that are large, or costly to re-create and seldom updated. When the disk cache is set up to be significantly larger than the memory cache, objects on disk stay in the disk cache longer than objects in memory.

Combining memory objects that are spooled to a local disk with the distributed feature from the DISTRIBUTE attribute provides object persistence (when the Java Object Cache is running in distributed mode). Object persistence allows objects to survive the restarting of the JVM.

Disk Objects

Disk objects are stored on a local disk and are accessed directly from the disk by the application using the Java Object Cache. Disk objects can be shared across Java Object Cache processes, or they can be local to a particular process, depending on disk location specified and the setting for the DISTRIBUTE attribute (and whether the Java Object Cache is running in distributed or local mode).

Disk objects can be invalidated explicitly or by setting the TimeToLive or IdleTime attributes. When the Java Object Cache requires additional space, disk objects that are not being referenced can be removed from the cache.

StreamAccess Objects

StreamAccess objects are special cache objects set up to be accessed using the Java InputStream and OutputStream classes. The Java Object Cache determines how to access the StreamAccess object, based on the size of the object and the capacity of the cache. Smaller objects are accessed from memory; larger objects are streamed directly from disk. All streamAccess objects are stored on disk.

The cache user's access to the StreamAccess object is through an InputStream. All the attributes that apply to memory objects and disk objects also apply to StreamAccess objects. A StreamAccess object does not supply a mechanism to manage a stream—for example, StreamAccess objects cannot manage socket endpoints. InputStream and OutputStream objects are available to access fixed-sized, potentially large objects.

Pool Objects

Pool objects are a special class of objects that the Java Object Cache manages. A pool object contains a set of identical object instances. The pool object itself is a shared object; the objects within the pool are private objects. Individual objects within the pool can be checked out to be used and then returned to the pool when they are no longer needed.

Attributes, including TimeToLive or IdleTime can be associated with a pool object. These attributes apply to the pool object as a whole.

The Java Object Cache instantiates objects within a pool using an application-defined factory object. The size of a pool decreases or increases based on demand and on the values of the TimeToLive or IdleTime attributes. A minimum size for the pool is specified when the pool is created. The minimum size value is interpreted as a request rather than a guaranteed minimum value. Objects within a pool object are subject to removal from the cache because of a lack of space, so the pool can decrease below the requested minimum value. A maximum pool size value can be set by putting a hard limit on the number of objects available in the pool.

Java Object Cache Environment

The Java Object Cache environment includes the following:

This section describes these Java Object Cache environment constructs.

Cache Regions

The Java Object Cache manages objects within a cache region. A cache region defines a name space within the cache. Each object within a cache region must be uniquely named, and the combination of the cache region name and the object name must uniquely identify an object. Thus, cache region names must be unique from other region names, and all objects within a region must be uniquely named relative to the region. (Multiple objects can have the same name if they are within different regions or subregions.)

You can define as many regions as you need to support your application. However, most applications require only one region. The Java Object Cache provides a default region; when a region is not specified, objects are placed in the default region.

Attributes can be defined for a region and are then inherited by the objects, subregions, and groups within the region.

Cache Subregions

The Java Object Cache manages objects within a cache region. Specifying a subregion within a cache region defines a child hierarchy. A cache subregion defines a name space within a cache region or within a higher cache subregion. Each object within a cache subregion must be uniquely named, and the combination of the cache region name, the cache subregion name, and the object name must uniquely identify an object.

You can define as many subregions as you need to support your application.

A subregion inherits its attributes from its parent region or subregion unless the attributes are defined when the subregion is defined. A subregion's attributes are inherited by the objects within the subregion. If a subregion's parent region is invalidated or destroyed, the subregion is also invalidated or destroyed.

Cache Groups

A cache group creates an association between objects within a region. Cache groups allow related objects to be manipulated together. Objects are typically associated in a cache group because they must be invalidated together, or they use common attributes. Any set of cache objects within the same region or subregion can be associated using a cache group, which can, in turn, include other cache groups.

A Java Object Cache object can belong to only one group at any given time. Before an object can be associated with a group, the group must be explicitly created. A group is defined with a name. A group can have its own attributes, or it can inherit its attributes from its parent region, subregion, or group.

Group names are not used to identify individual objects, but rather to define a set or collection of objects that have something in common. A group does not define a hierarchical name space. Object type does not distinguish objects for naming purposes; therefore, a region cannot include a group and a memory object with the same name. You must use subregions to define a hierarchical name space within a region.

Groups can contain groups, with the groups having a parent and child relationship. The child group inherits attributes from the parent group.

Region and Group Size Control

With the Java Object Cache, you can specify the maximum size of a region or group as either the number of objects in the region or group, or the maximum number of bytes allowed. If the number of bytes controls the region capacity, then set the size attribute for all objects in the region. This can be set either directly by the user when the object is created, or automatically by setting the Attributes.MEASURE attribute flag. You can set the size of a region or group at multiple levels in the naming hierarchy—that is, at the region and subregion level, or at the group level within a region or another group.

When the capacity of a region or group is reached, the CapacityPolicy object associated with that region or group, if defined, is called. If no capacity policy has been specified, then the default policy is used. The default policy follows: If a nonreferenced object of lesser or equal priority is found, then it is invalidated in favor of the new object. If the priority attribute has not been set for an object, then the priority is assumed to be Integer.MAX_VALUE. When searching for an object to remove, all objects in the immediate region or group and all subregions and subgroups are searched. The first object that can be removed, based on the capacity policy, is removed. So, for example, this may not be the object of lowest priority in the search area.

Figure 9-4 and Figure 9-5 give examples. In each illustration, the grayed portions indicate the search area.

The capacity of region A is set to 50 objects, with subregion B and subregion C set to 20 objects each. If the object count of region A reaches 50, with 10 directly in region A and 20 each in subregions B and C, then the capacity policy for region A is called. The object that is removed can come from region A or from one of its subregions. Figure 9-4 shows this situation.

If subregion B reaches 20 before the capacity of region A is reached, then the capacity policy for subregion B is called, and only objects within subregion B are considered for removal. Figure 9-5 shows this situation.

Figure 9-4 Capacity Policy Example, Part 1

This figure illustrates the first example in the previous text.
Description of the illustration O_1001.gif

Figure 9-5 Capacity Policy Example, Part 2

This figure illustrates the second example in the previous text.
Description of the illustration O_1002.gif

Cache Object Attributes

Cache object attributes affect how the Java Object Cache manages objects. Each object, region, subregion, and group has a set of associated attributes. An object's applicable attributes contain either the default attribute values; the attribute values inherited from the object's parent region, subregion, or group; or the attribute values that you select for the object.

Attributes fall into two categories:

  • The first category is attributes that must be defined before an object is loaded into the cache. Table 9-2 summarizes these attributes. None of the attributes shown in Table 9-2 has a corresponding set or get method, except the LOADER attribute. Use the Attributes.setFlags() method to set these attributes.

  • The second category is attributes that can be modified after an object is stored in the cache. Table 9-3 summarizes these attributes.


    Note:

    Some attributes do not apply to certain types of objects. See the "Object Types" sections in the descriptions in Table 9-2 and Table 9-3.

Using Attributes Defined Before Object Loading

The attributes shown in Table 9-2 must be defined for an object before the object is loaded. These attributes determine an object's basic management characteristics.

The following list shows the methods that you can use to set the attributes shown in Table 9-2 (by setting the values of an Attributes object argument).

  • CacheAccess.defineRegion()

  • CacheAccess.defineSubRegion()

  • CacheAccess.defineGroup()

  • CacheAccess.defineObject()

  • CacheAccess.put()

  • CacheAccess.createPool()

  • CacheLoader.createDiskObject()

  • CacheLoader.createStream()

  • CacheLoader.SetAttributes()


    Note:

    You cannot reset the attributes shown in Table 9-2 by using the CacheAccess.resetAttributes() method.

Table 9-2 Java Object Cache Attributes–Set at Object Creation

Attribute Name Description
DISTRIBUTE Specifies whether an object is local or distributed. When using the Java Object Cache distributed-caching feature, an object is set as a local object so that updates and invalidations are not propagated to other caches in the site.

Object Types: When set on a region, subregion, or a group, this attribute sets the default value for the DISTRIBUTE attribute for the objects within the region, subregion, or group unless the objects explicitly set their own DISTRIBUTE attribute. Because pool objects are always local, this attribute does not apply to pool objects.

Default Value: All objects are local.

GROUP_TTL_DESTROY Indicates that the associated object, group, or region should be destroyed when the TimeToLive expires.

Object Types: When set on a region or a group, all the objects within the region or group, and the region, subregion, or group itself are destroyed when the TimeToLive expires.

Default Value: Only group member objects are invalidated when the TimeToLive expires.

LOADER Specifies the CacheLoader associated with the object.

Object Types: When set on a region or group, the specified CacheLoader becomes the default loader for the region, subregion, or group. The LOADER attribute is specified for each object within the region or the group.

Default Value: Not set.

ORIGINAL Indicates that the object was created in the cache, rather than loaded from an external source. ORIGINAL objects are not removed from the cache when the reference count goes to zero. ORIGINAL objects must be explicitly invalidated when they are no longer useful.

Object Types: When set on a region or group, this attribute sets the default value for the ORIGINAL attribute for the objects within the region, subregion, or group, unless the objects set their own ORIGINAL attribute.

Default Value: Not set.

REPLY Specifies that a reply message will be sent from remote caches after a request for an object update or invalidation has completed. Set this attribute when a high level of consistency is required between caches. If the DISTRIBUTE attribute is not set, or the cache is started in non-distributed mode, REPLY is ignored.

Object Types: When set on a region or group, this attribute sets the default value for the REPLY attribute for the objects within the region, subregion, or group, unless the objects explicitly set their own REPLY attribute. For memory, StreamAccess, and disk objects, this attribute applies only when the DISTRIBUTE attribute is set to the value DISTRIBUTE. Because pool objects are always local, this attribute does not apply for pool objects.

Default Value: No reply is sent. When DISTRIBUTE is set to local, the REPLY attribute is ignored.

SPOOL Specifies that a memory object should be stored on disk rather than being lost when the cache system removes it from memory to regain space. This attribute applies only to memory objects. If the object is also distributed, the object can survive the death of the process that spooled it. Local objects are accessible only by the process that spools them, so if the Java Object Cache is not running in distributed mode, the spooled object is lost when the process dies.

Note: An object must be serializable to be spooled.

Object Types: When set on a region, subregion, or group, this attribute sets the default value for the SPOOL attribute for the objects within the region, subregion, or group unless the objects set their own SPOOL attribute.

Default Value: Memory objects are not stored to disk.

SYNCHRONIZE This attribute indicates that updates to this object must be synchronized. If this flag is set, only the "owner" of an object can load or replace the object. Ownership is obtained using the CacheAccess.getOwnership() method. The "owner" of an object is the CacheAccess object. Setting the SYNCHRONIZE attribute does not prevent a user from reading or invalidating the object.

Object Types: When set on a region, subregion, or group, the ownership restriction is applied to the region, subregion, or group as a whole. Pool objects do not use this attribute.

Default Value: Updates are not synchronized.

SYNCHRONIZE_DEFAULT Indicates that all objects in a region, subregion, or group should be synchronized. Each user object in the region, subregion, or group is marked with the SYNCHRONIZE attribute. Ownership of the object must be obtained before the object can be loaded or updated.

Setting the SYNCHRONIZE_DEFAULT attribute does not prevent a user from reading or invalidating objects. Thus, ownership is not required for reads or invalidation of objects that have the SYNCHRONIZE attribute set.

Object Types: When set on a region, subregion, or group, ownership is applied to individual objects within the region, subregion, or group. Pool objects do not use this attribute.

Default Value: Updates are not synchronized.

ALLOWNULL Specifies that the cache accepts null as a valid value for the affected objects. Null objects that are returned by a cacheLoader object are cached, rather than generating an ObjectNotFoundException.

Object Types: When set on a region, subregion, group, or pool, this attribute applies individually to each object within the region, subregion, group, or pool unless explicitly set for the object.

Default Value: OFF. (Nulls are not allowed.)

MEASURE Specifies that the size attribute of the cached object is calculated, automatically, when the object is loaded or replaced in the cache. The capacity of the cache or region can then be accurately controlled based on object size, rather than object count.

Object Types: When set on a region, subregion, group, or pool, this attribute applies individually to each object within the region, subregion, group, or pool unless explicitly set for the object.

Default Value: OFF. (The size of an object is not automatically calculated.)

CapacityPolicy Specifies the CapacityPolicy object to be used to control the size of the region or group. This attribute is ignored if set for an individual object.

Object Types: When set on a region, subregion, or group, this attribute applies to the entire region or group. This attribute is not applicable to individual objects or pools.

Default Value: OFF. (No capacity policy is defined for a region or group. If the region or group reaches capacity, the first nonreferenced object in the region or group is invalidated.)


Using Attributes Defined Before or After Object Loading

A set of Java Object Cache attributes can be modified either before or after object loading. Table 9-3 lists these attributes. These attributes can be set using the methods in the list under "Using Attributes Defined Before Object Loading", and can be reset using the CacheAccess.resetAttributes() method.

Table 9-3 Java Object Cache Attributes

Attribute Name Description
DefaultTimeToLive Establishes a default value for the TimeToLive attribute that is applied to all objects individually within the region, subregion, or group. This attribute applies only to regions, subregions, and groups. This value can be overridden by setting the TimeToLive on individual objects.

Object Types: When set on a region, subregion, group, or pool, this attribute applies to all the objects within the region, subregion, group, or pool unless the objects explicitly set their own TimeToLive.

Default Value: No automatic invalidation.

IdleTime Specifies the amount of time an object can remain idle, with a reference count of 0, in the cache before being invalidated. If the TimeToLive or DefaultTimeToLive attribute is set, the IdleTime attribute is ignored.

Object Types: When set on a region, subregion, group, or pool, this attribute applies individually to each object within the region, subregion, group, or pool unless the object explicitly sets IdleTime.

Default Value: No automatic IdleTime invalidation.

CacheEventListener Specifies the CacheEventListener associated with the object.

Object Types: When set on a region, subregion, or a group, the specified CacheEventListener becomes the default CacheEventListener for the region, subregion, or group unless a CacheEventListener is specified individually on objects within the region, subregion, or group.

Default Value: No CacheEventListener is set.

TimeToLive Establishes the maximum amount of time that an object remains in the cache before being invalidated. If associated with a region, subregion, or group, all objects in the region, subregion, or group are invalidated when the time expires. If the region, subregion, or group is not destroyed (that is, if GROUP_TTL_DESTROY is not set), the TimeToLive value is reset.

Object Types: When set for a region, subregion, group, or pool, this attribute applies to the region, subregion, group, or pool, as a whole, unless the objects explicitly set their own TimeToLive.

Default Value: No automatic invalidation.

Version An application can set a Version for each instance of an object in the cache. The Version is available for application convenience and verification. The caching system does not use this attribute.

Object Types: When set on a region, subregion, group, or pool, this attribute applies to all the objects within the region, subregion, group, or pool unless the objects explicitly set their own Version.

Default Value: The default Version is 0.

Priority Controls which objects are removed from the cache or region when its capacity has been reached. This attribute, an integer, is made available to the CapacityPolicy object used to control the size of the cache, region, or group. The larger the number, the higher the priority. For region and group capacity control, when an object is removed to make room, specifically for another object, an object of higher priority is never removed to allow an object of lower priority to be cached. For the cache capacity control, lower priority objects are chosen for eviction over higher priority.

Object Types: When set on a region, subregion, group, or pool, this attribute applies individually to each object within the region, subregion, group, or pool unless explicitly set for the object.

Default Value: integer.MAX_VALUE.

MaxSize Specifies the maximum number of bytes available for a region or group. If this attribute is specified for an object, it is ignored.

Object Types: When set on a region, subregion, or group, this attribute applies to the entire region or group. This attribute is not applicable to individual objects or pools.

Default Value: No limit.

MaxCount Specifies the maximum number of objects that can be stored in a region or group. If this attribute is specified for an object, it is ignored.

Object Types: When set on a region, subregion, or group, this attribute applies to the entire region or group. This attribute is not applicable to individual objects or pools.

Default Value: No limit.

User-defined attributes Attributes can be defined by the user. These are name-value pairs that are associated with the object, group, or region. They are intended to be used in conjunction with a CapacityPolicy object, although they can be defined as needed by the cache user.

Object Types: When set on a region, subregion, group, or pool, these attributes are available to each object within the region, subregion, group, or pool unless explicitly reset for the object.

Default Value: No user-defined attributes are set by default.


Developing Applications Using Java Object Cache

This section describes how to develop applications that use the Java Object Cache. This section covers the following topics:

Importing Java Object Cache

The Oracle installer installs the Java Object Cache JAR file cache.jar in the directory $ORACLE_HOME/javacache/lib on UNIX or in %ORACLE_HOME%\javacache\lib on Windows.

To use the Java Object Cache, import oracle.ias.cache, as follows:

import oracle.ias.cache.*;

Defining a Cache Region

All access to the Java Object Cache is through a CacheAccess object, which is associated with a cache region. You define a cache region, usually associated with the name of an application, using the CacheAccess.defineRegion()static method. If the cache has not been initialized, then defineRegion() initializes the Java Object Cache.

When you define the region, you can also set attributes. Attributes specify how the Java Object Cache manages objects. The Attributes.setLoader() method sets the name of a cache loader. Example 9-1 shows this.

Example 9-1 Setting the Name of a CacheLoader

Attributes attr = new Attributes();
MyLoader mloader = new MyLoader;
attr.setLoader(mloader);
attr.setDefaultTimeToLive(10);

final static String APP_NAME_ = "Test Application";
CacheAccess.defineRegion(APP_NAME_, attr);

The first argument for defineRegion uses a String to set the region name. This static method creates a private region name within the Java Object Cache. The second argument defines the attributes for the new region using the default cache attributes.

Defining a Cache Group

Create a cache group when you want to create an association between two or more objects within the cache. Objects are typically associated in a cache group because they must be invalidated together or because they have a common set of attributes.

Any set of cache objects within the same region or subregion can be associated using a cache group, including other cache groups. Before an object can be associated with a cache group, the cache group must be defined. A cache group is defined with a name and can use its own attributes, or it can inherit attributes from its parent cache group, subregion, or region. The code in Example 9-2 defines a cache group within the region named Test Application:

Example 9-2 Defining a Cache Group

final static String APP_NAME_ = "Test Application";
final static String GROUP_NAME_ = "Test Group";
// obtain an instance of CacheAccess object to a named region
CacheAccess caccess = CacheAccess.getAccess(APP_NAME_);
// Create a group
caccess.defineGroup(GROUP_NAME_);
// Close the CacheAccess object
caccess.close();

Defining a Cache Subregion

Define a subregion when you want to create a private name space within a region or within a previously defined subregion. The name space of a subregion is independent of the parent name space. A region can contain two objects with the same name, as long as the objects are within different subregions.

A subregion can contain anything that a region can contain, including cache objects, groups, or additional subregions. Before an object can be associated with a subregion, the subregion must be defined. A cache subregion is defined with a name and can use its own attributes, or it can inherit attributes from its parent cache region or subregion. Use the getParent() method to obtain the parent of a subregion.

The code in Example 9-3 defines a cache subregion within the region named Test Application.

Example 9-3 Defining a Cache Subregion

final static String APP_NAME_ = "Test Application";
final static String SUBREGION_NAME_ = "Test SubRegion";
// obtain an instance of CacheAccess object to a named region
CacheAccess caccess = CacheAccess.getAccess(APP_NAME_);
// Create a SubRegion
caccess.defineSubRegion(SUBREGION_NAME_);
// Close the CacheAccess object
caccess.close();

Defining and Using Cache Objects

You may sometimes want to describe to the Java Object Cache how an individual object should be managed within the cache before the object is loaded. You can specify management options when the object is loaded, by setting attributes within the CacheLoader.load() method. However, you can also associate attributes with an object by using the CacheAccess.defineObject() method. If attributes are not defined for an object, then the Java Object Cache uses the default attributes set for the region, subregion, or group with which the object is associated.

Example 9-4 shows how to set attributes for a cache object. The example assumes that the region APP_NAME_ has already been defined.

Example 9-4 Setting Cache Attributes

import oracle.ias.cache.*; 
final static String APP_NAME_ = "Test Application";
CacheAccess cacc = null;
try  
{ 
   cacc = CacheAccess.getAccess(APP_NAME_); 
// set the default IdleTime for an object using attributes
   Attributes attr = new Attributes(); 
// set IdleTime to 2 minutes 
   attr.setIdleTime(120); 
         
// define an object and set its attributes 
   cacc.defineObject("Test Object", attr);  

// object is loaded using the loader previously defined on the region
// if not already in the cache.
   result = (String)cacc.get("Test Object");
}  catch (CacheException ex){ 
     // handle exception
   } finally { 
      if (cacc!= null)
         cacc.close();
}

Implementing a CacheLoader Object

The Java Object Cache has two mechanisms for loading an object into the cache:

  • The object can be put into the cache directly by the application using the CacheAccess.put() method.

  • You can implement a CacheLoader object.

In most cases, implementing the CacheLoader is the preferred method. With a cache loader, the Java Object Cache automatically determines if an object needs to be loaded into the cache when the object is requested. And the Java Object Cache coordinates the load if multiple users request the object at the same time.

A CacheLoader object can be associated with a region, subregion, group, or object. Using a CacheLoader allows the Java Object Cache to schedule and manage object loading, and handle the logic for "if the object is not in cache then load."

If an object is not in the cache, then when an application calls the CacheAccess.get() or CacheAccess.preLoad() method, the cache executes the CacheLoader.load method. When the load method returns, the Java Object Cache inserts the returned object into the cache. Using CacheAccess.get(), if the cache is full, the object is returned from the loader, and the object is immediately invalidated in the cache. (Therefore, using the CacheAccess.get() method with a full cache does not generate a CacheFullException.)

When a CacheLoader is defined for a region, subregion, or group, it is taken to be the default loader for all objects associated with the region, subregion, or group. A CacheLoader object that is defined for an individual object is used only to load the object.


Note:

A CacheLoader object that is defined for a region, subregion, or group or for more than one cache object must be written with concurrent access in mind. The implementation should be thread-safe, because the CacheLoader object is shared.

Using CacheLoader Helper Methods

The CacheLoader cache provides several helper methods that you can use from within the load() method implementation. Table 9-4 summarizes the available CacheLoader methods.

Table 9-4 CacheLoader Methods Used in load()

Method Description
setAttributes() Sets the attributes for the object being loaded.
netSearch() Searches other available caches for the object to load. Objects are uniquely identified by the region name, subregion name, and the object name.
getName() Returns the name of the object being loaded.
getRegion() Returns the name of the region associated with the object being loaded.
createStream() Creates a StreamAccess object.
createDiskObject() Creates a disk object.
exceptionHandler() Converts noncache exceptions into CacheExceptions, with the base set to the original exception.
log() Records messages in the cache service log.

Example 9-5 illustrates a CacheLoader object using the cacheLoader.netSearch() method to check whether the object being loaded is available in distributed Java Object Cache caches. If the object is not found using netSearch(), then the load method uses a more expensive call to retrieve the object. (An expensive call may involve an HTTP connection to a remote Web site or a connection to the Oracle9i Database Server.) For this example, the Java Object Cache stores the result as a String.

Example 9-5 Implementing a CacheLoader

import oracle.ias.cache.*;
class YourObjectLoader extends CacheLoader{ 
      public YourObjectLoader () { 
      }
      public Object load(Object handle, Object args) throws CacheException
     {
         String contents; 
         // check if this object is loaded in another cache 
         try { 
            contents = (String)netSearch(handle, 5000);// wait for up to 5 scnds
            return new String(contents); 
         } catch(ObjectNotFoundException ex){}

         try { 
            contents =  expensiveCall(args); 
            return new String(contents); 
         } catch (Exception ex) {throw exceptionHandler("Loadfailed", ex);} 
           }

    private String expensiveCall(Object args) { 
        String str = null; 
        // your implementation to retrieve the information.
        // str = ... 
        return str; 
    } 
 } 

Invalidating Cache Objects

An object can be removed from the cache either by setting the TimeToLive attribute for the object, group, subregion, or region, or by explicitly invalidating or destroying the object.

Invalidating an object marks the object for removal from the cache. Invalidating a region, subregion, or group invalidates all the individual objects from the region, subregion, or group, leaving the environment—including all groups, loaders, and attributes—available in the cache. Invalidating an object does not undefine the object. The object loader remains associated with the name. To completely remove an object from the cache, use the CacheAccess.destroy() method.

An object can be invalidated automatically based on the TimeToLive or IdleTime attribute. When the TimeToLive or IdleTime expires, objects are, by default, invalidated and not destroyed.

If an object, group, subregion, or region is defined as distributed, the invalidate request is propagated to all caches in the distributed environment.

To invalidate an object, group, subregion, or region, use the CacheAccess.invalidate() method as follows:

CacheAccess cacc = CacheAccess.getAccess("Test Application");
cacc.invalidate("Test Object");  // invalidate an individual object
cacc.invalidate("Test Group"); // invalidate all objects associated with a group
cacc.invalidate();     // invalidate all objects associated with the region cacc
cacc.close();          // close the CacheAccess handle

Destroying Cache Objects

An object can be removed from the cache either by setting the TimeToLive attribute for the object, group, subregion, or region, or by explicitly invalidating or destroying the object.

Destroying an object marks the object and the associated environment, including any associated loaders, event handlers, and attributes for removal from the cache. Destroying a region, subregion, or a group marks all objects associated with the region, subregion, or group for removal, including the associated environment.

An object can be destroyed automatically based on the TimeToLive or IdleTime attributes. By default, objects are invalidated and are not destroyed. If the objects must be destroyed, set the attribute GROUP_TTL_DESTROY. Destroying a region also closes the CacheAccess object used to access the region.

To destroy an object, group, subregion, or region, use the CacheAccess.destroy() method as follows:

CacheAccess cacc = CacheAccess.getAccess("Test Application"); 
cacc.destroy("Test Object"); // destroy an individual object 
cacc.destroy("Test Group");  // destroy all objects associated with 
                             // the group "Test Group" 

cacc.destroy();       // destroy all objects associated with the region
                      // including groups and loaders

Multiple Object Loading and Invalidation

In most cases, objects are loaded into the cache individually; in some cases, however, multiple objects can be loaded into the cache as a set. The primary example of this is when multiple cached objects can be created from a single read from a database. In this case, it is much more efficient to create multiple objects from a single call to the CacheLoader.load method.

To support this scenario, the abstract class CacheListLoader and the method CacheAccess.loadList have been added. The CacheListLoader object extends the CacheLoader object defining the abstract method loadList and the helper methods getNextObject, getList, getNamedObject, and saveObject. The cache user implements the CacheListLoader.loadList method. Employing the helper methods, the user can iterate through the list of objects, creating each one and saving it to the cache. If the helper methods defined in CacheLoader are used from the CacheListLoader method, then getNextObject or getNamedObject should be called first to set the correct context.

The CacheAccess.loadList method takes as an argument an array of object names to be loaded. The cache processes this array of objects. Any objects that are not currently in the cache are added to a list that is passed to the CacheListLoader object that is defined for the cached objects. If a CacheListLoader object is not defined for the objects or the objects have different CacheListLoader objects defined, then each object is loaded individually, using the CacheLoader.load method defined.

It is always best to implement both the CacheListLoader.loadList method and the CacheListLoader.load method. Which method is called depends on the order of the user requests to the cache. For example, if the CacheAccess.get method is called before the CacheAccess.loadList method, then the CacheListLoader.load method is used rather than the CacheAccess.loadList method.

As a convenience, the invalidate and destroy methods have been overloaded to also handle an array of objects.

Example 9-6 shows a sample CacheListLoader, and Example 9-7 shows sample usage.

Example 9-6 Sample CacheListLoader

Public class ListLoader extends CacheListLoader
{
   public void loadList(Object handle, Object args) throws CacheException
   {
      while(getNextObject(handle) != null)
      {
         // create the cached object based on the name of the object
         Object  cacheObject = myCreateObject(getName(handle));
         saveObject(handle, cacheObject);
      }
   }

   public Object load(Object handle, Object args) throws CacheException
   {
      return myCreateObject(getName(handle));
   }

   private Object myCreateObject(Object name)
   {
      // do whatever to create the object
   }
}

Example 9-7 Sample Usage

// Assumes the cache has already been initialized

CacheAccess   cacc;
Attributes    attr;
ListLoader    loader = new
ListLoader();
String        objList[];
Object        obj;

// set the CacheListLoader for the region
attr  = new Attributes();
attr.setLoader(loader);

//define the region and get access to the cache
CacheAccess.defineRegion(Òregion nameÓ, attr);
cacc = CacheAccess.getAccess(Òregion nameÓ);

// create the array of object names
objList = new String[3];
for (int j = 0; j < 3; j++)
      objList[j] = Òobject Ò + j;

// load the objects in the cache via the CacheListLoader.loadList method
cacc.loadList(objList);

// retrieve the already loaded object from the cache
obj = cacc.get(objList[0]);

// do something useful with the object

// load an object using the CacheListLoader.load method
obj = cache.get(Òanother objectÓ)

// do something useful with the object

Java Object Cache Configuration

The Java Object Cache is NOT initialized automatically upon OC4J startup. You can force OC4J to initialize jcache by using -Doracle.ias.jcache=true in opmn.xml, as shown in the following example:

   <ias-component id="OC4J"> 
            <process-type id="home" module-id="OC4J" status="enabled"> 
              <module-data> 
                  <category id="start-parameters"> 
                    <data id="java-options" value="-server 
-Djava.security.policy=$ORACLE_HOME/j2ee/home/config/java2.policy
 -Djava.awt.headless=true 
-DApplicationServerDebug=true -Ddatasource.verbose=true 
-Djdbc.debug=true -Doracle.ias.jcache=true"/> 
                  </category> 
                  <category id="stop-parameters"> 
                    <data id="java-options" 
value="-Djava.security.policy=$ORACLE_HOME/j2ee/home/config/java2. 
policy -Djava.awt.headless=true"/> 
                  </category> 
              </module-data> 
              <start timeout="600" retry="2"/> 
              <stop timeout="120"/> 
              <restart timeout="720" retry="2"/> 
              <port id="ajp" range="3301-3400"/> 
              <port id="rmi" range="3201-3300"/> 
              <port id="jms" range="3701-3800"/> 
              <process-set id="default_island" numprocs="1"/> 
            </process-type> 
        </ias-component> 
 

The OC4J runtime initializes the Java Object Cache using configuration settings defined in the file javacache.xml. The file path is specified in the <javacache-config> tag of the OC4J server.xml file. The default relative path values of javacache.xml in server.xml are the following:

<javacache-config path="../../../javacache/admin/javacache.xml"/>

The rules for writing javacache.xml and the default configuration values are specified in an XML schema. The XML schema file ora-cache.xsd and the default javacache.xml are in the directory $ORACLE_HOME/javacache/admin on UNIX and in %ORACLE_HOME%\javacache\admin on Windows.

In earlier versions of Java Object Cache (before 9.0.4), configuration was done through the file javacache.properties. Starting with version 10g (9.0.4), Java Object Cache configuration is done through javacache.xml.


Note:

If you install both a release that uses javacache.properties (before 9.0.4) and a release that uses javacache.xml (9.0.4 or later) on the same host, then you must ensure that the javacache.xml discovery-port attribute and javacache.properties coordinatorAddress attribute are not configured to the same port. If they are, then you must manually change the value in one or the other to a different port number. The default range is 7000-7099.

A sample configuration follows:

<?xml version="1.0" encoding="UTF-8"?>
<cache-configuration
xmlns=http://www.oracle.com/oracle/ias/cache/configuration
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.oracle.com/oracle/ias/cache/configuration
ora-cache.xsd">
  <logging>
    <location>javacache.log</location>
    <level>ERROR</level>
  </logging>
  <communication>
    <isDistributed>true</isDistributed>
    <discoverer discovery-port="7000"/>
  </communication>
  <persistence>
    <location>diskcache</location>
    <disksize>32</disksize>
  </persistence>
  <max-objects>1000</max-objects>
  <max-size>48</max-size>
  <clean-interval>30</clean-interval>
</cache-configuration>

Table 9-5 contains the valid property names and the valid types for each property.

Table 9-5 Java Object Cache Configuration Properties

Configuration XML Element Description Type
clean-interval Specifies the time, in seconds, between each cache cleaning. At the cache-cleaning interval, the Java Object Cache checks for objects that have been invalidated by the TimeToLive or IdleTime attributes that are associated with the object. (Table 9-3 describes these attributes.)

Default value: 60

Positive integer
ping-interval Specifies the time, in seconds, between each cache death detection for determining the availability of the remote cache systems.

Default value: 60

Positive integer
max-size Specifies the maximum size of the memory, in megabytes, available to the Java Object Cache.

Default value: 10

Positive integer
max-objects Specifies the maximum number of in-memory objects that are allowed in the cache. The count does not include group objects, or objects that have been spooled to disk and are not currently in memory.

Default value: 5000

Positive integer
region-name-separator Specifies the separator between a parent region and a child region name. See "Examples".

Default value: /

String
preload-file Specifies the full path to the declarative cache configuration file. The format of the file must conform to the declarative cache schema (cache.xsd). The declarative cache configuration allows the system to predefine cache regions, groups, objects, attributes, and policies upon Java Object Cache service initialization. For more information about the declarative cache, see "Declarative Cache". Also see "Examples". Note: The file path of the declarative cache XML schema is ORACLE_HOME/javacache/admin/cache.xsd. Refer to the XML schema when writing a declarative cache file.

Default value: To not use a declarative cache.

String
communication Indicates whether the cache is distributed. Specifies the IP address and port that the Java Object Cache initially contacts to join the caching system, when using distributed caching.

If the distribute property is set for an object, then updates and invalidation for that object are propagated to other caches known to the Java Object Cache.

If the isDistributed subelement of the communication element is set to false, all objects are treated as local, even when the attributes set on objects are set to distribute. See "Examples".

Default value: Cache is not distributed (isDistributed subelement is set to false).

complex (has subelements)
logging Specifies the logger attributes such as log file name and log level. The available options of the log level are OFF, FATAL, ERROR, DEFAULT, WARNING, TRACE, INFO, and DEBUG. See "Examples".

Default log file name:

on UNIX:

$ORACLE_HOME/javacache/admin/logs/javacache.log

on Windows:

%ORACLE_HOME%\javacache\admin\logs\javacache.log

Default log level: DEFAULT

Complex (has subelements)
persistence Specifies the disk cache configuration, such as absolute path to the disk cache root and maximum size for the disk cache. If a root path is specified, the default maximum size of the disk cache is 10 MB. The unit of the disk cache size is megabytes. See "Examples".

Default value: Disk caching is not available.

Complex (has subelements)


Note:

Configuration properties are distinct from the Java Object Cache attributes that you specify using the Attributes class.

Examples

The following example illustrates the use of the <preload-file> element:

  • Specify a declarative cache configuration file:

    <preload-file>/app/oracle/javacache/admin/decl.xml</preload-file>
    
    

The following examples illustrate the use of the <communication> element:

  • Turn off distributed cache:

    <communication>
      <isDistributed>false</isDistributed>
    </communication>
    
    
  • Distribute cache among multiple JVMs in local machine:

    <communication>
      <isDistributed>true</isDistributed>
    </communication>
    
    
  • Specify the initial discovery port that the Java Object Cache initially contacts to join the caching system in the local node:

    <communication>
      <isDistributed>true</isDistributed>
      <discoverer discovery-port="7000">
    </communication>
    
    
  • Specify the IP address and initial discovery port that the Java Object Cache initially contacts to join the caching system.

    <communication>
    <isDistributed>true</isDistributed>
    <discoverer ip="192.10.10.10" discovery-port="7000">
    </communication>
    
    
  • Specify multiple IP addresses and the initial discovery port that the Java Object Cache initially contacts to join the caching system. If the first specified address is not reachable, it contacts the next specified address:

    <communication>
      <isDistributed>true</isDistributed>
      <discoverer ip="192.10.10.10" discovery-port="7000">
      <discoverer ip="192.11.11.11" discovery-port="7000">
      <discoverer ip="192.22.22.22" discovery-port="7000">
      <discoverer ip="192.22.22.22" discovery-port="8000">
    </communication>
    
    

The following examples illustrate the use of the <persistence> element:

  • Specify a root path for the disk cache using the default disk size:

    <persistence>
      <location>/app/9iAS/javacache/admin/diskcache</location>
    </persistence>
    
    
  • Specify a root path for the disk cache with a disk size of 20 MB:

    <persistence>
      <location>/app/9iAS/javacache/admin/diskcache</location>
      <disksize>20</disksize>
    </persistence>
    
    

The following examples illustrate the use of the <logging> element:

  • Specify a log file name:

    <logging>
    <location>/app/9iAS/javacache/admin/logs/my_javacache.log</location>
    </logging>
    
    
  • Specify log level as INFO:

    <logging>
    <location>/app/9iAS/javacache/admin/logs/my_javacache.log</location>
    <level>INFO</level>
    </logging>
    

Declarative Cache

With the 10g Release 2 (10.1.2) release of the Java Object Cache, object, group, and region, as well as cache attributes, can be defined declaratively. You do not need to write any Java code to define cache objects and attributes in your applications when using declarative cache.

A declarative cache file can be read automatically during Java Object Cache initialization. Specify the location of the declarative cache file in the <preload-file> element of the cache configuration file. (See "Sharing Cached Objects in an OC4J Servlet" for cache configuration file syntax.) In addition, the declarative cache file can be loaded programmatically or explicitly with the public methods in oracle.ias.cache.Configurator.class. Multiple declarative cache files are also permitted.

Figure 9-6 shows the declarative cache.

Figure 9-6 Declarative Cache Architecture

Declarative cache file sample.
Description of the illustration decachar.gif

You can set up the Java Object Cache to automatically load a declarative cache file during system initialization. Example 9-8 shows this. Example 9-9 shows how to programmatically read the declarative cache file.

Example 9-8 Automatically Load Declarative Cache

<!-- Specify declarative cache file:my_decl.xml in javacache.xml -->
<cache-configuration> 
  …
<preload-file>/app/9iAS/javacache/admin/my_decl.xml</preload-file>
  …
</cache-configuration>

Example 9-9 Programmatically Read Declarative Cache File

try {
  String filename = "/app/9iAS/javacache/admin/my_decl.xml";
Configurator config = new Configurator(filename);
Config.defineDeclarable();
} catch (Exception ex) {
}

Declarative Cache File Sample

<?xml version="1.0" encoding="UTF-8"?>
<cache xmlns="http://www.javasoft.com/javax/cache" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.oracle.com/javax/cache">
  <region name="fruit">
    <attributes>
      <time-to-live>3000</time-to-live>
      <max-count>200</max-count>
      <capacity-policy>
        <classname>com.acme.MyPolicy</classname>
      </capacity-policy>
    </attributes>
    <group name="apple">
      <attributes>
        <flag>spool</flag>
        <flag>distribute</flag>
        <cache-loader>
          <classname>com.acme.MyLoader</classname>
          <parameter name="color">red</parameter>
        </cache-loader>
      </attributes>
    </group>
    <cached-object>
      <name>
        <string-name>theme</string-name>
      </name>
      <object>
        <classname>com.acme.DialogHandler</classname>
        <parameter name="prompt">Welcome</parameter>
      </object>
    </cached-object>
  </region>
</cache>

Declarative Cache File Format

The declarative cache file is in XML format. The file contents should conform to the declarative cache XML schema that is shipped with Oracle Application Server 10g. The file path of the XML schema is ORACLE_HOME/javacache/admin/cache.xsd.

Table 9-6 lists the elements of the declarative cache schema, their children, and the valid types for each element. See "Examples" for code that shows usage for most elements.

Table 9-6 Description of Declarative Cache Schema (cache.xsd)

Element Description Children Type
region Declare a cache region or subregions. <attributes><region><group><cached-object> regionType
group Declare a cache group or subgroup. <attributes><group><cached-object> groupType
cached-object Declare a cache object. <attributes><name><object> objectType
name Declare the name for a cached object. The name can use a simple string type or it can be a type of a specified Java object. <string-name><object-name> nameType
object Declare a user-defined Java object. The class of the specified object must implement the declarable interface of the oracle.ias.cache package. <classname><parameter> userDefinedObjectType
attributes Declare an attributes object for a cache region, group, or cache object. Each child element corresponds to each field in the attributes class of the oracle.ias.cache package. See the Javadoc of Attributes.class for more details. <time-to-live><default-ttl><idle-time><version><max-count><priority><size><flag><event-listener><cache-loader><capacity-policy><user-defined> attributesType
event-listener Declare a CacheEventListener object. <classname> event-listenerType
cache-loader Declare a CacheLoader object. <classname><parameter> userDefinedObjectType
capacity-policy Declare a CapacityPolicy object. <classname><parameter> userDefinedObjectType
user-defined Declare user-defined string type attributes. <key><value> element

Figure 9-7 shows the attributes of the declarative cache schema.

Figure 9-7 Declarative Cache Schema Attributes

Declarative cache schema attributes.
Description of the illustration O_1005.gif

Examples

The following examples show use of elements in Table 9-6:

  • Declare cache region and subregions with the <region> element:

    <region name=ÓthemesÓ>
        <region name=ÓcartoonÓ>
          <!-- sub region definition -->
        </region>
      <group name=ÓcolorsÓ>
        <!-- group definition -->
      </group>
    </region>
    
    
  • Declare cache group and subgroups with the <group> element:

    <group name=ÓcolorsÓ>
      <group name=ÓdarkÓ>
        <!-- sub group definition -->
      </group>
    </group>
    
    
  • Declare a cached object with the <cached-object> element:

    <cached-object>
      <name>
        <string-name>DialogHandler</string-name>
      </name>
      <object>
        <classname>com.acme.ConfigManager</classname>
        <parameter name=ÓcolorÓ>blue</parameter>
      </object>
    </cached-object>
    
    
  • Declare the name for a cached object with the <name> element using a string:

    <name>
      <string-name>DialogHandler</string-name>
    </name>
    
    

    Declare the name for a cached object with the <name> element using an object:

    <name>
      <object-name>
        <classname>DialogHandler</classname>
        <parameter name="color">green</parameter>
      </object-name>
    </name>
    
    
  • Declare a user-defined Java object with the <object> element:

    <object>
      <classname>com.acme.CustomConfigManager</classname>
      <parameter name=ÓcolorÓ>blue</parameter>
    </object>
    
    // Implementation of CustomConfigManager.java
    package com.acme;
    import oracle.ias.cache.Declarable;
    public class CustomConfigManager implements Declarable {
    }
    
    
  • Declare an attributes object for a cache region, group, or cache object with the <attributes> element:

    <attributes>
      <time-to-live>4500</time-to-live>
      <default-ttl>6000</default-ttl>
      <version>99</version>
      <max-count>8000</max-count>
      <priority>50</priority>
      <flag>spool</flag>
      <flag>allownull</flag>
      <flag>distribute</flag>
      <flag>reply</flag>
      <cache-loader>
        <classname>MyLoader</classname>
        <parameter name="debug">false</parameter>
      </cache-loader>
    </attributes>
    
    
  • Declare user-defined string type attributes with the <user-defined> element:

    <attributes>
      <user-defined>
        <key>color</key>
        <value>red</value>
      </user-defined>
    </attributes>
    

Declarable User-Defined Objects

The topology of the cache objects, object attributes, and user-defined objects can all be described in the declarative cache file. For the system to load and instantiate a user-defined Java object (including CacheLoader, CacheEventListener, and CapacityPolicy) declared in the declarative cache file, the object must be an instance of the oracle.ias.cache.Declarable interface. That is, you must implement the oracle.ias.cache.Declarable interface for any Java objects declared in the declarative cache file. You must be aware that all user-defined Java objects are loaded by the JVM's default class loader instead of the application's class loaders. After the declarable object is instantiated, the system implicitly invokes its init(Properties props) method. The method uses the user-supplied parameters (name-value pair) defined in the declarative cache file to perform any necessary initialization task. Example 9-10 shows how to define an object by declaratively passing in a parameter (color = yellow).

Example 9-10 Define An Object by Declaratively Passing in a Parameter

In the declarative XML file:

<cached-object>
  <name>
    <string-name>Foo</string-name>
  </name>
  <object>
    <classname>com.acme.MyCacheObject</classname>
    <parameter name="color">yellow</parameter>
  </object>
</cached-object>

Declarable object implementation:

package com.acme;

import oracle.ias.cache.*; 
import java.util.Properties; 

public class MyCacheObject implements Declarable { 

  private String color_;

  /**
    * Object initialization
    */
  public void init(Properties prop) {
         color_ = prop.getProperty(ÒcolorÓ); 
  } 
}

Declarable CacheLoader, CacheEventListener, and CapacityPolicy

When you specify a CacheLoader, CacheEventListener, or CapacityPolicy object in the declarative cache file, the object itself must also be an instance of oracle.ias.cache.Declarable. This requirement is similar to that of the user-defined object. You must implement a declarable interface for each specified object in addition to extending the required abstract class. Example 9-11 shows a declarable CacheLoader implementation.

Example 9-11 Declarable CacheLoader Implementation

import oracle.ias.cache.*;
import java.util.Properties;

public class MyCacheLoader extends CacheLoader implements Declarable {

  public Object load(Object handle, Object argument) {
    // should return meaningful object based on argument
    return null;
  }

  public void init(Properties prop) { 
  }
}

Initializing the Java Object Cache in a Non-OC4J Container

To use the Java Object Cache in any Java application but run it in a non-OC4J runtime, insert the following reference to where the application (Java class) is initialized:

Cache.open(/path-to-ocnfig-file/javacache.xml);

If you invoke Cache.open() without any parameter in your code, then the Java Object Cache uses its internal default configuration parameter. You can also initialize the Java Object Cache by invoking Cache.init(CacheAttributes). This allows you to derive the configuration parameters from your own configuration file or generate them programmatically.

If the Java Object Cache is not used in the OC4J runtime, you must include cache.jar in the classpath where the JVM is launched. You must also initialize the Java Object Cache explicitly by invoking Cache.open(String config_filename), where config_filename is the full path to a valid javacache.xml file, or by invoking Cache.init(CacheAttributes).

Use any of the following method invocations to initialize the Java Object Cache explicitly in a non-OC4J container:

  • Cache.open();

    Use the default Java Object Cache configuration stored in the cache.jar file.

  • Cache.open(/path-to-oracle-home/javacache/admin/javacache.xml);

    Use the configuration defined in the javacache.xml file.

  • Cache.open(/path-to-user's-own-javacache.xml);

    Use the configuration defined in the specific javacache.xml file.

  • Cache.init(CacheAttributes);

    Use the configuration that is set in a CacheAttributes object.

For J2EE applications running in an OC4J container, the path to the javacache.xml file can be configured in the OC4J server.xml configuration file. The cache can be initialized automatically when the OC4J process is started. See OC4J configuration for details.

In a non-OC4J container, if you do not use any of the preceding method invocations, the Java Object Cache is initialized implicitly (using default configuration settings stored in cache.jar) when you invoke Cache.getAccess() or Cache.defineRegion().

Capacity Control

The new capacity control feature allows the cache user to specify the policy to employ when determining which objects should be removed from the cache when the capacity of the cache, region, or group has been reached. To specify the policy, extend the abstract class CapacityPolicy, and set the instantiated object as an attribute of the cache, region, or group.

For regions and groups, the CapacityPolicy object is called when the region or group has reached its capacity and a new object is being loaded. An object in the region or group must be found to invalidate, or the new object is not saved in the cache. (It is returned to the user but is immediately invalidated.)

The CapacityPolicy object that is associated with the cache as a whole is called when capacity of the cache reaches some "high water mark," some percentage of the configured maximum. When the high water mark is reached, the cache attempts to remove objects to reduce the load in the cache to 3% below the high water mark. The high water mark is specified by the capacityBuffer cache attribute. If the capacityBuffer is set to 5, then the cache begins removing objects from the cache when it is 95% full (100% -5%) and continues until the cache is 92% full (95% - 3%). The default value for capacityBuffer is 15.

The capacity policy used for the cache can be different from those used for specific regions or groups.

By default, the capacity policy for groups and regions is to remove a nonreferenced object of equal or lesser priority when a new object is added and capacity has been reached. For the cache, the default policy is to remove objects that have not been referenced in the last two clean intervals, with preference to objects of priority—that is, low priority objects that have not been referenced recently are removed first.

To help create a capacity policy, many statistics are kept for objects in the cache and aggregated across the cache, regions, and groups. The statistics are available to the CapacityPolicy object. For cache objects, the following statistics are maintained:

  • Priority

  • Access count—the number of times the object has been referenced

  • Size—the size of the object in bytes (if available)

  • Last access time—the time in milliseconds that the object was last accessed

  • Create time—the time in milliseconds when the object was created

  • Load time—the number of milliseconds required to load the object (if the object was added to the cache with CacheAccess.put, this value is 0)

Along with these statistics, all attributes associated with the object are available to the CapacityPolicy object.

The following aggregated statistics are maintained for the cache, regions, and groups. For each of these statistics, the low, high, and average value is maintained. These statistics are recalculated at each clean interval or when Cache.updateStats() is called.

  • Priority

  • Access count—the number of times that the object has been referenced

  • Size—the size of the object in bytes (if available)

  • Last access time—the time in milliseconds that the object was last accessed

  • Load time—the number of milliseconds required to load the object (if the object was added to the cache with CacheAccess.put, this value is 0)

Example 9-12 is a sample CapacityPolicy object for a region, based on object size.

Example 9-12 Sample CapacityPolicy Based on Object Size

class SizePolicy extends CapacityPolicy
{
   public boolean policy (Object victimHandle, AggregateStatus aggStatus,     long currentTime , Object newObjectHandle) throws CacheException
   {
      int             newSize;
      int             oldSize;

      oldSize = getAttributes(victimHandle).getSize();
      newSize = getAttributes(newObjectHandle).getSize();
      if (newSize >= oldSize)
         return true;
      return false;
   }

Example 9-13 is a sample CapacityPolicy for the cache, based on access time and reference count. If an object has below-average references and has not been accessed in the last 30 seconds, then it is removed from the cache.

Example 9-13 Sample CapacityPolicy Based on Access Time and Reference Count

class SizePolicy extends CapacityPolicy
{
public boolean policy (Object victimHandle, AggregateStatus aggStatus, long  currentTime , Object newObjectHandle) throws CacheException
{
   long          lastAccess;
   int           accessCount;
   int           avgAccCnt;

   lastAccess    = getStatus(victimHandle).getLastAccess();
   accessCount   = getStatus(victimHandle).getAccessCount();
   avgAccCnt     = aggStatus.getAccessCount(AggregateStatus.AVG);

   if (lastAccess + 30000 < currentTime && accessCount < avgAccCnt)
      return true;
   }

}

Implementing a Cache Event Listener

Many events can occur in the life cycle of a cached object, including object creation and object invalidation. This section shows how an application can be notified when cache events occur.

To receive notification of the creation of an object, implement event notification as part of the cacheLoader. For notification of invalidation or updates, implement a CacheEventListener, and associate the CacheEventListener with an object, group, region, or subregion using Attributes.setCacheEventListener().

CacheEventListener is an interface that extends java.util.EventListener. The cache event listener provides a mechanism to establish a callback method that is registered and then executes when the event occurs. In the Java Object Cache, the event listener executes when a cached object is invalidated or updated.

An event listener is associated with a cached object, group, region, or subregion. If an event listener is associated with a group, region, or subregion, then by default, the listener runs only when the group, region, or subregion itself is invalidated. Invalidating a member does not trigger the event. The Attributes.setCacheEventListener() call takes a boolean argument that, if true, applies the event listener to each member of the region, subregion, or group, rather than to the region, subregion, or group itself. In this case, the invalidation of an object within the region, subregion, or group triggers the event.

The CacheEventListener interface has one method, handleEvent(). This method takes a single argument, a CacheEvent object that extends java.util.EventObject. This object has two methods, getID(), which returns the type of event (OBJECT_INVALIDATION or OBJECT_UPDATED), and getSource(), which returns the object being invalidated. For groups and regions, the getSource() method returns the name of the group or region.

The handleEvent() method is executed in the context of a background thread that the Java Object Cache manages. Avoid using Java Native Interface (JNI) code in this method, because the expected thread context may not be available.

Example 9-14 illustrates how a CacheEventListener is implemented and associated with an object or a group.

Example 9-14 Implementing a CacheEventListener

import oracle.ias.cache.*;
   // A CacheEventListener for a cache object
   class MyEventListener implements
   CacheEventListener  {

       public void handleEvent(CacheEvent ev)
       {
          MyObject obj = (MyObject)ev.getSource();
          obj.cleanup();
        }

       // A CacheEventListener for a group object
       class MyGroupEventListener implements CacheEventListener {
       public void handleEvent(CacheEvent ev) 
       {
          String groupName = (String)ev.getSource();
          app.notify("group " + groupName + " has been invalidated");

       }
   }

Use the Attributes.listener attribute to specify the CacheEventListener for a region, subregion, group, or object.

Example 9-15 illustrates how to set a cache event listener on an object. Example 9-16 illustrates how to set a cache event listener on a group.

Example 9-15 Setting a Cache Event Listener on an Object

import oracle.ias.cache.*;

   class YourObjectLoader extends CacheLoader
   {
      public YourObjectLoader () {
      }

      public Object load(Object handle, Object args) {
         Object obj = null;
         Attributes attr = new Attributes();    
         MyEventListener el = new MyEventListener();
         attr.setCacheEventListener(CacheEvent.OBJECT_INVALIDATED, el);

         // your implementation to retrieve or create your object

         setAttributes(handle, attr);
         return obj;
    }      
}

Example 9-16 Setting a Cache Event Listener on a Group

import oracle.ias.cache.*;
try    
{
   CacheAccess cacc = CacheAccess.getAccess(myRegion);  
   Attributes attr = new Attributes ();

   MyGroupEventListener listener = new MyGroupEventListener();   
   attr.setCacheEventListener(CacheEvent.OBJECT_INVALIDATED, listener);

   cacc.defineGroup("myGroup", attr);
   //....
   cacc.close();

}catch(CacheException ex)      
{
   // handle exception
}

Restrictions and Programming Pointers

This section covers restrictions and programming pointers when using the Java Object Cache.

  • Do not share the CacheAccess object between threads. This object represents a user to the caching system. The CacheAccess object contains the current state of the user's access to the cache: what object is currently being accessed, what objects are currently owned, and so on. Trying to share the CacheAccess object is unnecessary and may result in unpredictable behavior.

  • A CacheAccess object holds a reference to only one cached object at a time. If multiple cached objects are being accessed concurrently, then use multiple CacheAccess objects. For objects that are stored in memory, the consequences of not doing this are minor, because Java prevents the cached object from being garbage collected, even if the cache believes it is not being referenced. For disk objects, if the cache reference is not maintained, the underlying file could be removed by another user or by time-based invalidation, causing unexpected exceptions. To optimize resource management, keep the cache reference open as long as the cached object is being used.

  • Always close a CacheAccess object when it is no longer being used. The CacheAccess objects are pooled. They acquire cache resources on behalf of the user. If the access object is not closed when it is not being used, then these resources are not returned to the pool and are not cleaned up until they are garbage collected by the JVM. If CacheAccess objects are continually allocated and not closed, then degradation in performance may occur.

  • When local objects (objects that do not set the Attributes.DISTRIBUTE attribute) are saved to disk using the CacheAccess.save() method, they do not survive the termination of the process. By definition, local objects are visible only to the cache instance where they were loaded. If that cache instance goes away for any reason, then the objects that it manages, including on disk, are lost. If an object must survive process termination, then both the object and the cache must be defined DISTRIBUTE.

  • The cache configuration, also called the cache environment, is local to a cache; this includes the region, subregion, group, and object definitions. The cache configuration is not saved to disk or propagated to other caches. Define the cache configuration during the initialization of the application.

  • If a CacheAccess.waitForResponse() or CacheAccess.releaseOwnership() method call times out, then you must call it again until it returns successfully. If CacheAccess.waitForResponse() does not succeed, then you must call CacheAccess.cancelResponse to free resources. If CacheAccess.releaseOwnership() doesn't succeed, then you must call CacheAccess.releaseOwnership with a timeout value of -1 to free resources.

  • When a group or region is destroyed or invalidated, distributed definitions take precedence over local definitions. That is, if the group is distributed, then all objects in the group or region are invalidated or destroyed across the entire cache system, even if the individual objects or associated groups are defined as local. If the group or region is defined as local, then local objects within the group are invalidated locally; distributed objects are invalidated throughout the entire cache system.

  • When an object or group is defined with the SYNCHRONIZE attribute set, ownership is required to load or replace the object. However, ownership is not required for general access to the object or to invalidate the object.

  • In general, objects that are stored in the cache should be loaded by the system class loader that is defined in the classpath when the JVM is initialized, rather than by a user-defined class loader. Specifically, any objects that are shared between applications or can be saved or spooled to disk must be defined in the system classpath. Failure to do so can result in a ClassNotFoundException or a ClassCastException.

  • On some systems, the open file descriptors can be limited by default. On these systems, you may need to change system parameters to improve performance. On UNIX systems, for example, a value of 1024 or greater can be an appropriate value for the number of open file descriptors.

  • When configured in either local or distributed mode, at startup, one active Java Object Cache cache is created in a JVM process (that is, in the program running in the JVM that uses the Java Object Cache API).

Working with Disk Objects

The Java Object Cache can manage objects on disk as well as in memory.

This section covers the following topics:

Local and Distributed Disk Cache Objects

This section covers the following topics:

Local Objects

When operating in local mode, the cache attribute isDistributed is not set and all objects are treated as local objects (even when the DISTRIBUTE attribute is set for an object). In local mode, all objects in the disk cache are visible only to the Java Object Cache cache that loaded them, and they do not survive after process termination. In local mode, objects stored in the disk cache are lost when the process using the cache terminates.

Distributed Objects

If the cache attribute isDistributed is set to true, the cache will operate in distributed mode. Disk cache objects can be shared by all caches that have access to the file system hosting the disk cache. This is determined by the disk cache location configured. This configuration allows for better utilization of disk resources and allows disk objects to persist beyond the life of the Java Object Cache process.

Objects that are stored in the disk cache are identified using the concatenation of the path that is specified in the diskPath configuration property and an internally generated String representing the remaining path to the file. Thus, caches that share a disk cache can have a different directory structure, as long as the diskPath represents the same directory on the physical disk and is accessible to the Java Object Cache processes.

If a memory object that is saved to disk is also distributed, the memory object can survive the death of the process that spooled it.

Adding Objects to the Disk Cache

There are several ways to use the disk cache with the Java Object Cache, including:

Automatically Adding Objects

The Java Object Cache automatically adds certain objects to the disk cache. Such objects can reside either in the memory cache or in the disk cache. If an object in the disk cache is needed, it is copied back to the memory cache. The action of spooling to disk occurs when the Java Object Cache determines that it requires free space in the memory cache. Spooling of an object occurs only if the SPOOL attribute is set for the object.

Explicitly Adding Objects

In some situations, you may want to force one or more objects to be written to the Java Object Cache disk cache. Using the CacheAccess.save() method, a region, subregion, group, or object is written to the disk cache. (If the object or objects are already in the disk cache, they are not written again.)


Note:

Using CacheAccess.save() saves an object to disk even when the SPOOL attribute is not set for the object.

Calling CacheAccess.save() on a region, subregion, or group saves all the objects within the region, subregion, or group to the disk cache. During a CacheAccess.save() method call, if an object is encountered that cannot be written to disk, either because it is not serializable or for other reasons, then the event is recorded in the Java Object Cache log, and the save operation continues with the next object. When individual objects are written to disk, the write is synchronous. If a group or region is saved, then the write is performed as an asynchronous background task.

Using Objects that Reside Only in Disk Cache

Objects that you access only directly from disk cache are loaded into the disk cache by calling CacheLoader.createDiskObject() from the CacheLoader.load() method. The createDiskObject() method returns a File object that the application can use to load the disk object. If the attributes of the disk object are not defined for the disk object, then set them using the createDiskObject() method. The system manages local and distributed disk objects differently; the system determines if the object is local or distributed when it creates the object, based on the specified attributes.


Note:

If you want to share a disk cache object between distributed caches in the same cache system, then you must define the DISTRIBUTE attribute when the disk cache object is created. This attribute cannot be changed after the object is created.

When CacheAccess.get() is called on a disk object, the full path name to the file is returned, and the application can open the file, as needed.

Disk objects are stored on a local disk and accessed directly from the disk by the application using the Java Object Cache. Disk objects can be shared by all Java Object Cache processes, or they can be local to a particular process, depending on the setting for the DISTRIBUTE attribute (and the mode that the Java Object Cache is running in, either distributed or local).

Example 9-17 shows a loader object that loads a disk object into the cache.

Example 9-17 Creating a Disk Object in a CacheLoader

import oracle.ias.cache.*;

class YourObjectLoader extends CacheLoader
{
   public Object load(Object handle, Object args) {
      File file;
      FileOutputStream = out;
      Attributes attr = new Attributes();

      attr.setFlags(Attributes.DISTRIBUTE);
      try
      // The distribute attribute must be set on the createDiskObject method
      {
         file = createDiskObject(handle, attr);
         out = new FileOutputStream(file);

         out.write((byte[])getInfofromsomewhere());
         out.close();
     }
     catch (Exception ex) {
       // translate exception to CacheException, and log exception
         throw exceptionHandler("exception in file handling", ex)
      }
      return file;
      }
   }

Example 9-18 illustrates application code that uses a Java Object Cache disk object. This example assumes that the region named Stock-Market is already defined with the YourObjectLoader loader that was set up in Example 9-17 as the default loader for the region.

Example 9-18 Application Code that Uses a Disk Object

import oracle.ias.cache.*;

try
{
   FileInputStream in;
   File file;
   String filePath;
   CacheAccess cacc = CacheAccess.getAccess("Stock-Market");

   filePath = (String)cacc.get("file object");
   file = new File(filePath);
   in = new FileInputStream(filePath);
   in.read(buf);

// do something interesting with the data
   in.close();
   cacc.close();
}
catch (Exception ex)
{
// handle exception
}

Working with StreamAccess Objects

A StreamAccess object is accessed as a stream and automatically loaded to the disk cache. The object is loaded as an OutputStream and read as an InputStream. Smaller StreamAccess objects can be accessed from memory or from the disk cache; larger StreamAccess objects are streamed directly from the disk. The Java Object Cache automatically determines where to access the StreamAccess object, based on the size of the object and the capacity of the cache.

The user is always presented with a stream object, an InputStream for reading and an OutputStream for writing, regardless of whether the object is in a file or in memory. The StreamAccess object allows the Java Object Cache user to always access the object in a uniform manner, without regard to object size or resource availability.

Creating a StreamAccess Object

To create a StreamAccess object, call the CacheLoader.createStream() method from the CacheLoader.load() method when the object is loaded into the cache. The createStream() method returns an OutputStream object. Use the OutputStream object to load the object into the cache.

If the attributes have not already been defined for the object, then set them using the createStream() method. The system manages local and distributed disk objects differently; the determination of local or distributed is made when the system creates the object, based on the attributes.


Note:

If you want to share a StreamAccess object between distributed caches in the same cache system, then you must define the DISTRIBUTE attribute when the StreamAccess object is created. You cannot change this attribute after the object is created.

Example 9-19 shows a loader object that loads a StreamAccess object into the cache.

Example 9-19 Creating a StreamAccess Object in a Cache Loader

import oracle.ias.cache.*;

class YourObjectLoader extends CacheLoader
{
   public Object load(Object handle, Object args) {
     OutputStream = out;
     Attributes attr = new Attributes();
     attr.setFlags(Attributes.DISTRIBUTE);

     try 
     {
        out = createStream(handle, attr);
        out.write((byte[])getInfofromsomewhere());
     }
     catch (Exception ex) {
        // translate exception to CacheException, and log exception
        throw exceptionHandler("exception in write", ex)
     }
     return out;
     }
}

Working with Pool Objects

A pool object is a special cache object that the Java Object Cache manages. A pool object contains a set of identical object instances. The pool object itself is a shared object; the objects within the pool are private objects that the Java Object Cache manages. Users access individual objects within the pool with a check out, using a pool access object, and then return the objects to the pool when they are no longer needed.

This section covers the following topics:

Creating Pool Objects

To create a pool object, use CacheAccess.createPool(). The CreatePool() method takes as arguments:

  • A PoolInstanceFactory

  • An Attributes object

  • Two integer arguments

The integer arguments specify the maximum pool size and the minimum pool size. By supplying a group name as an argument to CreatePool(), a pool object is associated with a group.

Attributes, including TimeToLive or IdleTime, can be associated with a pool object. These attributes can be applied to the pool object itself, when specified in the attributes set with CacheAccess.createPool(), or they can be applied to the objects within the pool individually.

Using CacheAccess.createPool(), specify minimum and maximum sizes with the integer arguments. Specify the minimum first. It sets the minimum number of objects to create within the pool. The minimum size is interpreted as a request rather than a guaranteed minimum. Objects within a pool object are subject to removal from the cache due to lack of resources, so the pool can decrease the number of objects below the requested minimum value. The maximum pool size puts a hard limit on the number of objects available in the pool.


Note:

Pool objects and the objects within a pool object are always treated as local objects.

Example 9-20 shows how to create a pool object.

Example 9-20 Creating a Pool Object

import oracle.ias.cache.*;

   try
   {
      CacheAccess cacc = CacheAccess.getAccess("Stock-Market");
      Attributes  attr = new Attributes();
      QuoteFactory poolFac = new QuoteFactory();

      // set IdleTime for an object in the pool to three minutes
      attr.setIdleTime(180);
      // create a pool in the "Stock-Market" region with a minimum of
      // 5 and a maximum of 10 object instances in the pool
      cacc.createPool("get Quote", poolFac, attr, 5, 10);
      cacc.close();
   }  
   catch(CacheException ex)  
   {
           // handle exception
   }
}

Using Objects from a Pool

To access objects in a pool, use a PoolAccess object. The PoolAccess.getPool() static method returns a handle to a specified pool. The PoolAccess.get() method returns an instance of an object from within the pool (this checks out an object from the pool). When an object is no longer needed, return it to the pool, using the PoolAccess.returnToPool() method, which checks the object back into the pool. Finally, call the PoolAccess.close() method when the pool handle is no longer needed.

Example 9-21 describes the calls that are required to create a PoolAccess object, check an object out of the pool, and then check the object back in and close the PoolAccess object.

Example 9-21 Using a PoolAccess Object

PoolAccess pacc = PoolAccess.getPool("Stock-Market", "get Quote");
//get an object from the pool
GetQuote  gq = (GetQuote)pacc.get();
// do something useful with the gq object
// return the object to the pool
pacc.returnToPool(gq);   
pacc.close();

Implementing a Pool Object Instance Factory

The Java Object Cache instantiates and removes objects within a pool, using an application-defined factory object—a PoolInstanceFactory. The PoolInstanceFactory is an abstract class with two methods that you must implement: createInstance() and destroyInstance().

The Java Object Cache calls createInstance() to create instances of objects that are being accumulated within the pool. The Java Object Cache calls destroyInstance() when an instance of an object is being removed from the pool. (Object instances from within the pool are passed into destroyInstance().)

The size of a pool object (that is, the number of objects within the pool) is managed using these PoolInstanceFactory() methods. The system decreases or increases the size and number of objects in the pool, based on demand, and based on the values of the TimeToLive or IdleTime attributes.

Example 9-22 shows the calls required when implementing a PoolInstanceFactory.

Example 9-22 Implementing Pool Instance Factory Methods

import oracle.ias.cache.*;
   public class MyPoolFactory implements PoolInstanceFactory 
   {
       public Object createInstance()
      {
         MyObject obj = new MyObject();
         obj.init();
         return obj;
       }
       public void destroyInstance(Object obj)
       {
           ((MyObject)obj).cleanup();
       }
   }

Pool Object Affinity

Object pools are a collection of serially reusable objects. A user "checks out" an object from the pool to perform a function, then "checks in" the object back to the pool when done. During the time the object is checked out, the user has exclusive use of that object instance. After the object is checked in, the user gives up all access to the object. While the object is checked out, the user can apply temporary modifications to the pool object (add state) to allow it to execute the current task. Since some cost is incurred to add these modifications, it would be beneficial to allow the user to, whenever possible, get the same object from the pool with the modifications already in place. Since the 9.0.2 version of the Java Object Cache, the only way to do this was never to check in the object, which would then defeat the purpose of the pool. To support the pool requirement described in this paragraph, the functionality described in the following two paragraphs has been added to the pool management of the Java Object Cache.

Objects checked into the pool using the returnToPool method of the PoolAccess object maintain an association with the last PoolAccess object that referenced the object. When the PoolAccess handle requests an object instance, the same object it had previously is returned. This association will be terminated if the PoolAccess handle is closed, or the PoolAccess.release method is called, or the object is given to another user. Before the object is given to another user, a callback is made to determine if the user is willing to give up the association with the object. If the user is not willing to dissolve the association, then the new user is not given access to the object. The interface PoolAffinityFactory extends the interface PoolInstanceFactory, adding the callback method affinityRelease. This method returns true if the association can be broken, and false otherwise.

If the entire pool is invalidated, the affinityRelease method is not called. Object instance cleanup is then performed with the PoolInstanceFactory.instanceDestroy method.

Running in Local Mode

When running in local mode, the Java Object Cache does not share objects or communicate with any other caches running locally on the same system or remotely across the network. Object persistence across system shutdowns or program failures is not supported when running in local mode.

By default, the Java Object Cache runs in local mode, and all objects in the cache are treated as local objects. When the Java Object Cache is configured in local mode, the cache ignores the DISTRIBUTE attribute for all objects.

Running in Distributed Mode

In distributed mode, the Java Object Cache can share objects and communicate with other caches running either locally on the same system or remotely across the network. Object updates and invalidations are propagated between communicating caches. Distributed mode supports object persistence across system shutdowns and program failures.

This section covers the following topics:

Configuring Properties for Distributed Mode

To configure the Java Object Cache to run in distributed mode, set the value of the distribute and discoveryAddress configuration properties in the javacache.xml file.

Setting the distribute Configuration Property

To start the Java Object Cache in distributed mode, set the isDistributed attribute to true in the configuration file. "Java Object Cache Configuration" describes how to do this.

Setting the discoveryAddress Configuration Property

In distributed mode, invalidations, destroys, and replaces are propagated through the messaging system of the cache. The messaging system requires a known host name and port address to allow a cache to join the cache system when it is first initialized. Use the discoverer attribute in the communication section in the javacache.xml file to specify a list of host name and port addresses.

By default, the Java Object Cache sets the discoverer to the value :12345 (this is equivalent to localhost:12345). To eliminate conflicts with other software on the site, have your system administrator set the discoveryAddress.

If the Java Object Cache spans systems, then configure multiple discoverer entries, with one hostname:port pair specified for each node. Doing this avoids any dependency on a particular system being available or on the order the processes are started. Also see "Java Object Cache Configuration".


Note:

All caches cooperating in the same cache system must specify the same set of host name and port addresses. The address list, set with the discoverer attributes, defines the caches that make up a particular cache system. If the address lists vary, then the cache system could be partitioned into distinct groups, resulting in inconsistencies between caches.

Using Distributed Objects, Regions, Subregions, and Groups

When the Java Object Cache runs in distributed mode, individual regions, subregions, groups, and objects can be either local or distributed. By default, objects, regions, subregions, and groups are defined as local. To change the default local value, set the DISTRIBUTE attribute when the object, region, or group is defined.

A distributed cache can contain both local and distributed objects.

Several attributes and methods in the Java Object Cache allow you to work with distributed objects and control the level of consistency of object data across the caches. Also see "Cached Object Consistency Levels".

Using the REPLY Attribute with Distributed Objects

When updating, invalidating, or destroying objects across multiple caches, it may be useful to know when the action has completed at all the participating sites. Setting the REPLY attribute causes all participating caches to send a reply to the originator when a requested action has completed for the object. The CacheAccess.waitForResponse() method allows the user to block until all remote operations have completed.

To wait for a distributed action to complete across multiple caches, use CacheAccess.waitForResponse(). To ignore responses, use the CacheAccess.cancelResponse() method, which frees the cache resources used to collect the responses.

Both CacheAccess.waitForResponse() and CacheAccess.cancelResponse() apply to all objects that are accessed by the CacheAccess object. This feature allows the application to update several objects, then wait for all the replies.

Example 9-23 illustrates how to set an object as distributed and handle replies when the REPLY attribute is set. In this example, you can also set the attributes for the entire region. Additionally, you can set attributes for a group or individual object, as appropriate for your application.

Example 9-23 Distributed Caching Using Reply

import oracle.ias.cache.*;

CacheAccess cacc;
String     obj;
Attributes attr = new Attributes ();
MyLoader   loader = new MyLoader();

// mark the object for distribution and have a reply generated 
// by the remote caches when the change is completed

attr.setFlags(Attributes.DISTRIBUTE|Attributes.REPLY);
attr.setLoader(loader);

CacheAccess.defineRegion("testRegion",attr); 
cacc = CacheAccess.getAccess("testRegion"); // create region with 
  //distributed attributes

obj = (String)cacc.get("testObject");
cacc.replace("testObject", obj + "new version"); // change will be 
  // propagated to other caches

cacc.invalidate("invalidObject"); // invalidation is propagated to other caches

try
{
// wait for up to a second,1000 milliseconds, for both the update 
// and the invalidate to complete
    cacc.waitForResponse(1000);

catch (TimeoutException ex)
{
   // tired of waiting so cancel the response
   cacc.cancelResponse();
}
cacc.close();
}

Using SYNCHRONIZE and SYNCHRONIZE_DEFAULT

When updating objects across multiple caches, or when multiple threads access a single object, you can coordinate the update action. Setting the SYNCHRONIZE attribute enables synchronized updates, and requires an application to obtain ownership of an object before the object is loaded or updated.

The SYNCHRONIZE attribute also applies to regions, subregions, and groups. When the SYNCHRONIZE attribute is applied to a region, subregion, or group, ownership of the region, subregion, or group must be obtained before an object can be loaded or replaced in the region, subregion, or group.

Setting the SYNCHRONIZE_DEFAULT attribute on a region, subregion, or group applies the SYNCHRONIZE attribute to all the objects within the region, subregion, or group. Ownership must be obtained for the individual objects within the region, subregion, or group before they can be loaded or replaced.

To obtain ownership of an object, use CacheAccess.getOwnership(). After ownership is obtained, no other CacheAccess instance is allowed to load or replace the object. Reads and invalidation of objects are not affected by synchronization.

After ownership has been obtained and the modification to the object is completed, call CacheAccess.releaseOwnership() to release the object. CacheAccess.releaseOwnership() waits up to the specified time for the updates to complete at the remote caches. If the updates complete within the specified time, ownership is released; otherwise, a TimeoutException is thrown. If the method times out, call CacheAccess.releaseOwnership() again. CacheAccess.releaseOwnership()must return successfully for ownership to be released. If the timeout value is -1, then ownership is released immediately, without waiting for the responses from the other caches.

Example 9-24 illustrates distributed caching using SYNCHRONIZE and SYNCHRONIZE_DEFAULT.

Example 9-24 Distributed Caching Using SYNCHRONIZE and SYNCHRONIZE_DEFAULT

import oracle.ias.cache.*;

CacheAccess cacc;
String     obj;
Attributes attr = new Attributes ();
MyLoader   loader = new MyLoader();

// mark the object for distribution and set synchronize attribute
attr.setFlags(Attributes.DISTRIBUTE|Attributes.SYNCHRONIZE);
attr.setLoader(loader);

//create region
CacheAccess.defineRegion("testRegion");
cacc = CacheAccess.getAccess("testRegion");
cacc.defineGroup("syncGroup", attr); //define a distributed synchronized group
cacc.defineObject("syncObject", attr); // define a distributed synchronized object
attr.setFlagsToDefaults()  // reset attribute flags

// define a group where SYNCHRONIZE is the default for all objects in the group
attr.setFlags(Attributes.DISTRIBUTE|Attributes.SYNCHRONIZE_DEFAULT);
cacc.defineGroup("syncGroup2", attr);
try
{
// try to get the ownership for the group don't wait more than 5 seconds
   cacc.getOwnership("syncGroup", 5000); 
   obj = (String)cacc.get("testObject", "syncGroup"); // get latest object
   // replace the object with a new version
   cacc.replace("testObject", "syncGroup", obj + "new version"); 
   obj = (String)cacc.get("testObject2", "syncGroup"); // get a second object
   // replace the object with a new version
   cacc.replace("testObject2", "syncGroup", obj + "new version"); 
}

catch (TimeoutException ex)
{
   System.out.println("unable to acquire ownership for group");
   cacc.close();
   return;
}
try
{
   cacc.releaseOwnership("syncGroup",5000);
}
catch (TimeoutException ex)
{
   // tired of waiting so just release ownership
   cacc.releaseOwnership("syncGroup", -1));
}
try
{
   cacc.getOwnership("syncObject", 5000); // try to get the ownership for the object
   // don't wait more than 5 seconds
   obj = (String)cacc.get("syncObject");  // get latest object
   cacc.replace("syncObject", obj + "new version"); // replace the object with a new version
}
catch (TimeoutException ex)
{
   System.out.println("unable to acquire ownership for object");
   cacc.close();
   return;
}
try
{
   cacc.releaseOwnership("syncObject", 5000);
}
catch (TimeoutException ex)
{
   cacc.releaseOwnership("syncObject", -1)); // tired of waiting so just release ownership
}
try
{
   cacc.getOwnership("Object2", "syncGroup2", 5000); // try to get the ownership for the object
   // where the ownership is defined as the default for the group don't wait more than 5 seconds
   obj = (String)cacc.get("Object2", "syncGroup2"); // get latest object
   // replace the object with new version
   cacc.replace("Object2", "syncGroup2", obj + "new version"); 
}

catch (TimeoutException ex)
{
   System.out.println("unable to acquire ownership for object");
   cacc.close();
   return;
}
try
{
   cacc.releaseOwnership("Object2", 5000);
}
catch (TimeoutException ex)
{
   cacc.releaseOwnership("Object2", -1)); // tired of waiting so just release ownership
}
   cacc.close();
}

Cached Object Consistency Levels

Within the Java Object Cache, each cache manages its own objects locally, within its JVM process. In distributed mode, when using multiple processes or when the system is running on multiple sites, a copy of an object can exist in more than one cache.

The Java Object Cache allows you to specify the consistency level that is required between copies of objects that are available in multiple caches. The consistency level that you specify depends on the application and the objects being cached. The supported levels of consistency vary, from none to all copies of objects being consistent across all communicating caches.

Setting object attributes specifies the level of consistency. The consistency between objects in different caches is categorized into the following four levels:

Using Local Objects

If there are no consistency requirements between objects in distributed caches, then define an object as a local object. (When Attributes.DISTRIBUTE is unset, this specifies a local object.) Local is the default setting for objects. For local objects, all updates and invalidation are visible to only the local cache.

Propagating Changes Without Waiting for a Reply

To distribute object updates across distributed caches, define an object as distributed by setting the DISTRIBUTE attribute. All modifications to distributed objects are broadcast to other caches in the system. Using this level of consistency does not control or specify when an object is loaded into the cache or updated, and does not provide notification as to when the modification has completed in all caches.

Propagating Changes and Waiting for a Reply

To distribute object updates across distributed caches and wait for the change to complete before continuing, set the object's DISTRIBUTE and REPLY attributes. When you set these attributes, notification occurs when a modification has completed in all caches. When you set Attributes.REPLY for an object, replies are sent back to the modifying cache when the modification has been completed at the remote site. These replies are returned asynchronously—that is, the CacheAccess.replace() and CacheAccess.invalidate() methods do not block. Use the CacheAccess.waitForResponse() method to wait for replies and block.

Serializing Changes Across Multiple Caches

To use the highest level of consistency of the Java Object Cache, set the appropriate attributes on the region, subregion, group, or object to make objects act as synchronized objects.

When you set Attributes.SYNCHRONIZE_DEFAULT on a region, subregion, or group, it sets the SYNCHRONIZE attribute for all the objects within the region, subregion, or group.

When you set Attributes.SYNCHRONIZE on an object, it forces applications to obtain ownership of the object before the object can be loaded or modified. Setting this attribute effectively serializes write access to objects. To obtain ownership of an object, use the CacheAccess.getOwnership() method. When you set the Attributes.SYNCHRONIZE attribute, notification is sent to the owner when the update is completed. Use CacheAccess.releaseOwnership() to block until any outstanding updates have completed and the replies are received. This releases ownership of the object so that other caches can update or load the object.


Note:

Setting Attributes.SYNCHRONIZE for an object is not the same as setting synchronized on a Java method. With Attributes.SYNCHRONIZE set, the Java Object Cache forces the cache to serialize creates and updates of the object, but does not prevent the Java programmer from obtaining a reference to the object and then modifying the object.

When using this level of consistency, with Attributes.SYNCHRONIZE, the CacheLoader.load() method calls CacheLoader.netSearch() before loading the object from an external source. Calling CacheLoader.netSearch() in the load method tells the Java Object Cache to search all other caches for a copy of the object. This process prevents different versions of the object from being loaded into the cache from an external source. Proper use of the SYNCHRONIZE attribute, along with the REPLY attribute and the invalidate method, supports consistency of objects across the cache system

Sharing Cached Objects in an OC4J Servlet

To take advantage of the distributed functionality of the Java Object Cache or to share a cached object among servlets, some minor modification to an application's deployment may be necessary. Any user-defined objects that will be shared among servlets or distributed among JVMs must be loaded by the system class loader. By default, objects that are loaded by a servlet are loaded by the context class loader. These objects are visible only to the servlets within the context that loaded them. The object definition is not available to other servlets or to the cache in another JVM. If the object is loaded by the system class loader, the object definition is available to other servlets and to the cache on other JVMs.


Note:

Deprecated: With the Apache JServ servlet environment (JServ), the preceding functionality was accomplished by including the cached object in the classpath definition available when the JServ process was started.

With OC4J, the system classpath is derived from the manifest of the oc4j.jar file and any associated JAR files, including cache.jar. The classpath in the environment is ignored. To include a cached object in the classpath for OC4J, copy the class file to ORACLE_HOME/javacache/sharedobjects/classes, or add it to the JAR file ORACLE_HOME/javacache/cachedobjects/share.jar. Both the classes directory and the share.jar file have been included in the manifest for cache.jar.

Using User-Defined Class Loaders

You can place objects in the cache that require user-defined class loaders. The Cache Service supports user-defined class loaders by providing two methods: Attributes.setClassLoader() and Attributes.getClassLoader(). Once you have set a region or a group to use a user-defined class loader, all objects under that region or group are loaded using this class loader (by inheriting attributes). This attribute does not apply to objects that are not region or group, and will be ignored if set.

The following example demonstrates setting user-defined class loader. Object A is loaded using MyClassLoader.

import oracle.ias.cache.*;
import java.lang.ClassLoader;
Classloader loader = this.getClass().getClassLoader();
CacheAttributes cAttr = new CacheAttributes();
Attributes attr = new Attributes();
CacheAccess cacc;
Cache.init(cAttr);
attr.setClassLoader(loader);
CacheAccess.defineRegion(Òregion AÓ, attr);
cacc = CacheAccess.getAccess(Òregion AÓ);
cacc.get(Òobject AÓ)

Note that user-defined class loaders can only be used for object contents, not object names. In other words, in the line

cacc.put(name, object);

object can require a user-defined class loader, but name cannot.

HTTP and Security for Distributed Cache

This section discusses HTTP and security for distributed cache.

HTTP

By default, the Cache Service uses a proprietary protocol built on top of TCP to communicate between caches. In addition to the proprietary protocol, the Cache Service also supports using HTTP to communicate between caches. While the proprietary protocol is kept for compatibility reasons, some of the newer functionalities are implemented exclusively for HTTP. In particular, in a distributed cache system, when getting disk or stream objects from remote caches, HTTP mode is required. CacheAccess.getAllCached(), CacheLoader.getFromRemote(), and CacheLoader.netSearch() are three example operations where HTTP mode is required for dealing with disk and stream objects. To enable HTTP mode, you must set CacheAttributes.transport.

To use HTTP, you must enable it on all of the caches within a distributed system. The functionality that previously used the proprietary protocol will also work with HTTP enabled.

The following examples show two ways to enable HTTP mode.

Example 1 - Enabling HTTP in cache_attributes.xml :

--------------------
<?xml version="1.0" encoding="UTF-8"?>
<cache-configuration xmlns="http://www.oracle.com/oracle/ias/cache/configuration" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 
   <communication>
      <isDistributed>true</isDistributed>
      <transport>HTTP</transport>
   </communication>
</cache-configuration>



import oracle.ias.cache.*;
Cache.open(Òcache_attributes.xmlÓ);


Example 2 - Enabling HTTP in code:

import oracle.ias.cache.*;
CacheAttributes cAttr = new CacheAttributes();
cAttr.distribute = true;
cAttr.transport = CacheAttributes.HTTP;
Cache.init(cAttr);

SSL

For secure communication between caches, the Cache Service supports the SSL protocol. The JDK keytool program can be used to generate certificates and set up the keystore, as documented on Sun's J2SE 1.4.2 Key and Certificate Management Tool web page. The same key pair and certificate used for OC4J can be used for the Cache Service.

To use SSL, you must enable it on all of the caches within a distributed system.

After setting up the keystore, you need to tell the cache where the keystore is with this command:

java –jar $ORACLE_HOME/javacache/lib/cache.jar sslconfig <cache_attributes.xml> <keystore_file> <password>

where

  • $ORACLE_HOME is the home directory of the Oracle IAS instance.

  • cache_attributes.xml is your cache configuration file.

  • keystore_file is the full path to your keystore file as generated by keytool.

  • password is the password you used in keytool to generate the key pair.

This generates an SSL configuration file to be used by the cache, where the name of the file is as specified in cache_attributes.xml. In addition, you need to set CacheAttributes.isSSLEnabled to true.

The following examples show two ways to enable SSL:

Example 1 - Enabling SSL in cache_attributes.xml :

<?xml version="1.0" encoding="UTF-8"?>
<cache-configuration
 xmlns="http://www.oracle.com/oracle/ias/cache/configuration" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 
   <communication>
      <isDistributed>true</isDistributed>
      <useSSL>true</useSSL>
      <keyStore>.keyStore</keyStore>
      <sslConfigFile>.sslConfig</sslConfigFile>
   </communication>
</cache-configuration>


import oracle.ias.cache.*;
Cache.open(Òcache_attributes.xmlÓ);

Example 2 - Enabling SSL in code:

import oracle.ias.cache.*;
CacheAttributes cAttr = new CacheAttributes();
cAttr.distribute = true;
cAttr.isSSLEnabled = true;
cAttr.keyStoreLocation = Ò.keyStoreÓ;
cAttr.sslConfigFilePath = Ò.sslConfigÓ;
Cache.init(cAttr);

Two caches must be using the same set of keys to communicate with each other. If the caches in a system reside on multiple machines, then you need to copy the keystore file to all machines and run the java –jar … command for every cache configuration file in the system.

Firewall

To make a distributed cache system work across a firewall, the current workaround is to enable a set of outbound TCP ports at the firewall and to define them in cache_attributes.xml.

For example, cache_attributes.xml might look something like this if the ports are within the range of 7100 to 7199:

cache_attributes.xml
--------------------
<?xml version = '1.0' encoding = 'UTF-8'?>
<cache-configuration xmlns="http://www.oracle.com/oracle/ias/cache/configuration" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
   <communication>
      <isDistributed>true</isDistributed>
      <useSSL>false</useSSL>
      <sslConfigFile>.sslConfig</sslConfigFile>
      <port lower=Ó7100Ó upper=Ó7199Ó/>
      <discoverer discovery-port="7100" original="true" xmlns=""/>
   </communication>
</cache-configuration>

Make sure that the discovery-port is within the range specified.

Restricting Incoming Connections

For systems that are configured with more than one address to support multiple network subnets (private and public, for example), you can specify a configuration element, localAddress, in cache_attributes.xml to restrict incoming connections to a specified local address. By default, the distributed cache system will bind the listener socket to the primary host address returned by the operating system. If localAddress is specified, however, the cache will bind the listener socket to the specified address. The value specified for localAddress must be a fully qualified hostname or IP address. For example:

cache_attributes.xml
--------------------
<?xml version = '1.0' encoding = 'UTF-8'?>
<cache-configuration xmlns="http://www.oracle.com/oracle/ias/cache/configuration" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
   <communication>
      <isDistributed>true</isDistributed>
      <localAddress>123.456.78.90</localAddress>
      <discoverer discovery-port="7100" original="true" xmlns=""/>
   </communication>
</cache-configuration>

or

cache_attributes.xml
--------------------
<?xml version = '1.0' encoding = 'UTF-8'?>
<cache-configuration xmlns="http://www.oracle.com/oracle/ias/cache/configuration" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
   <communication>
      <isDistributed>true</isDistributed>
      <localAddress>computer.oracle.com</localAddress>
      <discoverer discovery-port="7100" original="true" xmlns=""/>
   </communication>
</cache-configuration>

In the latter case, even if the IP underneath a virtual hostname changes, JOC will remain unaffected.

Monitoring and Debugging

Besides Cache.listCacheObjects() and Cache.dump(), the Cache Service provides additional methods to reflect the current status of the cache and of the regions, groups, and individual objects within the cache. These methods can be found in the classes CacheAccess, Cache, and AggregateStatus.

The methods under Cache reflect the cache's own status. getActiveHostInfo returns an array of CacheHostInfo objects for all active caches in a cache system. getCacheSize estimates total space (bytes) taken up by memory objects in the cache. getDistributedDiskCacheSize and getLocalDiskCacheSize estimate total space (bytes) taken up by objects in the distributed and local disk caches, respectively. getObjectCount returns the current total number of objects in the cache.

The methods under CacheAccess reflect region, group, and individual object status. listNames names all objects under the region. listObjects names all objects under the region and also provides access to them. listRegions names all sub-regions under the region. These three methods are not recursive. For example, listRegions does not list the sub-regions under the sub-regions of the region.

CacheAccess.getStatus() reflects more detailed status information for a named individual object or group under the region in the form of an ObjectStatus object. This includes the cached object's access count, time of creation, size on disk (if stored on disk), last time of access, loading time (ms), priority (as set by the object's creator), and size in cache (bytes). If no object or group name is specified, getStatus returns the status of the region.

CacheAccess.getAggregateStatus(), on the other hand, returns overall statistics for a named group or region (sub-region) in the form of an AggregateStatus object. AggregateStatus reflects the low, average, and high values of attributes of the objects under the region or group. These attributes include access count, time of creation, last time of access, loading time, priority, and size in cache. In addition, the AggregateStatus object also includes the total object count for the region or group. Reflection methods in the AggregateStatus class allows you to access all of these numbers individually.

The Cache Service automatically compiles the information reflected by getAggregateStatus during every clean interval. To obtain the latest information, you need to call Cache.updateStats() before calling getAggregateStatus.

Here is an example of using getAggregateStatus

import oracle.ias.cache.*;
import java.util.Date;
import java.io.*;

CacheAccess cacc;

// create objects, load objects, etc.
...

AggregateStatus aggStats;
long            avgCreateTime;
Date            avg;

Cache.updateStats();
aggStats = cacc.getAggregateStatus();
avgCreateTime = aggStats.getCreateTime(AggregateStatus.AVG);
avg = new Date(avgCreateTime);

System.out.println("average creation time: " + avg);

CacheWatchUtil

By default, the Cache Service provides the CacheWatchUtil cache monitoring utility that can display current caches in the system, display a list of cached objects, display caches' attributes, reset cache logger severity, dump cache contents to the log, and so on.

To invoke CacheWatchUtil, while caches are running, type one of the following commands:

java oracle.ias.cache.CacheWatchUtil [-config=cache_config.xml] [-help]

or

java –jar $ORACLE_HOME/javacache/lib/cache.jar watch [-config=cache_config.xml] [-help]

where Ò-config=Ó and Ò-helpÓ are optional parameters, and cache_config.xml is a cache configuration file.

Typing Òget config [CacheId]Ó returns the cache configuration information for a particular cache. You can retrieve remote cache configurations for verification, as shown in the following example.

cache> get config 3
ache 3 at localhost:53977
distribute = true
version = 9.0.4
max objects = 200
max cache size = 48
diskSize = 32
diskPath = <disk_path>
clean interval = 3
LogFileName = <log_file_name>
Logger = MyCacheLogger
Log severity = 3
cache address list = [127.0.0.1:22222, pos=-1, uid=0, orig, name=, pri=0
]

Typing Òlist cachesÓ or ÒlcÓ lists all of the active caches in the system. The cache watcher also occupies a spot on the list, as shown in the following example. The UID column displays every cache's ID. The cache watcher does not detect caches that have been configured but are not active.

cache> lc
Current coordinator: [127.0.0.1:53957, pos=0, uid=0, tag=27979955, pri=0]
#       UID     CacheAddress
-       ---     ---------------------
1       0       localhost:53957
2       1       localhost:53965
3       2       localhost:53974
4       3       localhost:53977
5       4       localhost:53980
6       5       localhost:53997 <-- this cache watcher

Typing

Òlist objects [CacheId] [region=<region>] [sort=<0...7>]Ó 

or

Òlo [CacheId] [region=<region>] [sort=<0...7>]Ó

lists all objects in a specified cache, under a specified region, and in the order specified by the sort option. The sort options are:

Without any options, lo lists all objects in all caches without sorting. The following example shows lo for cache 3, A-Region, sorted by object name. Columns have been adjusted to improve example readability.

cache> lo 3 region=A-Region sort=1
Cache 3 at localhost:53977
 REGION     OBJNAME    GROUP      TYPE   REFCNT   ACCCNT   EXPIRE      VALID   LOCK
--------   ---------  -------    ------ -------- -------- --------    ------- ------
[A-Region] [A-Group]  [A-Region] Group  0        1        None        true    null
[A-Region] [A-Region] [null]     Region 0        4        295 Seconds true    null
[A-Region] [B-Group]  [A-Region] Group  0        3        None        true    null
[A-Region] [bar]      [B-Group]  Loader 0        1        None        true    null

Finally, typing ÒgroupdumpÓ dumps all group communication information for all caches to the log file. It is unlikely that you will need to use this command or that you will find its output useful, but in the event of group communication errors, technical support might ask you to supply the information for problem diagnosis.

XML Schema for Cache Configuration

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema targetNamespace="http://www.oracle.com/oracle/ias/cache/configuration"
 xmlns:xs="http://www.w3.org/2001/XMLSchema"
 xmlns="http://www.oracle.com/oracle/ias/cache/configuration" 
elementFormDefault="qualified" attributeFormDefault="unqualified">
   <xs:element name="cache-configuration" type="CacheConfigurationType">
      <xs:annotation>         <xs:documentation>Oracle JavaCache implementation</xs:documentation>
      </xs:annotation>
   </xs:element>
   <xs:complexType name="CacheConfigurationType">
      <xs:sequence>
         <xs:element name="logging" type="loggingType" minOccurs="0"/>
         <xs:element name="communication" type="communicationType" minOccurs="0"/>
         <xs:element name="persistence" type="persistenceType" minOccurs="0"/>
         <xs:element name="preload-file" type="xs:string" minOccurs="0" maxOccurs="unbounded"/>
         <xs:element name="max-objects" type="xs:positiveInteger" default="1000" minOccurs="0"/>
         <xs:element name="max-size" type="xs:positiveInteger" default="1000" minOccurs="0"/>
         <xs:element name="clean-interval" type="xs:positiveInteger" default="60" minOccurs="0"/>
         <xs:element name="ping-interval" type="xs:positiveInteger" default="60" minOccurs="0"/>
         <xs:element name="cacheName" type="xs:string" minOccurs="0"/>
      </xs:sequence>
   </xs:complexType>
   <xs:complexType name="loggingType">
      <xs:sequence>
         <xs:element name="location" type="xs:string" minOccurs="0"/>
         <xs:element name="level" type="loglevelType" minOccurs="0"/>
         <xs:element name="logger" type="xs:string" minOccurs="0"/>
      </xs:sequence>
   </xs:complexType>
   <xs:complexType name="communicationType">
      <xs:sequence>
         <xs:element name="isDistributed" type="xs:boolean" default="false" minOccurs="0"/>
         <xs:element name="transport" type="transportType" minOccurs="0"/>
         <xs:element name="useSSL" type="xs:boolean" minOccurs="0"/>
         <xs:element name="sslConfigFile" type="xs:string" minOccurs="0"/>
         <xs:element name="keyStore" type="xs:string" minOccurs="0"/>
         <xs:element name="port" minOccurs="0">
            <xs:complexType>
               <xs:attribute name="lower" type="xs:nonNegativeInteger" use="optional" default="0"/>
               <xs:attribute name="upper" type="xs:nonNegativeInteger" use="optional" default="0"/>
            </xs:complexType>
         </xs:element>
         <xs:element name="localAddress" type="xs:string" minOccurs="0"/>
         <xs:element name="discoverer" minOccurs="0" maxOccurs="unbounded">
            <xs:complexType>
               <xs:complexContent>
                  <xs:extension base="discovererType">
                     <xs:attribute name="order" type="xs:nonNegativeInteger"/>
                     <xs:attribute name="original" type="xs:boolean"/>
                  </xs:extension>
               </xs:complexContent>
            </xs:complexType>
         </xs:element>
         <xs:element name="discovererElection" type="electionType" minOccurs="0"/>
      </xs:sequence>
   </xs:complexType>
   <xs:complexType name="discovererType">
      <xs:attribute name="ip" type="xs:string"/>
      <xs:attribute name="discovery-port" type="xs:positiveInteger" use="required"/>
   </xs:complexType>
   <xs:complexType name="persistenceType">
      <xs:sequence>
         <xs:element name="location" type="xs:string"/>
         <xs:element name="disksize" type="xs:positiveInteger" default="30" minOccurs="0"/>
      </xs:sequence>
   </xs:complexType>
   <xs:simpleType name="loglevelType">
      <xs:restriction base="xs:token">
         <xs:enumeration value="OFF"/>
         <xs:enumeration value="FATAL"/>
         <xs:enumeration value="ERROR"/>
         <xs:enumeration value="DEFAULT"/>
         <xs:enumeration value="WARNING"/>
         <xs:enumeration value="TRACE"/>
         <xs:enumeration value="INFO"/>
         <xs:enumeration value="DEBUG"/>
      </xs:restriction>
   </xs:simpleType>
   <xs:simpleType name="transportType">
      <xs:restriction base="xs:token">
         <xs:enumeration value="TCP"/>
         <xs:enumeration value="HTTP"/>
      </xs:restriction>
   </xs:simpleType>
   <xs:complexType name="electionType">
      <xs:sequence>
         <xs:element name="useMulticast" type="xs:boolean" minOccurs="0"/>
         <xs:element name="updateInterval" type="xs:positiveInteger" minOccurs="0"/>
         <xs:element name="resolutionInterval" type="xs:positiveInteger" minOccurs="0"/>
         <xs:element name="multicastAddress" minOccurs="0">
            <xs:complexType>
               <xs:attribute name="ip" type="xs:string" use="optional"/>
               <xs:attribute name="port" type="xs:string" use="optional"/>
               <xs:attribute name="TTL" type="xs:nonNegativeInteger" use="optional"/>
            </xs:complexType>
         </xs:element>
         <xs:element name="usePriorityOrder" type="xs:boolean" minOccurs="0"/>
      </xs:sequence>
   </xs:complexType>
</xs:schema>

XML schema for attribute declaration

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema targetNamespace="http://www.oracle.com/oracle/ias/cache/configuration/declarative"
 xmlns:xs="http://www.w3.org/2001/XMLSchema"
 xmlns="http://www.oracle.com/oracle/ias/cache/configuration/declarative"
 elementFormDefault="qualified" attributeFormDefault="unqualified">
   <xs:complexType name="regionType">
      <xs:sequence>
         <xs:element name="attributes" type="attributesType" minOccurs="0"/>
         <xs:element name="region" type="regionType" minOccurs="0" maxOccurs="unbounded"/>
         <xs:element name="group" type="groupType" minOccurs="0" maxOccurs="unbounded"/>
         <xs:element name="cached-object" type="cached-objectType" minOccurs="0" maxOccurs="unbounded"/>
      </xs:sequence>
      <xs:attribute name="name" type="xs:string" use="required"/>
   </xs:complexType>
   <xs:complexType name="attributesType">
      <xs:sequence>
         <xs:element name="time-to-live" type="xs:positiveInteger" minOccurs="0"/>
         <xs:element name="default-ttl" type="xs:positiveInteger" minOccurs="0"/>
         <xs:element name="idle-time" type="xs:positiveInteger" minOccurs="0"/>
         <xs:element name="version" type="xs:string" minOccurs="0"/>
         <xs:element name="max-count" type="xs:positiveInteger" minOccurs="0"/>
         <xs:element name="priority" type="xs:positiveInteger" minOccurs="0"/>
         <xs:element name="size" type="xs:positiveInteger" minOccurs="0"/>
         <xs:element name="flag" minOccurs="0" maxOccurs="unbounded">
            <xs:simpleType>
               <xs:restriction base="flagType">
                  <xs:enumeration value="distribute"/>
                  <xs:enumeration value="reply"/>
                  <xs:enumeration value="synchronize"/>
                  <xs:enumeration value="spool"/>
                  <xs:enumeration value="group_ttl_destroy"/>
                  <xs:enumeration value="original"/>
                  <xs:enumeration value="synchronize-default"/>
                  <xs:enumeration value="allownull"/>
                  <xs:enumeration value="measure"/>
               </xs:restriction>
            </xs:simpleType>
         </xs:element>
         <xs:element name="event-listener" type="event-listenerType" minOccurs="0"/>
         <xs:element name="cache-loader" type="userDefinedObjectType" minOccurs="0"/>
         <xs:element name="capacity-policy" type="userDefinedObjectType" minOccurs="0"/>
         <xs:element name="user-defined" minOccurs="0" maxOccurs="unbounded">
            <xs:complexType>
               <xs:sequence>
                  <xs:element name="key" type="xs:string"/>
                  <xs:element name="value" type="xs:string"/>
               </xs:sequence>
            </xs:complexType>
         </xs:element>
      </xs:sequence>
   </xs:complexType>
   <xs:simpleType name="flagType">
      <xs:list itemType="xs:token"/>
   </xs:simpleType>
   <xs:complexType name="userDefinedObjectType">
      <xs:sequence>
         <xs:element name="classname" type="xs:string"/>
         <xs:element name="parameter" type="propertyType" minOccurs="0" maxOccurs="unbounded"/>
      </xs:sequence>
   </xs:complexType>
   <xs:complexType name="propertyType">
      <xs:simpleContent>
         <xs:extension base="xs:string">
            <xs:attribute name="name" type="xs:string" use="required"/>
         </xs:extension>
      </xs:simpleContent>
   </xs:complexType>
   <xs:complexType name="event-listenerType">
      <xs:sequence>
         <xs:element name="classname" type="xs:string"/>
      </xs:sequence>
      <xs:attribute name="handle-event" type="handle-eventType" use="required"/>
      <xs:attribute name="default" type="xs:boolean"/>
   </xs:complexType>
   <xs:simpleType name="handle-eventType">
      <xs:restriction>
         <xs:simpleType>
            <xs:list itemType="xs:token"/>
         </xs:simpleType>
         <xs:enumeration value="object-invalidated"/>
         <xs:enumeration value="object-updated"/>
      </xs:restriction>
   </xs:simpleType>
   <xs:complexType name="groupType">
      <xs:sequence>
         <xs:element name="attributes" type="attributesType" minOccurs="0"/>
         <xs:element name="group" type="groupType" minOccurs="0" maxOccurs="unbounded"/>
         <xs:element name="cached-object" type="cached-objectType" minOccurs="0" maxOccurs="unbounded"/>
      </xs:sequence>
      <xs:attribute name="name" type="xs:string" use="required"/>
   </xs:complexType>
   <xs:complexType name="cached-objectType">
      <xs:sequence>
         <xs:element name="attributes" type="attributesType" minOccurs="0"/>
         <xs:element name="name" type="nameType" minOccurs="0"/>
         <xs:element name="object" type="userDefinedObjectType" minOccurs="0"/>
      </xs:sequence>
   </xs:complexType>
   <xs:complexType name="nameType">
      <xs:choice>
         <xs:element name="string-name" type="xs:string"/>
         <xs:element name="object-name" type="userDefinedObjectType"/>
      </xs:choice>
   </xs:complexType>
   <xs:element name="cache">
      <xs:complexType>
         <xs:sequence maxOccurs="unbounded">
            <xs:element name="region" type="regionType"/>
         </xs:sequence>
      </xs:complexType>
   </xs:element>
</xs:schema>