Introduction

Database access is usually costly. There is the cost of driving the Database engine. There is the cost of response time in the application waiting for database results. If a particular database result is used often, then caching the results of that SQL call in the application server is a natural requirement to reduce the effect of these costs.

Because the use of database calls is quite common in WebSphere Portal as well as WebSphere Application server, care must be taken to optimize all facets of these SQL calls. In Portal, it is common for the theme as well as Portlets to use database calls therefore caching is imperative here. The most common caching mechanism used in WebSphere is the Dynacache.

A Dynacache is simply a cluster aware Java Hashmap. This Hashmap is cluster aware in the sense that if a “key” is invalidated or updated on one cluster member, appropriate measures are taken on all cluster members to insure that the “value” in the Dynacache Hashmap is either updated or removed as well. The key/value pair can also be inserted into the Dynacache with a time-out value to insure freshness.

So, what are the best practice patterns for the use of a database backed Dynacache instance? This article will attempt to highlight those best practices.

Initial Code

Initially, one can use a simple “dao” (data access object) to fetch the database contents based on some key value. In this example, the key is the “uniqueID”.

DBResults results = dao.getRow(uniqueID);

Obviously, a call to “dao.getRow() “ results in a database access every call. If this call is frequent and uses the same parameter(s), consider caching the result in a Dynacache.

Initial Dynacache Implementation

First, we must create the Dynacache instance along with a JNDI name which applications will use to reference this instance. This is done on the Deployment Manager GUI under "object instances".

To use the new Dynacache instance, the simplest thing to do is to create a Dynacache "impl" class with a "get" method that looks exactly like the call to the database “dao” class' "get" method. It could use exactly the same parameters in most cases.

DBResults results = daoHelperImpl.getRow(uniqueID);

In the new Impl class, check first if the value is in the Dynacache. If not, fetch it. If so, return it:

Performance Improvements

This is perhaps the most important section of this paper. In a web based application, performance is very important. So, having a version of the Dynacache based database access that avoids repeated accesses to the database is important.

The “impl” class above is a good first pass. However, there is a problem that manifests under load. When there are multiple threads all using the same “uniqueID” and the Dynacache is not yet loaded, you could have lots of thread all trying to write the dao results into the cache if the cache was previously empty.

This problem is resolved by “synchronizing” on the moethod that is used for updating. Kudos to Antonio Fiol Bonnin for finding the error in my original pseudo code.

private synchronized DBResults checkAndSet(String uid) {
// Handle the case where another thread updated the value while you were waiting
System.out.println("UID was NOT in the cache. Wait for other threads, check to see if then added, otherwise must add");
if (!(aDynacache.keySet().contains(uid)))
aDynacache.put(uid, dao.getRow(uid));
return (DBResults) aDynacache.get(uid);
}

One might see that there is a redundancy here in that the “distributedMap.keySet().contains(uniqueID)” test is duplicated. The reason is simple. Running the test first without the “synchronized” block is much faster and should result in significant time savings if the cache is already loaded. If, however, the cache were empty and this thread was blocked waiting on another thread similarly blocked, it is not clear who wins the race and is first to access the database. You do not want both threads then hitting the database for the same key. It is sufficient for only one thread to actually read the key/value pair from the database and then to update the Dynacache instance.

This implementation insures that only one database access is used to update the key and provides the best performance for all threads as well as the database.

The customization of the Advanced cache key required the Personalized option of the WCM Advanced Cache to be used. This will enforce the cache key to contain the groups of the user.

In this post we will discuss on how to customize the cache key without requiring the Personalized option to be used - so you can use e.g. the Site option and so achieve a better cache hit ratio for your users.

Attached to this blog is a rendering preprocessor for the WCM JSR286 rendering portlets that can supply an arbitrary cache key.

To configure the preprocessor modify the source code and add your logic for the custom cache key to it. Build the project as a war file and deploy it to WebSphere Application Server. Update the WCM portlets to leverage the preprocessor.

To verify the functionality I would recommend to use the WebSphere Extended cache Monitor and looking at the cache contents of the Processing cache after hitting a WCM viewer portlet that has the preprocessor configured.

In today's blog post I will answer some customer questions I received lately.

1. Is it possible to customize the portlet unavailable message?

Issues with a portlet that result in the unavailability of a portlet should be caught during testing. It can happen though that for some reason the issue occurs in production. In this case you might not want to replace the Portlet unavailability default message with a nicer error message pointing the user to a help hotline or to try again later. All of these resource bundles are stored in the wp.ui.jar file in the PortalServer\ui\wp.ui\shared\app directory.
For the English language, you use the problem_en.properties file. In that file, you see the following line:
portlet.not.available = This portlet is unavailable.
You can change that text to whatever you wish. Note that the text you enter will be the same for every portlet that is unavailable.
For other languages you would modify the according file in the jar.

2. How can the login page that Portal displays be changed to a custom page?

In case you are not logged in and you access the protected area of Portal, Portal will redirect you to the login page of the according virtual Portal. The same is true when the login link is selected. To switch the default page to a custom page you can change the unique name of the default login page and of your custom page. Portal generates the link to the login page to the page that has the unique name "wps.Login".

3. How can I configure the Web Application Bridge to pass cookies from the browser to the backend integrated via WAB?

When integrating a backend application via the Web Application Bridge you might want cookies or headers to be forwarded from the browser of the user to the backend application.
An example could be to achieve single sign on to a backend WebSphere Application Server you want to forward the LTPA2 cookie.
In version 8.0 and earlier the Web Application Bridge does not forward cookies in any direction by default. If you are using version 8.0 or earlier you need to access the WAB Admin Portlet and configure the cookie to be propagated with direction as inbound in the Forwards section. Below is a screenshot of how to configure the propagation of the LTPA 2 cookie:

6. Can I update the JVM arguments of multiple JVMs in a cluster without having to go through every JVM?

As part of the generic JVM arguments of every JVM we reference the WebSphere variable ${WPS_JVM_ARGUMENTS_EXT}. It is possible to add a custom variable and then by updating the variable all JVMs will get the setting without having to edit the settings for each and every JVM in the cluster.