This chapter includes the following sections:
MAF supports the consumption of REST web services with JSON objects in MAF applications. This type of web service is recommended by MAF over alternative web services as the smaller payloads that it generates typically mean lower response times for communication between an application and the services that it accesses.
Using a REST-JSON web service in a MAF application requires you to configure a connection to the URL end point for the web service in your application. MAF stores this end point in the connections.xml
file of your application. You also write an adapter (RESTServiceAdapter
) that takes the value you configured in connections.xml
and uses it to construct the request URI that you submit to the web service. You must also write Java classes to model the data that the web service returns. Use these classes to generate data controls that bind your application’s AMX pages to the data that the web service accesses. If your application accesses secured web services, you must associate a security policy with the connection to the URL end point for the web service. If your application must access services hosted outside your corporate firewall, you may also need to configure entries in your application’s maf.properties
file.
Note:
As an alternative to writing aRESTServiceAdapter
, use the design-time support provided by MAF to generate the client data model that accesses REST web services. See Creating the Client Data Model in a MAF Application.The WorkBetter sample application provides examples of programmatically consuming REST services using the RESTServiceAdapter
. For more information about how to access the source code of the WorkBetter sample application, see MAF Sample Applications.
Use RestServiceAdapter
to access data sent using REST calls and to trigger execution of web service operations. The RestServiceAdapterFactory.createRestServiceAdapter()
API from the oracle.maf.api.dc.ws.rest
package creates adapters that implement RestServiceAdapter
.
Ensure that the connection to the URL end point for the service exists in the connections.xml
file, and then add your code to the bean class, as the following examples demonstrate.
Use the RestServiceAdapterFactory
.createMcsRestServiceAdapter()
API if you want to create an adapter that sends diagnostic information to Mobile Cloud Service, as described in Sending Diagnostic Information to Oracle Mobile Cloud Service.
For more information about RestServiceAdapterFactory
and RestServiceAdapter
, see Java API Reference for Oracle Mobile Application Framework.
.... import oracle.maf.api.dc.ws.rest.RestServiceAdapterFactory; import oracle.maf.api.dc.ws.rest.RestServiceAdapter; .... RestServiceAdapterFactory factory = RestServiceAdapterFactory.newFactory(); RestServiceAdapter restServiceAdapter = factory.createRestServiceAdapter(); // Clear any previously set request properties, if any restServiceAdapter.clearRequestProperties(); // Set the connection name restServiceAdapter.setConnectionName("RestServerEndpoint"); // Specify the type of request restServiceAdapter.setRequestMethod(RestServiceAdapter.REQUEST_TYPE_GET); // Specify the number of retries restServiceAdapter.setRetryLimit(0); // Set the URI which is defined after the endpoint in the connections.xml. // The request is the endpoint + the URI being set restServiceAdapter.setRequestURI("/WebService/Departments/100"); String response = ""; // Execute SEND and RECEIVE operation try { // For GET request, there is no payload response = restServiceAdapter.send(""); } catch (Exception e) { e.printStackTrace(); }
The following example demonstrates the use of the RestServiceAdapter
for the POST
request.
String id = "111"; String name = "TestName111"; String location = "TestLocation111"; .... restServiceAdapter.clearRequestProperties(); restServiceAdapter.setConnectionName("RestServerEndpoint"); restServiceAdapter.setRequestMethod(RestServiceAdapter.REQUEST_TYPE_POST); restServiceAdapter.setRetryLimit(0); restServiceAdapter.setRequestURI("/WebService/Departments"); String response = ""; // Execute SEND and RECEIVE operation try { String postData = makeDepartmentPost("DEPT", id, name, location); response = restServiceAdapter.send(postData); } catch (Exception e) { e.printStackTrace(); } System.out.println("The response is: " + response); private String makeDepartmentPost(String rootName, String id, String name, String location) { String ret = "<" + rootName + ">"; ret += "<DEPTID>" + id + "</DEPTID>"; ret += "<NAME>" + name + "</NAME>"; ret += "<LOCATION>" + location + "</LOCATION>"; ret += "</" + rootName + ">"; return ret; }
The following example demonstrates the use of the RestServiceAdapter
for the PUT
request.
String id = "111"; String name = "TestName111"; String location = "TestLocation111"; .... restServiceAdapter.clearRequestProperties(); restServiceAdapter.setConnectionName("RestServerEndpoint"); restServiceAdapter.setRequestMethod(RestServiceAdapter.REQUEST_TYPE_PUT); restServiceAdapter.setRetryLimit(0); restServiceAdapter.setRequestURI("/WebService/Departments"); String response = ""; // Execute SEND and RECEIVE operation try { String putData = makeDepartmentPut("DEPT", id, name, location); response = restServiceAdapter.send(putData); } catch (Exception e) { e.printStackTrace(); } System.out.println("The response is: " + response); private String makeDepartmentPut(String rootName, String id, String name, String location) { String ret = "<" + rootName + ">"; ret += "<DEPTID>" + id + "</DEPTID>"; ret += "<NAME>" + name + "</NAME>"; ret += "<LOCATION>" + location + "</LOCATION>"; ret += "</" + rootName + ">"; return ret; }
The following example demonstrates the use of the RestServiceAdapter
for the DELETE
request.
.... restServiceAdapter.clearRequestProperties(); restServiceAdapter.setConnectionName("RestServerEndpoint"); restServiceAdapter.setRequestMethod(RestServiceAdapter.REQUEST_TYPE_DELETE); restServiceAdapter.setRetryLimit(0); restServiceAdapter.setRequestURI("/WebService/Departments/44"); String response = ""; // Execute SEND and RECEIVE operation try { // For DELETE request, there is no payload response = restServiceAdapter.send(""); } catch (Exception e) { e.printStackTrace(); } System.out.println("The response is: " + response);
When you use the RestServiceAdapter
, you should set the Accept
and Content-Type
headers to ensure that your request and response payloads are not deemed invalid due to mismatched MIME type.
Note:
The REST web service adapter only supports UTF-8 character set on MAF applications. UTF-8 is embedded in the adapter program.
You can use the RestServiceAdapter
to obtain and customize the java.net.HttpURLConnection
, as well as access and interact with the input and output streams of the connection which allows you to read data from the HttpURLConnection
and write to it for further upload to the server.
The following example initializes and returns an HttpURLConnection
using the provided request method, request, and HTTP headers value. In addition, it injects basic authentication into the request headers from the credential store, obtains the input stream and closes the connection.
.... // Get the connection HttpURLConnection httpURLConnection = restServiceAdapter.getHttpURLConnection(requestMethod, request, httpHeadersValue); // Get the input stream InputStream inputStream = restServiceAdapter.getInputStream(connection); // Define data ByteArrayOutputStream byStream = new ByteArrayOutputStream(); int res = 0; int bufsize = 0, bufread = 0; byte[] data = (bufsize > 0) ? new byte[bufsize] : new byte[1024]; // Use the input stream to read data while ((res = inputStream.read(data)) > 0) { byStream.write(data, 0, res); bufread = bufread + res; } data = byStream.toByteArray(); // Use data ... restServiceAdapter.close(connection); ...
You can use the RestServiceAdapter
to handle binary (non-text) responses received from web service calls. These responses can include any type of binary data, such as PDF or video files. The RestServiceAdapter
method to use is sendReceive
.
The following example shows how to send a request for a file to a REST server, and then save the file to a disk.
RestServiceAdapterFactory factory = RestServiceAdapterFactory.newFactory(); RestServiceAdapter restServiceAdapter = factory.createRestServiceAdapter(); restServiceAdapter.clearRequestProperties(); restServiceAdapter.setConnectionName("JagRestServerEndpoint"); restServiceAdapter.setRequestMethod(RestServiceAdapter.REQUEST_TYPE_GET); restServiceAdapter.setRetryLimit(0); restServiceAdapter.setRequestURI("/ftaServer/v1/kpis/123/related/1"); // Set credentials needed to access the REST server String theUsername = "hr_spec_all"; String thePassword = "Welcome1"; String userPassword = theUsername + ":" + thePassword; String encoding = new sun.misc.BASE64Encoder().encode(userPassword.getBytes()); restServiceAdapter.addRequestProperty("Authorization", "Basic " + encoding); // Execute the SEND and RECEIVE operation. // Since it is a GET request, there is no payload. try { this.responseRaw = restServiceAdapter.sendReceive(""); } catch (Exception e) { e.printStackTrace(); } System.out.println("The response is: " + this.responseRaw); // Write the response to a file writeByteArrayToFile(this.responseRaw);
The following example demonstrates a method that is called by the code from the preceding example. This method saves a byte[]
response to a file on disk:
public void writeByteArrayToFile(byte[] fileContent) { BufferedOutputStream bos = null; try { FileOutputStream fos = new FileOutputStream(new File(fileToSavePath)); bos = new BufferedOutputStream(fos); // Write the byte [] to a file System.out.println("Writing byte array to file"); bos.write(fileContent); System.out.println("File written"); } catch(FileNotFoundException fnfe) { System.out.println("Specified file not found" + fnfe); } catch (IOException ioe) { System.out.println("Error while writing file" + ioe); } finally { if(bos != null) { try { // Flush the BufferedOutputStream bos.flush(); // Close the BufferedOutputStream bos.close(); } catch (Exception e) { } } } }
MAF supports both secured and unsecured web services. When a REST web service is secured, you must associate the REST connection with the predefined security policy that supports the REST web service.
Table 17-1 lists the predefined security policies that you can associate with connections to REST web services. How to Enable Access to Web Services describes how you associate the connection with the predefined security policy.
Table 17-1 Security Policies Supported for REST-Based Web Services
Authentication Type | REST Policy | Description |
---|---|---|
HTTP Basic |
|
This policy includes credentials in the HTTP header for outbound client requests and authenticates users against the Oracle Platform Security Services identity store. This policy also verifies that the transport protocol is HTTPS. Requests over a non-HTTPS transport protocol are refused. This policy can be enforced on any HTTP-based client. |
HTTP Basic |
|
This policy includes credentials in the HTTP header for outbound client requests. This policy can be enforced on any HTTP-based or HTTPS-based client. |
HTTP Basic |
|
This policy includes credentials in the HTTP header for outbound client requests and authenticates users against the Oracle Platform Security Services identity store. This policy also verifies that the transport protocol is HTTPS. Requests over a non-HTTPS transport protocol are refused. This policy can be enforced on any HTTP-based client. |
HTTP Basic Web SSO |
|
This policy injects cookies obtained after authentication in the HTTP request header, e.g: accessing OAM Webgate resources. This policy also sets response cookies. This policy can be enforced on any REST-based client. |
OAuth |
|
This policy injects bearer token (OAuth access token) in the HTTP request header while communicating with the endpoint. This token can be obtained from any OAuth2 server. This policy can be enforced on any REST-based client. |
For more information on these policies and their usage, see the Determining Which Predefined Policies to Use and Predefined Policies in Securing Web Services and Managing Policies with Oracle Web Services Manager.
When a web service is secured and expects an authentication token, you must associate the login connection with the predefined security policy that supports the web service.
maf-application.xml
overview editor. For details about creating the login server connection, see How to Create a MAF Login Connection.To associate a security policy with a web service:
JDeveloper stores the web service policy definitions in the wsm-assembly.xml
file in the META-INF
directory of the application workspace.
You can view the security policy already associated with the REST web service using the Edit Data Control Policies dialog shown in Figure 17-2. Click Override Properties to invoke a dialog where you can specify alternative values for properties that the selected policy permits you to override.
Figure 17-2 Editing Web Service Data Control Policies
When a user authenticates to access secured web services, MAF dynamically injects the credentials into the web service request using the Oracle Web Services Manager Mobile Agent.
For secured web services, the user credentials are dynamically injected into a web service request at the time when the request is invoked.
MAF uses Oracle Web Services Manager (OWSM) Mobile Agent to propagate user identity through web service requests.
Before web services are invoked, the user must respond to an authentication prompt triggered by the user trying to invoke a secured MAF application feature. The user credentials are stored in a credential store—a device-native and local repository used for storing credentials associated with the server URL of the authentication provider and the user. At runtime, MAF assumes that all credentials have already been stored in the IDM Mobile credential store before the time of their usage.
In the connections.xml
file, you have to specify the adfCredentialStoreKey
attribute value of the login server connection in the adfCredentialStoreKey
attribute of the web service connection reference in order to associate the login server to the web service security (see the following two examples).
Note:
Since JDeveloper does not provide an Overview editor for the connections.xml
file, you can use the Properties window to update the adfcredentialStoreKey
attribute of the <Reference>
element with the name configured for the adfCredentialStoreKey
attribute of the login server connection. Alternatively, you can add or update the attribute using the Source editor.
The following example shows the definition of the web service connection referenced as adfCredentialStoreKey="MyAuth"
, where MyAuth
is the name of the login connection reference.
<Reference name="URLConnection1" className="oracle.adf.model.connection.url.HttpURLConnection" adfCredentialStoreKey="MyAuth" xmlns=""> <Factory className="oracle.adf.model.connection.url.URLConnectionFactory"/> <RefAddresses> <XmlRefAddr addrType="URLConnection1"> <Contents> <urlconnection name="URLConnection1" url="http://myhost.us.example.com:7777/ SecureRESTWebService1/Echo"> <authentication style="challange"> <type>basic</type> <realm>myrealm</realm> </authentication> </urlconnection> </Contents> </XmlRefAddr> <SecureRefAddr addrType="username"/> <SecureRefAddr addrType="password"/> </RefAddresses> </Reference>
The following example shows the definition of the login connection, where MyAuth
is used as the credential store key value in the login server connection.
<Reference name="MyAuthName" className="oracle.adf.model.connection.adfmf.LoginConnection" adfCredentialStoreKey="MyAuth" partial="false" manageInOracleEnterpriseManager="true" deployable="true" xmlns=""> <Factory className="oracle.adf.model.connection.adfmf.LoginConnectionFactory"/> <RefAddresses> <XmlRefAddr addrType="adfmfLogin"> <Contents> <login url="http://172.31.255.255:7777/ SecuredWeb1-ViewController-context-root/faces/view1.jsf"/> <logout url="http://172.31.255.255:7777/ SecuredWeb1-ViewController-context-root/faces/view1.jsf"/> <accessControl url="http://myhost.us.example.com:7777/ UserObjects/jersey/getUserObjects" /> <idleTimeout value="10"/> <sessionTimeout value="36000"/> <userObjectFilter> <role name="testuser1_role1"/> <role name="testuser2_role1"/> <privilege name="testuser1_priv1"/> <privilege name="testuser2_priv1"/> <privilege name="testuser2_priv2"/> </userObjectFilter> </Contents> </XmlRefAddr> </RefAddresses> </Reference>
If a web service request is rejected due to the authentication failure, MAF returns an appropriate exception and invokes an appropriate action (see Using and Configuring Logging). If none of the existing exceptions correctly represent the condition, a new exception is added.
The connections.xml
file is deployed and managed under the Configuration Service. For more information, see Configuring End Points Used in MAF Applications .
The connections.xml
files in FARs are aggregated when the MAF application is deployed. The credentials represent deployment-specific data and are not expected to be stored in FARs.
MAF executes a cookie injection for the login connection associated with the URL endpoint of the REST web service for cookie-based authorization.
Each time a MAF application requests a REST web service for cookie-based authorization, the MAF security framework enables the transport layer of the REST web service to execute cookie injection for the login connection associated with the URL endpoint of the REST web service. This is handled at runtime without configuration of the MAF application by the MAF developer.
Configure Java system properties to use an HTTP proxy server to call web services that reside outside a corporate firewall. The proxy can either be defined by means of a generic connection framework or the java.net API.
By default, MAF determines the proxy information using the system settings on the platform where you deploy the application. For example, if the proxy information is set using the Settings utility on an iOS-powered device, then JVM automatically absorbs it.
Note:
It is possible to define a different proxy for each MAF application.
If you do not want to obtain the proxy information from the device settings, first you need to add the -Dcom.oracle.net.httpProxySource
system property. The default value of this property is native
, which means that the proxy information is to be obtained from the device settings. You need to disable it by specifying a different value, such as user
, for example: -Dcom.oracle.net.httpProxySource=user
JVM uses two different mechanisms for enabling the network connection:
The generic connection framework (GCF). If this mechanism is used, the proxy is defined through the system property -Dcom.sun.cdc.io.http.proxy=<host>:<port>
java.net
API. If this mechanism is used, the proxy is defined through the standard http.proxyHost
and http.proxyPort
.
In either case, it is recommended to define all three properties in the maf.properties
file, which would look similar to the following:
java.commandline.argument=-Dcom.oracle.net.httpProxySource=user java.commandline.argument=-Dcom.sun.cdc.io.http.proxy=www-proxy.us.mycompany.com:80 java.commandline.argument=-Dhttp.proxyHost=www-proxy.us.mycompany.com java.commandline.argument=-Dhttp.proxyPort=80
Note:
These properties affect only the JVM side of network calls.