Friday, May 1, 2009

How to Extend a View Object in OA Framework R12

View Object extensions in R12 are possible but inherently buggy. I've performed several but was not able to post a "bug-free" entry until now. This thread will show how to get through all the wizards and successfully deploy a VO extension in R12. Some of the steps are redundant and designed to avoid errors that the JDev IDE might throw. Hence, the product is not free of bugs but it can be used to complete an extension. For information on how to perform VO extensions in prior releases of Oracle Applications, see this article:

How to Extend a View Object in OA Framework

The View Object selected for this exercise is from the Employee Directory functionality in Oracle Applications. Log in to an R12 instance and click the Employee Directory link in the upper-right hand corner.

Search for the Oracle Hack:



Once the detail appears, click the About this Page link in the lower left-hand corner. The page definition will appear...click Expand All and note the View Object (VO) name next to the detail attributes:


EmpDetailVO is the VO that supplies the data seen on the page. View the details of this VO by clicking the link and reviewing the available attributes:


Scrolling down through the available attributes you will see there are many available but none involve the Address DFF. Any of these attributes here can be added to the page using Personalizations. However, the delivered VO oracle.apps.per.selfservice.empdir.server.EmpDetailVO must be extended to show the address DFF.

To do this, the following steps must be performed:
  1. Import the delivered View Object into JDeveloper
  2. Importing dependent classes into JDeveloper
  3. Extending the View Object
  4. Deploying the Extended VO and associated Java files to the application server
  5. Add extended VO columns to the page using personalizations
Before we move on to JDeveloper, enable the DFF segment by following the next steps.

(N) System Administrator -> Application -> Flexfield -> Descriptive -> Segments
  • Search for Additional Address Details
  • Uncheck Freeze Flexfield Definition checkbox
  • With the Global Data Elements Context selected, click the Segments button
  • Configure as follows:


  • Click the Open button
  • Uncheck the Required checkbox
  • Click Save
  • Close the Segments Summary window
  • Check Freeze Flexfield Definition checkbox
  • Click Yes at the Warning
  • Click Save
  • Click OK button to Compile Flexfield Definition
  • Click OK button when it says Flexfield has been compiled

Verify the DFF has a value:


To find the version of JDeveloper that's right for you, see Note:416708.1 on Metalink titled "How to find the correct version of JDeveloper to use with eBusiness Suite 11i or Release 12". I've never verified which version of R12 is "correct". If the instance is R12, I download the latest JDev patch and proceed to wreck shop. Do the following to get JDeveloper running on your 'puter:
  1. Download patch
  2. Extract to an empty directory dedicated to JDeveloper. I use "JDEVOAFR12"
  3. Right-click My Computer -> Propoerties -> Advanced -> Environment Variables
  • If you already have one called JDEV_USER_HOME, update the value to C:\JDEVOAFR12\jdevhome\jdev
  • If you don't use the old version, create the Variable
You are now ready to launch JDeveloper by double-clicking the binary at C:\JDEVOAFR12\jdevbin\jdev\bin\jdevW.exe.

Before you can use JDeveloper to create a custom View Object that extends oracle.apps.per.selfservice.empdir.server.EmpDetailVO, you must copy the Java files from $JAVA_TOP on the middle tier to the C:\JDEVOAFR12\jdevhome\jdev\myprojects\ directory on your computer.

As in 11.5.10, these files are stored in the $JAVA_TOP directory on the application (middle) tier and must be downloaded. Since we are extending the View Object (VO) oracle.apps.per.selfservice.empdir.server.EmpDetailVO, we must import the oracle.apps.per.selfservice.empdir.server pacakge and all dependent packages. In order to do this efficiently, tar/zip at least the "per" top and some of the related modules. Zipping the entire $JAVA_TOP can take substantial time due to its size. Here are the steps to move individual modules from $JAVA_TOP to your client:
  1. telnet to middle tier
  2. cd $JAVA_TOP/oracle/apps
  3. tar -cvf per_top.tar per
  4. FTP the .tar file to C:\JDEVOAF\jdevhome\jdev\myprojects
  5. extract the .tar
Before you begin, delete the following tutorial files:

C:\JDEVOAFR12\jdevhome\jdev\myprojects\mycompany
C:\JDEVOAFR12\jdevhome\jdev\myprojects\ExtendLabSolutions.jpr
C:\JDEVOAFR12\jdevhome\jdev\myprojects\ExtendLabSolutions.jpx
C:\JDEVOAFR12\jdevhome\jdev\myprojects\LabSolutions.jpr
C:\JDEVOAFR12\jdevhome\jdev\myprojects\LabSolutions.jpx
C:\JDEVOAFR12\jdevhome\jdev\myprojects\SampleLibrary.jpr
C:\JDEVOAFR12\jdevhome\jdev\myprojects\SampleLibrary.jpx
C:\JDEVOAFR12\jdevhome\jdev\myprojects\toolbox.jws
C:\JDEVOAFR12\jdevhome\jdev\myprojects\Tutorial.jpx
C:\JDEVOAFR12\jdevhome\jdev\myprojects\Tutorial.jpr

Now open JDeveloper and create a new Workspace for Oracle Applications.

File -> New


General -> Projects -> Workspace Configured for Oracle Applications


Give your new Workspace an arbitrary name:


Proceed in the Wizard to create a new project. Since the VO we're extending is in the package "oracle.apps.per.selfservice.empdir.server", create yours with a custom prefix. Naturally, mine will be called "hack.oracle.apps.per.selfservice.empdir.server":


Next!


It's time to specify a DBC file. This file is found somewheres on the application tier ($FND_TOP/secure in previous versions). Rather than bothering to find it, go to the Oracle Applications homepage and append this to the URL:

/OA_HTML/jsp/fnd/aoljtest.jsp

Enter the appropriate database information and click Test button:


Click "Enter AOL/J Setup Test"

Click "Locate DBC file"


Copy and paste this DBC file into C:\JDEVOAFR12\jdevbin\oaext\dbc_files\secure where "C:\JDEVOAFR12" is the directory where you installed R12 JDeveloper client. Now you can browse for your DBC file in Step 3:

Click Finish to see your project:

You will notice under Application Sources that the various "tops" copied from the application server appear. In previous versions of JDeveloper, you had to manually import the server.xml file from each business components package for it to appear in your project. In R12, it automatically imports.

Right-click Application Sources and choose New:


The "New Gallery" window appears. I'm not sure what a gallery is, but proceed to Business Tier -> ADF Business Components -> View Object


If you haven't already done so, JDev will ask you to setup a DB COnnection. Click New button to start the wizardry. Enter an arbitrary name and click Next:



Enter the APPS username/password and click Next:


Enter the values for host/port from the TNS Names file and click Next:


Test Connection on the last step and then Finish:


The VO wizard will now continue...the default package will already be specified. Enter a custom prefix to the delivered VO. Click the Browse button on the Extends field to choose the delivered VO oracle.apps.per.selfservice.empdir.server.EmpDetailVO:


If there are no VOs from which to choose, cancel the wizard...


...and expand the Application Source until you find oracle.apps.per.selfservice.empdir.server.EmpDetailVO. Then retry the wizard:




Keep clicking next...



If you get this error, click OK and then Cancel:


Retry adding a VO, except on step 1, click the "Updatable Access through Entity Objects" radio button and then click next through each screen.



Create a new attribute:


Configure as follows:

Click OK...Next!


Add the function call to the SQL Statement as well.

This step is clutch as you will potentially receive the following error if you deploy your VO to Oracle Applications without modifying the SQL:

JBO-27022: Failed to load value at index 53 with java object of type java.lang.String due to java.sql.SQLException.

Keep going on the train (6 of 8) ...




Click Finish and you'll see JDev work vigorously to update the Java files. The VO has now been created:



The function call used must of course exist in order to call it inside your VO. A slight detour as we write some PLSQL, compiling in it the database as APPS:


create or replace package hack_jdev_utility_pkg as
--
function get_address_region (p_person_id in number
,p_effective_date in date) return varchar2;
--
end hack_jdev_utility_pkg;
/
show errors;



CREATE OR REPLACE package body hack_jdev_utility_pkg as
----------------------------------------------------------------------------------------
-- get_address_region
----------------------------------------------------------------------------------------
function get_address_region (p_person_id in number
,p_effective_date in date) return varchar2 is
--
lv_address_region varchar2(155) := null;
--
cursor c_address (cp_person_id number
,cp_effective_date date) is
select addr_attribute10
from per_addresses
where person_id = cp_person_id
and cp_effective_date between date_from and nvl(date_to,hr_general.end_of_time);
--
begin
--
open c_address (p_person_id, p_effective_date);
fetch c_address into lv_address_region;
if c_address%notfound then
lv_address_region := null;
end if;
close c_address;
--
hr_utility.set_location('lv_address_region: '||lv_address_region,50);
return lv_address_region;
--
exception
when others then
hr_utility.set_location('Error: ',998);
hr_utility.set_location(substr(sqlerrm,40),999);
return 'NA';
end get_address_region;
--
end hack_jdev_utility_pkg;
/
show errors;


Save your works at this point and do the following:
  1. Close JDeveloper (yes, I'm serious)
  2. Copy per_top.tar to C:\JDEVOAFR12\jdevhome\jdev\myclasses\oracle\apps
  3. Extract files
This will make all the delivered files you will be extending available during compilation. Basically the myprojects folder uses the .xml files in $JAVA_TOP/oracle/apps/per and the myclasses folder uses the .class files. Once the files are extracted, open JDev again, right-click your project and perform a "Make" and "Rebuild":


Just a couple of warnings:


What happens if you try to Rebuild without the $JAVA_TOP/oracle/apps/per files extracted into myclasses? Mad errors:


It's time to generate a substitution, which is a file that will tell Oracle to use your View Object instead of the delivered VO. Inside JDeveloper, right-click the Project -> Project Properties -> Business Components -> Substitutions:


Select the delivered VO on the left pane, the custom VO on the right pane and click Add:


Click OK, make/rebuild your project and save your works.

The remaining steps are:
  1. upload substitution to database
  2. deploy Java and .xml files to middle tier
  3. bounce Apache
  4. Personalize page to display new items
Execute this at the command line to import the substitution:

C:\JDEVOAFR12\jdevbin\oaext\bin\jpximport C:\JDEVOAFR12\jdevhome\jdev\myclasses\hack0.jpx -username apps -password hack -dbconnection "(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=localhost.hack)(PORT=1521))(CONNECT_DATA=(SID=HACK)))"


Take a peek at the .jpx file. The substitution command must exist in this file in order for the import to be successful and thus allow your VO to be used instead of the delivered one. Peek-a-boo:


Now that the substitution has been uploaded, deploy the java files by zipping the compiled project files in C:\JDEVOAFR12\jdevhome\jdev\myclasses\hack and FTP them to $JAVA_TOP. Unzip them:


Bounce the apache and OC4J process:
  1. $ADMIN_SCRIPTS_HOME/adapcctl.sh stop
  2. $ADMIN_SCRIPTS_HOME/adapcctl.sh start
  3. $ADMIN_SCRIPTS_HOME/adoacorectl.sh stop
  4. sleep 10
  5. $ADMIN_SCRIPTS_HOME/adoacorectl.sh start
Log back into Oracle Applications and browse to the Employee Directory, searching for an employee of your choice. Click "Personalize Page" in the upper right-hand corner:


Click the Complete View radio button -> Expand All and Create an Item in this section:


Configure as follows:


Yay-yeah...

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:

Friday, November 14, 2008

Default/setRequired DFF Segments in R12

Defaulting the value of a Descriptive Flexfield's Context or Segment values on an OA Framework page comes up frequently. It is possible to achieve this functionality using a Controller Class (CO) extension in JDeveloper R12. This example will focus on the code necessary to default the values using a CO extension. For a complete discussion of Controller Class concepts and examples, see the previous topics:

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

Lettuce first setup a Descriptive Flexfield with some segments before rendering it on the Self Service page. If you already know how to do this and are just anxious to see the few lines of code to reach the solution, scroll down in this post until you find it. For our example we will use the "Change Pay:

Pay Details" page in Manager Self Service and the "Add'l Salary Admin. Details" Descriptive Flexfield attached to it. Navigate as follows:

(N) System Administrator -> Application -> Flexfield -> Descriptive -> Segments

Search for "Add'l Salary Admin. Details" and do the following:

  1. Uncheck "Freeze Flexfield Definition"
  2. Highlight "Global Data Elements"
  3. Add a Context called 'Oracle Hack' for the Code and Name
  4. Click the Segments button



Uncheck the Required Checkbox:


Save the DFF, Freeze Flexfield Definition and exit.

The first step to defaulting a DFF value on a Self Service page is to enable it. Browse to Manager Self Service -> Change Pay:


Choose an employee and click Action:


Click Propose Pay Change. On the "Change Pay: Pay Details" page, the DFF is now rendered under the Additional Details section:



Choosing the "Oracle Hack" Context then displays the one segment defined for it:




The goal of this exercise is to default the context as well as the segment value when the page loads. In order to do this, a Controller Class extension will need to be created that finds the DFF field and defaults the appropriate values. A cursory review of the "About this Page" link will show which CO's are already defined and where they are stored on the middle tier.


An extension to the oracle.apps.per.selfservice.changepay.webui.ProposedPayCO Controller Class will be performed in order to accomplish the defaulting:


The remaining steps to perform the defaulting are as follows:

  1. Download the page definition of /oracle/apps/per/selfservice/changepay/webui/ProposeNewPayPG from the database using jdr_utils.printDocument
  2. Import the page into JDeveloper
  3. Set a new controller class for the page that extends the default CO oracle.apps.per.selfservice.changepay.webui.ProposedPayCO
  4. write custom code to find and default the DFF fields

As mentioned earlier, the detailed instructions for steps 1-3 are explained in previous posts. The code in step 4 is presented here:


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

import oracle.apps.fnd.common.VersionInfo;
import oracle.apps.fnd.framework.webui.OAPageContext;
import oracle.apps.fnd.framework.webui.beans.OADescriptiveFlexBean;
import oracle.apps.fnd.framework.webui.beans.OAWebBean;
import oracle.apps.fnd.framework.webui.beans.message.OAMessageTextInputBean;
// import the delivered CO
import oracle.apps.per.selfservice.changepay.webui.ProposedPayCO;

/**
* Controller for ...
*/
public class hackProposedPayCO extends ProposedPayCO
{
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);
// first, find the flexfield's handle
OADescriptiveFlexBean oaDFF = (OADescriptiveFlexBean)webBean.findIndexedChildRecursive("FlexField1");
// default the Attribute Category (DFF context)
oaDFF.setFlexContext(pageContext,"Oracle Hack");
oaDFF.processFlex(pageContext);
// now set the attribute/segment value
OAMessageTextInputBean txtHackBonus = (OAMessageTextInputBean)oaDFF.findIndexedChild("FlexField11");
txtHackBonus.setText("43500");
}
/**
* 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 you are done coding, do a "Make" and "Rebuild" of the file and transfer it to $JAVA_TOP on the middle tier. Browse to the "Change Pay: Pay Details" page in Manager Self Service and personalize it to point at your new Controller:




Set the value of the new Controller to: hack.oracle.apps.per.selfservice.changepay.webui.hackProposedPayCO

Return to the Application and marvel at your handiwork:


For extra credit and part II of this topic, you can set the DFF segment to Required in the CO as well. Here is the code; note that the "yes" text is case-sensitive:



In 11.5.10, this seemed to not be possible, at least not in my experience hacking at it. Note that setting a DFF segment to required in the Controller is different from setting up a DFF segment as required when it is configured. When a segment is set to required in the application, it is required on all responsibilities throughout the app. Using the custom code approach allows you to mark specific segments required only when necessary.

Thursday, October 16, 2008

R12 Controller Class extension

Today's topic will cover how to perform a Controller class extension in the buggy, unstable product known as JDeveloper 10g, for use with Oracle Applications Release 12. The delay in posts is due partially to the fact that the documentation for JDeveloper 10g is actually for the 9i product. That's right, Oracle shipped documentation for Jdeveloper 10g that includes screen prints and instructions for an older product with a different user interface. Hence, all information presented on this page is a result of random and sometimes brutal hacking.

The example used to show that a Controller class extension *is* actually possible in R12 will be defaulting a MessageLoVInputBean within the New Hire process in Self Service Human Resources. For more information about what a Controller class is view the topic "Controller class extension in Oracle Applications".

First, log in to Oracle Applications to see where this defaulting will take place:

(N) Manager Self-Service -> Hire



Proceed to step 3 and notice that Oracle provides the Setup Business Group for the default Department/Organization name:



Click "About this Page" link in lower left corner to begin the process of finding the field name to default. Click "Expand All":



Then search for the Department; notice that the Controller class is called OrganizationCO:



Click Business Component Reference Details to get the complete path where the OrganizationCO is stored on the application tier:




Lettuce begin extending this file so that the Department name field is set to null. Open JDeveloper R12 on your client machine. This tutorial assumes you have already downloaded the client from Oracle and unzipped it to a root directory like

C:\JDEVOAR12. Also, set the Windows environment variable JDEV_USER_HOME:

Right-click My Computer -> Properties -> Advanced (tab) -> Environment Variables (button) -> JDEV_USER_HOME -> edit

Set the value to C:\JDEVOAFR12\jdevhome\jdev if "C:\JDEVOAFR12\" is where you unzipped JDeveloper R12.

Inside of JDeveloper, create a new Workspace by doing the following:

(N) File -> New and then choosing General -> Projects -> Workspace Configured for Oracle Applications




Enter an arbitrary value in the File Name dialog box to identify the kind of workspace this will be. I'll be hacking, so naturally mine is called 'hack.jws':



For a default project package, change the delivered names to a custom name.

oracle.apps.per.selfservice.deployperson.webui.OrganizationCO will be extended so our default package for the extended files will be hack.oracle.apps.per.selfservice.deployperson.webui:



Choose a .dbc file for the connection. If one is not already configured, follow these steps:

1. Browse to http://instance_name.domain.com:port_number/OA_HTML/jsp/fnd/aoljtest.jsp
2. Complete the information and click Test
3. Click "Enter AOL/J Setup Test"
4. Click "Locate DBC file"
5. Copy/paste the resulting DBC file and save it as hack.dbc to C:\JDEVOAFR12\jdevbin\oaext\dbc_files\secure







In order to extend the delivered Controller class and have your project work correctly, you will need to import the delivered

Controller class into your project. Each file in Oracle apps has many dependencies; rather than import one at a time, I download the entire JAVA_TOP to my local machine. Connect to the middle tier and do the following:

1. cd $JAVA_TOP
2. tar -cvf java_top.tar oracle
3. FTP the .tar file to C:\JDEVOAFR12\jdevhome\jdev\myclasses
4. extract the .tar file

Note that the above procedure could take a long time to complete as the $JAVA_TOP can be over 1GB. Now that the files are in place, connect to the database and run the following script:



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


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



Place it in C:\JDEVOAFR12\jdevhome\jdev\myhtml\OA_HTML. Now import the file into JDeveloper by doing File -> Import:



Even though it is not a Java file, you must choose "Java Source" (makes perfect sense):



Browse for C:\JDEVOAFR12\jdevhome\jdev\myhtml\OA_HTML



Deselect all and then check AssignmentPG and click OK. You will see the Page populate in the "Application Sources". Click on the Page and you will see the Structure populate in the "Structure" pane:




Right Click the HROrganizationRegion which has the HrDepartment field that will be updated and click "Set New Controller..."



Enter a package name identical to the delivered package but with your custom project name in front of it. For example, mine is: hack.oracle.apps.per.selfservice.deployperson.webui. The Controller class filename will follow the same standard: hackOrganizationCO



Note that this is an extended controller class that is not specific to the OrganizationCO:



You must import the delivered CO and extend that one; additionally, import the OAMessageLoVInputBean class for the field that will be defaulted:



The following code will default the Department Name field to null if it is equal to the value "Setup Business Group". The processRequest method has the code that performs this default. This is the code that is executed when a user hits the page. processFormRequest is called when the user submits the page to move on to the next one. Notice that the defaulting code is to occur when the page is first rendered. Also, the "super.processRequest(pageContext, webBean);" line tells Oracle to execute the delivered code and then fires the code inside processRequest.



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

import oracle.apps.fnd.common.VersionInfo;
import oracle.apps.fnd.framework.webui.OAPageContext;
import oracle.apps.fnd.framework.webui.beans.OAWebBean;
import oracle.apps.fnd.framework.webui.beans.message.OAMessageLovInputBean;
import oracle.apps.per.selfservice.deployperson.webui.OrganizationCO;

/**
* Controller for ...
*/
public class hackOrganizationCO extends OrganizationCO
{
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);
pageContext.writeDiagnostics(this,"Here2",3);
/*
* find the HrDepartment bean programatically
*/
OAMessageLovInputBean oaMessage = (OAMessageLovInputBean)webBean.findIndexedChildRecursive("HrDepartment");
/*
* if the value is not null...
*/
if (oaMessage.getValue(pageContext) != null) {
// get the value currently in the text box
String strDepartment = oaMessage.getValue(pageContext).toString();
pageContext.writeDiagnostics(this, "strDepartment: " + strDepartment, 3);
// If it's equal to the Setup Business Group...
if (strDepartment.equals("Setup Business Group")){
pageContext.writeDiagnostics(this, "Here10", 3);
// set it equal to null
oaMessage.setValue(pageContext,null);
}
}
//
pageContext.writeDiagnostics(this, "Here20", 3);
}

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

}



Now that the code is written, right-click the CO file and do a "Make" and then a "Rebuild". This creates the compiled .class files that will be transferred to the middle tier for execution inside Oracle Applications.



Go to C:\JDEVOAFR12\jdevhome\jdev\myclasses and find the folder called 'hack'. Right-click and create a .zip file. Follow these instructions to deploy it to the application tier:

1. FTP hack.zip to $JAVA_TOP
2. unzip hack.zip



Now browse to the page where this Controller .class code needs to be executed.

(N) Manager Self-Service -> Hire -> Step 3 -> Personalize Page



Click on Complete View then Expand All (link):



Find the Department Default Single Column and click the Pencil:



Set the Controller Class field to hack.oracle.apps.per.selfservice.deployperson.webui.hackOrganizationCO. Click Apply and then

"Return to Application" link.




This is Oracle so don't expect your changes to show up just yet. In R12, in addition to bouncing Apache, you must also bounce the OC4J process. Technology has advanced to the point that changes to the application require two laborious steps. You need to perform the following commands on the middle tier first:

1. $ADMIN_SCRIPTS_HOME/adapcctl.sh stop
2. $ADMIN_SCRIPTS_HOME/adapcctl.sh start

3. $ADMIN_SCRIPTS_HOME/adoacorectl.sh stop
4. sleep 10
5. $ADMIN_SCRIPTS_HOME/adoacorectl.sh start

Once these steps are complete, close your Browser and log back in to the application. In order to show that our code is being executed we will enable Diagnostics and check that our pageContext.writeDiagnostic messages are being written to output.

In order to enable diagnostics, click Diagnostics in the upper right hand corner. If this link is not present, set the profile option FND: Diagnostics to "Yes":



Show log on screen; click "Go":



Choose Event as the messages written out to diagnostics in the Controller class used a code of "3" for event. Going further down to Statement level will write more and more output to screen:



Now you've got mad junk written on the screen.



Go to the Hire process, step 3 and confirm that the Department field is null and that the output messages are written to the diagnostics dump at the bottom of the page:




Your code will also show up on the "About this Page" link. Score! Rah rah!


Sunday, June 22, 2008

HGrid AutoExpand in Oracle Applications Framework

In a break from tradition, today's topic is from the Manager Self Service module of Oracle Applications. Today we will demonstrate how one can invoke the following features of an HGrid bean in OA Framework:

  1. Rendering the ability to Expand All | Collapse All
  2. Auto-expanding the entire HGrid

An HGrid is what Oracle calls a tree structure with more complex features than a standard hierarchy tree. What we're concerned with is the client who asks, "Why can't I display the whole tree? It takes forever to expand every node!" There might be some HGrids that offer the ability to Expand/Collapse out of the box, but in Manager Self-Service, this must be enabled programmatically through an extension of the Controller class. First, browse to the page in question to see the standard functionality:

(N) Manager Self-Service -> My Employee Information



At a glance, we can see the first level of subordinates to the manager. In order to see the complete tree, one must click the plus signs. Suppose many levels are beneath these top level managers; clicking through each one could take forever. HGrids have the capability to Expand / Collapse and to auto-expand the tree, but this functionality is not currently available via personalizations. In order to change this part of the user interface, we must extend the delivered Controller class (CO) with our own custom code.

In order to understand how the page works and to identify which code needs to be extended, click the "About this Page" link in the lower left corner. There are many View Objects on this page; the Employment tab will be used in this example:



The OverviewDisplayCO Controller class file handles the user interface for this part of the page. In order to see what the default behavior is in this Controller, it must be retrieved from the server and decompiled. It's location is listed under the Business Component Reference Details heading on the About Page:



Expand the Business Component Reference Details and scroll down to the Controllers:



oracle.apps.per.selfservice.mgrviews.webui.OverviewDisplayCO is located on the middle tier at $JAVA_TOP/oracle/apps/per/selfservice/mgrviews/webui/OverviewDisplayCO.class. FTP to retrieve the file and decompile it. Find the ProcessRequest method:





// This line causes the HGrid to only display one level of subordinates:
hGridBean.setAutoExpansionMaxLevels(1);

// This line turns off the Expand All | Collapse All links:
hGridBean.setExpandAllEnabled(false);



In order to change this behavior, 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

These steps are detailed on the previous entry "Controller class extension in Oracle Applications" For brevity's sake, the extended CO code is shown below. This will be placed under the custom application hack.oracle.apps.per.selfservice.mgrviews.webui.on the middle tier. The custom CO will be called hackOverviewDisplayCO, naturally.



package hack.oracle.apps.per.selfservice.mgrviews.webui;

import oracle.apps.fnd.common.VersionInfo;
import oracle.apps.fnd.framework.webui.OAPageContext;
import oracle.apps.fnd.framework.webui.beans.OAWebBean;
import oracle.apps.per.selfservice.mgrviews.webui.OverviewDisplayCO;
import oracle.apps.fnd.framework.webui.beans.table.OAHGridBean;

/**
* Controller for ...
*/
public class hackOverviewDisplayCO extends OverviewDisplayCO
{
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);
OAHGridBean oaHgrid = (OAHGridBean)webBean.findIndexedChildRecursive("SupHierarchy");
//
if (oaHgrid != null)
{
oaHgrid.setExpandAllEnabled(true);
oaHgrid.setAutoExpansionMaxLevels(99); // int.MAX_VALUE
}
}

/**
* 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 -> My Employee Information -> Click "Personalize Page" in the upper right corner







Replace Inherit with hack.oracle.apps.per.selfservice.mgrviews.webui.hackOverviewDisplayCO:



If the changes are not yet visible, try clicking Home and then browsing to Manager Self-Service -> My Employee Information again:

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.

Thursday, March 27, 2008

How to Extend a View Object in OA Framework

View Objects are the queries that provide the data seen on a Self Service web page. Oracle offers many attributes in each View Object, but often an additional attribute is needed. Oracle allows developers to extend the delivered View Objects to meet this need. The following iRecruitment Vacancy Search Page will be used for demonstration, but any page developed using the OAF architecture is a candidate for this exercise.



In our example, the Posting's Job Title and Organization Name that were entered during step 4 of the Vacancy Create process are not offered in the delivered VO. These values are shown during data entry in the below screen print. We will write PL/SQL functions to retrieve them; our extended VO will then call these functions to return the values so they can be rendered on the page:



In order to find which VO to extend, the page definition must be analyzed. There is a distinct VO behind the fields shown in the results table. Only a portion of the available fields are shown by default. Click the "About this Page" link in the lower left corner to see the page definition.


Click Expand All and find the Results Table:


Click the IrcVacancyVO link to see the View Object Details:


Any attribute listed on this page can be added "declaratively", or without programming required by personalizing the results table. You're are not limited to what Oracle provides in the delivered View Objects, however, as you will soon come to know.

For our example, we will be extending the oracle.apps.per.irc.vacancy.server.IrcVacancyVO View Object. Extending a View Object involves the following steps:

1. Importing the delivered View Object into JDeveloper
2. Importing dependent classes into JDeveloper
3. Extending the View Object
4. Deploying the Extended VO to the application server
5. Add extended VO columns to the page using personalizations

To find the version of JDeveloper that's right for you, see Note:416708.1 on Metalink titled "How to find the correct version of JDeveloper to use with eBusiness Suite 11i or Release 12".

Open JDeveloper and Create a new OA Workspace and project following these steps. Naturally, my workspace and project is called 'hack':


It is best practice to place extended objects in a custom package. If you are extending an object in the delivered package oracle.apps.per.irc.vacancy.server, the custom package would be hack.oracle.apps.per.irc.vacancy.server


Continue to step 3 and specify a DBC file. This file is found on the application tier at $FND_TOP/secure. It must be copied to C:\JDEVOAF\jdevbin\jdev\multi\system\oa\dbc_files\secure on your local machine, where "JDEVOAF" is the directory where you installed JDeveloper. Enter an Oracle Applications user and valid short name and responsibility key before finishing:


When you have finished marveling over your newly created project, right click it and choose "New Business Components":




If you don't have a connection to use already defined, follow these steps below to create a new one. The connection name is arbitrary:


Enter a Valid Oracle Applications user name/password:


Enter the appropriate box information:


Test and Finish:


Click Finish and return to the Navigator. The custom package where the extended VO will be created is complete, but we must import the delivered VO before continuing. These files are stored in the $JAVA_TOP directory on the application (middle) tier and must be downloaded. Since we are extending the View Object (VO) oracle.apps.per.irc.vacancy.server.IrcVacancyVO, we must import the oracle.apps.per.irc.vacancy.server pacakge and all dependent packages. In order to do this efficiently, I perform the following steps:

1. telnet to middle tier
2. cd $JAVA_TOP/oracle/apps
3. tar -cvf ota_top.tar ota
4. tar -cvf per_top.tar per
5. tar -cvf pay_top.tar pay
6. tar -cvf ben_top.tar ben ... repeat for as many modules as you might need
7. FTP each .tar to C:\JDEVOAF\jdevhome\jdev\myclasses
8. extract each .tar in the C:\JDEVOAF\jdevhome\jdev\myclasses directory

Once this task is complete, right click your project and "Import Business Components..."


and answer "Yes" when presented with the dialog "The following XML file is on the classpath.
Would you like to add these objects to your project?"


Upon importing the first package, you may see an information message telling you that additional packages are needed. In this example, import the oracle.apps.per.schema.server (server.xml) package next. Repeat this process until no additional messages appear.

If you see an Information message like the following, it means that the server.xml has defined a file not contained in the classpath directory. It can be ignored; if it really bothers you, open an SR and request that Oracle fix the server.xml file.


Be sure to close JDeveloper and re-open after importing all packages. You may see an additional warning to import more. Your project will look like the following:


We must now create a new View Object in our custom package that extends the delivered VO. A common practice is to use a PL/SQL function for the new column so that any custom logic can be maintained easily. Rather than re-implementing the VO extension, the PL/SQL can be updated anytime the business rules change.

Before proceeding in JDeveloper, lettuce first create the PL/SQL function:

Package spec:

create or replace package hack_jdev_pkg as
--
function get_vac_posting_org (p_vacancy_id in number) return varchar2;
--
function get_vac_posting_job (p_vacancy_id in number) return varchar2;
--
end hack_jdev_pkg;
/
show errors;


Package body:

create or replace package body hack_jdev_pkg as
--
cursor c_vacancy_posting_data (cp_posting_id number) is
select org_name
,job_title
from irc_posting_contents_vl ipcv
,per_vacancies pv
where pv.primary_posting_id = cp_posting_id
and pv.primary_posting_id = ipcv.posting_content_id;
--
cursor c_posting_id (cp_vacancy_id number) is
select primary_posting_id
from per_all_vacancies
where vacancy_id = cp_vacancy_id;
--
function get_vac_posting_org (p_vacancy_id in number) return varchar2 is
--
ln_posting_id number;
rec_vac_posting_data c_vacancy_posting_data%rowtype;
--
begin
--
open c_posting_id (p_vacancy_id);
fetch c_posting_id into ln_posting_id;
close c_posting_id;
--
open c_vacancy_posting_data (ln_posting_id);
fetch c_vacancy_posting_data into rec_vac_posting_data;
if c_vacancy_posting_data%notfound then
rec_vac_posting_data := null;
end if;
close c_vacancy_posting_data;
--
return rec_vac_posting_data.org_name;
--
end get_vac_posting_org;
--
function get_vac_posting_job (p_vacancy_id in number) return varchar2 is
--
ln_posting_id number;
rec_vac_posting_data c_vacancy_posting_data%rowtype;
--
begin
--
open c_posting_id (p_vacancy_id);
fetch c_posting_id into ln_posting_id;
close c_posting_id;
--
open c_vacancy_posting_data (ln_posting_id);
fetch c_vacancy_posting_data into rec_vac_posting_data;
if c_vacancy_posting_data%notfound then
rec_vac_posting_data := null;
end if;
close c_vacancy_posting_data;
--
return rec_vac_posting_data.job_title;
--
end get_vac_posting_job;
--
end hack_jdev_pkg;
/
show errors;



Right click the project and create a new View Object:


Name your new VO; the best practice is to give it a prefix before the delivered name. Be sure to enter oracle.apps.per.irc.vacancy.server.IrcVacancyVO in the "Extends" field.


Continue to step 3 and click New and configure as shown in the following two screen prints. This is the actual extension to the VO where the values from Step 4 of the Vacancy Create process are added to the VO:


Repeat for the Posting Organization:


Continue to step 6 and configure as shown below and Finish. Check the "Generate Java File" if you need to extend the methods delivered with the VO:

Double click the .jpx file in your project to add a substitution, which tells Oracle to use your View Object instead of the delivered VO. Highlight the delivered VO and the extended VO and click "Add".

Make and Rebuild your project:


The remaining steps are:

1. upload substitution to database
2. deploy Java and .xml files to middle tier
3. bounce Apache
4. Personalize page to display new items

To upload the substitution, open a command prompt on the local machine and run the following command:


C:\JDEVOAF\jdevbin\jdev\bin\jpximport C:\JDEVOAF\jdevhome\jdev\myclasses\hack.jpx -username apps -password apps -dbconnection "(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=oracle.hack.com)(PORT=1521))(CONNECT_DATA=(SID=hack)))"






To deploy the files, zip the compiled project files in C:\\jdevhome\jdev\myclasses\hack and FTP them to $JAVA_TOP. Unzip them:


Bounce Apache and then return to iRecruitment Recruiter -> Search for Vacancies -> About this Page. The delivered VO has been replaced by your extended VO:


Create the necessary personalization fields on the Advanced Table Region of the page to render the new column, beginning with the Job Posting:



Yay-yeah...you are now an Oracle Hack:

Now challenge yourself by repeating the personalizations for the Posting Organization without the assistance of screen prints. Duplicate this effort on another Self Service page to practice your newly minted VO substitution hacking capabilities.