This chapter includes the following sections:
MAF supports the consumption of REST web services with JSON objects (REST-JSON) in MAF applications. This type of web service is recommended by MAF over alternative web services as the smaller payloads that REST-JSON web services generate 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 (located at assembly_project
/META-INF
).
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 a rest service adapter 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 .
.... 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 following RestServiceAdapter
methods to obtain and customize the javax.microedition.io.HttpConnection
, as well as access and interact with the connection's input and output streams which allows you to read data from the HttpConnection
and write to it for further upload to the server:
Get an HttpConnection
:
HttpConnection getHttpConnection(String requestMethod, String request, Object httpHeadersValue)
Get the HttpConnection
's OutputStream
:
OutputStream getOutputStream(HttpConnection connection)
Get the HttpConnection
's InputStream
:
InputStream getInputStream(HttpConnection connection)
Close the HttpConnection
:
void close (HttpConnection connection)
Look up a connection name in the connections.xml
file and return the connection's end point:
String getConnectionEndPoint(String connecionName)
These methods, while accomplishing the same functionality as the RestServiceAdapter
's send and sendReceive
methods, provide opportunity for customization of the connection and the process of sending requests and receiving responses.
The following example initializes and returns an HttpConnection
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.
.... import oracle.maf.api.dc.ws.rest.RestServiceAdapterFactory; import oracle.maf.api.dc.ws.rest.RestServiceAdapter; .... RestServiceAdapterFactory factory = RestServiceAdapterFactory.newFactory(); RestServiceAdapter restServiceAdapter = factory.createRestServiceAdapter(); restServiceAdapter.clearRequestProperties(); // Specify the type of request String requestMethod = RestServiceAdapter.REQUEST_TYPE_GET; // Get the connection end point from connections.xml String requestEndPoint = restServiceAdapter.getConnectionEndPoint("GeoIP"); // Get the URI which is defined after the end point String requestURI = "/xml/" + someIpAddress; // The request is the end point + the URI being set String request = requestEndPoint + requestURI; // Specify some custom request headers HashMap httpHeadersValue = new HashMap(); httpHeadersValue.put("Accept-Language", "en-US"); httpHeadersValue.put("My-Custom-Header-Item", "CustomItem1"); // Get the connection HttpConnection connection = restServiceAdapter.getHttpConnection(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.
estServiceAdapterFactory 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, as described in How to Enable Access to Web Services.
Table 15-1 lists the predefined security policies that you can associate with connections to REST web services.
Table 15-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 chapters 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. For a list of predefined security policies are supported for the authentication type available for REST-based web services, see Accessing Secure Web Services.
You create the login server connection using the Mobile Login Server Connection dialog in the MAF Application 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:
To create a persistent connection:
Figure 15-1 Editing Web Service Data Control Policies
OEPE stores the web service policy definitions in the wsm-assembly.xml
file (located in 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 dialog shown in Figure 15-1.
When the MAF application is containerized at deployment time, access to secured web services behind the corporate firewall will rely on the Mobile Security Access Server (MSAS), a component in the Oracle Mobile Security Suite (OMSS), to provide a central access point for securing traffic from mobile devices to corporate resources. In this case, the MSAS instance is configured to enforce an authentication endpoint for use in the initial authentication of the user.
Additionally, the backend service endpoints must be associated 1.) with a MSAS proxy application that ensures the URL of the resource is protected by an access policy that MSAS enforces and 2.) a client policy that MSAS adds to the proxied request, for example Single Sign-On (SSO).
In order to allow the MAF application to communicate with MSAS, the user installs and registers a Secure Workspace app for the type of authentication that has been configured for the MSAS instance. Then when the user attempts to access a protected resource, the MAF application and the Secure Workspace rely on a MSAS-generated Proxy Auto-Configuration file to determine which requests to proxy using the MSAS AppTunnel.
For more information about the role of MSAS AppTunnel in the authentication process of containerized MAF applications, see Overview of the Authentication Process for Containerized MAF Applications.
For an overview of OMSS support for containerized MAF applications, see Containerizing a MAF Application for Enterprise Distribution.
In the OMSS documentation library, see the for reference information about MSAS predefined security and management policies.
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 authentication provider's server URL 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 login server connection's adfCredentialStoreKey
attribute value in the adfCredentialStoreKey
attribute of the web service connection reference in order to associate the login server to the web service security (see the two examples below).
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 in MAF Applications). 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.
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.
Each time a MAF application requests a REST web service for cookie-based authorization, MAF's 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.
If the web service you are to call resides outside your corporate firewall, you need to ensure that you have set the appropriate Java system properties to configure the use of an HTTP proxy server.
By default, MAF determines the proxy information using the system settings on the platform where you deploy the application.
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:
-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 (located at assembly_project
/META-INF
), 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.