Showing posts with label OA Framework. Show all posts
Showing posts with label OA Framework. Show all posts

Friday, April 3, 2009

Row.STATUS_INITIALIZED

We were experiencing a very strange problem with an OA page. The page is used to update multiple rows from a transient VO using a table region. Following were the symptoms.
  • Sometimes after save, the old value used to reappear.
  • Sometimes after save, value from different row gets updated to current row.
  • It was not happening for all kind of data.

Finally (by sheer luck) we found that it was because the way we preparing the VO for update.

Old Code
Row row = vo.createRow();
row.setAttribute(0,"value1");
row.setAttribute(1,"value2");
row.setNewRowState(row.STATUS_INITIALIZED);
vo.insertRow(row);

It seems we accidentally were using STATUS_INTITIALIZED instead of STATUS_NEW. What a bummer?

I am not sure where or when we should be using STATUS_INTITIALIZED though but found out that it should never be used while preparing row for insert or update. Below is from the javadoc of oracle.jbo.Row.








static byte
STATUS_INITIALIZED



Indicates that the row is newly created and no setAttribute has been called on it yet.

static byte
STATUS_NEW



Indicates that the Row is newly created and this Row's consistuent entities have been added to the transaction.


Wednesday, March 25, 2009

Cursor Focus on OA page

Initial Cursor Focus is a highly under rated requirement in OA framework and mostly it is put on the back burner during design/coding. And there is no clear documentation for this feature and may be OA dev guide avoided it because we need to use Java Script for it; which is considered sacrilegious in OAF. We designed and deployed around 50 pages to production and realized the importance of cursor focus only when the users started whining about it. Hey, but they had a valid case, some times they open a page and scans a lot number immediately. But if the focus was on URL browser field, it will take them to different page. And worse, some users started complaining about carpal tunnel symptoms due to excessive usage of mouse. So when we started fixing the pages for initial cursor focus we found ourselves in a difficult situation for some pages like the one which have tab region or one with table region.

Simple messageText field.

Initial cursor focus on single row region is simple and straightforward.


String id = "myId"; // ID of the field
OABodyBean bB = (OABodyBean)pageContext.getRootWebBean();
bB.setInitialFocusId(id);


Tab region

We need to find the current active tab and then focus on the field for that tab.


OABodyBean bB = (OABodyBean)pageContext.getRootWebBean();
OASubTabLayoutBean tBean = (OASubTabLayoutBean)webBean.findIndexedChildRecursive("tabRegionId");
if(tBean != null)
{
int tabIndex = tBean.getSelectedIndex(pageContext);
if(tabIndex == 0)
bB.setInitialFocusId("id1");
else if (tabIndex == 1)
bB.setInitialFocusId("id2");


Table region

This is tricky and there is no direct OA supported way of doing this. OA framework (UIX) suffixes N: to the table field id while creating the final HTML page. Based on this fact following javascript function will do the trick.


// id is ID of your bean
// rowIndex is the row number you want to focus.
function setTableFocus(id,rowIndex)
{
for (i = 0; i< 100 ; i++)
{
var bean = document.getElementById('N' + i+ ':' + id + ':' + rowIndex);
if(bean != null)
{
bean.focus();
break;
}
}
}


OABodyBean bB = (OABodyBean)pageContext.getRootWebBean();
pageContext.putJavaScriptFunction("focusTag",);
bB.setOnLoad("setTableFocus('" + id + "'," + 1 + ")"); // focus on first row.



We created an utility class to handle all these scenarios. FocusMap.java. Read javadoc for its usage.

Tuesday, May 6, 2008

OA Framework Custom Component: Pivot Table 1.1 beta version


I am in the process of creating a custom component for OA Framework called Pivot Table which has similar features of Microsoft Excel Pivot Table, but UI more inline with OA Framework. I am releasing the first (beta) version. It is meant to be used with table region, preferably a read only table. But it can be used independently. Currently it supports only single level of summary and needs to be added to your page from JDeveloper. Future vesions will have multiple levels of summary and ability to add it through personalization. Following are the steps to use it in your page.

1. Download the beta version.
2. Follow the installation steps in ReadMe. It is simple.
3. Add a stackLayoutRegion below the table region region of your page.
4. For the above stackLayoutRegion, set the extends property as
/ramble/oracle/apps/qa/component/pivot/ui/webui/PivotSharedRN
5. Set User Defined: Attribute1 in Property Inspector as the View Object Instance name of the table region.

Pivot Table has two regions
Pivot Parameter Region:
It will have four picklist.
  • Row - Pivot row which will show all attributes of Source VO set in step 5. Can be null.
  • Column - Pivot column which will show all attributes of Source VO set in step 5. Can be null
  • Data - Pivot data which will show all attributes of Source VO set in step 5. Has to be Number attribute if you want some statistical function from pivot table.
  • Function - Pivot data function. Currently supports COUNT, SUM, AVERAGE, MIN and MAX.

Result Region
Based on the parameter region and if the pivot source specified in step 5 is executed, user can press "REFRESH" to see the pivot summary.

I am working on final version of release 1.0 and will come up with better documentation soon.

Monday, May 5, 2008

OAF v ADF: Finally its official

I always had tough time convincing my management and sales folks (who in turn must convince customers) to prefer OAF over much hyped ADF for custom extension of Ebusiness Suite. Well, to be honest there was one part of me, a teeny tiny part, that was skeptical and sometime cynically pointing out the conservative nature of me sticking to the technology I know rather than learning or adopting the new. Oracle finally managed to release a white paper on it. (Got it from Steve Chan's blog) You can download it from metalink.

I am happy that Oracle finally felt it important to release something of this sort. Some of the key highlights
- OAF and ADF are not entirely different. Both uses some common components like BC4J, UIX etc
- If you are planning to integrate with Ebusiness suite, stick with OAF.
- If your application is entirely new and independent of ebusiness suite then use ADF.

Some of my observations
  1. The disclaimer, quoted below, kinda scared me initially, but I guess its just some legal stuff.

"The following is intended to outline our general product direction. It is intended
for information purposes only, and may not be incorporated into any contract. It is
not a commitment to deliver any material, code, or functionality, and should not
be relied upon in making purchasing decisions. The development, release, and
timing of any features or functionality described for Oracle’s products remains at
the sole discretion of Oracle."


2. You have to believe things said in the article since it is from Oracle. But still I was curious about author of this white paper. Sarah Woodhull, not heard that name before but googled it found that she is Senior Product Analyst with ATG group. The co-author, Padmaprabodh Ambale, is famous in OAF circles and I have interacted with him many times during my stint in Oracle development and he took one of the OAF training class. (Ironically in that class like three years ago he kinda mentioned that OAF is gonna go away soon)

3. Oracle evades one key question. Can we easily migrate the custom extensions to fusion middle ware? White paper says that it is "possible" to migrate the UI (OK thats convincing) and Controller migration is non-trivial (How???) and easy migration for BC4J (phuh I guessed it).

4. Well guys it is final ..but not final yet. Wait until ADF11g is out. Oracle might change their mind.

"When ADF 11g becomes production, we will publish a revised paper that compares OAF with
ADF 11g, and discuss development against E-Business Suite."


5. OAF AND ADF – A DETAILED COMPARISON Table looks cool and totally favors OAF based on number of "X" marks against ADF. But I think the paper left out of lotsa cool things of ADF which would have cause lot many "X" against OAF. So it seems the table was made after making the decision or should I say recommendation.


6. It has "X" for PLSQL DML Operation Support for ADF. I dont know that much ADF, but thats scary ....


Overall I am sure that lotsa customers are gonna get huge benefits out of this white paper ....

Bound Values in OA framework - II

Lets take a closer look at the interface DataObject.

From javadoc

The DataObject interface provides an extremely simple API for retrieving arbitrarily structured data. All "queries" are based simply on a selection string. It is entirely up to an implementation of this interface to define the syntax for these strings.

It has only one method.

public java.lang.Object selectValue(RenderingContext context, java.lang.Object select)


OA Framework creates a named DataObject for each data source and then caches the DataObject on oracle.cabo.ui.RenderingContext. A data source is identified by the view usage name set on the web bean. OA Framework then gets the value from the DataObject using the view attribute on the bean as a lookup key.

OAWebBean.getValue() >> delegates to OADataBoundValue.getValue(RenderingContext context) and passes rendering context as parameter >> which lookups DataObject from
renderingcontext based on view usage name setup in the web bean and calls that DataObject.selectValue () with view attribute name as lookup key.

For a table bean OA fraemwork creates DataList which is a list of DataObject. ReneringContext.getCurrentDataObject() will return the DataObject for the current processing
row.

So code in OADataBoundValue.getValue(RenderingContext context) will look like


DataObject dataobject = renderingcontext.getCurrentDataObject();
if(dataobject == null)
{
// will return view usage name
String s = ((OAWebBeanData)mOAWebBean).getDataObjectName();
if(s != null) {
// first parameter is name space URI

dataobject = renderingcontext.getDataObject(
"oracle.apps.fnd.framework",
s);
}
}
// gets view attribute name
String s1 = ((OAWebBeanDataAttribute)mOAWebBean).getDataAttributeName();

if(s1 != null && !s1.equals(""))

return dataobject.selectValue(renderingcontext, s);




Most of the above things are just good to know kind of information. So lets take a look at this in OAF developer perspective on how to use this.

Typical use cases are
(a) To programaticaly bind a web bean property like "Rendered" or "Prompt" etc to a view object
(b) To programaticaly set fire action event parameters.

STEP 1: Find out whether the web bean takes BoundValue as parameter for the property/attribute.
STEP 2: Find the right BoundValue implementation to pass it to the web bean. For example for the USE CASE (a) we will use OADataBoundValueViewObject and for USE CASE (b) we will use OADataBoundValueFireActionURL.
STEP 3: Determine the parameters required to be passed to the BooundValue constructor.
STEP 4: Create the corresponding BoundValue object and pass it to the setAttribute() method.

Example 1: (Based on USE CASE a: To set prompt of web bean to a view object)

OAMessageStyledTextBean mTextBean =
(OAMessageStyledTextBean)webBean.findChildRecursive("TextID");

OADataBoundValueViewObject promptBV =
new OADataBoundValueViewObject(mTextBean, "VoAttribute");

mTextBean.setAttributeValue(
oracle.cabo.ui.UIConstants.PROMPT_ATTR, promptBV);


Example 2: (Based on USE CASE b: To set fire action event programaticaly )

OAMessageStyledTextBean b =
(OAMessageStyledTextBean)createWebBean(
pageContext,
MESSAGE_STYLED_TEXT_BEAN,
"NUMBER",
"TextID");

b.setViewUsageName("ViewusageName");

b.setViewAttributeName("ViewAttributeName");
Hashtable params = new Hashtable(1);
OADataBoundValueFireActionURL fireEventBV = new
OADataBoundValueFireActionURL(webBean,"{$ViewAttributeName}");

params.put("FireEventParameter",fireEventBV);
b.setFireActionForSubmit("fireEvent",null,
params,false,false);


Thursday, May 1, 2008

TemplateCO in OA Framework

RAD way of assigning a controller to a region is to right click on the region node in Structure Pane and selecting "Set new Controller" option. OA framework automatically creates the CO with some default code. That default code comes from <JDEV_HOME>\jdevbin\jdev\lib\ext\jrad\config\TemplateCO.java

I modified this template CO to import OAApplicationModule and OAException. You can play around with other templates in this folder (at your own risk).

Wednesday, April 30, 2008

Bound Values in OA framework - I

A web bean in OAF(UIX) consists of
  • Indexed Children
  • Named Children
  • Attributes.
Attributes can be specified at design time in which case it will be a simple name/value pair and value of that attribute will be static. Attribute value can also be determined during run time. If the attribute value has to be determined runtime it must be bound to a data source. When OAF(UIX) is building/rendering these UI nodes it establishes a context called rendering context. And to acheive this runtime behavior we get the data source from this rendering context.

Lets convert the above statement in English Language to Java language

RenderingContext - Interface representing the context when OAF(UIX) builds(renders) the UI nodes.
BoundValue - Is a simple interface with a single method getValue(RenderingContext context). It is left to the implementation of getValue() method to achieve the run time behavior based on rendering context object.

So OAWebBean (MutableUINode to be precise) have a method to set attribute value.

public void setAttributeValue(AttributeKey attrKey,Object value)

Value can be any implementation of BoundValue interface if it must be determined at runtime.

And at run time, when OAF(UIX) uses getAttributeValue(RenderingContext context, AttributeKey key), a typical code might look like

if ((value instanceof BoundValue))
{
return ((BoundValue)value).getValue(context);
}

Generally the parameters that determine the run time value will be passed to the constructor of BoundValue implementing object. For example DataBoundValue is a implementation of BoundValue which reads value based on DataObject in the context. DataObject is very simple interface to extract arbitarily structured data.

So one of the construtor of that Class is

public DataBoundValue(
Object select
)


where the parameter, select, is used to get the DataObject from RenderingContext.

And getValue() method implementation will be simple

return context.getCurrentDataObject().selectValue(context, select);

Thursday, April 3, 2008

Clearing Profile Cache

Its a royal pain in the **** to bounce the apache everytime you change a profile value, especially during OA page development. Well here is an easy way to clear the profile cache.

1. Login to APPS
2. Choose "Functional Administrator" responsibility
3. Navigate Core Services > Caching Framework > Cache Components
4. Search for %PROFILE%
5. Select "PROFILE_OPTION_CACHE" and "PROFILE_OPTION_CACHE_VALUES".
6. Press Clear Cache button.

Thursday, March 27, 2008

Cursor Focus for OAF Mobile Pages

OA Pages can be rendered in PDA or Mobile devices without doing special coding. Generally hand held devices are used in shop floor, warehouses or for some field work. And the keypad of a mobile device will be small and it is difficult to use navigation buttons. So we must design the User Interface in such way to minimize button clicks and user interventions. User would love a page where he simply has to scan the labels in shop floor and may be press a single button at the end to confirm the transaction. For such an user friendly UI it is mandatory to focus the cursor on the scan field. But javaScript is completely disabled if the device (agent) is PDA/Mobile. Even
OABodyBean.setInitialFocusId() wont work in mobile. We did the following to get the cursor focus on mobile page (11.5.10 RUP3).

a. Copy OA.jsp to XXOAMobile.jsp
b. Modify the following code in XXOAMobile.jsp

Old Code
try
{
redirectURL = pageBean.preparePage(pageContext);

if (redirectURL != null)
{
%>
<jsp:forward page="<%= redirectURL %>" />


New Code
try
{
redirectURL = pageBean.preparePage(pageContext);

if (redirectURL != null)
{
String x = redirectURL.substring(2); // modified
x= "XXOAMobile" + x; // modified
%>
<jsp:forward page="<%= x %>" />



c. Seed your AOL Menu function with WEB HTML Ref as XXOAMobile.jsp?page=<Func Name> instead of OA.jsp?page=<Func Name>

d. In your CO's always do a setForwardURL to XXOAMobile.jsp?page=<Func Name>

e. Add the java script code in XXOAMobile.jsp
WARNING: This code is definetely not upgrade safe and we must revisit it after every tech stack upgrade.

OAF LOV Overriding Default Where Clause

Oracle SQL never seems to like function in the WHERE clause and if the function got an indexed column as parameter then most likely the query will not perform good.

Say for example,

SELECT emp_no
FROM emp_table
WHERE UPPER(emp_name) like 'JOHN%'

If emp_table have an index on emp_name, the above query will not pick that index.

The default behavior of Oracle Framework (OAF) LOV is to add where clause with UPPER function.

SELECT * FROM (
SELECT emp_no
FROM emp_table) QRSLT
WHERE (( UPPER(emp_name) like :1 AND (emp_name like :2 OR emp_name like :3 OR emp_name like :4 OR emp_name like :5)))

And it binds values like 'JOHN%', 'John%','john%' and 'jOHN%'.



You might end up with performance issue due to this and if OAF suggested way of making the criteria passive is to0 painful then simply add the following code in the VOImpl


public void initQuery(Dictionary[] x)
{
if( x!= null)
{
for(int i = 0 ; i < x.length ; i++)
{
Dictionary z = x[i];
z.remove(OAViewObjectImpl.CRITERIA_LOOKUP_NAME);
}
}
super.initQuery(x);
}