Posts tonen met het label web service. Alle posts tonen
Posts tonen met het label web service. Alle posts tonen

woensdag 2 maart 2011

How to create web service based ADF pages

Technology: ADF11g
Developed in: JDeveloper 11.1.1.3.0
Used database schema: none


Summary

In this blog a solution is provided how to create a web service client. This blog is part of a sequence of 3 blogs:
  • How to create a RESTful web service that returns objects
  • How to create a web service client
  • How to create web service based ADF pages
I choose for a solution that:
  • Works for SOAP and RESTful web services
  • The location of the web service host can be changed while running the web service
Especially changing the host was an important criteria for me. For development I would like to use a development webservice and for production of course a production server.

The solution is build into my existing demo ADF application.

Step 1

Create a Common (generic) project in the demo ADF application add the following libraries:
  • BC4J Oracle Domains
  • Oracle JDBC
  • JSF 1.2
  • Commons Logging 1.0.4
And add the HrWebServiceClient.jar created in the ‘How to create a web service client’ blog.

Open the project properties of the Model project and set the dependency to the Common project:



Open the project properties of the ViewController project and also set the dependency to the Common project.

Step 2

In the Common project a basic view object implementation is created that will be used for all web service based view objects.

The class contains converters that converts Oracle data types to Java data types, it sets the end point based on the information of the web.xml (in the ViewController project) and has methods to execute the webservice.

Create a abstract java class WsViewObjectImpl which extends ViewObjectImpl. The implementation:

package nl.hr.demo.model.common;



import java.sql.ResultSet;

import java.sql.SQLException;

import java.sql.Timestamp;

import java.util.Iterator;

import java.util.List;

import javax.faces.context.FacesContext;

import oracle.jbo.server.ViewObjectImpl;

import oracle.jbo.server.ViewRowImpl;

import oracle.jbo.server.ViewRowSetImpl;



public abstract class WsViewObjectImpl extends ViewObjectImpl {

public WsViewObjectImpl() {

super();

}



protected String getWSBaseURL() {

return FacesContext.getCurrentInstance().getExternalContext().getInitParameter("wsBaseURL");

}



protected oracle.jbo.domain.Date toOracleDate(java.util.Calendar calendar) {

oracle.jbo.domain.Date jboDate = new oracle.jbo.domain.Date();

Timestamp t = jboDate.timestampValue();

t.setTime(calendar.getTime().getTime());

return new oracle.jbo.domain.Date(t);

}

protected oracle.jbo.domain.Number toOracleNumber(int i) {

return new oracle.jbo.domain.Number(i);

}

protected oracle.jbo.domain.Number toOracleNumber(double d) {

try {

return new oracle.jbo.domain.Number(d);

} catch (SQLException e) {

return null;

}

}



protected abstract List retrieveArrayFromWebService(Object qc, Object[] params);

private void storeNewIterator(Object qc, List rs) {

setUserDataForCollection(qc, rs.iterator());

hasNextForCollection(qc);

}

protected void executeQueryForCollection(Object qc, Object[] params, int noUserParams) {

storeNewIterator(qc, retrieveArrayFromWebService(qc, params));

super.executeQueryForCollection(qc, params, noUserParams);

}



private Iterator getArrayIterator(Object qc) {

return (Iterator)getUserDataForCollection(qc);

}

protected boolean hasNextForCollection(Object qc) {

boolean hasNext = getArrayIterator(qc).hasNext();

if (!hasNext) {

setFetchCompleteForCollection(qc, true);

}

return hasNext;

}



protected abstract void fillRow(Object data, ViewRowImpl row);

protected ViewRowImpl createRowFromResultSet(Object qc, ResultSet resultSet) {

Iterator iterator = getArrayIterator(qc);

ViewRowImpl row = createNewRowForCollection(qc);

fillRow(iterator.next(), row);

return row;

}



public long getQueryHitCount(ViewRowSetImpl viewRowSet) {

return super.getQueryHitCount(viewRowSet);

}

}


Step 3

Create a new programmatic view object in the Model project. The new view object:
  • Is programmatically
  • Extends the WsViewObjectImpl class
  • Contains a RowImpl class
  • Has a bind variable b_id data type Number
  • All attributes (of the EmployeeClient) are updatable
  • The EmployeeId attribute is Key Attribute.




Open the view object impl class (EmployeesWsImpl) and implement it (only added / changed methods are described below):

package nl.hr.demo.model.views.ws;



import java.util.ArrayList;

import java.util.List;

import nl.hr.demo.webservices.Employee;

import nl.hr.demo.webservices.client.EmployeeClient;

import oracle.jbo.server.ViewRowImpl;



public class EmployeesWsImpl extends WsViewObjectImpl {

protected List retrieveArrayFromWebService(Object qc, Object[] params) {

try {

EmployeeClient client = new EmployeeClient(getWSBaseURL());

if (getb_id() == null) {

return client.getAllEmployees();

} else {

List<Employee> result = new ArrayList<Employee>();

result.add(client.getEmployeeById(getb_id().intValue()));

return result;

}

} catch (Exception e) {

e.printStackTrace();

return null;

}

}



protected void fillRow(Object data, ViewRowImpl row) {

Employee empe = (Employee) data;

populateAttributeForRow(row, EmployeesWsRowImpl.EMPLOYEEID, toOracleNumber(emp.getEmployeeId()));

populateAttributeForRow(row, EmployeesWsRowImpl.FIRSTNAME, emp.getFirstName());

populateAttributeForRow(row, EmployeesWsRowImpl.LASTNAME, emp.getLastName());

populateAttributeForRow(row, EmployeesWsRowImpl.HIREDATE, toOracleDate(emp.getHireDate()));

populateAttributeForRow(row, EmployeesWsRowImpl.EMAIL, emp.getEmail());

populateAttributeForRow(row, EmployeesWsRowImpl.PHONENUMBER, emp.getPhoneNumber());

populateAttributeForRow(row, EmployeesWsRowImpl.JOBID, emp.getJobId());

populateAttributeForRow(row, EmployeesWsRowImpl.SALARY, toOracleNumber(emp.getSalary()));

populateAttributeForRow(row, EmployeesWsRowImpl.COMMISSIONPCT, toOracleNumber(emp.getCommissionPct()));

populateAttributeForRow(row, EmployeesWsRowImpl.MANAGERID, toOracleNumber(emp.getManagerId()));

populateAttributeForRow(row, EmployeesWsRowImpl.DEPARTMENTID, toOracleNumber(emp.getDepartmentId()));

}

}


Step 4

Add the view object to the application module.

Step 5

Create a new page: EmployeesWebServiceTable

Drag and drop the EmployeesWs onto it as read only table:



Add above the table a panelFormLayout containing:

<af:panelFormLayout id="pfl1">

<af:inputText binding="#{employeeBean.id}"

label="ID"

id="idFilter">

<af:convertNumber groupingUsed="false"

integerOnly="true"/>

</af:inputText>

<f:facet name="footer">

<af:commandButton text="Filter"

id="filter"

actionListener="#{employeeBean.filterWs}"/>

</f:facet>

</af:panelFormLayout>

Add to the af:table tag:

partialTriggers="::filter"

styleClass="AFStretchWidth"


Step 6

Create a java class EmployeeBean for the page. This bean class holds the ID input text and queries the view object when the filter button is used.

package nl.hr.demo.view.beans;



import javax.faces.context.FacesContext;

import nl.hr.demo.model.services.HrAppModuleImpl;

import nl.hr.demo.model.views.ws.EmployeesWsImpl;

import oracle.adf.model.binding.DCBindingContainer;

import oracle.adf.model.binding.DCDataControl;

import oracle.adf.view.rich.component.rich.input.RichInputText;

import oracle.binding.BindingContainer;

import oracle.jbo.domain.Number;



public class EmployeeBean {



private RichInputText id;



public EmployeeBean() {

super();

}



public void filterWs (ActionEvent actionEvent) {

EmployeesWsImpl view = getService().getEmployeesWs();

view.setb_id(getValue(id));

view.executeQuery();

}

private Number getValue(RichInputText item) {

if (item == null || item.getValue() == null) {

return null;

}

return new Number(((Long)item.getValue()).intValue());

}



private static HrAppModuleImpl getService() {

DCBindingContainer bc = (DCBindingContainer)FacesContext.getCurrentInstance().getApplication().evaluateExpressionGet(FacesContext.getCurrentInstance(), "#{bindings}", BindingContainer.class);

DCDataControl dc = bc.findDataControl("HrAppModuleDataControl");

return (HrAppModuleImpl) dc.getDataProvider();

}



public void setId(RichInputText id) {

this.id = id;

}

public RichInputText getId() {

return id;

}

}


Step 7

Add the page and the bean to the unbounded task flow:



Managed bean property Value
Name employeeBean
Class nl.hr.demo.view.beans.EmployeeBean
Scope Request

Step 8

Start the page it opens getAllEmployees is executed of the web service:



And if you fill an ID and click filter the web service is called again:

How to create a web service client

Technology: ADF11g
Developed in: JDeveloper 11.1.1.3.0
Used database schema: none


Summary

In this blog a solution is provided how to create a web service client. This blog is part of a sequence of 3 blogs:
  • How to create a RESTful web service that returns objects
  • How to create a web service client
  • How to create web service based ADF pages
I choose for a solution that:
  • Works for SOAP and RESTful web services
  • The location of the web service host can be changed while running the web service
Especially changing the host was an important criteria for me. For development I would like to use a development webservice and for production of course a production server.

Step 1

Create a new generic application in JDeveloper, call the project RpcWebServiceProject:



Step 2

On the project choose New – Web Service Proxy (under Business Tier – Web Services).


Choose:
  • Client Style: JAX-RPC Web Logic Style
  • Copy the URL or the location of the WSDL file
    • For this example we use: http://localhost:7101/HrWebServices-HrWebServicesProject-context-root/EmployeesWebPort?WSDL
  • Specify a package name:
    • For example: nl.hr.demo.webservice.client.employees
  • Leave all other settings to their default
A lot of files have been created in the project. The EmployeesWebPortClient class contains the entry point of calling the web service.

To make maintenance easier create a new project where a new entry point for each web service is created. If the web service ever changes then the sources in the RpcWebServiceProject project can be regenerated (right click on the EmployeesWebServiceProxy – Regenerate web service) and know custom code get lost.

Step 3

Create a new project HrWebServiceProject containing two java classes:
  • EmployeeClient (package nl.hr.demo.webservices.client)
  • HrWebServiceClient (package nl.hr.demo.webservices)
Set the dependencies of the HrWebServiceProject, add RpcWebServiceProject.

The HrWebServiceClient class is a generic class that creates the WSDL URL for given server location and contains methods to convert data types:

package nl.hr.demo.webservices;



import java.math.BigInteger;

import java.net.MalformedURLException;

import java.net.URL;

import java.util.ArrayList;

import java.util.List;



public class HrWebServiceClient {

private String webserviceBaseURL;



public HrWebServiceClient() {

super();

}

public HrWebServiceClient(String webserviceBaseURL) {

this.webserviceBaseURL = webserviceBaseURL;

}



protected String getWebserviceUrlAsString(String webservice) {

return webserviceBaseURL + "/" + webservice;

}

protected URL getWebserviceUrl(String webservice) {

URL wsdlLocationURL = null;

try {

wsdlLocationURL = new URL(getWebserviceUrlAsString(webservice));

} catch (MalformedURLException e) {

return null;

}

return wsdlLocationURL;

}



protected List convertToList(Object[] input) {

List list = new ArrayList();

for (int i = 0; i < input.length; i++) {

list.add(input[i]);

}

return list;

}

}

The EmployeeClient extends the HrWebServiceClient:

package nl.hr.demo.webservices.client;



import java.util.List;



import nl.hr.demo.webserivce.client.employees.EmployeesWebPortClient;

import nl.hr.demo.webservices.HrWebServiceClient;

import nl.hr.demo.webservices.Employee;



public class EmployeeClient extends HrWebServiceClient {

private static final String WSDL_NAME = "HrWebServices-HrWebServicesProject-context-root/EmployeesWebPort?WSDL";



public EmployeeClient() {

super();

}

public EmployeeClient(String webserviceBaseURL) {

super(webserviceBaseURL);

}



private EmployeesWebPortClient getClient() throws Exception {

EmployeesWebPortClient client = new EmployeesWebPortClient();

client.setPortCredentialProviderList();

client.setEndpoint(getWebserviceUrlAsString(WSDL_NAME));

return client;

}



public Employee getEmployeeById(int id) throws Exception {

EmployeesWebPortClient client = getClient();

return client.getEmployeeById(id);

}



public List getAllEmployees() throws Exception {

EmployeesWebPortClient client = getClient();

Employee[] result = client.getAllEmployees(null).getReturn();

return convertToList(result);

}

}

For each method in the web service a method is created in the java class. For test purposes some code can be added so the web service client can be executed from JDeveloper:

public static void main(String[] args) {

String LOCALHOST = "http://localhost:7101";

try {

System.err.println("Search employee ID 100");

Employee emp = new EmployeeClient(LOCALHOST).getEmployeeById(100);

print(emp);

System.err.println("Search employee ID 101");

emp = new EmployeeClient(LOCALHOST).getEmployeeById(101);

print(emp);

System.err.println("Search employee ID 102");

emp = new EmployeeClient(LOCALHOST).getEmployeeById(102);

print(emp);

System.err.println("Search all employees");

List result = new EmployeeClient(LOCALHOST).getAllEmployees();

for (int i = 0; i < result.size(); i++) {

print(result.get(i));

}

if (result.size() == 0) {

System.err.println("niets terug");

}

} catch (Exception e) {

e.printStackTrace();

}

}



private static void print(Employee employee) {

System.err.println(employee.getEmployeeId() + ": " +

employee.getFirstName() + " " +

employee.getLastName());

}

The result of this is:

Search employee ID 100

100: Steven King

Search employee ID 101

101: Neena Kochhar

Search employee ID 102

102: Lex De Haan

Search all employees

100: Steven King

101: Neena Kochhar

102: Lex De Haan


Step 4

Create a deployment profile (JAR file) for the HrWebServiceProject and create the jar file. This file will be needed in the next blog ‘How to create web service based ADF pages’.

dinsdag 1 maart 2011

How to create a RESTful web service that returns objects

Technology: ADF11g
Developed in: JDeveloper 11.1.1.3.0
Used database schema: none


Summary

In this blog a solution is provided how to create a RESTful web service that returns objects. One web service will be created with 2 methods to return an Employee instance and a list of Employee instances.

This blog is part of a sequence of 3 blogs:
  • How to create a RESTful web service that returns objects
  • How to create a web service client
  • How to create web service based ADF pages

Step 1

Create a new generic application in JDeveloper:



Step 2

Download the 'zip of Jersey' of the page:

http://jersey.java.net/nonav/documentation/latest/chapter_deps.html

Step 3

Extract the zip and copy the following jar files to the new created application (in a lib folder):
  • Asm-3.1.jar
  • Jersey-core-1.5.jar
  • Jersey-server-1.5.jar
  • Jersey-json-1.5.jar

Step 4

Open the project properties of the project in the new application and add these jar files (not the JAX-WS Web Services library will be added automatically later on):



Step 5

Create an Employee class which represents one employee (of the HR schema). Create accessors for all class variables. A second constructor is added so an employee can be created and initialized in one call.

Add above the class name the annotation XmlRootElement of class javax.xml.bind.annotation.XmlRootElement.

package nl.hr.demo.dataObjects;



import java.util.Date;

import javax.xml.bind.annotation.XmlRootElement;



@XmlRootElement

public class Employee {

private int employeeId;

private String firstName;

private String lastName;

private String email;

private String phoneNumber;

private Date hireDate;

private String jobId;

private double salary;

private double commissionPct;

private int managerId;

private int departmentId;



public Employee() {

super();

}

public Employee(int employeeId, String firstName, String lastName, String email, String phoneNumber, Date hireDate, String jobId, double salary, double commissionPct, int managerId, int departmentId) {

super();

setEmployeeId(employeeId);

setFirstName(firstName);

setLastName(lastName);

setEmail(email);

setPhoneNumber(phoneNumber);

setHireDate(hireDate);

setJobId(jobId);

setSalary(salary);

setCommissionPct(commissionPct);

setManagerId(managerId);

setDepartmentId(departmentId);

}



// For all class variables create accessors

public void setXXX (XXX xxx) {

this.xxx = xxx;

}

public XXX getXXX () {

return xxx;

}

}


Step 6

Create the web service class that returns one or a list of employees. If a web service contains several (GET) methods each method should have its own path.

package nl.hr.demo.webservices;



import java.text.SimpleDateFormat;

import java.util.ArrayList;

import java.util.List;

import javax.ws.rs.GET;

import javax.ws.rs.Path;

import javax.ws.rs.Produces;

import javax.ws.rs.QueryParam;

import nl.hr.demo.dataObjects.Employee;



@Path("EmployeesService")

public class EmployeesServices {

public EmployeesServices() {

super();

}



@GET

@Path("getEmployeeById")

@Produces("application/json")

public Employee getEmployeeById(@QueryParam("id")int id) {

SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy");

try {

if (id == 100) {

return new Employee(id, "Steven", "King", "SKING", "515.123.4567", sdf.parse("17-06-1987"), "AD_PRES", 24000, -1, -1, 90);

} else if (id == 101) {

return new Employee(id, "Neena", "Kochhar", "NKOCHHAR", "515.123.4568", sdf.parse("21-09-1989"), "AD_VP", 17000, -1, 100, 90);

}

return new Employee(id, "Lex", "De Haan", "LDEHAAN", "515.123.4569", sdf.parse("13-01-1993"), "AD_VP", 17000, -1, 100, 90);

} catch (Exception e) {

return null;

}

}



@GET

@Path("getAllEmployees")

@Produces("application/json")

public List<Employee> getAllEmployees() {

List<Employee> result = new ArrayList<Employee> ();

SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy");

try {

result.add(new Employee(100, "Steven", "King", "SKING", "515.123.4567", sdf.parse("17-06-1987"), "AD_PRES", 24000, -1, -1, 90));

result.add(new Employee(101, "Neena", "Kochhar", "NKOCHHAR", "515.123.4568", sdf.parse("21-09-1989"), "AD_VP", 17000, -1, 100, 90));

result.add(new Employee(102, "Lex", "De Haan", "LDEHAAN", "515.123.4569", sdf.parse("13-01-1993"), "AD_VP", 17000, -1, 100, 90));

} catch (Exception e) {

return new ArrayList<Employee> ();

}

return result;

}

}

For this blog the result of the web service is hard coded.

The @Path annotation above the class definition contains a warning:



If you click on this warning a jersey servlet is added to the web.xml:

<servlet>

<servlet-name>jersey</servlet-name>

<servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>

<load-on-startup>1</load-on-startup>

</servlet>

<servlet-mapping>

<servlet-name>jersey</servlet-name>

<url-pattern>/jersey/*</url-pattern>

</servlet-mapping>


Step 7

Now the EmployeeService can be created so it can be deployed.

Right click in the Application Navigator on the EmployeeService java class and choose Create Web Service:
  • Give the web service a name for example EmployeeWebService
  • Choose SOAP 1.1 Binding
  • Leave all other options to their default value
Between the @Path annotation and the class definition a new line is added:

@WebService(name = "EmployeesWeb", serviceName = "EmployeesWebService", portName = "EmployeesWebPort")

And in the web.xml is added:

<servlet>

<servlet-name>EmployeesWebPort</servlet-name>

<servlet-class>nl.hr.demo.webservices.EmployeesServices</servlet-class>

<load-on-startup>1</load-on-startup>

</servlet>

<servlet-mapping>

<servlet-name>EmployeesWebPort</servlet-name>

<url-pattern>/EmployeesWebPort</url-pattern>

</servlet-mapping>


Step 8

Deploy the application as a EAR file to the weblogic server:



If you click on the Service and go to the testing tab you can test the webservice:



If we test getEmployeeById and query id 101 we get:



With result:



And test getAllEmployees results in: