To avoid this, we have customized some of the ADF data control classes, namely DCTaskFlowBinding. What we have done, is added code to release the list of executables from a task-flow’s bindings when the task-flow is navigated away from. This avoids having its executables refreshed.
The underlying ISSUE:
As new train-stops are visited, the bindings for each of the train stops, which are task-flows in our case, are added to the main train stop task-flow's list of executables within it bindings. Each time you visit a new tab, or rather a new train stop, the bindings for the main task-flow get re-executed. This causes all of its executables, which basically are the bindings for each of the visited tabs' task-flows, to get executed as well. Which, as you may have figured, causes the entire tree of bindings to get refreshed. Since this main task-flow is a major part of our application, there are probably hundreds of iterators within this tree, especially after visiting each of the tabs. This was causing a major slow down.
The FIX:
Our solution to this problem was to simply release the old tab's executable bindings as it was navigated away from. There is a navigation listener on the main task-flow which contains the activityId of the currently selected train stop. Once a new train stop is selected, this listener gets called. The last part of the listener method calls cleanupBeforeRelease in the DCTaskFlowBinding class. What we have done is, customized the DCTaskFlowBinding class to, as a part of this method, release all of this task-flows's executable bindings. Releasing these bindings essentially removes them from the binding container itself, which prevents them from being executed when the top level task-flow navigates to a new tab. This old tab's bindings still get executed, however, it is much quicker since the costly executables have been released.
The CODE:
- In DataBindings.cpxReplaced:<factory nameSpace="http://xmlns.oracle.com/adf/controller/binding"
className="com.collectamerica.aquila.common.TaskFlowBindingDefFactoryImpl"/>
with<factory nameSpace="http://xmlns.oracle.com/adf/controller/binding"
className="com.collectamerica.aquila.common.CustomTaskFlowBindingDefFactoryImpl"/>- Create CustomTaskFlowBindingDefFactoryImpl.java and extend TaskFlowBindingDefFactoryImpl
Within that class we basically replaced:DCTaskFlowBindingDef taskflowBindingDef = new DCTaskFlowBindingDef();
withDCTaskFlowBindingDef taskflowBindingDef = new CustomDCTaskFlowBindingDef();
to end up with:public class CustomTaskFlowBindingDefFactoryImpl extends TaskFlowBindingDefFactoryImpl {
public CustomTaskFlowBindingDefFactoryImpl() {
super();
}
/**
* {@inheritDoc}
* @param element {@inheritDoc}
* @return {@inheritDoc}
*/
public DCDefBase createDefinition(DefElement element)
{
// In our case there is only one object we can create but we still do
// the check.
if (element.getNodeName().equals(Constants.ENAME_TASKFLOWBINDING))
{
DCTaskFlowBindingDef taskflowBindingDef = new CustomDCTaskFlowBindingDef();
return taskflowBindingDef;
}
return null;
}
}- Create a class named CustomDCTaskFlowBindingDef which extends DCTaskFlowBindingDef, and basically this changes the binding container class name to point to our own custom class that we'll create next:
public class CustomDCTaskFlowBindingDef extends DCTaskFlowBindingDef {
public CustomDCTaskFlowBindingDef() {
super();
}
@Override
public void init(HashMap initValues) {
super.init(initValues);
// Overide BindingContainer class name with our special TaskFlowBinding.
mBindingContainerClassName = CustomDCTaskFlowBinding.class.getName();
}
}- Create a class named CustomDCTaskFlowBinding which extends DCTaskFlowBinding and override the cleanupBeforeRelease method and implement it as follows:
public class CustomDCTaskFlowBinding extends DCTaskFlowBinding {
public CustomDCTaskFlowBinding() {
super();
}
/*
* This method has been customized in order to release bindings which are no
* no longer needed. You'll find that in the super's method,
* cleanupBeforeRelease, that there is a TODO which states that exactly what
* we're adding should be done. This will prevent these old bindings from being
* reexecuted everytime we switch between task-flows, and in the specific case
* this was originally done for, will prevent all previous tabs from reexectuing
* their executable bindings when switching tabs.
*/
@Override
protected void cleanupBeforeRelease(String childViewPortId) {
super.cleanupBeforeRelease(childViewPortId);
//if this task-flow is being notified, it is because this task-flow is being
// navigated away from, so release its executable bindings (the expensive ones)
// which will get relisted when the page is actually displayed again
List executables = this.getExecutableBindings();
if(executables != null){
for(int i=0; i<executables.size(); i++){
Object oExec = executables.get(i);
if(oExec instanceof JUFormBinding){
JUFormBinding jExec = (JUFormBinding)oExec;
jExec.release(DCDataControl.REL_ALL_REFS);
}
}
}
}
} - Create CustomTaskFlowBindingDefFactoryImpl.java and extend TaskFlowBindingDefFactoryImpl
No comments:
Post a Comment