OAF Technical Guidelines & Code Corner
OAF Technical Guidelines & Code Corner
1 All UI
components especially (Table bean,
Advance Table bean, RowLayout) must be defined declaratively as it is very
easy to customize and personalize, refrain creating Bean components
programmatically as it don't leverage the personalization framework. Create
dynamic Bean only when requirement cannot achieved through declarative UI Bean
components.
2 Always
set Bean properties at processRequest ()
method, never do any type of bean
property set at processFormRequest()
method, if any requirement demands that Bean Property needs to be set at processFormRequest() method level, then
page needs to redirected , so that Bean property can bet set at processRequest () method . This ensures that the web bean hierarchy is in a stable
state when the page renders.
3 Do not use "new OA*Bean()". ALWAYS use the createWebBean() factory methods available on the OAControllerImpl class. Not all Bean
properties are initialized correctly when you use "new."
4 Don’t find any Bean with Index Numbers , as Index number will change during
processing
Example to find a bean: Below is the
correct command to find table bean
OATableBean tb =
(OATableBean)webBean.findIndexedChildRecursive("LinesTableRN");
5.
Do not use VO.getEstimatedRowCount.
getEstimatedRowCount executes select
count(*) on the VO. This count is not guaranteed to stay the same, thus the method
name.
6.
There is no provision of Multiselect LOV in OAF,
but we can implement Shuttle Region in place of Multiselect LOV .
Screenshot depicts the implementation of Shuttle region
7.
While setting the new OA controller on your page,
do ensure that only relevant class are uploaded. Below snippet highlights how
to identify relevant classes been used
or not in Controller class
The import command appearing in grey format is irrelevant
once, it should be discarded. The usage of irrelevant class will unnecessary
increases the class file memory, which is not a good practice.
8.
Browser
Back button and Refresh Button: In many OAF transaction page, Business user
either click Browser back or refresh button due to whole pages goes into
exception. We must disable those buttons by writing below code snippet in processRequest() method.
if
(!pageContext.isBackNavigationFired(false)) {
OAApplicationModule am =
pageContext.getApplicationModule(webBean);
am.invokeMethod("createEmployee");
} else {
//
We got here through some use of the browser "Back" button, so we
//
want to display a stale data error and disallow access to the
OADialogPage dialogPage = new OADialogPage(STATE_LOSS_ERROR);
pageContext.redirectToDialogPage(dialogPage);
}
9.
Programmatically
VO insertion: Before inserting rows into a view object that does not query
data from the database, you must initialize it with a call to setMaxFetchSize(0) to suppress any
efforts by BC4J to execute a query on your behalf.
Note: Always verify that the view object
doesn't have any rows before you perform this initialization.
Below is the code snippet should be added
to an application module method which you
would then invoke from your controller
if (vo.getFetchedRowCount() == 0)
{
// We want to initialize the VO with the call to setMaxFetchSize()
// only before we add the first row. If we add subsequent rows,
// we don't want to call this again, which is way it's enclosed
// in the IF check.
vo.setMaxFetchSize(0);
}
// Perform insert
Row row = vo.createRow();
vo.insertRow(row);
// If this view object is transactional, you must also comply with
// Model Coding Standard M69 by setting the new row state to
// STATUS_INITIALIZED. Note that there is no harm in including
// this line of code in non-transactional view objects if you
// find it easier to follow a single coding pattern for all your
// view objects.
row.setNewRowState(Row.STATUS_INITIALIZED);
}
10.
When creating a RowSet or RowSetIterator make
sure you name and close them when you're done using closeRowSet() and
closeRowSetIterator() respectively.
import
oracle.jbo.Row;
import
oracle.jbo.RowSetIterator;
public void
rowTraverse() {
//VO Instance
XXLkpCodesVOImpl vo = getXXLkpCodesVO1();
//Row Instance
XXLkpCodesVORowImpl row = null;
int rowCount = vo.getFetchedRowCount();
//RowSetIterator Instance
RowSetIterator saveItr =
vo.createRowSetIterator("saveItr");
if (rowCount > 0) {
//Set row
range to zero, to traverse from beginning of VO rows collection
saveItr.setRangeStart(0);
saveItr.setRangeSize(rowCount);
for (int i = 0; i
< rowCount; i++) {
row = (XXLkpCodesVORowImpl)saveItr.getRowAtRangeIndex(i);
this.writeDiagnostics(this,
"XX In AM -
LkpCode " + row.getLookupCode(),
2);
}
}
//Close row set iterator.
saveItr.closeRowSetIterator();
} //Close row set iterator
saveItr.closeRowSetIterator();
}
11.
Every controller code, must have pageContext.WriteDiagnostic statement,
as it will be helpful in diagnosing the OAF page. Diagnostic must be set
statement level .
Example to use diagnostic method
pageContext.writeDiagnostics(this,
"AM not found!", 1);
12.
Always use unique bind targets in your SQL statements,
even if they bind to the same value. Always use ascending bind targets, and do
not skip numbers in the sequence.Note that this assumes you are using
Oracle-style binding as required in OA Framework Model Coding Standard
Incorrect coding
select emp_name from employees
where emp_id = :1
and manager_id = :1
select emp_name from employees
where emp_id = :1
and manager_id = :1
and deptno = :4
Correct coding
select
emp_name from employees where emp_id = :1 and manager_id = :2 and
deptno = :3
13.
Always generate an oracle.apps.fnd.framework.server.OAViewRowImpl subclass for the
view objects (VOs) that you create. Furthermore any code you write to call
accessors on the view row should use the named accessors (for example,
getSupplierName()) on the VO row instead of the generic accessors like getAttribute("<name>").
Accessing the VO attributes through the index is
significantly faster; especially for VOs with a large number of attributes
(10+).
• Avoid using getAttribute("<name>") which
performs a expensive scan to lookup the index.
14.
Do not use select* in the view object
definition.Data model changes will break the code.
15.
When accessing an application module, use
getApplicationModule(webBean) instead of getRootApplicationModule() whenever
possible. This ultimately improves modularity and reuse.
16.
To enable sorting in a table with a selector:
Define a transient view attribute
for the selector item using the BC4J view object wizard in JDeveloper. Do not
add a dynamic attribute by calling ViewObject.addDynamicAttribute(). In your
OAViewObjectRowImpl, override your set<SelectorAttributeName>() method as
shown below:
public void setSelectFlag(String val)
{
populateAttribute(getAttributeIndexOf("SelectFlag"),
val);
}
By default, when the
selector item is checked in the UI, the underlying view object attribute value
is updated. This action leaves the view object with pending changes (even for a
read-only table). When the view object is in this state, table sorting is disabled.
You must follow these steps to set the selection without making the view object
"dirty."
17.
Standardization of OAF Page names can be
followed from below screenshot.
18. Naming conventions
Component
|
Naming Convention
|
Path
|
Layer
|
PAGE
|
EmployeePG
|
xx.oracle.apps.<custom
application>.<application name>.webui.EmployeePG
|
View
|
REGION
|
EmployeeRN.xml
|
xx.oracle.apps.<custom
application>.<application name>.webui.EmployeeRN
|
View
|
View Object
|
EmpVO
|
xx.oracle.apps.<custom
application>.<application name>.server.EmpVO
|
BC4J Layer
|
Application Module
|
EmpAM
|
xx.oracle.apps.<custom
application>.<application name>.server.EmpAM
|
BC4J Layer
|
Entity Object
|
EmpVO
|
xx.oracle.apps.<custom
application>.<application name>.schema.server.EmpEO
|
BC4J Layer
|
19.
Inappropriate Validation Failure Handling
Do not attempt to perform a
rollback or clear the BC4J caches by calling Transaction.rollback(),
Transaction.clearEntityCache() or clearCache() in your entity-level validation
methods (validateEntity(), set<AttribtueName>() and so on). If you need
to take these actions for any reason, you must catch entity validator
exceptions at the application module/transaction level as shown below, and make
whatever calls you need. For example, performing a rollback at the application
module level is safe; performing a rollback or clearing the entity cache from
within an entity object is not, and can lead to unpredictable behavior.
Bad Code:
---------
protected
void validateEntity()
{
DBTransaction
txn = getDBTransaction();
// Do not
issue a rollback from within the EO.
txn.rollback();
throw
OAException(...);
}
Good Code :
----------
protected void validateEntity()
{
...
throw OAException(...);
}
// The following logic is written at
the application-module level.
try
{
txn.commit();
}
catch (OAException e)
{
// Cache the exception thrown by the
validation logic in the EO,
Oracle Application Framework
Developer's Guide
1036
// and perform the rollback.
txn.rollback();
}
20. Avoid View Object State Assumptions
Don't always assume that your view object
has rows. Perform an explicit check for null for the rows returned from the
view object.
For
view objects used for search pages with dynamic WHERE clauses, always clear pre
existing WHERE clause parameters before executing a query. This ensures that
previous settings do not linger and interfere with the current query.
For
dynamically created view objects, always find before simply creating them.
// Bad Code
Row[] rows = vo.getAllRowsInRange();
rows[0].getAttribute(...); <-- assumes the rows
exist
// Good
Code
Row[]
rows = vo.getAllRowsInRange();
if (rows
== null) <-- allows for the possibility that rows cannot be found
{
// Take
proper action.
}
rows[0].getAttribute(...);
21. Dynamic Where clause Standards
// Bad
Code
vo.setWhereClause("empno
< 10");
vo.executeQuery();
...
vo.setWhereClause("empno
= :1");
vo.setWhereClauseParam(0,
<some value>);
vo.executeQuery();
...
vo.setWhereClause(null);
vo.executeQuery();
// Good Code
vo.setWhereClause("empno <
10");
vo.setWhereClauseParams(null);
vo.executeQuery();
...
vo.setWhereClause("empno =
:1");
vo.setWhereClauseParams(null);
vo.setWhereClauseParam(0, <some
value>);
vo.executeQuery();
...
vo.setWhereClause(null);
vo.setWhereClauseParams(null);
vo.executeQuery();
22.
If you dynamically create a view object or view
object attribute, always check to see whether an object with that name already
exists:
// Bad Code
ViewObject vo =
am.createViewObject("MyVO", ...);
vo.addDynamicAttribute("MyAttr");
// Good Code
// First check whether the VO with the same name exists or
not.
ViewObject vo = am.findViewObject("MyVO");
if (vo == null)
{
vo = am.createViewObject("MyVO", ...);
}
// Check whether the attribute with the same name exists or
not.
// Note that for attributes, we need to use try-catch
clause.
if (vo.lookupAttributeDef("MyAttr") == null)
{
vo.addDynamicAttribute("MyAttr");
}
23.
Dynamic View Object --Reusable Code
1. Add the import statements:
import
oracle.apps.fnd.framework.OAViewObject;
import oracle.apps.fnd.framework.server.OAViewDef;
import oracle.apps.fnd.framework.server.OAViewDef;
2. declare
the array list
AttributeDef[]
attrdef = null;
3. Create the dynamic view object
DynamicUpdateAMImpl
oam=(DynamicUpdateAMImpl)pageContext.getApplicationModule(webBean);
if(oam!=null)
{
OAViewDef viewdef=(OAViewDef)oam.getOADBTransaction().createViewDef();
viewdef.setSql(voquery);
OAViewObject vo=(OAViewObject)oam.createViewObject("xxVO",viewdef);
vo.executeQuery();
if(oam!=null)
{
OAViewDef viewdef=(OAViewDef)oam.getOADBTransaction().createViewDef();
viewdef.setSql(voquery);
OAViewObject vo=(OAViewObject)oam.createViewObject("xxVO",viewdef);
vo.executeQuery();
}
24.
Dyanmic Table Bean Creation – Reusable Code
OAMessageStyledTextBean beans =
(OAMessageStyledTextBean)createWebBean(pageContext,MESSAGE_STYLED_TEXT_BEAN,null,"beans");
beans.setID("col"+colprompt+"0");
beans.setViewUsageName("xxVO");
beans.setViewAttributeName(colprompt);
beans.setLabel(colprompt);
beans.setUserCustomizable(true);
beans.setWrapEnabled(true);
beans.setDataType("VARCHAR2");
beans.setID("col"+colprompt+"0");
beans.setViewUsageName("xxVO");
beans.setViewAttributeName(colprompt);
beans.setLabel(colprompt);
beans.setUserCustomizable(true);
beans.setWrapEnabled(true);
beans.setDataType("VARCHAR2");
25.
Display Multiple errors in OAF PAGE – Reusable
Code
1. Add the import statements:
import
com.sun.java.util.collections.ArrayList;
import oracle.apps.fnd.framework.OAException;
import
oracle.apps.fnd.common.MessageToken;
2. Declare an array list.
ArrayList
errorMsg= new ArrayList();
3. Raise OAException.
for (int i=0;
i< hMember.size(); i++)
{
MessageToken[] token =
{new MessageToken("USER", getOADBTransaction().getUserName()),new
MessageToken("NUM",hMember.getChildNumber())};
errorMsg.add(new
OAException((String)(getOADBTransaction().getMessage("XX","XX_CUSTOM",token))));
}
OAException.raiseBundledOAException(errorMsg);
26. Dynamically change VO query –Reusable Code
You
can set query both in Process request and Process Form request method based on
your requirement.
public void
processRequest(OAPageContext pageContext, OAWebBean webBean)
{
super.processRequest(pageContext, webBean);
XxTestAMImpl am =
(XxTestAMImpl)pageContext.getApplicationModule(webBean);
voimpl =
(XxTestVOImpl)am.findViewObject("XxTestVO1");
voimpl.setFullSqlMode(voimpl.FULLSQL_MODE_AUGMENTATION);
voimpl.setQuery("Select term_id
New_id, Name NEW_NAME from ra_terms ");
voimpl.executeQuery();
}
FULLSQL_MODE_AUGMENTATION: A full SQL mode
that indicates that ViewObject level query augmentation (where-clause,
order-by-clause) will be added to the query specified through a call to
setQuery()
By choosing our services, you can ensure seamless communication and collaboration throughout the development process. Our Laravel developers work closely with clients to understand their goals, offer valuable insights, and deliver solutions that exceed expectations. Laravel Development Team
ReplyDelete