OA Framework Extension of Application Module
Extending AM is similar to extending a View Object or an Entity Object. But some of the steps are slightly different. Hence I would like to dedicate an article on Extending AM.
What is an Application Module in OA Framework?
Think of AM as a broker between your Client Activity and database activity.
Is extension of AM recommended by Oracle?
Not really, simple because doing so isn't upgrade safe.
But sometimes you are left with no choice, and also it is better to extend that customize.
Which example will I undertake to extend an Application Module?
In this instance, lets take an example of an iRecruitment Functionality.
iRecruitment [IRC] is a web facing application from Oracle. Let's say, that we wish to capture a record in some custom table when a invalid Logon attempt occurs on iRecruitment Login page. The validation for User Logon occurs in a class named VisitorAMImpl.class
This class can be found in $JAVA_TOP/oracle/apps/per/irc/candidateSelfService/server
If you decompile this class using jad, you will notice the below code
public String validateLogin(String s, String s1)
{
String s2 = null;
OracleCallableStatement oraclecallablestatement = null;
try
{
String s3 = "begin :1 := fnd_web_sec.validate_login( p_user => :2 ,p_pwd => :3 ); commit; end; ";
OADBTransactionImpl oadbtransactionimpl = (OADBTransactionImpl)getDBTransaction();
oraclecallablestatement = (OracleCallableStatement)oadbtransactionimpl.createCallableStatement(s3, 1);
We need to add extra logic, such that, if fnd_web_sec.validate_login returns N, then we either insert record into another table or raise a business event.
Note:- The new logic can be appended to the method of the parent class [as it is, without modifying original code, by using super.method() convention].
So we need to extend and substitute VisitorAMImpl.class?
Well, we can't substitute AM Implementation class, so we will need to substitute VisitorAM itself.
In the extend AM, do we need to write code for each and every method of AM Implementation class being extended?
Not really. You need to write the code for just that method for which you wish to incorporate new/additional logic.
What are the steps in brief, for doing so?
Step 1 [Optional].
Get a jad utility. This can be downloaded free. Just search on java decompiler jad. This will help you example the standard Oracle code.
Step 2. FTP all the files from $JAVA_TOP/oracle/apps/per/* to your PC and configure your PC for OA Framework development
Step 3. Create a new BC4J package in which the extension will reside.
Step 4. Note down the path and the properties of existing AM that we wish to extend
Step 5. Create a new AM, and specify the original AM being extended.
Step 6. Ensure that the properties of original AM are applicable for new AM too.
Step 7. Perform substitution. This will create a jpx file.
Step 8. Upload the jpx file into Database.
Step 9. Deploy the custom BC4J to $JAVA_TOP by FTP'ing all files.
In the Part-1 of Application Module extension, we saw the business case for extending an Application Module. Here in the Part-2, I will display Steps with screenshots.
Step 1. Download the jad utility
Go to www.google.com
Step 2. In my case, I have <jdevhome>/jdev/myprojects included in my CLASSPATH. Hence I ftp'ed the files to <jdevhome>/jdev/myprojects/oracle/apps/per directory tree.
Step 3. ->Create a new BC4J Package, by right clicking on Project.
->The AM that we wish to extend resides in oracle.apps.per.irc.candidateSelfService.server
Hence, our package name will be oracle.apps.xxper.irc.candidateSelfService.server
Ensure that XXPER is valid Application short name.
select 'x' from fnd_application_vl where application_short_name = 'XXPER'
->Click on Finish.
Step 4. We can see that, for VisitorAM, the RETENTION_LEVEL is MANAGE_STATE.
Hence we will ensure that our new AM will have the same property too.
Step 5.
--> Right click on the new BC4J, and create a new AM.
-->Name of the new AM will be xxircVisitorAM
In the Extends field, click browse and select the AM as shown below.
-> Keep on clicking next until you see Finish. Click on Finish.
--> You will notice that class xxircVisitorAMImpl has been created. Add the below method to that class.
public String validateLogin(String s, String s1)
{
String parentValidationResult = super.validateLogin(s,s1) ;
if (parentValidationResult.compareTo("Y")==0)
{
//raise your event here, or insert into some bespoke table
}
return parentValidationResult;
}
Step 6. Ensure that the properties and the same, and also ensure that your method being replaced is selected.
Double click on the newly created AM xxircVisitorAM and ensure that RETENTION_LEVEL is MANAGE_STATE.
Also, click on ClientMethods, and ensure that the method validateLogin has been selected.
Step 7. Perform Substitution. Right click on the project, and select "Edit Business Components Project"
Click on Substitution, and select xxIrcVisitorAM on left hand side, and VisitorAM on right hand side. Click on Add button.
Step 8. Your jpx file will look like below
<?xml version="1.0" encoding='windows-1252'?>
<!DOCTYPE JboProject SYSTEM "jbo_03_01.dtd">
<JboProject
Name="xxircVisitorAM.jpr"
SeparateXMLFiles="true"
PackageName="" >
<DesignTime>
<Attr Name="_version" Value="9.0.3.13.75" />
<Attr Name="_jprName" Value="xxircVisitorAM.jpr" />
<Attr Name="_ejbPackage" Value="false" />
</DesignTime>
<Substitutes>
<Substitute OldName ="oracle.apps.xxper.irc.candidateSelfService.server.xxircVisitorAM" NewName ="oracle.apps.per.irc.candidateSelfService.server.VisitorAM" />
</Substitutes>
</JboProject>
Name this file as xxVisitorAM.jpx
Now, load this jpx into Database using a shell similar to below.
APPS_PWD=apps
export APPS_PWD
MACHINE_NAME=0
PORT_NUMBER=0
export MACHINE_NAME
export PORT_NUMBER
getPortMachine()
{
MACHINE_NAME=`sqlplus -s apps/$APPS_PWD <<EOF
set pages 0
set lines 1023
select fnd_profile.value('CSF_EMAP_DS_HOST') || '.ad.ic.ac.uk' from dual ;
exit
EOF`
PORT_NUMBER=`sqlplus -s apps/$APPS_PWD <<EOF
set pages 0
set feed off
select fnd_profile.value('CSF_MAP_DB_PORT') from dual ;
exit
EOF`
}
getPortMachine
adjava \
oracle.jrad.tools.xml.importer.JPXImporter ./xxVisitorAM.jpx \
-username apps \
-password $APPS_PWD \
-dbconnection "(description=(address_list=(address=(community=tcp.world)(protocol=tcp)(host=$MACHINE_NAME)(port=$PORT_NUMBER)))(connect_data=(sid=$TWO_TASK)))"
Step 9. FTP all the files from directory tree xxper to $JAVA_TOP/oracle/apps/xxper/..
Bounce apache, and you will notice that your custom logic is now being invoked.
Comments
.
.
You are Spot on Ramya, root AM should not be substituted. Hence in this example, I did not use the Root AM.
Thanks for sharing your experience.
Regards,
Anil Passi
.
.
You are Spot on Ramya, root AM should not be substituted. Hence in this example, I did not use the Root AM.
Thanks for sharing your experience.
Regards,
Anil Passi
Inter esting question.
Inde ed a site level personalization is created. However the substituted AM will be extending your original AM itself. This substitution will occur at site level. Which means your custom AM[which is substituted] will replace all instances of original AM at runtime. Hence all the five pages will retain the same new AM
The bottomline is that this substitution does not impact ONE SINGLE PAGE.
This substitution impacts all the regions that use that AM
Thanks,
Anil
I need to Insert some records in a custom Table based on the Requisitions Selected for receipting ...when user Clicks Next/Express Receive on the Receiving screen in iProc .. should i just Create a new controller for this page.. or should i extend the AM .. as this process is a Worktrain consisting of three pages.
Harjit
Usually extension to controller is not recommended, as it has no automated migration path to Fusion Apps tech-stack.
Al so, from controller, it is not a good practice to call JDBC.
Having said that even Oracle calls JDBC from some of the FND Controller class files.
Action plan for you
AM Extension
Option 1 . See if the AM can be extended{I f this isn't a root AM}, if so, find out the name of the AM method that standard CO is invoking
Optio n 2 . Extend the Controller
An other option to consider is the perform these inserts from PO Requisition Approval Workflow itself.
Thank s,
Anil Passi
Tanks a lot for all you suggestions.
He re are a few more details about the changes i am trying to make:
1) Page that has to be changed is "IcxPorRcvSrchP G.xml" i.e. receiving page
2) We have to add a checkbox in the ResultsTableRN so that user can select the Requisitions that he wants zero items and close the PO. (against the Receipt tolerance which is 10%)
3) The PageLayoutRN on this page is having "oracle.apps.ic x.por.rcv.serve r.ReceiveItemsA M" as its Application module. Is this the Root AM ? should i try extending this ..
4) How should i call the databases Package from the AM class that i extend.
Cheers !!
HS
Extend the controller for that page and in the extended controller use pageContext.get RootAm to find out the root AM for that page.
Dislpay that AM in the debug message
This is the safest way to know if the AM in question can be extended.
Than ks,
Anil Passi
Thanks,.. will check it that way.... I am back with some more questions ;)
------------ --------------- --------------- --------------- --------------- -
Issue1: Can you please let me know how do i extend the VO that has been built in a Expert mode and the Query is also getting generated at run time i.e. is is not a statis query.
I need to add a column to such a VO ... how will i be able to do that? , will i have to put all the Query creation logic in my new VO and then make a complete query that will also be having my new Column.
------ --------------- --------------- --------------- --------------- -------
Issue2 : How can i create a check box in a already existing table region and take the Value of Selected/Not Selected from here .. and relate each selection to some other column of the Table (i.e. for each row selected (using my checkbox) i want to check the Value in OrderNumber Column for the same row)
What is a table Selection, how can i use it in this scenario.
Chee rs !!
Harjit
Chee rs!!
Harjit
Usually the query of the VO would be static however the whereclause will be dynamic. In this case you can simply extend the View Object and add a new transient column to this VO.
See this URL for example
www.google.com/search?q=site:apps2fusion.com+oa-framework-r12-extension-example
Issue2: How can i create a check box in a already existing table region and take the Value of Selected/Not Selected from here
Sounds like a multi-selection checkbox. However, you can create a simple checkbox using personalization . At the time of creating the new item of type checkbox[at site level], you must map this to the view object column that you have created by extending VO.
By doing so, when the page has been submitted, the values from the checkbox will be transferred to View Object. You can then loop through the rows in the view object[from CO or from AM], and check for those rows that have the newly created Attribute with a value of "Y". This will give you the records for which checkbox would have been checked by the user.
Thanks,
Anil Passi
I'm trying extend the Standard Application Module (DocumentAM) from Oracle Purchasing, but I can't extend the validateLogin method. How can I know, if this AM is the Root AM in the page from the Application. And How can I extend this AM with the original functionality? Can I ?.
thank you. :)
I have to create new view object and i have create the one extended application module. I have add the view object in the extended application module.
But however i am not able to get the view object from extended application module.
I have also import the JPX file.
Waiting for your response.
Best regards
Paras
Error: Cannot acess Class java.io.seriali zable; file java\io\seriali zable not found.
From where I can get the Class and where I can place the Class on physical location
My Code is below...
/*============ =============== =============== =============== =============== ===+
| Copyright (c) 2001, 2005 Oracle Corporation, Redwood Shores, CA, USA |
| All rights reserved. |
+============== =============== =============== =============== =============== =+
| HISTORY |
+============== =============== =============== =============== =============== =*/
package xxt.oracle.apps .ak.xxperson.we bui;
import oracle.apps.fnd .common.Version Info;
import oracle.apps.fnd .framework.webu i.OAControllerI mpl;
import oracle.apps.fnd .framework.webu i.OAPageContext ;
import oracle.apps.fnd .framework.webu i.beans.OAWebBe an;
/*import com.sun.java.ut il.collection.H ashMap;
*/
impo rt oracle.apps.fnd .framework.webu i.*;
import oracle.apps.fnd .framework.webu i.beans.*;
impo rt oracle.apps.fnd .framework.*;
i mport java.io.seriali zable;
/**
* Controller for ...
*/
public class xxPersonMainCO extends OAControllerImp l
{
public static final String RCS_ID="$Header $";
public static final boolean RCS_ID_RECORDED =
VersionInfo.rec ordClassVersion (RCS_ID, "pa;ckagenam e%");
/**
* 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.processRe quest(pageConte xt, 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 processFormRequ est(OAPageConte xt pageContext, OAWebBean webBean)
{
super.processFo rmRequest(pageC ontext, webBean);
String actionInMainPer sonScreen = pageContext.get Parameter(EVENT _PARAM);
String paramPersonId = pageContext.get Parameter("para mPersonId");
if (actionInMainPer sonScreen.equals("deletePerson"))
{
Serializable paramDelete[] = {actionInMainPer sonScreen,paramPersonId};
OAApplicationMo dule am = pageContext.get ApplicationModu le(webBean);
am.invokeMethod ("deletePersonM ethod",paramDel ete);
}
}
}
ssaedzcvcxbnhkb vfs
RSS feed for comments to this post