31 Mar 2012

Update model in the ValueChangeListener

After reading of the Understanding the JSF Immediate Attribute post, my friend asked me whether there is any sense to use the Immediate attribute for inputTexts. The answer is Yes, off course. In general we set the Immediate to true when we need to validate the component and execute its value change events before the common validation process, before the Process Validation phase. We move up the validation and the value change events processing to the Apply Request Values phase. In other words, we split our components into two parts: front-line or Immediate inputs that are validated first at the Apply Request Values and all others that are validated later at the usual Process Validation phase. In this post I'm going to show one of use-cases when the Immediate attribute for inputTexts could be useful.
Let's say we have two inputTexts:

        <af:inputText label="Label Value" id="it1"
                      value="#{backing_Main.labelValue}" autoSubmit="true"
                      />

        <af:inputText label="#{backing_Main.labelValue}" id="it2"
                      partialTriggers="it1"/>

The first one stores its value in some backing bean property (in the model), and the second input reads this property to render its label. The first input is autosubmit and it partially triggers the second input, so when we change value of the first input and press Tab, label of the second one is going to be changed immediately. At this point both inputs are not Immediate and everything works fine:

Let's change the required attribute of the second input to true and we get validation error:

To resolve this issue let's set Immediate of the first input to true and add a valueChangeListener. In the valueChangeListener we need to manually update model for the first input because we are going to skip all the subsequent phases (including Update Model phase) except Render Response:

   public void labelListener(ValueChangeEvent valueChangeEvent)
  { UIComponent c = valueChangeEvent.getComponent();
    
    //This step actually invokes Update Model phase for this 
    //component
    c.processUpdates(FacesContext.getCurrentInstance());
    
    //Jump to the Render Response phase in order to avoid 
    //the validation
    FacesContext.getCurrentInstance().renderResponse();
  }

And it works fine again:



That's it!

11 Mar 2012

Managed bean scopes for page fragments in ADF Task Flow

Introduction
When we work with ADF Task Flows and need to implement some flow specific business logic or store some information connected with the flow, we usually use pageFlowScope managed beans. And when we need to service view activities of the flow (pages or page fragments) we use shorter scopes for such managed beans. The common practice is to use requestScope, backingBeanScope and viewScope scopes for pages/fragments backing beans. In this post I'm going to play with these three options and discover the differences in the behavior of fragment based Task Flow.

Let's say I have some simple task flow template task-flow-template.xml:


   <managed-bean id="__5">
      <managed-bean-name id="__3">viewBean</managed-bean-name>
      <managed-bean-class id="__2">com.cs.blog.ViewBean</managed-bean-class>
      <managed-bean-scope id="__4">request</managed-bean-scope>
    </managed-bean>
    <managed-bean id="__15">
      <managed-bean-name id="__13">flowBean</managed-bean-name>
      <managed-bean-class id="__12">com.cs.blog.FlowBean</managed-bean-class>
      <managed-bean-scope id="__14">pageFlow</managed-bean-scope>
    </managed-bean>

    <view id="MainView">
      <page>/MainView.jsff</page>
    </view>
    

It has one view activity MainView and two backing beans. The flowBean has pageFlow scope and is responsible to store flow information. The viewBean has request scope (we will play with that) and it services the ManView view activity.

The flowBean has the following method returning the tittle of the task flow:

    public String getFlowTitle() {
        return null;
     }   

The viewBean has some string field testString to store input value:

    protected String testString;
    
    public void setTestString(String testString) {
        this.testString = testString;
    }

    public String getTestString() {
        return testString;
    }

The MainView shows the task flow's title and has an inputText for the testString. It looks like this:


We also have two task flows built on the task-flow-template - first-flow-definition and second-flow-definition. They have overridden managed beans.

For the  first-flow-definition:

    <managed-bean id="__5">
      <managed-bean-name id="__3">viewBean</managed-bean-name>
      <managed-bean-class id="__21">com.cs.blog.FirstViewBean</managed-bean-class>
      <managed-bean-scope id="__4">request</managed-bean-scope>
    </managed-bean>    
    
    <managed-bean id="__15">
      <managed-bean-name id="__13">flowBean</managed-bean-name>
      <managed-bean-class id="__12">com.cs.blog.FirstFlowBean</managed-bean-class>
      <managed-bean-scope id="__14">pageFlow</managed-bean-scope>
    </managed-bean>
 

public class FirstFlowBean extends FlowBean {
    public FirstFlowBean() {
        super();
    }
    
    public String getFlowTitle() {
        return "FirstFlow";
     }   
   
}

public class FirstViewBean extends ViewBean {
    public FirstViewBean() {
        super();
        
    }
    
    @PostConstruct
    public void init() {
        testString = "FirstFlow";  
    }
}

So the title and default value for testString is "FirstFlow".


For the  second-flow-definition:

    <managed-bean id="__5">
      <managed-bean-name id="__3">viewBean</managed-bean-name>
      <managed-bean-class id="__21">com.cs.blog.SecondViewBean</managed-bean-class>
      <managed-bean-scope id="__4">request</managed-bean-scope>
    </managed-bean>    
    
    <managed-bean id="__15">
      <managed-bean-name id="__13">flowBean</managed-bean-name>
      <managed-bean-class id="__12">com.cs.blog.SecondFlowBean</managed-bean-class>
      <managed-bean-scope id="__14">pageFlow</managed-bean-scope>
    </managed-bean>

public class SecondFlowBean extends FlowBean {
    public SecondfFowBean() {
        super();
    }
    
    public String getFlowTitle() {
        return "SecondFlow";
     }   
    
}

public class SecondViewBean extends ViewBean {
    public SecondViewBean() {
        super();
       
    }
   
    @PostConstruct
    public void init() {
        testString = "SecondFlow"; 
    }
   
}

So the title and default value for testString is "SecondFlow".


Ok. It's time to experiment. Let's put on our page two regions with first-flow-definition and second-flow-definition task flows:

              <af:region value="#{bindings.firstflowdefinition1.regionModel}"
                         id="r1"/>
              <af:separator id="s1"/>           
                         
              <af:region value="#{bindings.secondflowdefinition1.regionModel}"
                         id="r2" />

requestScope
Leaving the scope for the viewBean as requestScope we will get the following result:

In the SecondFlow we see the testString from the FirstViewBean instance. We can have only one instance of the requestScope bean per request. The viewBean was created for the FirstFlow task flow and the same instance was used again for the SecondFlow.

backingBeanScope
Somebody could recommend to use backingBeanScope for the viewBean instead of requestScope. The backingBeanScope is commonly used to manage regions and declarative components. It has the same length of life as the requestScope but for different instances of regions/declarative components you will have separate instances of backingBean scoped managed beans. In our case we have two different regions, so let's try:

And, Yes, the backingBeanScope has fixed the problem. We have two instances of the viewBean - for the regions r1 and r2.
But let's make the first-flow-definition task flow a bit more complicated:


Now we can call child task flow (of the same definition) from the MainView. And let's repeat the experiment. On the initial rendering:

So far, so good. Let's input something in the input text of the FirstFlow and press "call child task flow":


Oooops! We have only one instance of the viewBean for the region r1 during the request. So, value "FirstFlow111111" entered in the parent task flow was rendered again in the child task flow.


viewScope
And now let's change the viewBean's scope to the viewScope and have the same experiment. On the initial rendering:

 Ok. Inputting the same garbage in the inputText:

And pressing the "call child task flow":
And everything is ok. We have not only separate viewScope beans instances for different viewport IDs (for different regions and task flow instances), but additionally the controller is resetting the viewScope during the navigation process. But the cheese is not free. You have to pay by memory. If requestScope or backingBeanScope live not longer than the request, viewScope lives in memory until the viewport ID is changed. Perhaps in my further posts I will show how to manage the issue with the backingBeanScope.

So, when you choose the appropriate scope for your fragment managed beans, consider how the task flow is going to be used. Probably, in order to get really high reusable task flow, using the viewScope is the best approach for fragment beans.

That's it!