Skip Headers
Oracle® Fusion Middleware Portlet Development Guide for Oracle WebLogic Portal
10g Release 3 (10.3.4)

Part Number E14244-05
Go to Documentation Home
Home
Go to Table of Contents
Contents
Go to Feedback page
Contact Us

Go to previous page
Previous
Go to next page
Next
View PDF

11 Monitoring and Determining Portlet Performance

Oracle WebLogic Portal supports the collection of analytics. You can use these analytics to deliver information to other products such as Oracle WebCenter Analytics or they can be consumed locally via custom code. These analytics are exposed through a public WebLogic Portal API in the com.bea.netuix.servlets.controls.analytics package. For more information, see the Oracle Fusion Middleware Java API Reference for Oracle WebLogic Portal. For information on using Oracle WebCenter Analytics, see the Oracle Fusion Middleware Oracle WebCenter Analytics Administrator's Guide for Oracle WebLogic Portal.

This chapter focuses on deriving and using these metrics for uses such as monitoring Service Level Agreements (SLAs), triggering a warning if a specific portlet's response time is excessive, and replacing a misbehaving portlet with an alternate portlet.

This appendix contains the following sections:

11.1 Introduction

Portals aggregate content and applications. Portals encapsulate these applications or content into subcomponents called portlets. Portlets are then brought together into a unified view that can be managed in one place. What happens when one of these portlets misbehaves or becomes unavailable? WebLogic Portal has many options for dealing with these scenarios. A few common ones are Web Service for Remote Portlets (WSRP) timeouts, interceptors, caching, threading, and AJAX enabled portlets. Each of these solutions deals with the problem in a different way and each has their own set of advantages and disadvantages. Using the public API com.bea.netuix.servlets.controls.analytics package, you can provide a more comprehensive way of dealing with this problem.

11.2 Use Case

Supposed that you have a portal that brings together different applications (portlets) into a single portal. Each of these applications (portlets) is mission critical in their own right and if one goes down it is mandatory that it not disrupt the other applications. Additionally, if one application goes down, an alternate (backup) application must be displayed in its place. After the original application resumes normal service levels, it should be brought back online to replace the temporary application.

The first challenge is determining when an a portlet is not meeting a particular Service Level Agreement (SLA). The second challenge is providing the ability to bring certain portlets online or offline based on logic applicable the SLA.

Note:

The other previously mentioned methods for dealing with these types of issues can be used in conjunction with the method described here. For simplicity, this example does not include any other mechanisms.

The solution to portlet failure and replacement uses two features available in WebLogic Portal. The first feature deals with detecting when a portlet is not meeting a particular SLA. The second feature deals with disabling the poorly behaving portlet and enabling a temporary portlet in its place. Each of these features are useful by themselves but when combined provide a more comprehensive solution to the problem.

11.3 Detecting a Misbehaving Portlet

To capture analytic events, you use the same hook that Oracle WebCenter Analytics uses to capture all of its events. However, rather than using that hook to provide the rich set of reporting capabilities provided by Oracle WebCenter Analytics, you can use the hook to simply determine when a portlet is misbehaving.

The first step is to implement the AnalyticEventHandler interface. One ore more implementations of this interface are called by the server whenever a portlet or page completes its processing. This means any implementation must be extremely efficient, as it may get called 50 or more times per request.

Example 11-1 Portlet Rendering Time Detection

public class MyAnalyticEventHandlerImpl implements AnalyticEventHandler
{
   private final static long SLA = 5000000000L;  // Five seconds (nano time)

   /**
   * <p>Implementation class may perform any one-time initializations here. If
   * this method fails (throws an exception) the event handler will not be
   * registered and no event handling will take place.</p>
   */
   public void init() {
      System.out.println("My Analytic Event Handler Initialized");
   }

   /**
   * <p>This method is called by the container at the end of each page's and
   * portlet's run. It is invoked for every page and portlet on every request.
   * Since this method is called so frequently the implementation must be
   * extremely efficient, or the entire portal's performace will suffer.</p>
   * @param analyticEvent the event to be logged.
   */
   public void log(AnalyticEvent analyticEvent)
   {
      // Ignore all but portlet events.
      if (analyticEvent.getAnalyticEventObject().equals
            (AnalyticEvent.AnalyticEventObject.PORTLET))
      {
         if (analyticEvent.getTotalTime() > SLA)
         {
            System.out.println("WARNING: portlet " +
               analyticEvent.getDefinitionLabel() + " is exceeding SLA of " +
               String.valueOf(SLA / 1000000000L) + " seconds.");
         }
      }
   }

   /**
   * <p>Implementation class may perform cleanup operations here.
   * Note: there is no guarantee this method will be called.
   * </p>
   */
   public void dispose() {
   }
}

The main method of interest is the log(AnalyticEvent analyticEvent) method. This method is invoked for every page and portlet on every request. The AnalyticEvent class contains a variety of information including the times for various lifecycle phases of the portlet.

The AnalyticEventObject has three attributes or methods that provide the functionality to detect a misbehaving portlet:

If the total time for a portlet to render exceeds 5 seconds, an error message is logged to the console. Note that times returned by these methods are in nanoseconds. As illustrated in the next section, you can use the ServiveLevelManager service to disable the portlet an enable another portlet.

Generally, you should package the service provider in a JAR file. The JAR should consist of any necessary classes (including the AnalyticEventHandler), and file named META-INF/services/com.bea.netuix.servlets.controls.analytics.AnalyticEventHandler. This services file must contain one and only one class name and must be a concrete AnalyticEventHandler implementation.

The service provider JAR or JARs should then be deployed with the application by including the JAR in the web application's WEB-INF/lib directory. Provider JARs may also be included in the application or system class path, although this changes the scoping of the provider class objects, and causes the provider implementations to be shared by multiple web applications.

11.4 Disabling the Bad Portlet and Enabling an Alternative Portlet

The ServiceLevelManager service allows you to enable and disable portlets based on a variety of identifiers. You can either disable a specific instance of a portlet or all instances of the portlet definition. In this example, all instances of the portlet definition are disabled. This choice is based on the assumption that if a portlet definition is poorly behaving, then all instances of that portlet are behaving poorly. You can just as easily disable one offending instance.

Alternatively, you can call the ServicLevelManger interface from an administration JSP. If you are using this approach, the administration JSP would list all the poorly behaving portlets and an administrator would have to manually disable the misbehaving portlets and re-enable the good ones.

In the scenario described in Section 11.2, "Use Case," you create an alternate portlet that could display a message saying the service is down, or provide a cached set of results, or get information from an alternate source. Regardless of what the alternate portlet does, it goes in the same placeholder as the misbehaving portlet.

As illustrated in Example 11-2, the alternate portlet is disabled on startup. When a portlet goes amiss, the alternate portlet is enabled and the bad portlet is disabled.

Example 11-2 Enabling an Alternate Portlet and Disabling a Misbehaving Portlet

/** Service-provider interface for {@link AnalyticEventHandler} implementations.
 * <p/>
 * An analytic event handler is a concrete subclass of this interface that
 * has a public no-argument constructor and implements the interface methods
 * specified below.
 * <p/>
 * An AnalyticEventHandler implementer should generally package their
 * provider in a jar. That jar should consist of any necessary classes
 *(including, of course, an implementation of AnalyticEventHandler), as well
 * as a file named <tt>META-INF/services/com.bea.netuix.servlets.controls.
 * analytics.AnalyticEventHandler<tt>. That services file must contain one
 * and only one class name which must be a concrete AnalyticEventHandler
 * implementation.
 * <p/>
 * The provider jar(s) should then be deployed with the application by
 * including the jar in the webapp's <tt>WED-INF/lib</tt> directory. 
 * Provider jars may also be included in the application or system classpath,
 * although this changes the scoping of the provider class objects, and
 *causes the provider implementations to be shared by multiple web apps.
 * <p/>
 * On initialization, the {@link com.bea.netuix.servlets.controls.
 * analytics.AnalyticEventDispatcher} will load such provider. Id the
 * Dispatcher fails to load or initialize the event handler a error message
 * will be logged and no event handling will take place.
 * <p/>
 * NOTE: Implementations of the interface methods must be safe for use by
 * multiple concurrent threads.
 * <p/>
 */
public class MyAnalyticEventHandlerImpl implements AnalyticEventHandler
{
   private final static long SLA = 5000000000L;  // Five seconds (nano time)
   /**
    * <p>Implementation class may perform any one-time initializations here.
    * If this method fails (throws an exception) the event handler will not
    * be registered and no event handling will take place.</p>
    */
   public void init() {
      System.out.println("My Analytic Event Handler Initialized");
      // Disable alternate portlet
      ServiceLevelManagerFactory serviceLevelManagerFactory =
      ServiceLevelManagerFactory.getInstance();
      ServiceLevelManager serviceLevelManager =
      serviceLevelManagerFactory.getServiceLevelManager("/portal_1");
      serviceLevelManager.setServiceLevelForDefinitionLabel(PortletServiceLevel.suspended, "alternate_pdl");
   }
   /**
    * <p>This method is called by the container at the end of each page's
    * and portlet's run. It is invoked for every page and portlet on every
    * request. Since this method is called so frequently the implementation
    * must be extremely efficient, or the entire portal's performace will
    * suffer.</p>
    * @param analyticEvent the event to be logged.
    */
   public void log(AnalyticEvent analyticEvent)
   {
      // Ignore all but portlet events.
      if (analyticEvent.getAnalyticEventObject().equals
         (AnalyticEvent.AnalyticEventObject.PORTLET))
      {
         // This will disable any portlet that has a response time > then
         // the SLA
         if (analyticEvent.getTotalTime() > SLA)
         {
            System.out.println("WARNING: portlet " +
               analyticEvent.getDefinitionLabel() + " is exceeding SLA of "
               + String.valueOf(SLA / 1000000000L) + " seconds.");
            ServiceLevelManagerFactory serviceLevelManagerFactory =
            ServiceLevelManagerFactory.getInstance();
            System.out.println("Servlet context path: " +
            analyticEvent.getServletContextName());
            // Note: service level manager is scoped to the context path
            // (request.getContextPath()). Before 10.2 this has to be known,
            // in 10.2, you can retrieve it from the AnalyticEvent using 
            // String getWebappContextPath();
            ServiceLevelManager serviceLevelManager =
            serviceLevelManagerFactory.getServiceLevelManager("/portal_1");
            PortletServiceLevel portletServiceLevel =
            serviceLevelManager.getServiceLevelForDefinitionLabel
            (analyticEvent.getDefinitionLabel());
            System.out.println("Suspending Portlet: " +
            analyticEvent.getDefinitionLabel());
            serviceLevelManager.setServiceLevelForDefinitionLabel
            (PortletServiceLevel.suspended,
            analyticEvent.getDefinitionLabel());
            // Activating alternate portlet
            System.out.println("Activating Alternate Portlet ");
                serviceLevelManager.setServiceLevelForDefinitionLabel(PortletServiceLevel.active, "alternate_pdl");
         }
      }
   }
   /**
    * <p>Implementation class may perform cleanup operations here.
    * Note: there is no guarantee this method will be called.
    * </p>
    */
   public void dispose() {
   }
}

To get a reference to the ServiceLevelManager, you need to access it through the service level factory. ServiceLevelManagers are scoped to the web application. As such the factory requires the webapp context path. The method of interest is:

serviceLevelManagerFactory.getServiceLevelManager("/mywebapp");

To disable (or enable) a particular portlet, set the PortletServiceLevel on the selected portlet. In Example 11-2, the following code disables the alternate portlet:

serviceLevelManager.setServiceLevelForDefinitionLabel(PortletServiceLevel.
   suspended, analyticEvent.getDefinitionLabel()); 

The alternate portlet is enabled by the same method:

serviceLevelManager.setServiceLevelForDefinitionLabel(PortletServiceLevel.
   active, "alternate_pdl"); 

In this example, the bad portlet is not disabled until it has actually run because you do not know it is bad until it takes more then 5 seconds to run. In an actual application, you would probably use timeouts for a better implementation. Also, the alternate portlet does not go online until the next request, as this request has already finished. If you want to have the alternate portlet run as part of this request, you could perform a redirect that picks up the new portlet.

In WebLogic Portal 10.0, you had to hard code the web application context path:

ServiceLevelManager serviceLevelManager =
      serviceLevelManagerFactory.getServiceLevelManager("/portal_1"); 

In WebLogic Portal 10.2 and later versions, you can get this path from the analytic event using:

String getWebappContextPath();