Tuesday Feb 04, 2014

HTTP Basic Auth in REST Client

When a web service is secured using basic authentication, the client can access the web service only after providing the appropriate credentials.

In this blog, I take you through the code which will enable the client to access such a service.

Pre-requisites:

Use JDeveloper 12c  version or above.

Creating the Service:

Let us start by creating a REST service and securing it with basic authentication. 

For creating the service, please refer the section "Creating the service" in blog.

Basic Authentication setup:

Once the REST service has been created, in order to secure it using basic authentication, follow the below steps:

Open the web.xml file. At the end of the file, add the lines:

<login-config>
        <auth-method>BASIC</auth-method>
        <realm-name>myrealm</realm-name>
    </login-config>
    <security-constraint>
        <web-resource-collection> 
           <web-resource-name>MyResource</web-resource-name> 
           <url-pattern>/*</url-pattern> 
        </web-resource-collection> 
        <auth-constraint> 
           <role-name>MyRole</role-name> 
        </auth-constraint> 
    </security-constraint>
    <security-role> 
        <role-name>MyRole</role-name> 
    </security-role> 
</web-app>

Next, you need to create a weblogic.xml file. For this, go to New Gallery -> General -> Weblogic Deployment Descriptor.

weblogic xml file

On clicking Ok, another popup appears. Under Select Descriptor, select weblogic.xml and click Next. Select the deployment descriptor version in accordance with your weblogic version and then click Finish. This will generate a weblogic.xml file under WEB-INF. Open weblogic.xml file and select 'Security' from LHS. Under 'Security Role Assignments', add the Role Name 'MyRole', and add the Principals 'Administrators' as shown.

Configuring weblogic.xml file

At this point, your web service has been secured using basic authentication mechanism. Run the service and copy the generated WADL URL. This will be used to create the proxy for the service.

Accessing the service through REST Client:

First, to create the REST Client, create a new Custom Project.Let us name it ClientProj. Right click on the Project and invoke the New Gallery window. Under Business Tier -> Web services category, select REST Client and Proxy. Provide the generated WADL URL and click Next.

A prompt will appear asking for username/password.

Credential pop up

Provide the Administrator username and password that you would use to log into the WLS Console.On providing the correct credentials and clicking on Finish, the client class gets generated with some in-built code. Within the class 'Localhost_EmployeeServiceEmployeeProjContextRootResourcesClient.java' auto generated for you, write the following lines:


public class Localhost_EmployeeServiceEmployeeProjContextRootResourcesClient {
    public static void main(String[] args) {
        Client client = Localhost_EmployeeServiceEmployeeProjContextRootResources.createClient();

        Localhost_EmployeeServiceEmployeeProjContextRootResources.Employeeproj localhost_employeeserviceemployeeprojcontextrootresourcesemployeeproj =
            Localhost_EmployeeServiceEmployeeProjContextRootResources.employeeproj(client);
        
        // add your code here
        client.addFilter(new HTTPBasicAuthFilter("weblogic","weblogic1"));
        System.out.println(localhost_employeeserviceemployeeprojcontextrootresourcesemployeeproj.getAsXml(String.class));
    } 

Use the import as below:

import com.sun.jersey.api.client.filter.HTTPBasicAuthFilter;

We use the HTTPBasicAuthFilter provided by Jersey to pass the basic auth credentials. Refer link for more details.

Alternate method:

Alternately, within the public class Localhost_EmployeeServiceEmployeeProjContextRootResourcesClient.java auto generated for you, write the following lines:

public class Localhost_EmployeeServiceEmployeeProjContextRootResourcesClient {
    public static void main(String[] args) {
        Client client = Localhost_EmployeeServiceEmployeeProjContextRootResources.createClient();

        Localhost_EmployeeServiceEmployeeProjContextRootResources.Employeeproj localhost_employeeserviceemployeeprojcontextrootresourcesemployeeproj =
            Localhost_EmployeeServiceEmployeeProjContextRootResources.employeeproj(client);
        
        // add your code here
        Authenticator.setDefault(new MyAuthenticator());
        System.out.println(localhost_employeeserviceemployeeprojcontextrootresourcesemployeeproj.getAsXml(String.class));
    }
    
    static class MyAuthenticator extends Authenticator {    
        public PasswordAuthentication getPasswordAuthentication() {
                
        return (new PasswordAuthentication("weblogic", "weblogic1".toCharArray()));
            }
        } 

Use the imports:

import java.net.Authenticator;

import java.net.PasswordAuthentication;

Here, in the code block above, we basically extend the Authenticator class, and override the getPasswordAuthentication method, in which we pass the username and password. (Replace username and password above with the credentials you provided to create the client class)

In the main method, we then invoke the setDefault method of the Authenticator class and pass our Authenticator class name. This method will set the credentials whenever a proxy or HTTP server asks for authentication. The next two lines are for invoking a method of the service.

If you run the client code by supplying incorrect credentials, you will get a 401 Unauthorized error.

Wednesday Dec 18, 2013

Client Proxy Generation for REST style services

This blog mainly talks about generating a client for REST style web services. It begins by creating a REST style service and then consuming that service using some client code.

Pre-requisites:

Use JDeveloper 12c  version.

Creating the Service:

To start with, invoke the New Application wizard, and create a Custom application. Let us call the application EmployeeService and the Project, EmployeeProj. Next invoke the New Gallery window and create a Java class. Lets name the class Employee.java. [Refer Employee.java ].

Similarly, create another Java class and name it EmpService.java. [Refer EmpService.java]

Right click on EmpService.java and select Create RESTful Service. Under Configure HTTP methods, set the following:

Name

Type

Consumes

Produces

getEmpList

GET

Application/xml

addEmployee

PUT

Application/xml

Application/xml

deleteEmployee

DELETE

Under Configure Parameter: For name, select  Annotation - PathParam; Parameter - name

updateEmployee

POST

Application/json

Under Configure Parameter: For name, select  Annotation - PathParam; Parameter - name

Leave getEmp and addEmp methods. They will not be exposed.

createREST

Click on Finish. EmpService.java should now look like [FinalEmpService.java]. Now the web service is ready to use.

Run the web service and test the methods in HTTP Analyzer. Copy the generated WADL URL.

WADL URL

Creating the REST Proxy:

Next, to create the REST proxy, follow the steps mentioned below:

Create a new Custom Project. Let us name it ClientProj.  Right click on the Project and invoke the New Gallery window. Under Business Tier -> Web services category, select RESTful Client and Proxy.

In the Create REST Proxy Client dialog that appears, enter the WADL URL generated on running the service and click on Finish. 

The generated client will consist of some in-built code.

The auto generated code consists of 2 important public classes -

Localhost_EmployeeServiceEmployeeProjContextRootResourcesClient.java and 

Localhost_EmployeeServiceEmployeeProjContextRootResources.java.

The former class basically consists of a main() method using which we can readily invoke the REST service methods. The latter, i.e., Localhost_EmployeeServiceEmployeeProjContextRootResources.java consists of all the internal logic involved in invoking the methods and handling data.

This class has various methods which allow access to the web service methods. 

For example, to access the getEmpList() method of the service, normally, the code would look like:

Client client = Client.create();

WebResource service = client.resource(UriBuilder.fromUri("http://localhost:7101/REST_Sanity-Project1-context-root/resources/employeeproj").build());

System.out.println(service.accept(MediaType.APPLICATION_XML).get(String.class));

But, now we can use the auto generated class and methods to invoke the GET method as follows:

Open Localhost_EmployeeServiceEmployeeProjContextRootResourcesClient.java and add the following lines where it is written "//add your code here".

System.out.println(localhost_employeeserviceemployeeprojcontextrootresourcesemployeeproj.getAsXml(String.class));

The put method invocation would look like:

localhost_employeeserviceemployeeprojcontextrootresourcesemployeeproj.putXml("<?xml version = '1.0' encoding = 'UTF-8'?> <employee><id>2</id><name>Simon</name></employee>",String.class);

The delete method uses @PathParam in the service. So its invocation would be:

localhost_employeeserviceemployeeprojcontextrootresourcesemployeeproj.name("Simon").deleteAs(String.class);

Here localhost_employeeserviceemployeeprojcontextrootresourcesemployeeproj.name(..) returns an instance of the static Name class present within the Localhost_EmployeeServiceEmployeeProjContextRootResources class. Using that, you can then access the methods within the Name class.

Similarly, the post method can be invoked as:

localhost_employeeserviceemployeeprojcontextrootresourcesemployeeproj.name("Test").postAsJson(String.class);

Below is the complete main method:

public class Localhost_EmployeeServiceEmployeeProjContextRootResourcesClient {

public static void main(String[] args) {

Client client = Localhost_EmployeeServiceEmployeeProjContextRootResources.createClient();   Localhost_EmployeeServiceEmployeeProjContextRootResources.Employeeproj localhost_employeeserviceemployeeprojcontextrootresourcesemployeeproj = Localhost_EmployeeServiceEmployeeProjContextRootResources.employeeproj(client);

// add your code here

System.out.println("Put a new employee:" + localhost_employeeserviceemployeeprojcontextrootresourcesemployeeproj.putXml("<?xml version = '1.0' encoding = 'UTF-8'?> <employee><id>2</id><name>Simon</name></employee>", String.class)); localhost_employeeserviceemployeeprojcontextrootresourcesemployeeproj.name("Simon").deleteAs(String.class); System.out.println("Delete new employee:"+localhost_employeeserviceemployeeprojcontextrootresourcesemployeeproj.getAsXml(String.class)); System.out.println("After Post:" + localhost_employeeserviceemployeeprojcontextrootresourcesemployeeproj.name("Test").postAsJson(String.class));

}

[Refer Localhost_EmployeeServiceEmployeeProjContextRootResourcesClient.java ].

On running the client, the following output will be seen in the log:

ClientOutput

The first line of the output corresponds to Put operation. In the put operation, we enter a new employee, Simon's details and the XML data after this operation is shown in the output.

The next line shows the result of delete operation after deleting the employee with name "Simon".

This is followed by the result of post operation which is displayed in Json format. 

Monday Dec 16, 2013

XSLT Transformation in REST DC

Use Case:
This blog explains about applying XSLT transformation on a REST Service while creating the Rest DataControl. Here I will be explaining on how the data is getting manipulated and is rendered by the REST DC when XSL is applied on it.

JDeveloper Version used : 12.1.2

Steps:
1. Consider an Scenario where an REST Service API is retuning an XML response as mentioned below

<?xml version = '1.0' encoding = 'UTF-8' standalone = 'yes'?>
<departments>
   <department>
      <deptId>1001</deptId>
      <deptName>HumanResource</deptName>
   </department>
   <department>
      <deptId>2002</deptId>
      <deptName>Finance</deptName>
   </department>
   <department>
      <deptId>3003</deptId>
      <deptName>Research</deptName>
   </department>
   <department>
      <deptId>5005</deptId>
      <deptName>Sales</deptName>
   </department>
</departments>


2. Lets create an XSD structure to contain two more new attributes e.g CUSTOMNAME of type String and UNIQUEID of type integer

<?xml version="1.0" encoding="windows-1252" ?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
  <xsd:element name="departments">
    <xsd:complexType>
      <xsd:sequence>
        <xsd:element name="department" maxOccurs="unbounded">
          <xsd:complexType>
            <xsd:sequence>
              <xsd:element name="deptId" type="xsd:integer"/>
              <xsd:element name="deptName" type="xsd:string"/>
              <xsd:element name="customUniqueId" type="xsd:integer"/>
              <xsd:element name="customName" type="xsd:string"/>
            </xsd:sequence>
          </xsd:complexType>
        </xsd:element>
      </xsd:sequence>
    </xsd:complexType>
  </xsd:element>
</xsd:schema>

3. Now we have to create an XSL File to transform data , so that the values can be populated for the new attributes.

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0" xmlns:ns2="http://project1/">
    <xsl:template match="departments">
        <departments>
          <xsl:for-each select="department">
              <department>
                  <deptName><xsl:value-of select="deptName"/></deptName>
                  <deptId><xsl:value-of select="deptId"/></deptId>
                  <customName><xsl:value-of select="concat('CUST_',deptName)"/></customName>
                  <customUniqueId><xsl:value-of select="deptId * 2"/></customUniqueId>
              </department>      
          </xsl:for-each> 
        </departments>
    </xsl:template>
</xsl:stylesheet>

4. In Jdeveloper, invoke the WSDC wizard, select the type as REST, in the wizard provide the name for the DC and create the connection.



5. In the Next Step of the wizard, provide the resource path and the method name for the operation



6. In the Method Details Step of the wizard provide the Cutsom XSD and  XSL file for the method as shown below



7.  Click Next and Complete the Wizard, then Expand the DC palette to find the Structure as shown below



8. Drag and Drop the departmentNode onto the page as an ADF table and Run the page


9. Here we can observe the value being populated for the customUniqueId and customName as per the definition given in the XSL file

Thursday Oct 17, 2013

Simple GET operation with JSON data in ADF Mobile

Usecase:

This sample uses a RESTful service which contains a GET method that fetches employee details for an employee with given employee ID along with other methods. The data is fetched in JSON format.

This RESTful service is then invoked via ADF Mobile and the JSON data thus obtained is parsed and rendered in mobile in a table.

Prerequisite:

Download JDev build JDEVADF_11.1.2.4.0_GENERIC_130421.1600.6436.1 or higher with mobile support. 

Steps:

Run EmployeeService.java in JSONService.zip. This is a simple service with a method, getEmpById(id) that takes employee ID as parameter and produces employee details in JSON format. 

Copy the target URL generated on running this service. The target URL will be as shown below:

http://127.0.0.1:7101/JSONService-Project1-context-root/jersey/project1

Now, let us invoke this service in our mobile application. For this, create an ADF Mobile application. 

Gallery

Name the application JSON_SearchByEmpID and finish the wizard.

appName

Now, let us create a connection to our service. To do this, we create a URL Connection. Invoke new gallery wizard on ApplicationController project. 

newGallery

Select URL Connection option.

urlConn

In the Create URL Connection window, enter connection name as ‘conn’. For URL endpoint, supply the URL you copied earlier on running the service. Remember to use your system IP instead of localhost. Test the connection and click OK.

conn

At this point, a connection to the REST service has been created.

Since JSON data is not supported directly in WSDC wizard, we need to invoke the operation through Java code using RestServiceAdapter. For this, in the ApplicationController project, create a Java class called ‘EmployeeDC’. We will be creating DC from this class.

javaclass

Add the following code to the newly created class to invoke the getEmpById method.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

public Employee fetchEmpDetails(){

RestServiceAdapter restServiceAdapter = Model.createRestServiceAdapter();

restServiceAdapter.clearRequestProperties();

restServiceAdapter.setConnectionName("conn"); //URL connection created with this name

restServiceAdapter.setRequestType(RestServiceAdapter.REQUEST_TYPE_GET);

restServiceAdapter.addRequestProperty("Content-Type", "application/json");

restServiceAdapter.addRequestProperty("Accept", "application/json; charset=UTF-8");

restServiceAdapter.setRetryLimit(0);

restServiceAdapter.setRequestURI("/getById/"+inputEmpID);

String response = "";

JSONBeanSerializationHelper jsonHelper = new JSONBeanSerializationHelper();

try {

response = restServiceAdapter.send(""); //Invoke the GET operation

System.out.println("Response received!");

Employee responseObject = (Employee) jsonHelper.fromJSON(Employee.class, response);

return responseObject;

} catch (Exception e) {

}

return null;

}

Here, in lines 2 to 9, we create the RestServiceAdapter and set various properties required to invoke the web service. At line 4, we are pointing to the connection ‘conn’ created previously.

Since we want to invoke getEmpById method of the service, which is defined by the URL

http://IP:7101/REST_Sanity_JSON-Project1-context-root/resources/project1/getById/{id}

we are updating the request URI to point to this URI at line 9. inputEmpID is a variable that will hold the value input by the user for employee ID. This we will be creating in a while.

As the method we are invoking is a GET operation and consumes json data, these properties are being set in lines 5 through 7. Finally, we are sending the request in line 13.

In line 15, we use jsonHelper.fromJSON to convert received JSON data to a Java object. The required Java objects' structure is defined in class Employee.java whose structure is provided later. Since the response from our service is a simple response consisting of attributes like employee Id, name, design etc, we will just return this parsed response (line 16) and use it to create DC.

As mentioned previously, we would like the user to input the employee ID for which he/she wants to perform search. So, in the same class, define a variable inputEmpID which will hold the value input by the user. Generate accessors for this variable.

accessor

Lastly, we need to create Employee class. Employee class will define how we want to structure the JSON object received from the service. To design the Employee class, run the services’ method in the browser or via analyzer using path parameter as 1. This will give you the output JSON structure.

jsonOutput

Ours is a simple service that returns a JSONObject with a set of data. Hence, Employee class will just contain this set of data defined with the proper data types.

Create Employee.java in the same project as EmployeeDC.java and write the below code:

package application;

import oracle.adfmf.java.beans.PropertyChangeListener;

import oracle.adfmf.java.beans.PropertyChangeSupport;

public class Employee {

private String dept;

private String desig;

private int id;

private String name;

private int salary;

private PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(this);

public void setDept(String dept) {

        String oldDept = this.dept;

this.dept = dept;

propertyChangeSupport.firePropertyChange("dept", oldDept, dept);

}

public String getDept() {

return dept;

}

public void setDesig(String desig) {

String oldDesig = this.desig;

this.desig = desig;

propertyChangeSupport.firePropertyChange("desig", oldDesig, desig);

}

public String getDesig() {

return desig;

}

public void setId(int id) {

int oldId = this.id;

this.id = id;

propertyChangeSupport.firePropertyChange("id", oldId, id);

}

public int getId() {

return id;

}

public void setName(String name) {

String oldName = this.name;

this.name = name;

propertyChangeSupport.firePropertyChange("name", oldName, name);

}

public String getName() {

return name;

}

public void setSalary(int salary) {

int oldSalary = this.salary;

this.salary = salary;

propertyChangeSupport.firePropertyChange("salary", oldSalary, salary);

}

public int getSalary() {

return salary;

}

public void addPropertyChangeListener(PropertyChangeListener l) {

propertyChangeSupport.addPropertyChangeListener(l);

}

public void removePropertyChangeListener(PropertyChangeListener l) {

propertyChangeSupport.removePropertyChangeListener(l);

    }

}

Now, let us create a DC out of EmployeeDC.java.

createDC

 DC as shown below is created.

DC

Now, you can design the mobile page as usual and invoke the operation of the service. To design the page, go to ViewController project and locate adfmf-feature.xml. Create a new feature called ‘SearchFeature’ by clicking the plus icon.

feature

Go the content tab and add an amx page. Call it SearchPage.amx.

createPage

Call it SearchPage.amx. Remove primary and secondary buttons as we don’t need them and rename the header.

preview

Drag and drop inputEmpID from the DC palette onto Panel Page in the structure pane as input text with label.

inputText

Next, drop fetchEmpDetails method as an ADF button.

fetchButton

For a change, let us display the output in a table component instead of the usual form. However, you will notice that if you drag and drop Employee onto the structure pane, there is no option for ADF Mobile Table. Hence, we will need to create the table on our own.

To do this, let us first drop Employee as an ADF Read -Only form. This step is needed to get the required bindings. We will be deleting this form in a while.

form

finalPage

Now, from the Component palette, search for ‘Table Layout’. Drag and drop this below the command button. 

table tableStructure

Within the tablelayout, insert ‘Row Layout’ and ‘Cell Format’ components. Final table structure should be as shown below. Here, we have also defined some inline styling to render the UI in a nice manner.

<amx:tableLayout id="tl1" borderWidth="2" halign="center" inlineStyle="vertical-align:middle;"

width="100%" cellPadding="10">

<amx:rowLayout id="rl1" >

<amx:cellFormat id="cf1" width="30%">

<amx:outputText value="#{bindings.dept.hints.label}" id="ot7" inlineStyle="color:rgb(0,148,231);"/>

</amx:cellFormat>

<amx:cellFormat id="cf2">

<amx:outputText value="#{bindings.dept.inputValue}" id="ot8" />

</amx:cellFormat>

</amx:rowLayout>

<amx:rowLayout id="rl2">

<amx:cellFormat id="cf3" width="30%">

<amx:outputText value="#{bindings.desig.hints.label}" id="ot9" inlineStyle="color:rgb(0,148,231);"/>

</amx:cellFormat>

<amx:cellFormat id="cf4" >

<amx:outputText value="#{bindings.desig.inputValue}" id="ot10"/>

</amx:cellFormat>

</amx:rowLayout>

<amx:rowLayout id="rl3">

<amx:cellFormat id="cf5" width="30%">

<amx:outputText value="#{bindings.id.hints.label}" id="ot11" inlineStyle="color:rgb(0,148,231);"/>

</amx:cellFormat>

<amx:cellFormat id="cf6" >

<amx:outputText value="#{bindings.id.inputValue}" id="ot12"/>

</amx:cellFormat>

</amx:rowLayout>

<amx:rowLayout id="rl4">

<amx:cellFormat id="cf7" width="30%">

<amx:outputText value="#{bindings.name.hints.label}" id="ot13" inlineStyle="color:rgb(0,148,231);"/>

</amx:cellFormat>

<amx:cellFormat id="cf8">

<amx:outputText value="#{bindings.name.inputValue}" id="ot14"/>

</amx:cellFormat>

</amx:rowLayout>

<amx:rowLayout id="rl5">

<amx:cellFormat id="cf9" width="30%">

<amx:outputText value="#{bindings.salary.hints.label}" id="ot15" inlineStyle="color:rgb(0,148,231);"/>

</amx:cellFormat>

<amx:cellFormat id="cf10">

<amx:outputText value="#{bindings.salary.inputValue}" id="ot16"/>

</amx:cellFormat>

</amx:rowLayout>

    </amx:tableLayout>

The values used in the output text of the table come from the bindings obtained from the ADF Form created earlier. As we have used the bindings and don’t need the form anymore, let us delete the form. 

tableImg

One last thing before we deploy. When user changes employee ID, we want to clear the table contents. For this we associate a value change listener with the input text box.

valChange

Click New in the resulting dialog to create a managed bean.

valChangeDialog managedBean

Next, we create a method within the managed bean. For this, click on the New button associated with method. Call the method ‘empIDChange’.

newMethod empIDChange

Open myClass.java and write the below code in empIDChange().

public void empIDChange(ValueChangeEvent valueChangeEvent) {

// Add event code here...

//Resetting the values to blank values when employee id changes

AdfELContext adfELContext = AdfmfJavaUtilities.getAdfELContext();

ValueExpression ve = AdfmfJavaUtilities.getValueExpression("#{bindings.dept.inputValue}", String.class);

ve.setValue(adfELContext, "");

ve = AdfmfJavaUtilities.getValueExpression("#{bindings.desig.inputValue}", String.class);

ve.setValue(adfELContext, "");

ve = AdfmfJavaUtilities.getValueExpression("#{bindings.id.inputValue}", int.class);

ve.setValue(adfELContext, "");

ve = AdfmfJavaUtilities.getValueExpression("#{bindings.name.inputValue}", String.class);

ve.setValue(adfELContext, "");

ve = AdfmfJavaUtilities.getValueExpression("#{bindings.salary.inputValue}", int.class);

ve.setValue(adfELContext, "");

}

That’s it. Deploy the application to android emulator or device. Some snippets from the app.

Snapshot1 Snapshot2

Monday Oct 07, 2013

XML Parsing in ADF Mobile

Usecase:

In this usecase, we have a web service that returns employee details(like name, designation, salary etc.) for an employee with given ID. In the mobile app, we will be calculating tax on the returned salary and displaying it to the user in a pop-up.

To do this, we will be parsing the returned XML to fetch the current salary and add a tax of 5% on it.

Here, we are assuming that tax is 5% of the current salary.

Steps:

Run EmployeeService.java in RESTApp.zip. Copy the target URL. 

Create a new ADF Mobile application. 

Name the application ‘XmlParsingSample’ and finish the wizard.

Create a URL Connection in the ApplicationController project.

Name the connection ‘conn’ and suppy the target URL copied earlier. Remember to use IP instead of localhost. Test the connection and click OK to close the wizard.

Since the service returns XML data, also create a Data control. This will be useful for designing the UI page. To create DC, invoke URL Service data control wizard in the ApplicationController project.

Test the URL connection in the last step and finish the wizard.

Now, let us create the AMX pages. Open adfmf-feature.xml present in ViewController project. Add a new feature ‘EmpFeature’ by clicking the plus icon as shown.

Go to the content tab and add an AMX page.

Call it EmpPage.amx. We don’t need the primary and secondary actions. So, uncheck them.

Drag and drop ‘id’ parameter from the DC palette onto the Panel Page of the Structure pane for this page.

Drag and drop a button from the component palette onto the page. Change the text of the button to ‘Get salary’.

As we want to invoke the service on click of this button, let us associate an ActionListener with this. Focus on the button and from the PI, select the arrow button for Action Listener propery and click Edit to bring up the below dialog. Click New to create a new managed bean.

Name the manged bean as  myBean and class as myClass.

Next, create a new method called calculateTax.

Go to myClass.java. In calculateTax method, write the code provided in the below table. Use the imports:

import oracle.adfmf.amx.event.ActionEvent;

import oracle.adfmf.dc.ws.rest.RestServiceAdapter;

import oracle.adfmf.framework.api.AdfmfContainerUtilities;

import oracle.adfmf.framework.api.Model;

import org.xmlpull.v1.XmlPullParser;

import org.kxml2.io.KXmlParser;

import java.io.Reader;

import java.io.StringReader;

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.

31.

32.

33.

34.

35.

36.

37.

38.

39.

40.

41.

42.

43.

44.

45.

46.

47.

48.

49.

50.

public void calculateTax(ActionEvent actionEvent) {

// Add event code here...

RestServiceAdapter restServiceAdapter = Model.createRestServiceAdapter();

restServiceAdapter.clearRequestProperties();

restServiceAdapter.setConnectionName("conn");

restServiceAdapter.setRequestType(RestServiceAdapter.REQUEST_TYPE_GET);

restServiceAdapter.addRequestProperty("Content-Type", "application/xml");

restServiceAdapter.addRequestProperty("Accept", "application/xml; charset=UTF-8");

restServiceAdapter.setRetryLimit(0);

Object emppIDObj = AdfmfJavaUtilities.evaluateELExpression("#{bindings.id.inputValue}");

String empIDString = emppIDObj.toString();

restServiceAdapter.setRequestURI("/byID?id="+empIDString);

String response = "";

try {

response = restServiceAdapter.send("");

System.out.println("Response received!");

String name = "";

int sal = 0;

int salAfterTax = 0;

KXmlParser parser = new KXmlParser(); //create a parser instance

Reader stream = new StringReader(response);

parser.setInput(stream);

parser.nextTag();

parser.require(XmlPullParser.START_TAG, null, "employee");

while (parser.nextTag() != XmlPullParser.END_TAG) { //loop through until you encounter an end tag

parser.require(XmlPullParser.START_TAG, null, null); //go to start tag

String tagName = parser.getName(); //get the name of the current tag

String tagValue = parser.nextText(); //get the value within the current tag

if (tagName.equals("name")) { //if current tag is ‘name’, assign its value to variable ‘name’

name = tagValue;

}

if (tagName.equals("salary")) { //if current tag is ‘salary’, calculate salary after tax

System.out.println("Salary:" + tagValue);

sal = Integer.parseInt(tagValue);

salAfterTax = (int)(sal - sal * 0.05);

}

parser.require(XmlPullParser.END_TAG, null, tagName); //go to end tag of current tag

//parse through all the tags

}

parser.require(XmlPullParser.END_TAG, null, "employee");

parser.next();

parser.require(XmlPullParser.END_DOCUMENT, null, null);

AdfmfContainerUtilities.invokeContainerJavaScriptFunction("EmpFeature", "navigator.notification.alert",

new Object[] { "Salary for employee " + name +

" is " + sal +

". After tax deduction, salary is:" +

salAfterTax, "", "Note", "OK!" });

} catch (Exception e) {

System.out.println("Exception is:" + e);

}

}

}

 Lines 3 to 15 set various properties required to invoke the web service. In lines 10 and 11, we are getting the value input by the user and converting that to String inorder to pass the parameter to the service. In line 20, we are creating a kXml parser instance. kXML is one of the core ADF Mobile libraries that provides API that you can use to parse XML. As the parser needs a Reader object, we are converting our services’ response into Reader in line 21 and passing it in line 22.

 The response returned by our service is of the form

<?xml version="1.0" encoding="UTF-8"?>
<employee>
<dept>HR</dept>
<desig>Officer</desig>
<id>2</id>
<name>Myra</name>
<salary>70000</salary>
</employee>

To parse this response, we are setting the parser to the first tag ‘employee’ in line 24. In lines 25 through 42, we are going through the XML elements. The comments are in-line for these lines. Finally, lines 43 through 47 are for displaying the pop-up. To display the pop-up, we are utilizing AdfmfContainerUtilities.invokeContainerJavaScriptFunction. For more information, see link.

As mentioned in the article, we make use of the javascript function which comes from phonegap-1.0.0.js. Hence, we need to include an entry to this javascript file in our AMX page. Put the below entry in EmpPage.amx above the panelPage.

<script type = "text/javascript" charset="utf-8" src="../../../www/js/phonegap-1.0.0.js"></script>

That’s it. Deploy the app to a device or an emulator. Some snippets from the final app. 

Enjoy coding! 

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.


About

Tips and Tricks from Oracle's JDeveloper & ADF QA

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