Monday, September 30, 2013

Row number on paginated af:table

A quick tip..

Usually we use #{row.index + 1} to show the row number in table component. But when we use the same in a paginated table, for every page the row number will starts with 1 because row.index starts with 0 for every page.

How to display the correct row number?

bindings.<TREE_BINDING_ID>.rangeStart will give the corresponding page range start value. For eg if the page size is 10 and if you are in 4th page then rangeStart value will be 40.

So adding this rangeStart with row.index will display proper row number:

#{row.index + 1 + bindings.< TREE_BINDING_ID>.rangeStart}

Eg: #{row.index + 1 + bindings.EmpVO.rangeStart}


Here 'row' refers to af:table 'var' property value.


and EmpVO refers to tree binding id

Sunday, May 5, 2013

af:region/taskflow lazy loading with loading message

I have a page where I consumed a taskflow as region. Sometimes this taskflow takes few more seconds extra where the entire page rendering is waiting just for this taskflow.

I was looking for something like let the whole page render first, then the region should show loading and it should make another request to render its actual view activity. So that the user can see rest of the page and let the region loads on its own as soon as ready.

I was looking for something out of the box from ADF but I don't see any property for this. So here is my own way of implementation to achieve that.

This is my actual page(Home.jspx):


Here all the content is from Home.jspx and the right side is info region (InfoTF). This region I need to load it lazily.

Created a taskflow template(LazyLoadingTFTemplate) with a switcher & view activity. It has a boolean parameter EnableLazyLoading.



The switcher will check if the parameter EnableLazyLoading is true go to Loading page otherwise Next switcher.

Loading page has output text : Loading (put your own loading image if needed) and a poll component with a listener set to 3 seconds.


And the poll listener makes programmatic navigation to next..

Now the info taskflow InfoTF will extend  LazyLoadingTFTemplate and its default activity is set to EnableLazyLoading switcher.



Also it has a control flow from Next(via template) to Info view activity



Thats it. Drag & drop InfoTF on Home.jspx as region and set EnableLazyLoading parameter to true. Run the page.



and after 3 seconds



Note : After 3 seconds when the poll component request(r1) is in progress when user makes some changes on main area which initiates another request(r2) then r2 will get the response only after r1's response. Figuring out how to make r1 async so that r2 will not wait for r1.


Above implementation code is uploaded here.

Happy ADF Coding..

Sunday, April 21, 2013

Life of Dynamic View Object & Entity Object Across Passivation/Activation

For one of the requirement I use Dynamic VO & EO along with dynamic form extensively. This works perfectly until the AM passivates. But when it activates it started throwing exception:

javax.el.PropertyNotFoundException: Target Unreachable, 'DynamicForm_dynamic_VO_form1' returned null

This issue is visible only on JDeveloper 11.1.2.0.0 & even it exists in later versions but its hidden by some other bug as per Oracle dev.

Looking into the code deeper.. I have put my code as per dev guide:


private static final String DYNAMIC_EO = "dynamic.EO";
private static final String DYNAMIC_VO = "dynamic.VO";
private static final String DYNAMIC_VO_INSTANCE_INTERNAL = "DynamicVOInternal";


//Entity creation
EntityDefImpl newEntity = new EntityDefImpl(DYNAMIC_EO);
newEntity.setSource("TEST_TABLE");

//Code for AttributeDefImpl creations..

newEntity.resolveDefObject();

newEntity.registerDefObject();

//ViewDef creation

ViewDefImpl newView = new ViewDefImpl(DYNAMIC_VO);
newView.addEntityUsage("e", DYNAMIC_EO, false, false);
newView.addAllEntityAttributes("e");

newView.resolveDefObject();
newView.registerDefObject();

//ViewObject instance creation
ViewObject dynmVO = createViewObject(DYNAMIC_VO_INSTANCE_INTERNAL, DYNAMIC_VO);

And this view instance is used for dynamic form in UI. Debugged and found that the View Instance not exists after activation hence the above error is thrown. Why its not recreated, no clue so I reached back to Oracle.

It was one of my interesting technical discussion with Oracle.

When the def is created dynamically its called temporal def and its deleted at the time of passivation. The code pattern we used to create view def is by calling registerDefObject() is meant for a view def which is meant for a singleton VO, i.e., view def with one VO instance. When ADFbc see such a temporal view def, it delete the view def from memory when the singleton VO instance is removed. Because the framework doesn't know how to create the temporal view def back.

Since the view def does not exists after the activation the dynamic form throws above exception.

Below are few suggestions from Oracle.

First suggestion:
1. Set up the mds-config section in adf-config.xml to declare a proper MDS repos
2. On the above code replace:

newEntity.resolveDefObject();
newEntity.registerDefObject();

with
newEntity.resolveDefObject();
newEntity.writeXMLContents();
newEntity.saveXMLContents();
newEntity = EntityDefImpl.findDefObject(<full-EO-name>);

3. And replace
newView.resolveDefObject();
newView.registerDefObject();

with
newView.resolveDefObject();
newView.writeXMLContents();
newView.saveXMLContents();
newView = ViewDefImpl.findDefObject(<full-VO-name>);

Here the dynamic view def is stored in MDS so that its not considered as temporal def and also its not deleted when its getting passivated.

But I can't enable MDS just like that without doing complete re-test of my whole application. So I thought of storing the vo def at the time of passivation & recreate the same on my own overidding prepareForActivation. Reached Oracle with this suggestion and they provided another good suggestion:

Second suggestion:
If the dynamic eo & vo is created with a package and put the def object in a package, then the view def is not considered temporal view def any more. So, the view def is not deleted when the VO instance is removed at the time of passivation and the vo instance will be recreated & available after activation. And the new code is:


private static final String DYNAMIC_PACKAGE = "dynamic";
private static final String DYNAMIC_EO = "EO";
private static final String DYNAMIC_VO = "VO";

public void createDynamicViewDef(){
//Create dynamic package

        PackageDefImpl newPackage;
        java.lang.reflect.Method setParentMth;
        try {
            java.lang.reflect.Method mth = MetaObjectManager.class.getDeclaredMethod("createContainerDefObject", new Class[] { boolean.class });
         
            setParentMth = oracle.jbo.server.DefObject.class.getDeclaredMethod("setParent", new Class[] { oracle.jbo.common.NamedObjectImpl.class });
         
            mth.setAccessible(true);
         
            setParentMth.setAccessible(true);
         
            newPackage = (PackageDefImpl) mth.invoke(MetaObjectManager.getSingleton(), new Object[] { true });
        }catch(Exception ex) {
            throw new JboException(ex);
        }
     
        newPackage.setDefScope(PackageDefImpl.DEF_SCOPE_SESSION);
        newPackage.setName(DYNAMIC_PACKAGE);
        newPackage.setFullName(DYNAMIC_PACKAGE);
        MetaObjectManager.insertSessionMetaObject(newPackage.getFullName(), newPackage);

//Create Entity
        EntityDefImpl newEntity = new EntityDefImpl(DYNAMIC_EO);
        newEntity.setFullName(DYNAMIC_PACKAGE + "." + DYNAMIC_EO);
        try {
            setParentMth.invoke(newEntity, new Object[] { newPackage });
            }catch(Exception ex) {
                throw new JboException(ex);
            }
     
        newEntity.setSource("TEST_TABLE");

//Code for AttributeDefImpl creations..

        newEntity.resolveDefObject();
        newEntity.registerDefObject();

//Create ViewDef
        ViewDefImpl newView = new ViewDefImpl(DYNAMIC_VO);
        newView.setFullName(DYNAMIC_PACKAGE + "." + DYNAMIC_VO);      
        try {
            setParentMth.invoke(newView, new Object[] { newPackage });
        }catch(Exception ex) {
            throw new JboException(ex);
        }
       
        newView.addEntityUsage("e", newEntity.getFullName(), false, false);      
        newView.addAllEntityAttributes("e");

        newView.resolveDefObject();
        newView.registerDefObject();
}

//Create ViewObject Instance
        ViewObject dynmVO = createViewObject(DYNAMIC_VO_INSTANCE_INTERNAL, DYNAMIC_PACKAGE + "." + DYNAMIC_VO);

Thats it.. I have modified my code as per their second suggestion and it works perfectly...

Please note that when the AM gets activated in different node on a cluster then the view def needs to re-created. Override prepareForActivation and use the below code to recreate view def:

    protected void prepareForActivation(Element element) {
        super.prepareForActivation(element);
        ViewDefImpl existing = null;
        try{
            existing = ViewDefImpl.findDefObject(DYNAMIC_PACKAGE + "." + DYNAMIC_VO);
        }
        catch(NoDefException ex){
            existing = null;
        }
     
        if (existing == null){
            this.createDynamicViewDef();
        }      
    }

None of the above information is available in dev guide and Oracle have logged an internal documentation bug to update the same.

All the above discussions are tracked on
Bug 16320619 : DYNAMIC FORM WITH DYNAMIC VO & EO THROWS EXCEPTION ON PASSIVATION/ACTIVATION

Happy ADF Coding...!!






PanelCollection features

Blogging after long time... Was quite busy at work...

very useful post for panel collection..

https://blogs.oracle.com/aramamoo/entry/what_does_featureoff_attribute_do

Saturday, December 15, 2012

Never forget resetActionListener when there is rollbackTransaction action


Whenever you put a button (any action component) to rollbackTransaction make sure you have resetActionListener also.. Usually when you drag and drop rollback operation as action component this is created by default. But in the scenarios where you add action component separately you have to put it manually..

Many times I missed to put resetActionListener inside my button and the application data looks very odd when I click Cancel button... And I spent hours to debug the issue and found that resetActionListener  is missing..

<af:commandToolbarButton text="#{viewcontrollerBundle.DISCARD_CHANGES}" id="ctb2"
                                                   icon="/images/Discard.png" accessKey="Z"
                                                   actionListener="#{ManagedBean.rollbackChanges}" immediate="true">
         <af:resetActionListener/>
</af:commandToolbarButton>

So never forget(saying to myself) resetActionListener and rollbackTransaction!!

Jdeveloper 11.1.2.0 & Debug Mode

When you run the application in Debug mode in Jdeveloper 11.1.2.0, compile any java file and refresh the page you get java.lang.NullPointerException.

This issue is discussed in detail at
https://forums.oracle.com/forums/thread.jspa?threadID=2244097&tstart=0

and the summary is:
------------------------------------------------------------------------------------------
Option 1:  Change Tools->Preferences->Run->WebLogic and setting Select Hot Class Reload Policy to Fast Swap.

Option 2 : Turn off copying of any rebuilt files into the exploded EAR.
Usually the jdev shortcut target will be:
C:\Oracle\Middleware\jdeveloper\jdeveloper.exe

Modify this to C:\Oracle\Middleware\jdeveloper\jdeveloper.exe -J-Doracle.jdeveloper.adrs.incr.buildMonitor=false
and then restart jdeveloper.

Please use option 2 as a last resort. Since the debugger already provides some support for class redefinition, perhaps this will be useful for many who use debug mode.
------------------------------------------------------------------------------------------

I set Option 1 and it was working fine. But my weblogic server started crashing intermittently. I'm still working on exact reproducible steps but meanwhile I tried option 2 and it works properly.

East to West

Moved to California from New York.. Just got settle down..

Next posts are on the way...

Thiru