Skip Headers
Oracle® Application Development Framework Developer's Guide
10g Release 3 (10.1.3)
B25386-01
  Go To Documentation Library
Home
Go To Product List
Solution Area
Go To Table Of Contents
Contents
Go To Index
Index

Previous
Previous
Next
Next
 

16.5 Debugging the Oracle ADF Model Layer

The processing of your JSF page in combination with Oracle ADF Model is controlled by two classes:

FacesPageLifecycle implements certain methods of PageLifecycleImpl to provide customized error-handling behavior for ADF Faces applications. Generally, however, you will set breakpoints on PageLifecycleImpl, as this class provides the starting point for creating the objects of the Oracle ADF binding context.


Tip:

The FacesPageLifecycle class provides the default implementation of the phase of the ADF Lifecycle. A good place to set a breakpoint is on the prepareModel() method, as it initiates the first phase of the ADF lifecycle. For details about the Oracle ADF lifecycle, see Section 6.2.2.4, "The JSF and ADF Lifecycles".

The successful interaction between the web page and these objects of the Oracle ADF binding context ensures that the page's components display with correct and complete data, that methods and actions produce the desired result, and that the page renders properly with the appropriate validation errors.

16.5.1 Correcting Failures to Display Pages

At runtime, several things must happen before the ADF lifecycle can prepare the model and display the web page. When the first request for an ADF databound web page occurs, the servlet registers the Oracle ADF servlet filter ADFBindingFilter, named in the web.xml file. The method ADFBindingFilter.doFilter() sets up the ADF processing state, and the method ADFBindingFilter.initializeBindingContext() creates an instance of oracle.adf.model.BindingContext by reading the CpxFileName init param from the web.xml file.

16.5.1.1 Fixing Binding Context Creation Errors

Immediately after ADFBindingFilter.initializeBindingContext() is called, BindingContext is an empty container object that will define a hierarchy of the Oracle ADF Model layer objects. However, as the container object, BindingContext must exist in order for the page's binding to be created. If it does not, an internal servlet error for the Container /oracle/<path>/DataBinding.cpx will be thrown:

oracle.jbo.NoXMLFileException: JBO-26001: XML File not found

To debug creating the binding context for the web application:

  1. In the oracle.adf.model.servlet.ADFBindingFilter class, set a break on chain.doFilter() and step into this method.

    This image shows a breakpoint on doFilter().
  2. Set another break on ctx.get(BindingContext.IS_INITIALIZED) and step into this method.

    This image shows a breakpoint on ctx.get().
  3. In the oracle.jbo.uicli.mom.JUMetaObjectManager class, set a break on chain.getClientProjectExtension() and step into this method.

    screenshot of a breakpoint on getClientProjectExtension()
  4. When processing pauses, look in slot0 for a file with the expected package name in the Data window.

    This image shows slot0 in the Data window for loadCpx()

If the DataBindings.cpx file is not found, then check that the servlet context parameter element correctly defines the fully qualified name for the .cpx file and verify that the file exists in your project in the location specified by the qualified name path. Example 16-2 shows the context parameter for the SRDemo application.


Tip:

The name specified in the param-value element of the context parameter must be the fully qualified name of the .cpx file.

Example 16-2 Sample web.xml Servlet Context Parameter

<context-param>
        <param-name>CpxFileName</param-name>
        <param-value>oracle.srdemo.view.DataBindings</param-value>
</context-param>

16.5.1.2 Fixing Binding Container Creation Errors

After BindingContext is created by ADFBindingFilter, the method PageLifeCycle.xXX() passes the request's web page URL to the method BindingContext.findBindingContainer() to find a page definition from the <pageMap> element in the DataBindings.cpx file that matches the web page. This becomes the BindingContainer. This BindingContainer object is the runtime instance object with all bindings created on it. If page definition file is not found, an internal servlet error will be thrown:

oracle.jbo.NoDefException: JBO-25002: Definition oracle.<path>.pageDefs.<pagedefinitionName> of type Form Binding Definition not found

To debug creating the binding container for the web page:

  1. In the oracle.adf.model.BindingContext class, set a break on findBindingContainerIdByPath() and step into this method.

    screenshot of a breakpoint on findBindingContainerIdByPath()
  2. Look for the name of the databound web page associated with the binding container in the Data window.

    This image shows slot1 displays a web page file name.
  3. In the Smart Data window, look for a matching entry for the expected databound web page file name.

    This image shows variable 11 displays a web page file name
  4. In the Data window, there should be a matching page definition entry for the databound web page.

    This image shows a matching page definition in variable 1

If the <pagename>PageDef.xml file is not found, then check that the <pageMap> element in the DataBindings.cpx file specifies the correct name and path to the web page in your project. Example 16-3 shows a sample DataBindings.cpx file for the SRDemo application. Notice that the <pageMap> element maps the JSF page to its page definition file.


CAUTION:

If you change the name of a JSF page or a page definition file, the .cpx file is not automatically refactored. You must manually update the page mapping in the .cpx to reflect the new page name.

Example 16-3 Sample Databinding.cpx Page Definitions

<?xml version="1.0" encoding="UTF-8" ?>
<Application xmlns="http://xmlns.oracle.com/adfm/application"
             version="10.1.3.34.12" id="DataBindings" SeparateXMLFiles="false"
             Package="oracle.srdemo.view" ClientType="Generic">
  <pageMap>
    <page path="/app/SRList.jspx" usageId="SRListPageDef"/>
    ...>
  </pageMap>
  <pageDefinitionUsages>
    <page id="SRListPageDef" path="oracle.srdemo.view.pageDefs.            app_SRListPageDef"/>
    ...
  </pageDefinitionUsages>
  <dataControlUsages>
    <dc id="SRSessionFacade" path="oracle.srdemo.model.SRSessionFacade"/>
  </dataControlUsages>
</Application>

16.5.2 Correcting Failures to Display Data

After BindingContainer is created by BindingContext, the ADF lifecycle initates the Prepare Model and the Render Model phases before data can be displayed in the web page. Several things must happen before the bindings are resolved and data can appear in the web page:

  • Page parameters must be set.

  • Iterator and Method executables must be get refreshed by executing named service methods and ADF iterator bindings.

16.5.2.1 Fixing Executable Errors

The ADF lifecycle enters the Prepare Model phase by calling BindingContainer.refresh(PREPARE_MODEL). During the Prepare Model phase, BindingContainer page parameters get prepared and then evaluated. Next, BindingContainer executables get refreshed based on the order of entry in the pagedef.xml file's <executables> section and on the evaluation of their Refresh and RefreshCondition properties (if present). When an executable leads to an iterator binding refresh, the corresponding data control will be executed, and that leads to execution of one or more collections in the service objects. If an iterator binding fails to refresh, a JBO exception will be thrown and the data will not be available to display.

To debug all executables for the binding container:

  1. In the oracle.adf.model.binding.DCBindingContainer class, set a break on internalRefreshControl(int, boolean) as the entry point to debug the executables.

    This image shows a breakpoint on internalRefreshControl()

    Tip: In the DCBindingContainer.internalRefreshControl() method, you can determine whether the executable will be refreshed by checking the outcome of the condition if (/*execute ||*/ execDef == null || execDef.isRefreshable(this, iterObj, refreshFlag)). If the condition evaluates to true, then the executable is refreshed and processing will continue to initSourceRSI().

  2. In the oracle.adf.model.binding.DCIteratorBinding class, set a break on callInitSourceRSI() to halt processing and step into the method.

    This image shows a breakpoint on initSourceRSI()
  3. When processing pauses, look for callInitSourceRSI() in the Stack window. The result displayed in the Smart Data window should show the result that you expect.

    This image shows variable mHasResult displays a result false

When your web page fails to display data from a method iterator binding, you can drill down to the entry point in JUMethodIteratorDef.java and its nested class JUMethodIteratorBinding to debug its execution.

To debug the method iterator executable for the binding container:

  1. In the oracle.jbo.uicli.binding.JUMethodIteratorDef class, set a break on initSourceRSI() as the entry point to debug a method iterator binding executable.

    This image shows a breakpoint on initSourceRSI()
  2. Set a break on invokeMethodAction() to halt processing and step into the method.

    This image shows a breakpoint on invokeMethodAction()

    Note that if the method returns a valid collection or a bean, then that object becomes the datasource for the rowset iterator that this iterator binding is bound to. For bean data controls, an instance of DCRowSetIteratorImpl is created to provide the rowset iterator functionality for the iterator binding to work with. (Note that for For ADF Business Components, this method would ideally return a ADF BC RowSetIterator so that ADF BC can manage the state of the collection.)

  3. When initSourceRSI() returns a rowset iterator, pause processing and look for mProvider in the Smart Data window. The mProvider variable is the datasource fetched for this RowSetIterator. If the method returned successfully, it should show a collection bound to an iterator or a bean.

    This image shows a breakpoint and the mProvider variable.

When your web page fails to display the detail data from an accessor binding, you can drill down to the entry point in JUAccessorIteratorDef.java to debug its execution.

To debug only the accessor binding executable for the binding container:

  1. In the oracle.jbo.uicli.binding.JUAccessorIteratorDef class, set a break in initSourceRSI() as the entry point to debug an accessor executable.

    Image of breakpoint on getMasterBinding()in initSourceRSI()
  2. In the oracle.adf.model.generic.DCGenericDataControl class, set a break in fetchProperty(RowImpl row, String propName) to halt processing before looking into the Data window. Check if the method returns any property that is a collection, iterator, or a bean.

    This image shows a breakpoint on isProviderMap()
  3. When initSourceRSI() returns a rowset iterator, pause processing and look for callInitSourceRSI() in the Smart Data window. The result should show the collection that you expect.

    This image shows the variable mProvider has a value

Tip:

If the debugger does not reach a breakpoint that you set on an executable in the binding container, then the error is most likely a result of the way the executable's Refresh and RefreshCondition attribute was defined. Examine the attribute definition. For details about the Refresh and RefreshCondition attribute values, see Section A.7.1, "PageDef.xml Syntax".

When the executable that produced the exception is identified, check that the <executables> element in the pagedef.xml file specifies the correct attribute settings.

Whether the executable is refreshed during the Prepare Model phase, depends on the value of Refresh and RefreshCondition (if they exist). If Refresh="prepareModel" or Refresh does not have a value (uses the default), then RefreshCondition is used. If no RefreshCondition setting exists, then the executable is refreshed. If RefreshCondition exists, then it is evaluated and if the return value of the evaluation is true, then the executable is refreshed; otherwise, if the evaluation is false, the executable is not refreshed. The default value, always, enforces execution.

Example 16-4 shows a sample pagedef.xml file from the SRDemo application. Notice that the <executables> element lists the executables in the order in which they should be executed, with the accessor iterator positioned after its master binding iterator.

Example 16-4 Sample Page Definition Master and Detail Executables

<executables>
    ...
    <methodIterator id="findUsersByNameIter" Binds="findUsersByName.result"
                    DataControl="SRService" RangeSize="1"
                    BeanClass="oracle.srdemo.model.User"
                    RefreshCondition="#{adfFacesContext.postback}"/>
    <accessorIterator id="expertiseAreasIterator" RangeSize="2"
                      Binds="expertiseAreas" DataControl="SRService"
                      BeanClass="oracle.srdemo.model.ExpertiseArea"
                      MasterBinding="findUsersByNameIter"/>
</executables>

16.5.2.2 Fixing Render Value Errors Before Submit

During the prepareRender phase of the ADF lifecycle, the bindings determine the data to display, and properties on the bindings determine the conditions in which to display the data. When the web page is rendered the first time, each EL expression that points to a binding gets resolved by the BindingContainer instance for that page. Based on the expression appropriate values like format, isEnabled, and isViewable, the data value for a binding is returned from BindingContainer. If the binding is unable to return the data, a JBO exeception is thrown.

To debug the binding resolution for the binding container:

  1. In the oracle.jbo.uicli.binding.JUCtrlValueBinding class, set a break in getInputValue() and step into the method.

    Screenshot of breakpoint on getError() in getInputValue()
  2. If getInputValue() returns an error, pause processing and and look for the binding name in the Data window.

    Screenshot of the variable mAttrNames has a binding name
  3. Continue stepping into getInputValue(), and look for a return value in the Data window that you expect for the current row that this binding represents.

    A breakpoint on the return on getInputValue()

When the binding that produced the exception is identified, check that the <bindings> element in the pagedef.xml file specifies the correct attribute settings. Example 16-5 shows a sample pagedef.xml file for the SRDemo application.

Example 16-5 Sample Page Definition Value Bindings

<bindings>
    ...
    <attributeValues id="name" IterBinding="variables">
      <AttrNames>
        <Item Value="findUsersByName_name"/>
      </AttrNames>
    </attributeValues>
    <attributeValues id="email" IterBinding="findUsersByNameIter">
      <AttrNames>
        <Item Value="email"/>
      </AttrNames>
    </attributeValues>
    <attributeValues id="lastName" IterBinding="findUsersByNameIter">
      <AttrNames>
        <Item Value="lastName"/>
      </AttrNames>
    </attributeValues>
    <table id="UserexpertiseAreas" IterBinding="expertiseAreasIterator">
      <AttrNames>
        <Item Value="expertiseLevel"/>
        <Item Value="product"/>
      </AttrNames>
    </table>
  </bindings>

In case of submit, again, the lifecycle first looks up and prepares the BindingContainer instance. If the lifecycle finds a state token that was persisted for this BindingContainer, it asks the BindingContainer to process this state token. Processing the state token restores the variable values that were saved out in previous the render. If you need to debug processing the state token, break in DCIteratorBinding.processFormToken() and DCIteratorBinding.buildFormToken().

After this, all posts are applied to the bindings through setInputValue() on the value bindings.

16.5.3 Correcting Failures to Invoke Actions and Methods

When the executables are refreshed, actions and custom methods may be invoked on the page. At this stage, the corresponding action or method binding is refreshed. If an executable or its target binding is not executed, the action will be ignored.

The entry point for action and method execution is the DCDataControl.invokeOperation() method. Although JUCtrlActionBinding.invoke() is another potential entry point, method iterator bindings also use it to invoke methods implicitly. Intstead, debugging on DCDataControl.invokeOperation() allows you to work with the same method that the data control uses to invoke the method. This is preferred because some adapter data controls can interpret the method name in a custom way rather than leave it to ADF to call the method.

To debug the action or method invocation for the binding container:

  1. In the oracle.adf.model.binding.DCDataControl class, set a break on invokeOperation() as the entry point to debug an action or method invocation.

    This image shows a breakpoint on invokeMethod()
  2. When processing pauses, step though the method to verify instanceName in the Data window shows the method being invoked is the intended method on the desired object.

    This image shows the variable instanceName has a value
  3. Verify args in the Data window shows the parameter value for each parameter being passed into your method is as expected. The parameter value below shows null.

    This image shows the variable args has a null value

To debug a custom method invocation for the binding container:

  1. In your class, set a breakpoint on the desired custom method.

  2. In oracle.adf.model.generic.DCGenericDataControl class, set a break on invokeMethod() to halt processing before looking into the Data window.

    This image shows a breakpoint on invokeMethod().
  3. When processing pauses, step though the method to verify instanceName in the Data window shows the method being invoked is the intended method on the desired object.

    This image shows the variable instanceName has a value
  4. Verify args in the Data window shows the parameter value for each parameter being passed into your method is as expected. The parameter value below shows null.

    This image shows the variable args has a null value

When the ignored action or custom method is identified, check that the <invokeAction> definitions in <executables> element and their corresponding <action> and <methodAction> definitions in the <bindings> element of the pagedef.xml file specifies the correct attribute settings.


Tip:

If the debugger does not reach a breakpoint that you set on an action in the binding container, then the error is most likely a result of the way the executable's Refresh and RefreshCondition attribute was defined. Examine the attribute definition. For details about the Refresh and RefreshCondition attribute values, see Section A.7.1, "PageDef.xml Syntax".

Whether the <invokeAction> executable is refreshed during the Prepare Model phase, depends on the value of Refresh and RefreshCondition (if they exist). If Refresh="prepareModel" or Refresh does not have a value (uses the default), then RefreshCondition is used. If no RefreshCondition setting exists, then the executable is refreshed. If RefreshCondition exists, then it is evaluated and if the return value of the evaluation is true, then the executable is refreshed; otherwise, if the evaluation is false, the executable is not refreshed. The default value, always, enforces execution.

Example 16-6 shows a sample of the action and custom method binding definitions in the pagedef.xml file for the SRDemo application.

Example 16-6 Sample Page Definition Executables and Action Bindings

<executables>
    ...
    <invokeAction Binds="clearSearchField" id="invokeClearSearchField"
                  Refresh="prepareModel"
                  RefreshCondition="#{!adfFacesContext.postback}"/>
    <invokeAction Binds="clearSearchResult" id="invokeClearSearchResults"
                  Refresh="prepareModel"
                  RefreshCondition="#{!adfFacesContext.postback}"/>
     ...
</executables>
<bindings>
    <methodAction id="findUsersByName" InstanceName="SRService.dataProvider"
                  DataControl="SRService" MethodName="findUsersByName"
                  RequiresUpdateModel="true" Action="999"
                  ReturnName="SRService.methodResults.SRService_dataProvider_                       findUsersByName_result">
      <NamedData NDName="name" NDValue="${bindings.findUsersByName_name}"                   NDType="java.lang.String"/>
    </methodAction>
    <action id="Next" IterBinding="findUsersByNameIter"
            InstanceName="SRService.dataProvider" DataControl="SRService"
            RequiresUpdateModel="true" Action="10"/>
    <action id="Previous" IterBinding="findUsersByNameIter"
            InstanceName="SRService.dataProvider" DataControl="SRService"
            RequiresUpdateModel="true" Action="11"/>              
    <action id="clearSearchResults"
            InstanceName="findUsersByNameIter"
            DataControl="SRService" RequiresUpdateModel="false"
            Action="999" IsLocalObjectReference="true"
            MethodName="release">
      <NamedData NDName="flags" NDType="int" NDValue="1"/>
    </action> 
        <action id="clearSearchField"
            InstanceName="name"
            DataControl="SRService" RequiresUpdateModel="false"
            Action="999" IsLocalObjectReference="true"
            MethodName="setInputValue">
      <NamedData NDName="varVal" NDType="java.lang.Object" NDValue=""/>
    </action>
    ...
  </bindings>

16.5.4 Correcting Page Validation Failures

The method validate() on the BindingContainer gets called, which calls validateInputValue() on each of the bindings referred to in this BindingContainer. If the validation set on an input field fails to behave as expected, then no validation error message will be displayed in the web page.

To debug validation-checking failures for the binding container:

  1. In oracle.jbo.uicli.binding.JUCtrlValueBinding class, set a break in validateInputValue(Object value) to halt processing before looking into the Data window.

    This image shows a breakpoint on validateAttributeValue()
  2. When processing pauses, look for slot1 in the Data window and confirm that the validation is performed. The value not shown below indicates validation was not performed.

    This image shows the variable slot1 has the value not.

When the validation that failed is identified, check that the validation rule for the value binding is correctly defined and that the input field component's <af:validator> tag is bound to the same attribute defined by the value binding. Example 16-7 shows a sample validation rule in the pagedef.xml file for the SRDemo application.

Notice that the ADF Model validation rule should appear on the attribute binding. For details about working with validation rules, see Section 12.3, "Adding Validation".


Tip:

To process ADF Model layer validation, the Faces validator tag must be bound to the associated attribute's validator property. For example:
<af:validator binding="#{bindings.<attribute>.validator}"/>

where <attribute> would be createProducts_description to work with the sample validation rule shown in Example 16-7.


Example 16-7 Reference to Validation Rule in Page Definition File

<attributeValues id="description" IterBinding="variables" ApplyValidation="true">
  <LengthValidationBean xmlns="http://xmlns.oracle.com/adfm/validation"
             OnAttribute="createProducts_description"
             DataType="CHARACTER" CompareType="LESSTHAN"
             ResId="description_Rule_0" Inverse="false"
             CompareLength="20"/>
  <AttrNames>
     <Item Value="createProducts_description"/>
  </AttrNames>
</attributeValues>