Monday May 21, 2012

Executing Put operation of REST service programatically from ADF App

In quite some cases, we would like to call the PUT method on a REST service by constructing the parameters during runtime and pass it on. In this article, we would go through how to deal with such cases when building an ADF Application.

Refer this tutorial for introduction to REST service in where, GET and DELETE methods are explained. In this sample, we'll see how to implement PUT operation using a HashMap. In fact, as like in the above tutorial, we can directly execute the PUT method as well. This article is mainly concentrated on how to construct the parameters dynamically at runtime.

First let us create a simple POJO to hold employee records.

package project1;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement

public class Emp {
    public Emp() {
        super();
    }
    
    private String name;
    private int id;
    private int exp;
    private int salary;

    public Emp(String name, int id, int exp, int salary) {
        super();
        this.name = name;
        this.id = id;
        this.exp = exp;
        this.salary = salary;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setId(int id) {
        this.id = id;
    }

    public int getId() {
        return id;
    }

    public void setExp(int exp) {
        this.exp = exp;
    }

    public int getExp() {
        return exp;
    }

    public void setSalary(int salary) {
        this.salary = salary;
    }

    public int getSalary() {
        return salary;
    }
    
    public String toString() {
        String empXml = "<name>"+getName()+"</name>"+"\n"+
                       "<id>"+getId()+"</id>"+"\n"+
                        "<experience>"+getExp()+"</experience>"+"\n"+
                       "<salary>"+getSalary()+"</salary>";
        return empXml;                  
    }
}
Then, create a REST service using the for the Employee.

package project1;

import javax.ws.rs.Path;
import java.util.*;

import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;

import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Response;

@Path("/test")
public class Service {
    
   static ArrayList<Emp> emp = new ArrayList<Emp>();
  
    public Service() {
        super();
     }
    
    @GET
    @Produces("application/xml")
    public  ArrayList<Emp> getEmps() {
       
        return emp;
        
    }
    
    @DELETE
    public void deleteEmp(@QueryParam("id") int id) {
       emp.remove(getObj(id));
    }
    
    @PUT
    @Consumes("application/xml")
    public void addEmp( Emp e) {
        emp.add(e);
    }
    
    @PUT
    @Path("defaultEmp")
    public Response addEmp() {
        emp.add(new Emp("abc",1,5,10000));
        emp.add(new Emp("xyz",2,7,15000));
        emp.add(new Emp("lmn",3,5,8000));
        return Response.ok().build();
            
    }
    
    @POST
    public void upadteEmp(@QueryParam("id")int id,Emp e) {
      deleteEmp(id);
      addEmp(e);
    }
    
    public Emp getObj(int id) {
        Iterator i = emp.iterator();
        while(i.hasNext()){
        Emp emp = (Emp)i.next();
        if((emp.getId())==id)
        {
            System.out.println(emp.getName());
            return emp;
        }
        } 
        return null;
    }
}

We'll come to the UI part now.

After creating a Fusion Web Application from JDeveloper, create a new URL Data Control for the REST service created above (for GET and PUT Operations).

DataControls.dcx looks like below

DataControls.jpg



Now, our aim is to have a UI, from where we can enter the employee details. Once after having the data, construct parameter object and execute loadData (PUT) method.

This is done by having 4 input texts and bind them to attributes in the backing bean. Drag and Drop the loadData method from RestPut DataControl (and do not specify a value for the parameter).



And the code snippet of the jspx page

<af:panelFormLayout id="pfl1">
    <f:facet name="footer">
        <af:commandButton text="Put"
          disabled="#{!bindings.loadData.enabled}" id="cb1"
          actionListener="#{pageFlowScope.RestBean.performPut}"/>
    </f:facet>
    <af:inputText label="Id" id="it1" 
                  value="#{pageFlowScope.RestBean.id}" autoSubmit="true"/>
    <af:inputText label="Name" id="it2" 
                  autoSubmit="true" value="#{pageFlowScope.RestBean.name}"/>
    <af:inputText label="Exp" id="it3" 
                  value="#{pageFlowScope.RestBean.exp}" autoSubmit="true"/>
    <af:inputText label="Sal" id="it4" 
                  autoSubmit="true" value="#{pageFlowScope.RestBean.sal}"/>
</af:panelFormLayout>

In the backing bean (RestBean), we have 4 attributes with accessors that are mapped to the Text Items.

    private Number id,sal,exp;
    private String name;


    public void setId(Number id) {
        this.id = id;
    }

    public Number getId() {
        return id;
    }

    public void setSal(Number sal) {
        this.sal = sal;
    }

    public Number getSal() {
        return sal;
    }

    public void setExp(Number exp) {
        this.exp = exp;
    }

    public Number getExp() {
        return exp;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }


Now, we'll add an actionListener code in the backing bean, in that, we can construct a Map with the required values and then execute the method by passing Map to it.

    public void performPut(ActionEvent actionEvent) {
        BindingContainer bindings = getBindings();
        Map putParamMap = new HashMap();
        putParamMap.put("id", getId());
        putParamMap.put("name", getName());
        putParamMap.put("exp", getExp());
        putParamMap.put("sal", getSal());

        OperationBinding operationBinding = bindings.getOperationBinding("loadData");
        operationBinding.getParamsMap().put("emp",putParamMap);
        Object result = operationBinding.execute();
        if (!operationBinding.getErrors().isEmpty()) {
            System.out.println("Error processing put operation..");    
        }
    }

    public BindingContainer getBindings() {
        return BindingContext.getCurrent().getCurrentBindingsEntry();
    }
In the above code, we find the loadData method from the DataBindings entry, create a Map with all the required attributes to create an Employee record, get the Parameter list for the method and pass the Map to method as parameter to execute it.


Thursday Dec 29, 2011

Business Rules Editor for View Objects in JDeveloper 11.1.2.0.0

JDeveloper 11.1.2.0.0 has a new tab in the View Objects Editor - Business Rules.
This easily tend to make people misunderstand that this Editor can be used for adding validation rules for the attributes in the View Object. However, it is not true.

Lets check out what this editor is all about. As the online help for this page states
Use to create and maintain business rules based on Groovy Language expressions and declarative validation rules for this view object including:

  • Validators for transient attributes
  • Bind variable default value expressions for SQL queries
  • Bind variable value mappings for view accessors
  • Transient attribute value expressions
  • Transient attribute value expression recalculation conditions
  • Attribute default value expressions

We'll see how we can use this editor to edit different types :

Transient Attributes : 

We can use this editor for a. adding validation rules, b. edit default value expression

a. As like the Entity Attributes, we can add many validation rules for the transient attributes in VO as well.

Ex.


In the above image, EmpType is a transient attribute on Emp VO.We can see there are two rules added. First one is a validation rule (List Validator), restricting the user to enter either one of the value specified for the attribute. Second one is the default value expression for the attribute. Upon selecting the node, the default value groovy expression would become editable in the Script Expression field below, wherein we can modify it and test the syntax as well.

Note : We can add the validation rule only for the transient attributes which are Updatable. Also, we can edit only the default values which are script expressions only. Not the literal values.

Bind Variables :

Similar to the transient attributes, we can use this editor for modifying and testing the default value expression for the Bind Variables of the VO as well.

Ex :



In the above example image, we can see a Bind Variable (Bind_Hiredate) added to the Query, which has the default value expression as adf.currentDate.

Using this editor, we can modify this expression and test the syntax.

View Accessor :

If we have a bind variable to the VO and use it as List Data Source for any of the attributes in the VO, we can use this editor to change the value of the bind variable in the View Accessor.

Ex :


In the above example image, we have couple of Bind Variables in the View Accessors (they are used as Lists and Dependent Lists for this View Object). Using this editor, we can edit the values of those bind variables.

We can also use this editor for modifying and testing the default value expression on the VO attributes and the re-calculation conditions.



Monday Dec 13, 2010

Getting all selected rows in ADF Table with multiple rows selection enabled

When we build a web application which contains an ADF Table (with multiselect option), in many cases, we require to get all the selected rows to process through backing bean. This example will illustrate how to achieve that.

Assuming that we already have an application, that contains an ADF Table with multi-selection enabled (i.e the web page look something like the image shown below).

empTableRT-thumb-301x302-20887.jpg

img empTableRT : Table based on Emp

To access the table in the backing bean (through command button click, for ex.), we add an attribute with accessors in the backing bean and bind it to ADF Table

    RichTable empTable;
    public void setEmpTable(RichTable empTable) {
        this.empTable = empTable;
    }

public RichTable getEmpTable() { return empTable; }

code snippet of the af:table in jspx page.

<af:table value="#{bindings.EmpView1.collectionModel}" var="row"
                  rows="#{bindings.EmpView1.rangeSize}"
                  emptyText="#{bindings.EmpView1.viewable ? 'No data to display.' : 'Access Denied.'}"
                  fetchSize="#{bindings.EmpView1.rangeSize}"
                  rowBandingInterval="0"
                  selectedRowKeys="#{bindings.EmpView1.collectionModel.selectedRow}"
                  selectionListener="#{bindings.EmpView1.collectionModel.makeCurrent}"
                  rowSelection="multiple" id="t1"
                  binding="#{backingBeanScope.EmpBean.empTable}">

Let us add a command button in the jspx page to print down the "Ename"s of selected rows.

<af:commandButton text="Print selected Emps" id="cb1" 
      action="#{backingBeanScope.EmpBean.printSelectedEmpNames}"/>

The method printSelectedEmpNames in the backing bean gets the selected row keys from the table, gets the corresponding Enames from the iterator (on which the table is based on) and prints them.
public String printSelectedEmpNames() {
        RowKeySet selectedEmps = getEmpTable().getSelectedRowKeys();    
        Iterator selectedEmpIter = selectedEmps.iterator();
        DCBindingContainer bindings =
                          (DCBindingContainer)BindingContext.getCurrent().getCurrentBindingsEntry();
        DCIteratorBinding empIter = bindings.findIteratorBinding("EmpView1Iterator");
        RowSetIterator empRSIter = empIter.getRowSetIterator();
         while(selectedEmpIter.hasNext()){
           Key key = (Key)((List)selectedEmpIter.next()).get(0);
           Row currentRow = empRSIter.getRow(key);
           System.out.println(currentRow.getAttribute("Ename"));
         }
         return null;
}

We run the page and click button to check the selected rows.

empTableMultiSelect-thumb-321x325-20890.jpg

As we've selected 7 rows, clicking on the "Print selected Emps" button is expected to print 7 Enames.

But..... It just prints only one Ename.

CLARK

Well, this is because of the selectedRowKeys property of the af:table. Let us try removing that and see if we get the expected output.

<af:table value="#{bindings.EmpView1.collectionModel}" var="row"
                  rows="#{bindings.EmpView1.rangeSize}"
                  emptyText="#{bindings.EmpView1.viewable ? 'No data to display.' : 'Access Denied.'}"
                  fetchSize="#{bindings.EmpView1.rangeSize}"
                  rowBandingInterval="0"
selectionListener="#{bindings.EmpView1.collectionModel.makeCurrent}" rowSelection="multiple" id="t1" binding="#{backingBeanScope.EmpBean.empTable}">

Now, when we run the page, select 7 rows and click on the print button, it prints out

JONES
ALLEN
CLARK
WARD
SMITH
MARTIN
BLAKE

That is what we expected. Now, the question is why this happens?. It is because, since value of this selectedRowKeys property is #{bindings.EmpView1.collectionModel.selectedRow}, the selectedRowKeys will contain only the "row which is selected last". By unsetting this attribute, we let the table to push all the selected rows to selectedRowKeys, which will help us during

getEmpTable().getSelectedRowKeys();

in the backing bean. JDeveloper automatically adds this property to the ADF Table when it is created by dragging from the data control. So, removing this property from the af:table would get us desired result.

[Read More]
About

Tips & Tricks from Arun on JDev ADF, Forms, SQL & PL/SQL.

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