Wednesday, May 22, 2013

ADF ViewLink - Cardinality & Accessor

Oracle ADF view links are business components that defines a relationship between two ADF view objects . when we say relationship between two ADF view objects and it is obvious it can be used in Master-Detail data representation . For more info on Master-Detail relationship ADF Master - Detail Relationship .

In general view objects contains query that queries the database and view link will relate those queries using where clause.

For ex :  you want to render  employees based on department as a master - child ..



View Link = DepartmentsVO --> EmployeesVO

select DepartmentId from DepartmentsVO and DepartmentId from EmployeesVO and the click Add . Let cardinality be 1 to * [ Means : One department can contain many employees ] This cardinality will have an impact in the accessor generation .

In the next step
























Generate Accessor :

 By default Destination Accessor , In View Object  : DepartmentsVO check box ll be selected . we will check the In View Object  : Employees VO in the Source Accessor.  This will add some code in both the VO Row Impl class .

 DepartmentsVO :

    public RowIterator getEmployeesVO() {
        return (RowIterator)getAttributeInternal(EMPLOYEESVO);
    }


Employees VO :

    public Row getDepartmentsVO() {
        return (Row)getAttributeInternal(DEPARTMENTSVO);
    }



The cardinality is 1 to * [1 to Many ] so ideally a department can be able to get all employees in it and tats why it has an accessor defined in its  DepVORowImpl class with return type Row Iterator . And the accessor in EmpVORowImpl will return a single row (as an employee can be in only one dept )

If the cardinality is 1 to 1  > Both the class will have a return type Row as it says 1 to 1 .

you can use these methods as Groovy expressions to get values in the ADF BC attribute level and in AM Impl class..

 

Monday, May 13, 2013

ADF DataControl Built-in View Operations - Part II

Followed from ADF Data Control built-in view operations I .

1) Execute :

      It will execute the View Object's Query . It Refreshes the data collection . This is similar to
      vo.executeQuery();

2) ExecuteWithParameters :

     This operation appears only for ADF view objects that have defined one or more bind variables . This  will also execute the view object with the parameter values being passed to the bind variables .

3) setCurrentRowWithKey :

    If ever want to avoid the default selected row of view object and set an any other row as current row , you can do this using setCurrentRowWithKey . Every row in the view object will have a String representation that uniquely identifies a particular row and using that string being passed as a parameter to rowset. If found set that as current row .

Note :  This Method will work only on the collection that has only one key attribute.

3) setCurrentRowWithKeyValue :

          This takes the value for a key attribute , if found set that as current row.

you can access the value of the string key of  a row  by using  rowKeyStr property  (e g:#{row.rowKeyStr})

4) removeRowWithKey :

      If ever want to delete a particular row you can remove that row using removeRowWithKey. The delete operation can be used to delete rows but it will always delete the current row.
  







ADF DataControl Built-in View Operations - Part I

Every view object instance added to ADF AM data model appears in the Data Controls panel. The attributes in the view object will also be displayed under the corresponding data control view object . Along with it, there are many Built-in view object operations available .Lets see each one of them with an example.

Data Control View object operations

you can drag and drop operations on to the UI page as a ADF Link /ADF Button and with the available options .

Drag and Drop the Employee Data control on to the UI page as ADF Table .

1) Create and CreateInsert :

I have quite a big story to explain and how did i understood this . I have dragged and dropped EmpVO1(Employee VO data control ) on to the page as ADF Table and as ADF Form . I have also dragged and dropped Create and CreateInsert operations as ADF Link . See the below image

Create will creates a new row but does not insert it . But what does it mean , it creates but does not insert ?
Yes.... Create will just open a slot . Row will be initialized. But it does not insert a row .

see this code :

vo.insertRow(row); // This is how insertion happens . In the case of Create , this will not be invoked

Create will just initialize a row whereas CreateInsert initialize the row as well as insert row.  Look at the image , when we click CreateInsert a new blank row is being created and displayed in the ADF table as well as in ADF Form. CreateInsert will work in ADF Form component and ADF Table

Create will work only on ADF Form component.
When we click Create , new row added being displayed ADF Form component and not to ADF Table


OK.. we can directly use CreateInsert instead of Create. why confuse? There are situations we need to bulk insert or selective insert based on the user choice .
Remember operation carried by 'Create' is not part of transaction so need not to be roll backed when don't want commit the new rows . when a row is marked as initialized it will be removed from Transaction pending changes.The new row which is initialized with any default values that the underlying EO has defined. If the user never enters any data , then it means no row is being created logically. .no worries during commit time

Just to check this, write a custom method and bind it to the both the links. Look at the snippet .

<af:commandLink actionListener="#{backingBeanScope.DCOperations.onCreate}" text="Create"
                    disabled="#{!bindings.Create.enabled}" id="cl1"/>
 <af:commandLink actionListener="#{backingBeanScope.DCOperations.onCreateIns}"
                    text="CreateInsert"
                    disabled="#{!bindings.CreateInsert.enabled}" id="cl2"/>

I have made action listener of both the links pointing to a custom method .



After clicking the Create link in the UI when u check the output  row count before and after will be the same. But in CreateInsert , row count will not be same and it will be +1 always compare to the before row count because it  has already inserted  a row in the iterator.

When u want to remove a row once CreateInsert is made , u need to rollback and careful what you are removing because CreateInsert operation is part of transaction.

Finally the difference between Create and CreateInsert is : User can just navigate away from the page without worrying about the created row in Create operation. User has to justify the created row  because it is already inserted in the iterator and a part of transaction too..  Another important case is , difference between two really matters if it is ADF Table.

2) Create with Parameters :

            It creates a new row  accepting parameter values.

3) First,Last,Next :

           Sets the current row to the First,Last,Next row in the rowset.

4) Next and Previous Set :

       Sets the set of rows forward to one set and backwards (i.e) previous.


Thursday, May 9, 2013

Programmatically Accessing ADF Application Module in Java

Oracle ADF Application Modules are business components . The ADF Application module contains data models that is nothing but the ADF view object instances  as well as view link instances. Lets see an use case where we need to execute a view object pragmatically  without having the binding context . There are times when we need to write a custom method and run that method that is dependent on a view object in turn is a part of ADF application module.

The Following two screen shots shows you the application module configuration which we will be referring to see the package name of the Application Module under General section and Configuration from Configurations section.






















Now lets see the code snippet :



Access ADF Bindings from Managed Bean

ADF enables bindings through Oracle ADF Model layer. whenever ADF view layer is created JDeveloper creates data bound client and thus enable the bridge between model and view components to access data .In some cases we may want to access page bindings Programatically from managed bean . Lets see how it can be done.

Look at the screen shot of the page bindings section of a jsff page.


When u drag and drop employee data control on to the page, Bindings section will contain the data control instance and executable section contains Employee Iterator .  For more on information on page bindings ADF Page Bindings .

Now lets see how we can access table bindings from Managed Bean . The Code to access



The same way we can get Iterator bindings too ..

 

Execution of Operation binding

 

There are many other bindings exists in ADF and we can access it all via java code.


Monday, May 6, 2013

ADF Select Many Listbox / Select Many Checkbox LOV


Few days back ,I was looking for an inbuilt feature of multi-select LOV in ADF and was quite surprised that ADF does not have this feature as a part of available LOV bindings.We cannot bind the LOV's to a selectManyListBox directly.To Achieve this we need to use a managed bean to dispatch between the ADF binding layer and the multi select component.The ADF selectManyListbox component allows the user to select many values from a list of items. It can contain any number of <f:selectitem>, <f:selectitems>, or <af:selectitem> components, each of which represents an available option that the user may select.

A typical ADF Multi select LOV looks like this :

<af:selectmanylistbox required="yes" value="#{bean.aValue}">
  <f:selectitem itemlabel="Option1" itemvalue="1">
  <f:selectitem itemlabel="Option1" itemvalue="2">
</f:selectitem></f:selectitem></af:selectmanylistbox>


Step 1 :

 1) Prepare a List of items that your Multi select LOV holds in a Managed Bean.The SelectManyListbox and -Choice value property writes/reads its value to/from a List (e.g. ArrayList)



2) Drag and drop the selectManyListbox component from Jdev Component palette on to the page and bind it to the list created above from managed bean. After creating list it should look like below code .Also create an another list with getters and setters in the managed bean and bind to the value property of af:selectManyListbox manually.

  <af:selectManyListbox label="Label 1" id="sml1"
                              value="#{backingBeanScope.MultiSelect.lovValue}">
          <f:selectItems
                         id="si2"
                         value="#{backingBeanScope.MultiSelect.actualList}"/>
  </af:selectManyListbox>




Now create an ADF button and action listener to a custom method in the managed bean.Inside the method write this code and you ll get the values which are being selected/checked by the user.



Input screen :





















After checking the required value click the commandbutton and in the jdev console you will see the output like this

Selected Value:ACTIVE
Selected Value:COMPLETED

All you need to do is when the getter is called you make sure the data is read from where it is created .when you write back take the list transform its entries in to the way you want. some may want to create comma delimited list of string,semi-colon separated ,individual strings which they want to store in DB .

ADF currently doesn't support binding the selectManyListBox value to the VO attribute directly this is the approach that I have followed as workaround!!

Sunday, May 5, 2013

Programatic handle to ADF Query Component - Add View Criteria dynamically

we have already seen how to get handle to the query event : http://howtolearnadf.blogspot.in/2013/05/programatic-handle-to-adf-query.html . with this , we move ahead and add a view criteria dynamically to the query event .

Sometimes we may want to validate the query input and based on it we want to add an another criteria. For example :  If the employe id is greater than 100 then add one more criteria which is not a part of ADF view criteria which was created in the adf vo. Lets see the snippet

public void onSearch(QueryEvent queryEvent) {

        String  EmployeeId = null;
      
        // Query Event is delivered when a query action is triggered
        QueryDescriptor qd = queryEvent.getDescriptor();
       
        // This line will represent group of criterion objects
        ConjunctionCriterion conCrit = qd.getConjunctionCriterion();
       
        //access the list of all search fields
        List<Criterion> criterionList = conCrit.getCriterionList();

        for (Criterion criterion : criterionList) {
            AttributeDescriptor attrDescriptor = ((AttributeCriterion)criterion).getAttribute();

            if (attrDescriptor.getName().equalsIgnoreCase("EmployeeId")) { // EmployeeId is one of the query items in the search pane
                EmployeeId  =  (String)((AttributeCriterion)criterion).getValues().get(0);
               //This is how we will access the query field
                System.out.println("EmployeeId :" + EmployeeId );

            }
        }

        DCBindingContainer bc =
            (DCBindingContainer)BindingContext.getCurrent().getCurrentBindingsEntry();
        ViewCriteria vc = getViewCriteria(bc, qd);

    System.out.println("View Object"+ vc.getViewObject);

  
         if (EmployeeId > 100 )
        {
             ViewObject vo  = vc.getViewObject();
              // since we are adding one more vc, we cant invoke querylistener and run it.
             vo.applyViewCriteria(vc,true);
             ViewCriteria vc1 = vo.createViewCriteria();
             ViewCriteriaRow vcr = vc1.createViewCriteriaRow();
             vcr.setAttribute("salary", "109090"); // This is not part of VC created at VO
       
            vc1.add(vcr);

            //This will append the newly created ADF vc to VO along with the VC created in the query event
            vo.applyViewCriteria(vc1,true);
               
           vo.executeQuery();

       }
        
       else
      {
      //Execute the query Listener using EL. This will execute the query component .If u see the exp , this    was  initially applied to QueryListener.. Later we assigned QueryListener to our custom method.
     
       invokeMethodExpression("#{bindings.VOCriteriaQuery.processQuery}", queryEvent);
      } 


       
    }

Friday, May 3, 2013

Programatic handle to ADF Query Component - see Query Input values


You can create ADF Query search forms that will allow users to search based on some input fields. The results of the query can be displayed as ADF Table , form or any other ADF UI Component . In general search forms are based on af:query and af:quickquery components.


ADF Search forms are based on view criteria defined at ADF VO level or implicit view criteria defined by the framework . Once you define the View criteria ,drag and drop it from the data control palette on the the page as ADF Query pane with table . ADF will take care of the rest of the things. Everything will be configured on its own ranging from search button binding  to the particular model and to the table which is being refreshed whenever results are being fetched .

Suppose we may want to modify the query values / see the current query values / validate the user input . we will see how to get handle to the ADF Query component to do this .


you will see the ADF:Query pane code in the page like this :

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

queryListener having an expression that deals with invoking of corresponding binding dynamically. In order to get handle to this component we will write our custom method and bind it to the queryListener.

After modifying it looks like queryListener="#{backingBeanScope.managedBean1.onSearch}"

 The Below custom method will tell you everything in clear

  public void onSearch(QueryEvent queryEvent) {
       
        String EmployeeId = null;
        // Query Event is delivered when a query action is triggered
        QueryDescriptor qd = queryEvent.getDescriptor();
       
        // This line will represent group of criterion objects
        ConjunctionCriterion conCrit = qd.getConjunctionCriterion();
       
        //access the list of all search fields
        List<Criterion> criterionList = conCrit.getCriterionList();

        for (Criterion criterion : criterionList) {
            AttributeDescriptor attrDescriptor =  ((AttributeCriterion)criterion).getAttribute();

            if (attrDescriptor.getName().equalsIgnoreCase("EmployeeId")) { // EmployeeId is one of the query items in the search pane
             EmployeeId  =  (String)((AttributeCriterion)criterion).getValues().get(0);
             
            //This is how we will access the query field
             System.out.println("EmployeeId :" + EmployeeId );

            }
        }


        DCBindingContainer bc =
            (DCBindingContainer)BindingContext.getCurrent().getCurrentBindingsEntry();
        ViewCriteria vc = getViewCriteria(bc, qd);

    System.out.println("View Object"+ vc.getViewObject);

    //Execute the query Listener using EL. This will execute the query component .If u see the exp , this was initially applied to QueryListener.. Later we assigned QueryListener to our custom method.
     
   invokeMethodExpression("#{bindings.VOCriteriaQuery.processQuery}", queryEvent); 
       
    }
    
      //helper method to execute the QueryListener EL

       private void invokeMethodExpression(String expr, QueryEvent queryEvent) {
        FacesContext fctx = FacesContext.getCurrentInstance();
        ELContext elContext = fctx.getELContext();
        ExpressionFactory eFactory =
            fctx.getApplication().getExpressionFactory();
        MethodExpression mexpr =
            eFactory.createMethodExpression(elContext, expr, Object.class,
                                            new Class[] { QueryEvent.class });
        mexpr.invoke(elContext, new Object[] { queryEvent });
    }
 


    private ViewCriteria getViewCriteria(DCBindingContainer bc,
                                         QueryDescriptor qd) {

        Object execBinding =  bc.findExecutableBinding("VOCriteriaQuery"); // This will be seen in the page executable section as we have dropped for af:query
        ViewCriteria vc =
            JUSearchBindingCustomizer.getViewCriteria((DCBindingContainer)execBinding,
                                                      qd.getName());
        return vc;

    }