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.

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

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