Fusion Applications provides several types of interfaces to facilitate integration with other applications within the enterprise and on the cloud.As one of the key integration interfaces, Fusion Applications (FA) supports SOAP services based integration, both inbound and outbound. At this point FA doesn’t provide REST API’s but it is planned for a future release. It is however possible to invoke external REST APIs from FA which we will discuss. Oracle continues to invest in improving both SOAP and REST based connectivity. The content in this blog is based on features that were available at the time of writing it.
In this two part blog, I will cover the following topics briefly.
1. Invoking FA SOAP web services from external applications
a. Identifying the FA SOAP web service to be invoked
b. Sample invocation from an external application
c. Techniques to invoke FA services from an ADF application
2. Invoking external SOAP Web Services from FA (covered in Part 2)
3. Invoking external REST APIs from FA (covered in Part 2)
I’ll touch upon some basics, so that you can quickly build a few SOAP/REST interactions with FA. If you do not already have access to an FA instance (on-premise or SaaS), you can request for a free 30 day trial of the Oracle Sales Cloud using http://cloud.oracle.com
1. Invoking FA SOAP web services from external applications
There are two main types of services that FA exposes
- ADF Services – These services allow you to perform CRUD operations on Fusion business objects. For example, Sales Party Service, Opportunity Service etc. Using these services you can typically perform operations such as get, find, create, delete, update etc on FA objects.These services are typically useful for UI driven integrations such as looking up FA information from external application UIs, using third party Interfaces to create/update data in FA. They are also used in non-UI driven integration uses cases such as initial upload of business or setup data, synchronizing data with an external systems, etc.
- Composite Services – These services involve more logic than CRUD and often involving human workflows, rules etc. These services perform a business function such as Get Orchestration Order Service and are used when building larger process based integrations with external systems.These services are usually asynchronous in nature and are not typically used for UI integration patterns.
1a. Identifying the FA SOAP web service to be invoked
All FA web service metadata is available through an OER instance (Oracle Enterprise Repository) which is publicly available via http://fusionappsoer.oracle.com. This is the starting point for you to discover the services that you are going to work with. You do not need to own a FA account to browse the services using the above UI
You can use the search area on the left to narrow down your search to what you are looking for. For example, you can choose the type as by ADF Services or Composite, you can narrow your search to a specific FA version, Product Family etc.
Once you hit ‘Search’ you can see all the details of the service. There is a bunch of details for each service, but to get started check for the following
- Make sure that under the Taxonomy Tab, Keywords contains ‘EXTERNAL’.
- Using the Details tab, identify for the operation that you are planning to use.
- Using the Details tab, view the Abstract WSDL URL (scroll down to the end to find it). At this point you need an actual FA instance (on premise or on the cloud) to get started. Once you have an actual FA instance, you can view the concrete WSDL by using URL mentioned as ‘Service Path’.
The Composite Services do not provide a Service Path and are not candidates for SaaS integration. On-Premise Customers have access to the SOA servers where these composites are deployed. Using the Component Name and SAR location under the overview tab on fusionappsoer.oracle.com, customers can identify the composite in the Oracle Enterprise manager. Using the information on Enterprise Manager, customers can build integrations with other On-Premise assets such as Siebel, E-Business Suite etc. These services are usually long running asynchronous processes and often involve human workflow, configurations and monitoring.
Oracle Fusion Distributed Order Orchestration is a good example where Oracle pre-built integrations with Siebel using these composite services. More information can be found at http://www.oracle.com/us/products/applications/fusion/supply-chain-management/fusion-distr-order-orch-ds-1555648.pdf
In the rest of this post, we will focus on building simple UI centric use cases using ADF services.
1b. Sample invocation of ADF services from an external application
Take a closer look at the concrete WSDL. Couple of items to notice here
- Most operations have synchronous as well as asynchronous variations.
- Notice the security policy entry under binding. The synchronous operations are associated usually with wss11_saml_or_username_token_with_message_protection_service_policy
To being with, simply invoke these web services using a SOAP UI client. The following blog entry provides detailed explanation and step by step instructions to do this – http://www.ateam-oracle.com/using-soapui-for-secure-asynchronous-web-service-invocations-in-fusion-applications.
When dealing with external applications, ensure that the appropriate SSL certificates are imported similar to what is being done with SOAP UI example in the link above. Presently FA Sales Cloud does not provide an interface to import SSL certifications limiting certain integration abilities especially when self-signed certificates are used.
You may also have noticed is the size of the response payload from the FA services is very large. Especially with Find operations, the results may be too large to be meaningful. Imagine that you want to build a simple search feature in your custom application where you want the search results to display a valid set of Sales Accounts – as defined in FA. You may want the results to display as a list of Accounts (organizations), with information just four key pieces of information – Organization Name, Address, City and Country.
If the service invocation with find operation results in providing ALL details for each Sales Party, then it makes it hard for the custom application to handle the output. There is an unnecessary performance overhead as well. Fortunately, the Find operation provides a set of parameters in the input payload that can be used to control the output.
For example, the XML request payload in theSOAP UI blog linked earlier, can be modified as follows
Request:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"> <soapenv:Body> <typ:findSalesParty xmlns:typ="http://xmlns.oracle.com/apps/crmCommon/salesParties/salesPartiesService/types/"> <typ:findCriteria xmlns:typ1="http://xmlns.oracle.com/adf/svc/types/"> <typ1:fetchStart>0</typ1:fetchStart> <typ1:fetchSize>10</typ1:fetchSize> <typ1:filter> <typ1:group> <typ1:conjunction>And</typ1:conjunction> <typ1:item> <typ1:attribute>PartyName</typ1:attribute> <typ1:operator>STARTSWITH</typ1:operator> <typ1:value>Art</typ1:value> </typ1:item> <typ1:item> <typ1:attribute>PartyType</typ1:attribute> <typ1:operator>=</typ1:operator> <typ1:value>ORGANIZATION</typ1:value> </typ1:item> </typ1:group> </typ1:filter> <typ1:findAttribute>PartyName</typ1:findAttribute> <typ1:findAttribute>OrganizationParty</typ1:findAttribute> <typ1:childFindCriteria> <typ1:childAttrName>OrganizationParty</typ1:childAttrName> <typ1:findAttribute>Address1</typ1:findAttribute> <typ1:findAttribute>City</typ1:findAttribute> <typ1:findAttribute>Country</typ1:findAttribute> </typ1:childFindCriteria> </typ:findCriteria> </typ:findSalesParty> </soapenv:Body> </soapenv:Envelope>
The above request translates to – give me the top 10 hits for Organizations whose names start with “Art” and give me only the Name, Address, City and Country details of these Organizations. When executed against my FA instance, the response displays something like below
Response:
<env:Envelope ..> <env:Header>..</env:Header> <env:Body> <ns0:findSalesPartyResponse .."> <ns2:result ..> <ns1:PartyName>Artemis International Solutions Corp</ns1:PartyName> <ns1:OrganizationParty ..> <ns3:Address1>1000 Louisiana</ns3:Address1> <ns3:Country>US</ns3:Country> <ns3:City>Houston</ns3:City> </ns1:OrganizationParty> </ns2:result> <ns2:result ..> <ns1:PartyName>Artisan Press Ltd</ns1:PartyName> <ns1:OrganizationParty ..> <ns3:Address1>4 BOSTON ROAD</ns3:Address1> <ns3:Country>GB</ns3:Country> <ns3:City>Leeds</ns3:City> </ns1:OrganizationParty> </ns2:result> <ns2:result ..> <ns1:PartyName>Artwise Messe</ns1:PartyName> <ns1:OrganizationParty..> <ns3:Address1>Bergengrünstr. 9</ns3:Address1> <ns3:Country>DE</ns3:Country> <ns3:City>Essen</ns3:City> </ns1:OrganizationParty> </ns2:result> </ns0:findSalesPartyResponse> </env:Body> </env:Envelope>
Note that the response is much smaller and manageable. They key here is to use the findAttribute to control the output. In my system, the response time for this request without the findAttribute was 2000 to 2500ms. With the findAttribute the response time improved to 500ms.
In general, you can play with the findCriteria to exactly define what you want to search and what you want in the output. Think of it as the web service equivalent of the find functionality that you see in many enterprise applications. This is a powerful feature and is present only for the Find Operation.
Another key point to note about ADF web services is that they encapsulate details originating from more than one individual object in FA. For example in the case of SalesParty, in addition to the basic details of the Sales Party, the ADF service provides dependent information from OrganizationParty and SalesAccount objects. Each of these objects again bring in dependencies that they need.
This allows the consumers of the webservice, to get all relavant information in one go, without having to make multiple calls to retrieve related information. This makes ADF services, granular and right-sized business services, which is a corner store to building robust web services based integration architectures.
1c. Techniques to invoke ADF FA services from an ADF based external application
Let us see some techniques when invoking FA services from a custom built ADF application. This is useful when you have standalone ADF based application in your organization, or if you are building ADF extensions to FA, say on Oracle Java Cloud Service.
Some parts of these instructions can be useful when invoking FA web services from any J2EE based application.
There are several ways to invoke FA web services from ADF. We will look at two simple options
- Using ADF Web Service Data Control
- Using Web Service Proxy
ADF Web Service data control is a simple and declarative approach to invoke a web service from ADF pages. The web service data control is particularly useful when the end objective is to simply display the results of a web service invocation on an ADF Page.
The Web Service Proxy option provides more flexibility and control, and can be used in conjunction with a programmatic VO or a bean data control.
The blog entry https://blogs.oracle.com/jdevotnharvest/entry/which_option_to_choose_for provides guidelines to pick a suitable approach when accessing web services in ADF.
If you have JDeveloper 11g installed in your system, you can simply follow the steps below to invoke your FA on premise or SaaS instance.
Using ADF Web Service Data Control
- Create an Application of type Fusion Web Application. I named mine ‘SalesPartySample’. Ensure that you choose and shuttle ‘Web Services’ when on the Model project creation page. Accept all other defaults in the Wizard
- Under the Model Project, create a web service data control and provide the WSDL for the SalesParty web service. Select the getSalesParty Operation. Note that you can also include custom HTTP Headers. We won’t be using it in this example but it is one way of authenticating against an FA service
- In the Endpoint authentication, provide the username/password
- At this point you should see something like this in the data controls. Notice the Parameters and results
- Now we will use this data control from a simple UI. In the View Control Project, create a new JSF page. I created mine as index.jspx
- Drag and drop the partyId parameter from the Data Control into the jspx. Choose the display type as Text Input w/ Label. Underneath it, drag and drop the getSalesParty(Long). Choose to display it as an ADF button. Underneath it, drag and drop the PartyName as Text Output. Drag and drop Address1, City and Country from under Organization Party. Your jspx should look like below
- Simply right click your .jspx and Run.
- In this page, plug in a Party ID. I entered the Party ID for ‘Artisan Press Ltd’ that I got from the previous SOAP UI exercise
- It’s that simple! No coding effort!! Of course the UI can be made much better looking and there could be more complex usecases such as using custom HTTP Headers and this will require some amount of coding.
- At this point if you face a SSL related error, it is because your Jdev keystore doenst have the necessary SSL certificates imported.To fix this, navigate to your FA instance >Export the SSL certificate as .pem using your favorite browser (plenty of instruction on the internet). Import it to your JDev keystore as follows
C:\Oracle\Middleware\jdk160_24\bin>keytool -importcert -alias fusionapps -file <locationtotheexportedPEM>\mypk.pem -trustcacerts -keystore C:\Oracle\Middleware\wlserver_10.3\server\lib\DemoTrust.jks -storepass DemoTrustKeyStorePassPhrase
Using Web Service Proxy
Next we will look at using a Web Service Proxy to invoke the Sales Party Service. This time we will not use the get operation but use the find operation. We will build the FindCriteria that we used in SOAPUI using Java.
- Click New and select Web Service Proxy
- Choose JAX WS style
- Enter the package name as oracle.sample.salesparty.proxy and oracle.sample.salesparty.proxy.types
- Unselect generate as async and subsequently select Don’t Generate Async
- You should see SalesPartyServiceSoapHttpPortClient.java with the text, “Add your code to call the desired methods”
- It is a good practice to not use the above Proxy Client directly. This is because the when the proxy gets regenerated the changes made to the above client changes will be be lost. Instead it is good to create a separate facade. The facade also allows you to control the data type of the response
- Create a facade like below. The idea is to build the same XML request payload using ‘findCriteria’ like we built in the earlier example. The getSalesPartyList method takes only “startsWith” as input from the user, builds the findcriteria and executes the service, returning a list of Sales Party records
public class SalesPartyFacade { private SalesPartyService_Service salesPartyService_Service; public List<SalesParty> getSalesPartyList(String startsWith) throws ServiceException { List<SalesParty> SalesParties; FindCriteria findCriteria = createFindCriteria(startsWith); SecurityPolicyFeature[] securityFeatures = new SecurityPolicyFeature[] { new SecurityPolicyFeature("oracle/wss_username_token_over_ssl_client_policy") }; salesPartyService_Service = new SalesPartyService_Service(); SalesPartyService salesPartyService = salesPartyService_Service.getSalesPartyServiceSoapHttpPort(securityFeatures); WSBindingProvider wsbp = (WSBindingProvider)salesPartyService; wsbp.getRequestContext().put(BindingProvider.USERNAME_PROPERTY,"User1"); wsbp.getRequestContext().put(BindingProvider.PASSWORD_PROPERTY,"Passwd1"); FindSalesParty fSalesParty= new FindSalesParty(); fSalesParty.setFindCriteria(findCriteria); SalesParties = salesPartyService.findSalesParty(fSalesParty).getResult(); return SalesParties; } private static FindCriteria createFindCriteria(String startsWith) { FindCriteria findCriteria = new FindCriteria(); ChildFindCriteria childFindCriteria = new ChildFindCriteria(); findCriteria.setFetchStart(0); findCriteria.setFetchSize(10); ViewCriteria filter = new ViewCriteria(); ViewCriteriaRow group1 = new ViewCriteriaRow(); ViewCriteriaItem item1 = new ViewCriteriaItem(); item1.setAttribute("PartyName"); item1.setOperator("STARTSWITH"); item1.getValue().add(startsWith); ViewCriteriaItem item2 = new ViewCriteriaItem(); item2.setAttribute("PartyType"); item2.setOperator("="); item2.getValue().add("ORGANIZATION"); group1.getItem().add(item1); group1.getItem().add(item2); group1.setConjunction(Conjunction.AND); filter.getGroup().add(group1); findCriteria.setFilter(filter); findCriteria.getFindAttribute().add("PartyName"); findCriteria.getFindAttribute().add("OrganizationParty"); /* childFindCriteria.setChildAttrName("OrganizationParty"); childFindCriteria.getFindAttribute().add("Address1"); childFindCriteria.getFindAttribute().add("City"); childFindCriteria.getFindAttribute().add("Country"); findCriteria.getChildFindCriteria().add(childFindCriteria); */ return findCriteria; } }
- Now, you can write a simple test class to test this facade.
String filter = "Art"; SalesPartyFacade spf = new SalesPartyFacade(); List<SalesParty> salesparties = spf.getSalesPartyList(filter); for (SalesParty sp: salesparties) {System.out.print("Party Name = " + sp.getPartyName().getValue()+"\n"); System.out.print("Address1 = " + sp.getOrganizationParty().get(0).getAddress1().getValue()+"\n"); System.out.print("City = " + sp.getOrganizationParty().get(0).getCity().getValue()+"\n"); System.out.print("Country = " + sp.getOrganizationParty().get(0).getCountry().getValue()+"\n"); System.out.println("\n\n"); }
- This facade can now be used in any manner to invoke the Sales Party Service from your UI.
This concludes part 1 of this two part blog. In the next post I’ll be talking about invoking external SOAP and REST services from Fusion Applications.
Stay tuned!
All content listed on this page is the property of Oracle Corp. Redistribution not allowed without written permission