Follow by Email

Friday, 27 December 2013

Overriding default query listener ,field validation of af:query- Oracle ADF


Hello All,
this post talks about a common requirement - can we apply custom validation in af:query fields ? yes , we can do that by overriding default query listener of af:query component

What af:query is ?

see- Oracle Docs-af:query
"The query component provides the user the ability to perform a query based on a saved search or personalize saved searches. The component displays a search panel with various elements, each of which help the user to accomplish various tasks."


Follow steps to apply validation on af:query-
  • Here i am taking example of Departments table of HR Schema
  • First create business components for Departments table


  • then create  bind variables and a view-criteria in departments view object



  • See the view criteria is applied for LocationId, ManagerId and Department Name
  • Now create a page and drop criteria with table on page- it will look like this

  • Next is to select af:query on page and go to property inspector and copy text of default query listener



  • Now create a managed bean and create a custom query listener for af:query

     
  • In this custom query listener , in this example i am checking for negative Location Id and Manager Id, if there is any negative values ,custom method will show a message otherwise default queryListener will be executed
  • We can get af:query's components value using 2 methods
    First One  - Using Bind Variable (getNamedWhereClauseParam)
    Second One - Using QueryDescriptor and ConjunctionCriterion
  • I'm going to explain both methods - see code of custom query listener using first method, two generic methods will be used in this process to invoke expression language and to get BindingContainer of current context

  •     /**Method to invoke EL Expression
         * @param el
         * @param paramTypes
         * @param params
         * @return
         */
        public static Object invokeEL(String el, Class[] paramTypes, Object[] params) {
            FacesContext facesContext = FacesContext.getCurrentInstance();
            ELContext elContext = facesContext.getELContext();
            ExpressionFactory expressionFactory = facesContext.getApplication().getExpressionFactory();
            MethodExpression exp = expressionFactory.createMethodExpression(elContext, el, Object.class, paramTypes);
    
            return exp.invoke(elContext, params);
        }
    
        /**Method to get Binding Container of current page
         * @return
         */
        public BindingContainer getBindings() {
            return BindingContext.getCurrent().getCurrentBindingsEntry();
        }
    

  • See the first method to get af:query components value and validate that

  •     /**Custome Query Listener- Using getNamedWhereClauseParam
         * @param queryEvent
         */
        public void customQueryListener(QueryEvent queryEvent) {
            String deptName = null;
            Integer locId = null;
            Integer mgrId = null;
    
            /**Get Iterator of Table*/
            DCIteratorBinding iter = (DCIteratorBinding)getBindings().get("DepartmentsView1Iterator");
    
            /**Get ViewObject from Iterator*/
            ViewObjectImpl vo = (ViewObjectImpl)iter.getViewObject();
    
            /**Get Bind Variable's Value*/
            if (vo.getNamedWhereClauseParam("LocIdBind") != null) {
                locId = Integer.parseInt(vo.getNamedWhereClauseParam("LocIdBind").toString());
            }
            if (vo.getNamedWhereClauseParam("MgrIdBind") != null) {
                mgrId = Integer.parseInt(vo.getNamedWhereClauseParam("MgrIdBind").toString());
            }
            if (vo.getNamedWhereClauseParam("DeptNmBind") != null) {
                deptName = vo.getNamedWhereClauseParam("DeptNmBind").toString();
            }
    
            /**Check for Negative values*/
            if ((locId != null && locId < 0) || (mgrId != null && mgrId < 0)) {
                FacesMessage msg = new FacesMessage("Id Value can not be negative");
                msg.setSeverity(FacesMessage.SEVERITY_ERROR);
                FacesContext.getCurrentInstance().addMessage(null, msg);
            } else {
                /**Execute default query listener with help of invokeEL method*/
    
                invokeEL("#{bindings.DepartmentsViewCriteriaQuery.processQuery}", new Class[] { QueryEvent.class },
                         new Object[] { queryEvent });
            }
        }
    

  • And Second Method using QueryDescriptor is-

  •     /**Custom Query Listener-Using QueryDescriptor
         * @param queryEvent
         */
        public void customqueryProcess(QueryEvent queryEvent) {
            String deptName = null;
            Integer locId = null;
            Integer mgrId = null;
    
            /**Reference-Frank Nimphius Example- ADF Code Corner
           * http://www.oracle.com/technetwork/developer-tools/adf/learnmore/85-querycomponent-fieldvalidation-427197.pdf
           * */
            QueryDescriptor qd = queryEvent.getDescriptor();
    
            ConjunctionCriterion conCrit = qd.getConjunctionCriterion();
            //access the list of search fields
            List<Criterion> criterionList = conCrit.getCriterionList();
            //iterate over the attributes to find FromDate and ToDate
            for (Criterion criterion : criterionList) {
                AttributeDescriptor attrDescriptor = ((AttributeCriterion)criterion).getAttribute();
    
                if (attrDescriptor.getName().equalsIgnoreCase("DepartmentName")) {
                    deptName = (String)((AttributeCriterion)criterion).getValues().get(0);
    
                } else {
                    if (attrDescriptor.getName().equalsIgnoreCase("LocationId")) {
                        locId = (Integer)((AttributeCriterion)criterion).getValues().get(0);
    
                    }
                }
                if (attrDescriptor.getName().equalsIgnoreCase("ManagerId")) {
                    mgrId = (Integer)((AttributeCriterion)criterion).getValues().get(0);
    
                }
            }
            if ((locId != null && locId < 0) || (mgrId != null && mgrId < 0)) {
                FacesMessage msg = new FacesMessage("Id Value can not be negative");
                msg.setSeverity(FacesMessage.SEVERITY_ERROR);
                FacesContext.getCurrentInstance().addMessage(null, msg);
            } else {
                /**Process default query listener*/
                invokeEL("#{bindings.DepartmentsViewCriteriaQuery.processQuery}", new Class[] { QueryEvent.class },
                         new Object[] { queryEvent });
            }
    
        }
    

  • Now Run your application and check it for negative values

Cheers- Download Sample App Happy Learning :-)


2 comments :

  1. Very good this post and very useful.

    In the criteria for the item type to date between option,
    simply select the indices of them as 0 and 1 for the name of the desired field.

    if (attrDescriptor.getName().equalsIgnoreCase("MyDateFieldName")) {
    beginDate =(Date)((AttributeCriterion)criterion).getValues().get(0);
    endDate =(Date)((AttributeCriterion)criterion).getValues().get(1);
    }

    ReplyDelete
    Replies
    1. Thanks Natan but I didn't understand the code part
      Is this additional info when using between operator for dates ?

      Ashish

      Delete