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! 

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