JHeadstart custom search with default values

JHeadstart has a powerful generator for ADF Faces pages. One of the features of the generator is the generation of search functionality into a page. The search functionality offers a Quick Search with a single search item and an Advanced Search for multiple search criteria. When generating search functionality with JHeadstart 11g a design decision has to be made whether to use the ADF Model or JHeadstart custom approach.

With the ADF Model approach the Quick- and/or Advanced Search is defined in the View Object using Query Criteria. The generated page uses a single component (<af:query> or <af:quickQuery>) that renders a complete search area. This approach is recommended if you

The JHeadstart custom approach uses meta-information in JHeadstart to generate the search areas. There is no need to specify something on the View Object. The generated search areas are composed by more page components which can be flexible arranged. This approach is recommended if you

  • have special layout requirements like organizing search items in groups using tabs
  • need to use the JHeadstart custom List Of Values because of your LOVs need multi-selection, detail disclosure or special layout requirements
  • want to keep you metadata in the JHeadstart application definition instead of in the ADF Business Components
  • want to customize your search

Often it would be nice to have initial values for the search items, but this is not supplied by JHeadstart by default. For customization reason I am using JHeadstart Search custom approach to add this functionality.

Based on the idea of the article by Lucas Jellema Using default search values on the JHeadstart advanced search the solution described here shows how to implement the feature of default values for search items. In this solution default values can be specified for both Quick- and Advanced Search. An additional "Default" button is added into the search region to manually apply the default values. In addition the default values are always set when the task flow starts e.g. when be called from the menu. The final pages will look like these:

Quick Search with Default button:

JHSSearchDefaultQS.png

Advanced Search with Default button:

JHSSearchDefaultAS.png

The demo application is based on the employee data of the HR demo database schema. Here are the steps to implement it.

  1. Create a new Fusion Web Application (ADF) and define an ADF BC Model with only one updateable Viewobject EmployeesView based on the table EMPLOYEES.

  2. Enable JHeadstart on the ViewController project and create a new Service Definition. Choose the following settings:

    • Quick Search Style=JHeadstart - Dropdown List
    • Advanced Search Style=JHeadstart - Same Page
    • Always use JHeadstart LOVs in JHeadstart search area: Checked

    For the other options accept the default values of the wizard.

  3. Define a default value for the item DepartmentId when creating new rows. This is not the definition for the default value of a search item but it will be used later for demo supplying a default value from the generated bean. Open the JHS Application Definition Editor navigate to group Employees and select DepartmentId in Items. Enter 50 to the property "Default Display Value".

  4. Generate the application and run it to see everything is working.

  5. Now it is time to add search with default values functionality. In this solution the default values will be supplied as managed properties of the search bean generated by JHeadstart. A new custom generator template needs to be registered on the Employees group in the application definition:

      SEARCH_BEAN = custom/misc/facesconfig/EmployeesSearchBean.vm
    

    In the custom generator template the new Search bean class and the managed properties are defined:

    <managed-bean>
      <managed-bean-name>${bean.beanName}</managed-bean-name>
      <managed-bean-class>
    com.jhssearchdemo.controller.jsf.bean.SearchBeanWithDefaultValues
    </managed-bean-class>
        ...
        <managed-property>
          <property-name>advancedSearchDefaultValues</property-name>
          <map-entries>
            <key-class>java.lang.String</key-class>
            <map-entry>
              <key>EmployeesDepartmentId</key>
              <value>
           #{pageFlowScope.EmployeesDefaultValues.defaultValues['DepartmentId']}
              </value>
            </map-entry>
            <map-entry>
              <key>EmployeesHireDate</key>
              <value>10-Apr-1997</value>
            </map-entry>
          </map-entries>  
        </managed-property>
        <managed-property>
          <property-name>quickSearchDefaultValues</property-name>
          <map-entries>
            <key-class>java.lang.String</key-class>
            <map-entry>
              <key>EmployeesLastName</key>
              <value>O*</value>
            </map-entry>
          </map-entries>  
      </managed-property>
    </managed-bean>
    

    Defining the managed properties as a Map allows to use the item name as key and the default value as value of the map entry. The item name is the name of the associated control binding generated for the page fragment. The value can be a constant or a reference to another bean. The Advanced Search default value for EmployeesDepartmentId shows an example how to reference a value from the default value bean for new rows.

    The new enhanced search bean has to supply managed properties to hold the default values and a method to apply the default values. The new class will extend the JHeadstart search bean class JhsSearchBean.

    package com.jhssearchdemo.controller.jsf.bean;
    public class SearchBeanWithDefaultValues extends JhsSearchBean {
        // Maps of default values
        private Map quickSearchDefaultValues;
        private Map advancedSearchDefaultValues;
        ...  // getter and setters
    
        /**
         * Appy default values to searchBean
         */
        @PostConstruct
        public void applyDefaultSearchValues() {
            sLog.debug("enter applyDefaultSearchvalues");
    
            Map criteria = super.getCriteria();
            sLog.debug("current criteria:" + criteria);
    
            // clear all search criterias
            super.clearSearchCriteria();
    
            DCBindingContainer container = getBindingsInternal();
    
            if (advancedSearchDefaultValues != null) {
                // Apply default values for advanced search
                sLog.debug("set advanced search items:" + 
                  advancedSearchDefaultValues);
                for (String searchItemName :
                     (Set)advancedSearchDefaultValues.keySet()) {
    
                    // copy default value only to items that exists
                    if (findSearchControlBinding(container, searchItemName) !=
                        null) {
                        Object asItemValue =
                            advancedSearchDefaultValues.get(searchItemName);
                        sLog.debug("set default value " + asItemValue +
                                   " for advsearch item: " + searchItemName);
                        criteria.put(searchItemName, asItemValue);
                    } else {
                        sLog.warn("search item for default value doesn't exist: " +
                                  searchItemName);
                    }
                }
                // super.getCriteria().putAll(advancedSearchDefaultValues);
            }
    
            // Apply default value for simple search
            if (quickSearchDefaultValues != null &&
                !quickSearchDefaultValues.isEmpty()) {
                // get first key from Quicksearch Map
                Set keyset = quickSearchDefaultValues.keySet();
                Iterator keyIter = keyset.iterator();
                String qsItem = (String)keyIter.next();
    
                sLog.debug("previous search item was " + getSearchItem());
                if (findSearchControlBinding(container, qsItem) != null) {
    
                    Object qsItemValue = quickSearchDefaultValues.get(qsItem);
    
                    // set Quicksearch item
                    sLog.debug("set quicksearch item: " + qsItem);
                    setSearchItem(qsItem);
                    if (qsItemValue != null && !"".equals(qsItemValue)) {
                        sLog.debug("set quicksearch item value: " + qsItemValue);
                        setSearchText(qsItemValue);
                    }
                } else {
                    sLog.warn("search item for default value doesn't exist: " +
                              qsItem);
                }
            }
            sLog.debug("exit applyDefaultSearchvalues");
        }
    

    The method applyDefaultSearchValues() clears the existing search criteria, looks up and applies the default search values from the managed properties. Take a note on the annotation @PostConstruct. JSF will fire the method applyDefaultSearchValues() when all managed properties are set. As the Search Bean is pageflow-scoped the method will be automatically applied every time the pageflow is entered like from a menu item. This way the default search values will be already set when entering the page. The method findSearchControlBinding() checks if the specified item name is valid (has a control binding with the same name).

  6. To manually invoke the method applyDefaultSearchValues() add a "Default" Button next to the Search button of the Advanced Search. The button has an actionListener to invoke the new method of the search bean. In the JHeadstart Application Definition Editor customize the template DO_ADVANCED_SEARCHED_BUTTON at group (Employees) level. Add the following at the end of the new template custom/button/doAdvancedSearchDefaultButton.vm:

    ...
    <af:commandButton textAndAccessKey="#{nls['FIND_DEFAULT']}"
        actionListener="#{#SEARCH_BEAN().applyDefaultSearchValues}"
        id="${JHS.current.group.shortName}AdvancedSearchDefaultButton"/>
    

    The same way create a new customized template DO_QUICK_SEARCH_BUTTON (custom/button/doQuickSearchDefaultButton.vm):

    <af:commandButton textAndAccessKey="#{nls['FIND_DEFAULT']}"
        actionListener="#{#SEARCH_BEAN().applyDefaultSearchValues}"
        id="${JHS.current.group.shortName}QuickSearchDefaultButton"/>
    
  7. Add the button label to the application resource file. Locate the resource file ViewController\src\com\jhssearchdemo\view\ApplicationResources_en.properties and add a new entry:

    FIND_DEFAULT=&Default
  8. Add the actionListener applyDefaultSearchValues to the search bean class. Note that there is already a method applyDefaultSearchValues in the search bean class but not with the rigtht signature for an action listener. Adding a small wrapper will help:

        /**
         * Wrapper to set default values with action listener
         * @param evt
         */
        public void applyDefaultSearchValues(ActionEvent evt) {
            applyDefaultSearchValues();
        }
    
  9. Generate the application again, compile and run it. Navigate to the Employees tab to see the new button "Default" in the Quick Search. Also the default search item "Lastname" and value "O*" is shown. Change the search item and/or value and apply the new "Default" button to initialize the search again. Execute the search to verify that it works.

    The same functionality is available in Advanced Search. Once the search is initialized either manually or by the annotation both Quick Search and Advanced search is defaulted. The reason is that the method applyDefaultSearchValues() set the default values for both Quick Search and Advanced Search. If this is not desired the method can be splitted into default values for Quick Search and Advanced Search. Two separate action listeners can invoke these methods.

That's it. You can download a sample workspace that illustrates the solution

here
.

Comments:

Post a Comment:
  • HTML Syntax: NOT allowed
About

Java EE Consultants - JHeadstart, ADF, JSF

Search

Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today