Wednesday, March 4, 2009

Controller class extension using JavaScript

Our example today takes us to the HR Effective Date page inside Self Service. The goal is to default a field on a page. While this is old news using a standard CO extension, achieving it using JavaScript is a lesser known alternative. To ensure the application isn't hacked to pieces while testing this, a custom repsonsibility, menu and function have been created to limit collateral damage:

(N) Hack Manager Self-Service -> Hack Change Pay



Choose employee -> Action



A reasonable request would be to alter the Effective Date field to a default value on this page:



As noted, this can easily be accomplished using a Controller .class (CO) extension. However, this page and it's corresponding Java code seems to be unique in that it doesn't respect the supported method of extending the CO, finding the Effective Date field's handle and assigning it a default value. After much hacking and cursing, it was discovered that JavaScript can be used to default the value of the field. The JavaScript will be written inside of the CO and a Java method will be used to load it into Oracle's script tags.

A cursory inspection of the "About this Page" shows which CO code is responsible for the Effective Date section of the page:





The EffectiveDateCO is the Controller .class to be extended. The field that needs to be defaulted is called HrEffectiveDate. There are two ways to ascertain this:

  1. Examine the delivered CO code found in oracle.apps.pqh.selfservice.common.webui.EffectiveDateCO
  2. Examine the page definition stored in the "JDR" database tables

Here is the decompiled version of oracle.apps.pqh.selfservice.common.webui.EffectiveDateCO:



At the top of the "About this Page" is the name of the document: /oracle/apps/pqh/selfservice/common/webui/EffectiveDatePG, the layout of which is stored in a group of database tables prefixed with "JDR":



This layout can be retrieved from the database using the following SQL*Plus script:



set feedback off
set serveroutput on format wrapped
set linesize 100
spool hack.lst
--
execute jdr_utils.printDocument('/oracle/apps/pqh/selfservice/common/webui/EffectiveDatePG',100);
--
spool off





Again, take note of the HrEffectiveDate field. Since JavaScript will be the solution to this exercise, you can also do a View Source on the actual web page and search for the field's ID. This technique may cause blindness, so proceed at your own risk. Here is a glimpse of the HTML source code:



The ultimate goal of this exercise is to get our JavaScript code embedded into that tangled mess. Like recent CO extension topics, this one will focus on the coding necessary to achieve the result. For a complete guide to CO extensions, see the previous topics:

  1. R12 Controller Class extension
  2. Controller class extension in Oracle Applications

In order to implement this, we need to do the following:

  1. extend the delivered controller class with our own
  2. FTP this file to the $JAVA_TOP on the middle tier
  3. Personalize the page to execute our controller class instead of the delivered one

There are three lines of code necessary for defaulting the date field:



OABodyBean bodyBean = (OABodyBean) pageContext.getRootWebBean();
String javaS = "return document.getElementById(\"HrEffectiveDate\").value=\"31-Oct-2009\"";
bodyBean.setOnLoad(javaS);



In keeping with tradition, we'll use a hard-coded value to simply hack the date to something arbitrary. If you are so inclined, you can choose a date based on logic by calling a PL/SQL procedure or a SQL function. For now...lettuce use a static date as shown above.

The complete extended CO is shown here:


/*===========================================================================+
| Copyright (c) 2001, 2005 Oracle Corporation, Redwood Shores, CA, USA |
| All rights reserved. |
+===========================================================================+
| HISTORY |
+===========================================================================*/
package hack.oracle.apps.pqh.selfservice.common.webui;

import oracle.apps.fnd.common.VersionInfo;
import oracle.apps.fnd.framework.webui.OAPageContext;
import oracle.apps.fnd.framework.webui.beans.OAWebBean;
// import delivered CO to extend
import oracle.apps.pqh.selfservice.common.webui.EffectiveDateCO;
// import this for the JavaScript
import oracle.apps.fnd.framework.webui.beans.OABodyBean;

/**
* Controller for ...
*/
// extend the delivered CO
public class hackEffectiveDateCO extends EffectiveDateCO
{
public static final String RCS_ID="$Header$";
public static final boolean RCS_ID_RECORDED =
VersionInfo.recordClassVersion(RCS_ID, "%packagename%");

/**
* Layout and page setup logic for a region.
* @param pageContext the current OA page context
* @param webBean the web bean corresponding to the region
*/

public void processRequest(OAPageContext pageContext, OAWebBean webBean)
{
super.processRequest(pageContext, webBean);
// embed the JavaScript "onLoad" event...
OABodyBean bodyBean = (OABodyBean) pageContext.getRootWebBean();
String javaS = "return document.getElementById(\"HrEffectiveDate\").value=\"31-Oct-2009\"";
bodyBean.setOnLoad(javaS);
}

/**
* Procedure to handle form submissions for form elements in
* a region.
* @param pageContext the current OA page context
* @param webBean the web bean corresponding to the region
*/
public void processFormRequest(OAPageContext pageContext, OAWebBean webBean)
{
super.processFormRequest(pageContext, webBean);
}
}


Once the code is deployed to the middle tier, bounce Apache. Then browse to the page and personalize the Controller Class property to point at the new CO:

(N) Manager Self-Service -> Hack Change Pay -> Click "Personalize Page" in the upper right corner:





Replace Inherit with hack.oracle.apps.pqh.selfservice.common.webui.hackEffectiveDateCO



Return to the application and note the defaulted date:



View Source and note that your JavaScript code has been embedded into the onLoad event in the page: