Monday, May 12, 2008

Controller class extension in Oracle Applications

A Controller .class (CO) file is the Java code that controls the user interface on a Self-Service/OA Framework page within Oracle Applications. Events such as button clicks and other user activities are handled via the CO.

To demonstrate how to perform a simple Controller .class extension, we will show a Create Vacancy transaction from iRecruitment. It just so happens most of the JDeveloper extensions requested are in the iRecruitment module. In this example, we are going to default the posting Date on step 4 to a date 365 days in the future.

The reasoning behind this extension is to prevent or delay the job posting from being pushed to the Job Sites. There is always at least one root CO per page but there can be any number of additional COs. If there is much disparate data on the page, it is likely there are multiple COs. Click "About this Page" to find out which CO needs to be extended:


Scroll down further on the "About this Page" and click the "+" sign next to the Business Component Reference Details. Scroll down until you find the Controllers:


The Controller oracle.apps.per.irc.vacancy.webui.VacNewPostingPageCO is located on the application tier at:

$JAVA_TOP/oracle/apps/per/irc/vacancy/webui/VacNewPostingPageCO.class

Unless you are curious about what is in the .class file, you don't need to view the file. An extension of this file is being performed, so any code will be in addition to what Oracle has written in this file. To complete a CO extension, a new Oracle Applications Workspace and project will be created in JDeveloper.

The following screen prints will step through this procedure:


Use the package name of the Controller class, adding a prefix of your custom application name. As always, I use 'hack' for my custom package:


Choose a .dbc file and user for the Runtime Connection. If you are uncertain of how to create a connection, see the steps outlined in the VO Extension how-to. Continue until you reach the last page of the wizard and click Finish. We will take a short detour here in order to import the VacNewPostingPG into JDeveloper. If you are adept at JDeveloper already, it is not necessary to import the .xml page's layout before creating the Controller .class. However, these steps will allow you to point-and-click and let JDeveloper write some Java code for you so you don't have to. Letting Oracle create the code will allow you to maximize your role as a hack as well. The page layout is stored in the database and can be retrieved by running the following code:


set feedback off
set serveroutput on format wrapped
set linesize 100
spool hack.lst
--
execute jdr_utils.printDocument('/oracle/apps/per/irc/vacancy/webui/VacNewPostingPG',100);
--
spool off


This will spool the VacNewPostingPG page to a flat file, which can be saved and imported into JDeveloper.



Save the page's .xml to C:\JDEVOAF\jdevhome\jdev\myprojects\oracle\apps\per\irc\vacancy\webui\VacNewPostingPG.xml where "JDEVOAF" is the directory where you installed JDeveloper:

Do a File -> Import to bring it into JDeveloper:




Browse to the directory where you saved it:


Right click the IRC_VACANCY_NEW_POSTING_PAGE and click Set New Controller...



There are two required methods in an OA Framework controller .class:
  1. ProcessRequest - This method is called when the page loads. Any events you want to occur when a user first visits the page should be put here.
  2. ProcessFormRequest - This method is called when the Form is submitted. If you want to override any data inputted by the user or add additional business rules you would add code here to change the behavior of the transaction prior to it being submitted.
It is best practice not to access the View Objects (VOs) directly in the Controller .class as shown below. This was done to demonstrate a basic CO extension. Heavier business logic should be placed in the Application Module (AM) versus the CO. Further row-level validation and code can be pushed down to the Java .class files associated with the View Objects. The super.processRequest call is what makes this an "extension". That is, our code extends the functionality of Oracle's delivered application by being done after it completes.

Your code should look as follows:


/*===========================================================================+
| Copyright (c) 2001, 2005 Oracle Corporation, Redwood Shores, CA, USA |
| All rights reserved. |
+===========================================================================+
| HISTORY |
+===========================================================================*/
package hack.oracle.apps.per.irc.vacancy.webui;
import oracle.apps.fnd.common.VersionInfo;
import oracle.apps.fnd.framework.webui.OAControllerImpl;
import oracle.apps.fnd.framework.webui.OAPageContext;
import oracle.apps.fnd.framework.webui.beans.OAWebBean;
import oracle.apps.fnd.framework.OAApplicationModule;
import oracle.apps.fnd.framework.server.OADBTransaction;
import oracle.apps.fnd.framework.OAViewObject;
import oracle.jbo.Row;
import oracle.jbo.domain.Date;
/**
* Controller for ...
*/
public class hackVacNewPostingPageCO extends OAControllerImpl
{
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 assignFutureDate(OAPageContext pageContext, OAWebBean webBean)
{
OAApplicationModule oaapplicationmodule = pageContext.getApplicationModule(webBean);
OADBTransaction dbtrans = oaapplicationmodule.getOADBTransaction();
Date currentDate = dbtrans.getCurrentDBDate();
Date currentDatePlus365 = new Date(currentDate.addJulianDays(365, 0));
OAViewObject vo = (OAViewObject)oaapplicationmodule.findViewObject("IrcEditRecruitmentActivitiesVO");
for(Row row = vo.first(); row != null; row = vo.next())
{
row.setAttribute("DateStart", currentDatePlus365);
}
}
public void processRequest(OAPageContext pageContext, OAWebBean webBean)
{
// this next line forces Oracle to fire the delivered code
super.processRequest(pageContext, webBean);
// default a date 365 days in the future to the external site
assignFutureDate(pageContext, webBean);
}

/**
* 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);
}

}


Make and rebuild your project:


The compiled files are now available in C:\JDEVOAF\jdevhome\jdev\myclasses\hack\oracle\apps\per\irc\vacancy\webui. Zip this and FTP it to $JAVA_TOP. Unzip the files to create $JAVA_TOP/hack/oracle/apps/per/irc/vacancy/webui and then bounce Apache. In order for Oracle to use the new Controller, the page must be personalized to point at the new CO. Browse to the Vacancy New Posting Page and click Personalize Page in the upper right-hand corner:


Add the string hack.oracle.apps.per.irc.vacancy.webui.hackVacNewPostingPageCO to the Responsibility level personalization:


Marvel at your new defaulted Job Posting Site fields:


To prevent the users from overriding the date, the assignFutureDate method can be copied to the ProcessFormRequest. This would cause the dates to default again when the form is submitted, thereby overriding whatever the user inputs.