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;

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();
}







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");





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()

Comments

  1. 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

Post a Comment

Popular posts from this blog

Sample HZ API's script to Create Contacts and Contact Points in Oracle

REST integration built-in OIC to read Large files with size more than 10MB