29 Jan 2016

Dynamic Iterator Binding Definition

In one of my previous posts I showed how we can use multiple iterator binding definitions to represent data on a page provided by different row sets of a single VO instance. A blog reader asked me a reasonable question about this technique. Suppose that at design time we don't know what row sets and what view objects are going to be shown on a page. So, we're not able to define all necessary iterator bindings in the page def file at design time. Is it possible to dynamically create those iterator binding definitions at run time? Yes, it is!

This job can be done using the following managed bean method:

private DCIteratorBinding createIterator(String iteratorName, String voName,
                                         String dataControlName, String rsiName)
{
  DefinitionFactory defFactory =
    JUMetaObjectManager.getJUMom().getControlDefFactory();
 
  //Create and init an iterator binding definition
  JUIteratorDef iterDef = (JUIteratorDef)
    defFactory.createControlDef(DCDefBase.PNAME_Iterator);

  HashMap initValues = new HashMap();
  initValues.put(JUTags.ID, iteratorName);
  initValues.put(JUTags.DataControl, dataControlName);
  initValues.put(JUTags.PNAME_VOName, voName);
  initValues.put(JUTags.PNAME_RSIName, rsiName);

  iterDef.init(initValues);

  //Create an iterator binding instance
  DCIteratorBinding iter =
    iterDef.createIterBinding(BindingContext.getCurrent(), getBindings());

  //Add the instance to the current binding container
  getBindings().addIteratorBinding(iteratorName, iter);

  return iter;
}

At the very beginning the method gets an instance of the control definition factory. This factory is used to produce an iterator binding definition object. This definition is going to be initialized with a map containing iterator name, data control name, view object name and row set name. So, basically, all those attributes that we set up for an iterator binding definition in a page def file at design time. Finally, the method creates an iterator binding instance and adds it to the current binding container.

This managed bean method can be consumed while creating dynamic value bindings such as an attribute value binding, a button value binding, a lov binding, a tree binding etc. Examples of these techniques are described and implemented in a sample application here.

That's it!

24 Jan 2016

Handling the Close Icon for Dialogs with Running Task Flows

We can run an ADF bounded task flow in a modal dialog using out-of-the-box ADF controller functionality. This feature is fully described in the documentation. So, let's say there is task-flow-definition which we want to run in a dialog from Main page:

In order to get it working we have to set up task flow call activity property Run As Dialog to true and the Display Type property to inline-popup. Besides that the caller command button should have the useWindow property set to true:

  <af:button text="Dialog" id="b1" useWindow="true"
             action="dlg"
             returnListener="#{pageFlowScope.TheBean.returnDialogListener}"/>

Whenever the task flow reaches its Return activity, the framework closes the dialog and invokes a return listener specified for the caller command button. In this way a caller is notified that the dialog is closed and it is able to handle the task flow return values. 

However, if the user closes the dialog using a standard close icon, the task flow is considered abandoned and the framework won't fire any event. So, the caller will never know about that. Obviously, there are some use-cases when the caller needs to get notified about such case. This requirement can be implemented using Chaperone technique. 

Let's define the following interface:

public interface DialogCancelListener {
  void dialogCanceled();
}

and implement it with our caller managed bean (TheBean):

  @Override
  public void dialogCanceled(){
     //Handle dialog cancel event
  }


There is an input parameter of the task flow:

<input-parameter-definition id="__6">
 <name>cancelListener</name>
 <value>#{pageFlowScope.FlowBean.cancelListener}</value>
 <class>com.adfpractice.taskflowdialogapp.view.DialogCancelListener</class>
</input-parameter-definition>

The value of this parameter is going to be an instance of our caller managed bean:


The task-flow-definition looks like this:

So, whenever the task flow is about to be finished in a normal way it is going to set up return values that will be handled by the caller in the return listener. If the user finishes the task flow by clicking on the close icon, the task flow is abandoned and setupReturnValues method will never be invoked. The task flow has a finalizer checking if the return values have been set up. If they have not been set up it invokes dialogCanceled method of the cancelListener.

  public void taskFlowFinalizer() {
    if (!returnValuesSetUp) {
      cancelListener.dialogCanceled(); 
    }
  }
In his way the caller managed bean (TheBean) is going to be notified about abandoning of the target task flow.

That's it!