Tuesday, December 13, 2011

Validator or ValueChangeListener. ADF 11g lifeCycle

Hi,

This is an example that will demonstrate the lifeCycle phases involved with validations and ValueChangeEvents.
There is some confusion on which is triggered first and when they are triggered.
This post will try to clear things a bit.
Even though the documentation is sufficient enough, this post will work as a helper by pointing only the important elements in order to understand the process as a general concept.

Download Sample Application.

According to the documentation:

http://docs.oracle.com/cd/E15523_01/web.1111/b31973/af_lifecycle.htm

Validations should fire first and then ValueChangeEvents should be issued:


The two important phases in our case are :

Apply Request Values and Process Validations.

According to Documentation:


  • Apply Request Values: Each component in the tree extracts new values from the request parameters (using its decode method) and stores the values locally. Most associated events are queued for later processing. If a component has its immediate attribute set to true, then the validation, the conversion, and the events associated with the component are processed during this phase. For more information, see Section 4.2, "Using the Immediate Attribute."




  • Process Validations: Local values of components are converted from the input type to the underlying data type. If the converter fails, this phase continues to completion (all remaining converters, validators, and required checks are run), but at completion, the lifecycle jumps to the Render Response phase.
    If there are no failures, the required attribute on the component is checked. If the value is true, and the associated field contains a value, then any associated validators are run. If the value is true and there is no field value, this phase completes (all remaining validators are executed), but the lifecycle jumps to the Render Response phase. If the value is false, the phase completes, unless no value is entered, in which case no validation is run. For more information about conversion and validation, see Chapter 6, "Validating and Converting Input."





  • What we understand here is that, for input components, by default, the validations are going to be fired in the Process Validations phase. Furthermore, they have a specific order:

    1)  converters
    2)  required checks (check if it is required)
    3)  validators

    NOTE: Of course there are some other cases were the required checks are not fired.. but the above is the general idea.

    As you may have noticed, in the Apply Request Values phase, it is mentioned that if the component has it's immediate property to true, then the validations will take place in tha phase.

    Which means, that they are not skipped.

    What we understand here is that validations will fire no matter if the component is immediate =true or not.

    But when does the ValueChangeEvent is triggered?

    Again, according to the documentation:



    ValueChangeEvent is an intermediate phase between Process Validations and and updae model Values.

    This means that ValueChangeListener are invoked right after validations. It does not matter if the component is immediate true or not.

    The difference lays in the phase those operations will be executed.


    The case of the commandButton:

    CommandButtons will trigger the validations and valueChangelisteners of inputComponent while pressed. It is the same case weither the the button is partialSubmit and the inputComponent partialTriggered by the button, or the button is not partialSubmit.

    If we set the commandButton to immediate true, then some phases are skipped:


    According to documentation:

     When actionSource components (such as a commandButton) are set to immediate, events are delivered in the Apply Request Values phase instead of in the Invoke Application phase. The actionListener handler then calls the Render Response phase, and the validation and model update phases are skipped.

    This means that if the button is set to immediate only the ApplyRequestValues phase will be invoked, the Process Validations phase will be skipped.

    So, if we will have a selectOneChoice component with autoSubmit=false and immediate=false and a commandButton with immediate=true. 


    According to what we know so far, the commandButton will invoke the ApplyRequestValues phase and then render response phase. Our selectOneChoise, will invoke the validation and ValueChangeListener in the Process Validations phase.. which in our case, will not be invoked.

    So we are bypassing everything...

    If we want to invoke validators and valueChangeListeners while having the button immediate=true, we will have to have the selectOneChoice to immediate=true as well!


     why? simply because, according to documentation, while having the input component immediate=true, all validators and valuChangeListeners will be shifted to ApplyRequestValues. Which is exactly what we want.

    Conclusion: Validators are executed before ValueChangeListeners. They are executed even if the input component is immediate=true. The only change is the which phase they will be executed in.
    The combination of commandButton can bypass he validations and valuechangelisteners if it set to immediate=true. We can still have validations and valueChangeListeners triggered if we have the inputComponent to immediate=true. Since the validations and ValueChangelisteners will be triggered in a different phase and more specifically, they will be triggered in the ApplyRequestValues phase.

    Well, this is it.  Of Course we could continue investigating more programmatic ways and workarounds but this would be out of the scope of this post

    Download Sample Application.


    Regards.


    10 comments:

    1. Hi!

      I see that after a valueChangeListener action is issued, the Application Module transaction remains Dirty even if the value on Database has already changed. It is because the listener's phase is before prepareModel.

      Is there any way to bypass this and notify the appModule that there is no transaction left???

      I tried the following ways:

      valueChangeEvent.getComponent().processUpdates(FacesContext.getCurrentInstance());
      FacesContext.getCurrentInstance().renderResponse();
      ADFUtils.getAppModuleTransaction().postChanges();

      No success at all =(

      ReplyDelete
      Replies
      1. Hey Renan,

        Can you please elaborate a bit more on your case? It seems to me that you are trying to set a transaction not to be dirty even though it is dirty..

        What exactly is your case?

        Regards.

        Delete
      2. Hi Dimitrios,
        Why does a transaction remains dirty (isDirty method returns true) even if all changes are commited to Database?
        What does "Dirty" stands for?

        Delete
    2. Hi Renan,

      According to the documentation: http://docs.oracle.com/cd/E21764_01/apirefs.1111/e10653/oracle/jbo/Transaction.html#isDirty__

      " Checks if any data within this Application Module has been modified but not yet committed. This method is typically called before an attempt is made to post the data.
      For example, this method can be called when the user at the client attempts to close an application. If there is unsaved data, this method can return true. In response, the client can prompt the user to save before closing the application. "


      So, it says that only if there are uncommitted data this method will result to "Dirty".
      If you could elaborate a bit more on your case, maybe we could find some solution why your transaction is Dirty. Note that even transient attributes will indicate that the Transaction isDirty:

      http://adfbugs.blogspot.com/2009/12/pending-changes-in-adf-application.html

      Further reading:

      http://andrejusb.blogspot.com/2010/03/integration-in-oracle-adf-with-adf-task.html

      http://www.oracle.com/technetwork/developer-tools/adf/unsaveddatawarning-100139.html

      Regards.

      ReplyDelete
    3. Dimitrios,

      I'll elaborate a test application and send it to you OK?

      I made a little progress calling FacesContext.getCurrentInstance().renderResponse() makes the #{bindings.Commit.enabled} returns false!

      ReplyDelete
      Replies
      1. Yes ok. Send it to me and I will look into it.

        Regards.

        Delete
    4. Great post.. Nice Explanation..!!

      ReplyDelete
    5. Please can you tell me one attribute value set to another attribute in same view object .like EmployeesId value set to EmployeeSysId.

      ReplyDelete

    LinkWithin

    Related Posts Plugin for WordPress, Blogger...