Extending POJO based Bean Data Control to add the features you wanted (such as Named Criteria and af:query) !

I blogged about bean data control and pagination support a while back http://www.jobinesh.com/2011/03/what-you-may-need-to-know-about.html. Look like it is time to revisit this stuff to share few more interesting things on extending the features offered. While talking to some developers I realized that POJO based bean data control need few more extra fittings to make it more developer friendly ;) . For example out of the box support for af:query (i.e af:query backed up by named criteria that you may find for JPA based Bean Data Control) is one feature that is still missing. In this post, I'm sharing a sample which uses an enhanced custom  DataControlHandler to help you with out of the box query component and pagination support that you may otherwise  find missing.

The sample that I'm sharing here is built using 12.1.2.0.0. As 12 C has a lot of improvements on bean data control implementation,  the custom DataControlHandler used in this sample will not work on previous JDeveloper/ADF versions (as it uses the new APIs from 12C). With this sample, I just wanted to show you that most of  the pieces that you may see in the framework are extendable, and you can add the features your own. Try it out if you love fun.  Ah yes, you may need to spend some time on understanding their working though.

Download

You can download the sample workspace from here. Take a look at the ExtndPOJOModel project to get a feel of the framework extension classes that we are talking in the following section.
[ Runs with Oracle JDeveloper 12.1.2.0.0 or higher.]

A glance at the implementation

This sample uses following framework extension classes. These classes are available in ExtndPOJOModel project which is part of the sample work space that I shared above.
  • SimpleBeanDCDataFilterHandler extends DataFilterHandler : This is the custom data control handler class used in this sample in order to enable query and pagination support for a bean data control. This class is hooked to the ADF run time by pointing DataControlHandler entry that you see for bean-definition entry (in DataControls.dcx) to this class.
  • SimpleBeanDataCollection extends BeanDataCollection: The SimpleBeanDCDataFilterHandler uses this class as a data structure to return the collection  of Java bean requested by the client. In fact this class does more work than you expect, its the real 'work horse'  here which reads collection from your Java service class and issues appropriate queries to it whenever client ask for data.
  • SimpleSearchCriteria : A custom data structure used by the  SimpleBeanDataCollection to pass the search conditions to your Java Bean. 
  • SimpleCriteriaItem : Search conditions are represented by this class. SimpleSearchCriteria holds collection of SimpleCriteriaItem.

The extended data control handler that you find in this sample (SimpleBeanDCDataFilterHandler.java) offers the pagination and query support  for your POJO bean data control even if the data collection returned by your Java class is not based on JPA entities. The SimpleBeanDCDataFilterHandler is built by extending oracle.adf.model.adapter.bean.DataFilterHandler. It overrides the invoke(RowContext rowCtx, String name, DataFilter filter) method  to return a custom SimpleBeanDataCollection. The SimpleBeanDataCollection is extended from oracle.adf.model.adapter.bean.provider.BeanDataCollection. The SimpleBeanDataCollection  is the real work horse here, which invokes appropriate method in your Java Bean during the page life cycle phases as appropriate. The class SimpleBeanDataCollection  expects a method of following signature in your Java service class(the one you selected for building data control)
public Object queryByRange(SimpleSearchCriteria searchCriteria). This method will be triggered when user queries using af:query component and also during paginated fetch facilitated by the binding layer. For a Java Bean Data Control that returns POJO collection, there is no automated 'query' thing  involved and no other back magic). So if you use the extension given in this post, the queryByRange(SimpleSearchCriteria ) method in your Java class should have logic to return the collection requested by the client. You can get the search conditions and paging parameters from SimpleSearchCriteria parameter of this method. On a related note, framework will do an in-memory filtering for you if the named criteria's (that you defined in you POJO model's xml definition, e.g Departments.xml) query mode is set to In
-Memory or Both. That said, however, in-memory filtering may not be a right choice if you have large number of elements. As I said earliear, these are extensible pieces, feel free to add more features as you need.

Is there any manual labor involved to use custom SimpleBeanDCDataFilterHandler ?

Answer is Yes, You may not see visual editor support to leverage the offerings from SimpleBeanDCDataFilterHandler. The following are the steps that you may want to do manually:
  • Build you POJO based model, then create data control by selecting appropriate Java service class
  • After creating data control, open DataControls.dcx and update the value for DataControlHandler in bean-definition tag as shown below.

  <bean-definition BeanClass="pojo.model.extension.ExtendedJavaService" 
                       DataControlHandler="com.jobinesh.framework.extension.SimpleBeanDCDataFilterHandler" AccessMode="scrollable"
                       EagerPersist="false" xmlns="http://xmlns.oracle.com/adfm/adapter/bean"/>

  • Open the Java service class that you selected for building data control and add the following method:

           public Object queryByRange(SimpleSearchCriteria searchCriteria) { ... }
          This method will have logic to return appropriate collection by reading search conditions and paging               parameters passed through SimpleSearchCriteria parameter.

  • Now let us add a view criteria to the appropriate Java bean sparse XML. Edit the collection in the data control panel to create XML file for the Java bean used in the collection. As there is no visual editor support, you may need to manually add a view criteria in to the Java bean sparse XML and mark all attributes used in the view view criteria as Queriable, by setting IsQueriable="true". Take a look at Department.xml in the sample work space where you may see the code snippet that I added manually(Shhh, I copied this from a JPA based bean data control).  Relevant part is here:

 <ViewCriteria
        Name="DepartmentCriteria"
        ViewObjectName="pojo.model.extension.Department"
        Conjunction="AND"
        Mode="3">
        <Properties>
            <CustomProperties>
                <Property
                    Name="displayOperators"
                    Value="InAdvancedMode"/>
                <Property
                    Name="autoExecute"
                    Value="false"/>
                <Property
                    Name="allowConjunctionOverride"
                    Value="true"/>
                <Property
                    Name="showInList"
                    Value="true"/>
                <Property
                    Name="mode"
                    Value="Basic"/>
            </CustomProperties>
        </Properties>
        <ViewCriteriaRow
            Name="DepartmentCriteria_row_0"
            UpperColumns="1">
            <ViewCriteriaItem
                Name="DepartmentCriteria_DepartmentCriteria_row_0_departmentId"
                ViewAttribute="departmentId"
                Operator="=" 
                Conjunction="AND"
                Required="Optional"/>
            <ViewCriteriaItem
                Name="DepartmentCriteria_DepartmentCriteria_row_0_departmentName"
                ViewAttribute="departmentName"
                Operator="STARTSWITH"
                Conjunction="AND"
                Required="Optional"/>
            <ViewCriteriaItem
                Name="DepartmentCriteria_DepartmentCriteria_row_0_locationId"
                ViewAttribute="locationId"
                Operator="="
                Conjunction="AND"
                Required="Optional"/>
        </ViewCriteriaRow>
    </ViewCriteria>

Update on 9 July 2014 : Please note that later built JDeveloper extension for the custom Bean DC discussed in this post, which may help you to leverage visual  editor support for building VC http://www.jobinesh.com/2014/07/java-bean-dc-extension-for-jdeveloper.html
  • To build a search page, go to view controller project , create a page. Then drop the appropriate collection  from the data control to the page as table component. There is no visual editor support for building query component for our data control with custom handler, so let us do it manually. Open page definition editor, select source tab and add the search region binding as appropriate. An example is here(Short cut is copy this entry from any of your pages where you have af:query with binding support, and make appropriate changes):


 <executables> ...
   <searchRegion Criteria="DepartmentCriteria" Customizer="oracle.jbo.uicli.binding.JUSearchBindingCustomizer"
                  Binds="departmentsFindAllIterator" id="DepartmentCriteriaQuery"/>                   
  </executables>
  • Move back to the jsf source, and add af:query component  with binding to the the search region binding that we created in last step.


  <af:query id="qryId1" headerText="Search" disclosed="true"
                              value="#{bindings.DepartmentCriteriaQuery.queryDescriptor}"
                              model="#{bindings.DepartmentCriteriaQuery.queryModel}"
                              queryListener="#{bindings.DepartmentCriteriaQuery.processQuery}"
                              queryOperationListener="#{bindings.DepartmentCriteriaQuery.processQueryOperation}"
                              resultComponentId="::t1"/>

You are done. If you run the page, you may get a nice search page powered by af:query on the front end and your own handler on the back end.



Comments

Don Kleppinger said…
I created a simple data control that returns a list of POGO objects. The page retrieves the list once and displays the data but I Can't seem to get it to refresh when the backing data changes. Calling Execute on the list binding does nothing. What is the best way to force the datacontrol to refresh?
Don Kleppinger said…
Your download link doesn't work for me (using firefox)

Secure Connection Failed

An error occurred during a connection to drive.google.com. SSL received a record that exceeded the maximum permissible length. (Error code: ssl_error_rx_record_too_long)
ownhirepeople said…
The download link is working. You should try another network before posting here.

Disclaimer

The views expressed on this blog are my own and do not necessarily reflect the views of my employer.