Friday May 20, 2016

Creating custom Fusion Application User Interfaces using Oracle JET

Introduction

JET is Oracle's new mobile toolkit specifically written for developers to help them build client slide applications using JavaScript. Oracle Fusion Applications implementers are often given the requirement to create mobile, or desktop browser, based custom screens for Fusion Applications. There are many options available to the developer for example Oracle ADF (Java Based) and Oracle JET (JavaScript based). This blog article gives the reader a tutorial style document on how to build a hybrid application using data from Oracle Fusion Sales Cloud Data. It is worth highlighting that although this tutorial is using Sales Cloud, the technique below is equally applicable to HCM cloud, or any other Oracle SaaS cloud product which exposes a REST API.

Main Article

Pre-Requisites

It is assumed that you've already read the getting started guide on the Oracle Jet website and installed all the pre-requisites. In addition if you are to create a mobile application then you will also need to install the mobile SDKs from either Apple (XCode) or Android (Android SDK).

 

You must have a Apple Mac to be able to install the Apple IOS developer kit (XCode), it is not possible to run XCode on a Windows PC

 

Dealing with SaaS Security

Before building the application itself we need to start executing the REST calls and getting our data and security is going to be the first hurdle we need to cross.Most Sales Cloud installations allow "Basic Authentication" to their APIs,  so in REST this involves creating a HTTP Header called "Authorization" with the value "Basic <your username:password>" , with the <username:password> section encoded as Base64. An alternative approach used when embedding the application within Oracle SaaS is to use a generated JWT token. This token is generated by Oracle SaaS using either groovy or expression language. When embedding the application in Oracle SaaS you have the option of passing parameters, the JWT token would be one of these parameters and can subsequently be used instead of the <username:password>. When using JWT token the Authorization string changes slightly so that instead of "Basic" it become "Bearer",

 

UsageHeader NameHeader Value
Basic AuthenticationAuthorizationBasic <your username:password base64 encoded>
JWT AuthenticationAuthorizationBearer <JWT Token>

 

Groovy Script in SalesCloud to generate a JWT Token

def thirdpartyapplicationurl = oracle.topologyManager.client.deployedInfo.DeployedInfoProvider.getEndPoint("My3rdPartyApplication" )
def crmkey= (new oracle.apps.fnd.applcore.common.SecuredTokenBean().getTrustToken())
def url = thirdpartyapplicationurl +"?jwt ="+crmkey
return (url)

Expression Language in Fusion SaaS (HCM, Sales, ERP etc) to generate a JWT Token

#{EndPointProvider.externalEndpointByModuleShortName['My3rdPartApplication']}?jwt=#{applCoreSecuredToken.trustToken}

Getting the data out of Fusion Applications using the REST API

When retrieving  data from Sales Cloud we need to make sure we get the right data, not too much and not too little. Oracle Sales Cloud, like many other Oracle SaaS products, now supports the REST API for inbound and outbound data access. Oracle HCM also has a REST API but at the time of writing this article, the API is in controlled availability.

Looking at the documentation hosted at Oracle Help Center :http//docs.oracle.com/cloud/latest/salescs_gs/FAAPS/ 

The REST call to get all Sales Cloud Opportunities looks like this :

https://yourCRMServer/salesApi/resources/latest/opportunities

If you executed the above REST call you will notice that the resulting payload is large, some would say huge. There are good reasons for this, namely that the Sales Cloud Opportunity object contains a large number fields, secondly the result not only contains data but also contains metadata and finally the request above is a select all query. The metadata includes links to child collections, links to List of Values, what tabs are visible in Sales Cloud , custom objects, flexfields etc. Additionally the query we just executed is a the equivalent of a select * from table, i.e. it brings back everything so we'll also need to fix that.

 

Example snippet of a SalesCloud Opportunity REST Response showing custom fields,tabs visible, child collections etc

"Opportunity_NewQuote_14047462719341_Layout6": "https://mybigm.bigmachines.com/sso/saml_request.jsp?RelayState=/commerce/buyside/document.jsp?process=quickstart_commerce_process_bmClone_4%26formaction=create%26_partnerOpportunityId=3000000xxx44105%26_partnerIdentifier=fusion%26_partnerAccountId=100000001941037",
  "Opportunity_NewQuote_14047462719341_Layout6_Layout7": "https://mybigMmachine.bigmachines.com/sso/saml_request.jsp?RelayState=/commerce/buyside/document.jsp?process=quickstart_commerce_process_bmClone_4%26formaction=create%26_partnerOpportunityId=300000060xxxx5%26_partnerIdentifier=fusion%26_partnerAccountId=100000001941037",
  "ExtnFuseOpportunityEditLayout7Expr": "false",
  "ExtnFuseOpportunityEditLayout6Expr": "false",
  "ExtnFuseOpportunityCreateLayout3Expr": "false",
  "Opportunity_NewQuote_14047462719341_Layout8": "https://mybigm-demo.bigmachines.com/sso/saml_request.jsp?RelayState=/commerce/buyside/document.jsp?process=quickstart_commerce_process_bmClone_4%26formaction=create%26_partnerOpportunityId=300000060744105%26_partnerIdentifier=fusion%26_partnerAccountId=100000001941037",
  "ExtnFuseOpportunityEditLayout8Expr": "false",
  "CreateProject_c": null,
  "Opportunity_DocumentsCloud_14399346021091": "https://mydoccloud.documents.us2.oraclecloud.com/documents/embed/link/LF6F00719BA6xxxxxx8FBEFEC24286/folder/FE3D00BBxxxxxxxxxxEC24286/lyt=grid",
  "Opportunity_DocsCloud_14552023624601": "https://mydocscserver.domain.com:7002/SalesCloudDocCloudServlet/doccloud?objectnumber=2169&objecttype=OPPORTUNITY&jwt=eyJhxxxxxy1pqzv2JK0DX-xxxvAn5r9aQixtpxhNBNG9AljMLfOsxlLiCgE5L0bAI",
  "links": [
    {
      "rel": "self",
      "href": "https://mycrmserver-crm.oracledemos.com:443/salesApi/resources/11.1.10/opportunities/2169",
      "name": "opportunities",
      "kind": "item",
      "properties": {
        "changeIndicator": "ACED0005737200136A6176612E7574696C2E41727261794C6973747881D21D99C7619D03000149000473697A65787000000002770400000010737200116A6176612E6C616E672E496E746567657212E2A0A4F781873802000149000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B020000787200106A6176612E6C616E672E4F626A65637400000000000000000000007870000000017371007E00020000000178"
      }
    },
    {
      "rel": "canonical",
      "href": "https://mycrmserver-crm.oracledemos.com:443/salesApi/resources/11.1.10/opportunities/2169",
      "name": "opportunities",
      "kind": "item"
    },
    {
      "rel": "lov",
      "href": "https://mycrmserver-crm.oracledemos.com:443/salesApi/resources/11.1.10/opportunities/2169/lov/SalesStageLOV",
      "name": "SalesStageLOV",
      "kind": "collection"
    },

Thankfully we can tell the REST API that we :

  • Only want to see the data, achieved by adding onlyData=true parameter
  • Only want to see the following fields OpportunityNumber,Name,CustomerName (TargetPartyName), achieved by adding a fields=<fieldName,fieldname> parameter
  • Only want to see a max of 10 rows, achieved by adding the limit=<value> parameter
  • Only want to see open opportunities, achieved by adding the q= parameter with a query string, in our case StatusCode=OPEN

If we want to get the data in pages/blocks we can use the offset parameter. The offset parameter tells the REST service to get the data "from" this offset. Using offset and limit we can effectively page through the data returned by Oracle Fusion Applications REST Service.

Our final REST request URL would look like :

https://myCRMServeroracledemos.com/salesApi/resources/latest/opportunities?onlyData=true&fields=OptyNumber,Name,Revenue,TargetPartyName,StatusCode&q=StatusCode=OPEN&offset=0&limit=10

The Oracle Fusion Applications REST API is documented in the relevant Oracle Fusion Applications Documentation, e.g. for Sales Cloud, http://docs.oracle.com/cloud/latest/salescs_gs/FAAPS/ but it is also worth noting that the Oracle Fusion Applications REST Services are simply an implementation of the Oracle ADF Business Components REST Services, these are very well documented here  https://docs.oracle.com/middleware/1221/adf/develop/GUID-8F85F6FA-1A13-4111-BBDB-1195445CB630.htm#ADFFD53992

Our final tuned JSON result from the REST service will look something like this (truncated) :

{
  "items": [
    {
      "Name": "Custom Sentinel Power Server @ Eagle",
      "OptyNumber": "147790",
      "StatusCode": "OPEN",
      "TargetPartyName": "Eagle Software Inc",
      "Revenue": 104000
    },
    {
      "Name": "Ultra Servers @ Beutelschies & Company",
      "OptyNumber": "150790",
      "StatusCode": "OPEN",
      "TargetPartyName": "Beutelschies & Company",
      "Revenue": 175000
    },
    {
      "Name": "Diablo Technologies 1012",
      "OptyNumber": "176800",
      "StatusCode": "OPEN",
      "TargetPartyName": "Diablo Technologies",
      "Revenue": 23650
    }
}

Creating the Hybrid Application

Now we have our datasource defined we can start to build the application. We want this application to be available on a mobile device and therefore we will create a "Mobile Hybrid" application using Oracle JET, using the --NavDrawer template.

yo oraclejet:hybrid OSCOptyList --template=navDrawer --platforms=android

Once the yeoman script has built your application, you can test the (basic) application using the following two commands.

grunt build --platform=android 
grunt serve --platform=android --web=true

The second grunt serve command has a web=true parameter at the end, this is telling the script that we're going to be testing this in our browser and not on the device itself. When this is run you should see basic shell [empty] application in your browser window.

For

Building Our JavaScript UI

Now that we have our data source defined we can now get onto to task of building the JET User Interface. Previously you executed the yo oraclejet:hybrid command, this created you a hybrid application using a template. Opening the resulting project in an IDE, like NetBeans, we can see that the project template has created a collection of files and that one of them is "dashboard.html" (marked 1 in the image), edit this file using your editor.

dashboard.html

 

Within the file delete everything and replace it with this snippet of html code

<div class="oj-hybrid-padding">
    <div class="oj-flex">
        <div class="oj-flex-item">
            <button id= "prevButton" 
                    data-bind="click: previousPage, 
                       ojComponent: { component: 'ojButton', label: 'Previous' }">
            </button>
            <button id= "nextButton"
                    data-bind="click: nextPage, 
                       ojComponent: { component: 'ojButton', label: 'Next' }">
            </button>
        </div>
    </div>
    <div class="oj-flex-item">    
        <div class="oj-panel oj-panel-alt1 oj-margin">
            <table id="table" summary="Opportunity List" aria-label="Opportunity List"
                   data-bind="ojComponent: {component: 'ojTable', 
                                data: opportunityDataSource, 
                                columnsDefault: {sortable: 'none'}, 
                                columns: [{headerText: 'Opty Number', 
                                           field: 'OptyNumber'},
                                          {headerText: 'Name', 
                                           field: 'Name'},
                                          {headerText: 'Revenue', 
                                           field: 'Revenue'},
                                          {headerText: 'Customer Name', 
                                           field: 'TargetPartyName'},
                                          {headerText: 'Status Code', 
                                           field: 'StatusCode'}
           ]}">
            </table>
        </div>    
    </div>
</div>

The above piece of html adds a JET table to the page, for prettiness we've wrapped the table in a decorative panel and added a next and previous buttons. The table definition tells Oracle JET that the data is coming from a JavaScript object called "opportunityDataSource", it also defines defines the columns, column header text and that the columns are not sortable. The button definitions reference two functions in our JavaScript (to follow) which will paginate the data.

Building The logic

We can now move onto the JavaScript side of things, that is the part where we get the data from Sales Cloud and makes it available to the table object in the html file. For this simplistic example we'll get the data direct from Sales Cloud and display it in the table, with no caching and nothing fancy like collection models for pagination .

Edit the dashboard.js file, this is marked as 2 in the above image. This file is a RequiresJS AMD (Application Module Definition File) and is pre-populated to support the dashboard.html page.

Within this file, cut-n-paste the following JavaScript snippet.

define(['ojs/ojcore', 'knockout', 'jquery', 'ojs/ojtable', 'ojs/ojbutton'],
        function (oj, ko, $) {
            function DashboardViewModel() {
                var self = this;
                var offset = 0;
                var limit = 10;
                var pageSize = 10;
                var nextButtonActive = ko.observable(true);
                var prevButtonActive = ko.observable(true);
                //
                self.optyList = ko.observableArray([{Name: "Fetching data"}]);
                console.log('Data=' + self.optyList);
                self.opportunityDataSource = new oj.ArrayTableDataSource(self.optyList, {idAttribute: 'Name'});
                self.refresh = function () {
                    console.log("fetching data");
                    var hostname = "https://yourCRMServer.domain.com";
                    var queryString = "/salesApi/resources/latest/opportunities?onlyData=true&fields=OptyNumber,Name,Revenue,TargetPartyName,StatusCode&q=StatusCode=OPEN&limit=10&offset=" + offset;
                    console.log(queryString);
                    $.ajax(hostname + queryString,
                            {
                                method: "GET",
                                dataType: "json",
                                headers: {"Authorization": "Basic " + btoa("username:password")},
                                // Alternative Headers if using JWT Token
                                // headers : {"Authorization" : "Bearer "+ jwttoken; 
                                success: function (data)
                                {
                                    self.optyList(data.items);
                                    console.log('Data returned ' + JSON.stringify(data.items));
                                    console.log("Rows Returned"+self.optyList().length);
                                    // Enable / Disable the next/prev button based on results of query
                                    if (self.optyList().length < limit)
                                    {
                                        $('#nextButton').attr("disabled", true);
                                    } else
                                    {
                                        $('#nextButton').attr("disabled", false);
                                    }
                                    if (self.offset === 0)
                                        $('#prevButton').attr("disabled", true);
                                },
                                error: function (jqXHR, textStatus, errorThrown)
                                {
                                    console.log(textStatus, errorThrown);
                                }
                            }
                    );
                };
                // Handlers for buttons
                self.nextPage = function ()
                {

                    offset = offset + pageSize;
                    console.log("off set=" + offset);
                    self.refresh();
                };
                self.previousPage = function ()
                {
                    offset = offset - pageSize;
                    if (offset < 0)
                        offset = 0;
                    self.refresh();
                };
                // Initial Refresh
                self.refresh();
            }
            
            return new DashboardViewModel;
        }
);

Lets examine the code

Line 1: Here we've modified the standard define so that it includes a ojs/table reference. This is telling RequiresJS , which the JET toolkit uses, that this piece of JavaScript uses a JET Table object
Line 8 & 9 : These lines maintain variables to indicate if the button should be enabled or not
Line 11: Here we created a variable called optyList, this is importantly created as a knockout observableArray.
Line 13: Here we create another variable called "opportunityDataSource", which is the variable the HTML page will reference. The main difference here is that this variable is of type oj.ArrayTableDataSource and that the primary key is OptyNumber
Lines 14-47 :  Here we define a function called "refresh". When this javascript function is called we execute a REST Call back to SalesCloud using jquery's ajax call. This call retrieves the data and then populates the optyList knockout data source with data from the REST call. Specifically here note that we don't assign the results to the optyData variable directly but we purposely pass a child array called "items". If you execute the REST call, we previously discussed, you'll note that the data is actually stored in an array called items
Line 23 : This line is defining the headers, specifically in this case we're defining a header called "Authorization" , with the username & password formatted as "username:password" and then the base64 encoded.
Line 24-25  :These lines define an alternative header which would be appropriate if a JWT token was being used. This token would be passed in as a parameter rather than being hardcoded
Lines 31-40 : These query the results of the query and determine if the next and previous buttons should be enabled or not using jQuery to toggle the disabled attribute
Lines 50-63 : These manage the next/previous button events
Finally on line 65 we execute the refresh() method when the module is initiated.

Running the example on your mobile

To run the example on your mobile device execute the follow commands

grunt build --platform=android 
grunt serve --platform=android

or if you want to test on a device

grunt serve --platform=android -destination=[device or emulator name]

If all is well you should see a table of data populated from Oracle Sales Cloud

 

For more information on building JavaScript applications with the Oracle JET tool make sure to check out our other blog articles on JET here , the Oracle JET Website here and the excellent Oracle JET You Tube channel here

Running the example on the browser and CORS

If you try and run the example on your browser you'll find it probably won'twork. If you look at the browser console (control+shift+I on most browsers) you'll probably see that the error was something like "XMLHttpRequest cannot load..." etc

cors

This is because the code has violated "Cross Origin Scripting" rules. In a nut shell "A JavaScript application cannot access a resource which was not served up by the server which itself was served up from".. In my case the application was served up by Netbeans on http://localhost:8090, whereas the REST Service from Sales Cloud is on a different server, thankfully there is a solution called "CORS". CORS stands for Cross Origin Resource Sharing and is a standard for solving this problem, for more information on CORS see this wikipedia article, or other articles on the internet.

Configuring CORS in Fusion Applications

For our application to work on a web browser we need to enable CORS in Fusion Applications, we do this by the following steps :

  1. 1. Log into Fusion Applications (SalesCloud, HCM etc) using a user who has access to "Setup and Maintenance"
  2. 2. Access setup and Maintenance screens
  3. 3. Search for Manage Administrator Profile Values and then navigate to that task
  4. 4. Search for "Allowed Domains" profile name (case sensitive!!).
  5. 5. Within this profile name you see a profile option called "site", this profile option has a profile value
  6. 6. Within the profile value add the hostname, and port number, of the application hosting your JavaScript application. If you want to allow "ALL" domains set this value to "*" (a single asterisk )
  7. WARNING : Ensure you understand the security implication of allowing ALL Domains using the asterisk notation!
  8. 7. Save and Close and then retry running your JET Application in your browser.
[caption id="attachment_38119" align="alignnone" width="300"]setupandMaiteanceCORS CORS Settings in Setup and Maintenance (Click to enlarge)[/caption]

If all is good when you run the application on your browser, or mobile device, you'll now see the application running correctly.

[caption id="attachment_38120" align="alignnone" width="300"]JETApplication Running JET Application (Click to enlarge)[/caption]

 

Final Note on Security

To keep this example simple the security username/password was hard-coded in the mobile application, not suitable for a real world application. For a real application you would create a configuration screen, or use system preferences, to collect and store the username , password and the SalesCloud Server url which would then be used in the application.

If the JET Application is to be embedded inside a Fusion Applications Page then you will want to use JWT Token authentication. Modify the example so that the JWT token is passed into the application URL as a parameter and then use that in the JavaScript (lines 24-25) accordingly.

For more information on JWT Tokens in Fusion Applications see these blog entries (Link 1, Link 2) and of course the documentation

Conclusion

As we've seen above its quite straightforward to create mobile, and browser, applications using the Oracle JET Framework. The above example was quite simple and only queried data, a real application would also have some write/delete/update operations and therefore you would want to start to look at the JET Common Model and Collection Framework (DocLink) instead. Additionally in the above example we queried data direct from a single SalesCloud instance and did no processing on it.. Its very likely that a single mobile application will need to get its data from multiple data sources and require some backend services to "preprocess" and probably post process the data, in essence provide an API.. We call this backend a  "MBaaS", ie Mobile Backend As A Service, Oracle also provides a MBaaS in its PaaS suite of products and it is called Oracle Product is called "Mobile Cloud Service"..

In a future article we will explore how to use Oracle Mobile Cloud Service (Oracle MCS) to query SalesCloud and Service cloud and provide an API to the client which would be using the more advanced technique of using the JET Common Model/Collection framework.

 

 

Saturday Apr 30, 2016

Accessing Fusion Data from BI Reports using Java

Introduction

In a recent article by Richard Williams on A-Team Chronicles, Richard explained how you can execute a BI publisher report from a SOAP Service and retrieve the report, as XML, as part of the response of the SOAP call.  This blog article serves as a follow on blog article providing a tutorial style walk through on how to implement the above procedure in Java.

This article assumes you have already followed the steps in Richard's blog article and created your report in BI Publisher, exposed it as a SOAP Service and tested this using SOAPUI, or another SOAP testing tool.

Following Richards guidance we know that he correct SOAP call could look like this

<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:pub="http://xmlns.oracle.com/oxp/service/PublicReportService">
   <soap:Header/>
   <soap:Body>
      <pub:runReport>
         <pub:reportRequest>
            <pub:reportAbsolutePath>/~angelo.santagata@oracle.com/Bi report.xdo</pub:reportAbsolutePath>
            <pub:reportRawData xsi:nil="true" >true</pub:reportRawData>
            <pub:sizeOfDataChunkDownload>-1</pub:sizeOfDataChunkDownload>
            <pub:flattenXML>true</pub:flattenXML>
            <pub:byPassCache>true</pub:byPassCache>
         </pub:reportRequest>
         <pub:appParams/>
      </pub:runReport>
   </soap:Body>
</soap:Envelope>

Tip :One easy way to determine the reports location is to run the report and then examine the URL in the browser.

 

Implementing the SOAP call using JDeveloper 11g

We can now need to implement the Java SOAP Client to call our SOAP Service. For this blog we will use JDeveloper 11g, the IDE recommended for extending Oracle Fusion, however you are free to use your IDE of choice, e.g. NetBeans, Eclipse, VI, Notepad etc, the steps will obviously be different.

Creating the project

Within JDeveloper 11g start by creating a new Application and within this application create two generic projects. Call one project “BISOAPServiceProxy” and the other “FusionReportsIntegration”. The "BISOAPServiceProxy" project will contain a SOAP Proxy we are going to generate from JDeveloper 11g and the "FusionReportsIntegration" project will contain our custom client code. It is good practice to create separate projects so that the SOAP Proxies resides in its own separate project, this allows us to regenerate the proxy from scratch without affecting any other code.

Generating the SOAP Proxy

For this example we will be using the SOAP Proxy wizard as part of JDeveloper. This functionality generates a static proxy for us, which in turn makes it easier to generate the required SOAP call later.

  1. 1. With the BISOAPService project selected, start the JDeveloper SOAP Proxy wizard.
    File-> New-> Business Tier-> Web Services-> Web Service Proxy
  2. Proxy1
  3. 2. Click Next
  4. 3. Skipping the first welcome screen, in step 2 enter the JAX-WS Style as the type of SOAP Proxy you wish to generate in step 3 enter the WSDL of your Fusion Application BI Publisher webservice WSDL. It’s best to check this URL returns a WSDL document in your web browser before entering it here. The WSDL location will normally be something like : http://<your fusion Applications Server>/xmlpserver/services/ExternalReportWSSService?wsdl
  5. Proxy2
  6. It's recommended that you leave the copy WSDL into project check-box selected.
  7. 4. Give a package name, unless you need to it's recommended to leave the Root Package for generated types to be left blank
  8. proxy3
  9. 5. Now hit Finish

Fixing the project dependencies

We now need to make sure that the “FusionReportsIntegration” is able to see classes generated by the  “BISOAPServiceProxy” proxy. To resolve this in JDeveloper we simply need to setup a dependency between the two projects.

  1. 1. With the FusionReportsIntegration project selected, right-mouse click on the project and select “Project properties
  2. 2. In the properties panel select Dependencies
  3. 3. Select the little pencil icon and in the resulting dialog select “Build Output”. This selection tells JDeveloper that “this project depends on the successful build output” of the other project.
  4. 4. Save the Dialog
    dependancies1
  5. 5. Close [OK] the Project Properties dialog
  6. 6. Now is a good time to hit compile and make sure the SOAP proxy compiles without any errors, given we haven't written any code yet it should compile just fine.

Writing the code to execute the SOAP call

With the SOAP Proxy generated, the project dependency setup, we’re now ready to write the code which will call the BI Server using the generated SOAP Proxy

  1. 1. With the Fusion Reports Integration selected , right mouse Click -> New -> Java -> Java Class
    javacode
  2. 2. Enter a name, and java package name, for your class
  3. 3. Ensure that “Main Method” is selected. This is so we can execute the code from the command line, you will want to change this depending on where you execute your code from, e.g. A library, a servlet etc.
  4. 4. Within the main method you will need to enter the following code snippet, once this code snippet is pasted you will need to correct and resolve imports for your project.
  5. 1.	ExternalReportWSSService_Service externalReportWSSService_Service;
    2.	// Initialise the SOAP Proxy generated by JDeveloper based on the following WSDL xmlpserver/services/ExternalReportWSSService?wsdl
    3.	externalReportWSSService_Service = new ExternalReportWSSService_Service();
    4.	// Set security Policies to reflect your fusion applications
    5.	SecurityPoliciesFeature securityFeatures = new SecurityPoliciesFeature(new String[]
    6.	{ "oracle/wss_username_token_over_ssl_client_policy" });
    7.	// Initialise the SOAP Endpoint
    8.	ExternalReportWSSService externalReportWSSService = externalReportWSSService_Service.getExternalReportWSSService(securityFeatures);
    9.	// Create a new binding, this example hardcodes the username/password, 
    10.	// the recommended approach is to store the username/password in a CSF keystore
    11.	WSBindingProvider wsbp = (WSBindingProvider)externalReportWSSService;
    12.	Map<String, Object> requestContext = wsbp.getRequestContext();
    13.	//Map to appropriate Fusion user ID, no need to provide password with SAML authentication
    14.	requestContext.put(WSBindingProvider.USERNAME_PROPERTY, "username");
    15.	requestContext.put(WSBindingProvider.PASSWORD_PROPERTY, "password");
    16.	requestContext.put(WSBindingProvider.ENDPOINT_ADDRESS_PROPERTY, "https://yourERPServer:443/xmlpserver/services/ExternalReportWSSService");
    
    17.	// Create a new ReportRequest object using the generated ObjectFactory
    18.	ObjectFactory of = new ObjectFactory();
    19.	ReportRequest reportRequest = of.createReportRequest();
    20.	// reportAbsolutePath contains the path+name of your report
    21.	reportRequest.setReportAbsolutePath("/~angelo.santagata@oracle.com/Bi report.xdo");
    22.	// We want raw data
    23.	reportRequest.setReportRawData("");
    24.	// Get all the data
    25.	reportRequest.setSizeOfDataChunkDownload(-1); 
    26.	// Flatten the XML response
    27.	reportRequest.setFlattenXML(true);
    28.	// ByPass the cache to ensure we get the latest data
    29.	reportRequest.setByPassCache(true);
    30.	// Run the report
    31.	ReportResponse reportResponse = externalReportWSSService.runReport(reportRequest, "");
    32.	// Display the output, note the response is an array of bytes, you can convert this to a String
    33.	// or you can use a DocumentBuilder to put the values into a XLM Document object for further processing
    34.	System.out.println("Content Type="+reportResponse.getReportContentType());
    35.	System.out.println("Data ");
    36.	System.out.println("-------------------------------");
    37.	String data=new String (reportResponse.getReportBytes());
    38.	System.out.println(data);
    39.	System.out.println("-------------------------------");
  6. Going through the code

  7.  
    LineWhat does it do
    1-3This is the instantiation of a new class containing the WebService Proxy object. This was generated for us earlier
    5Initialise a new instance of a security policy object, with the correct security policy, for your Oracle Fusion server . The most common security policy is that of “oracle/wss_username_token_over_ssl_client_policy", however your server maybe setup differently
    8Calls the factory method to initialise a SOAP endpoint with the correct security features set
    9-16These lines setup the SOAP binding so that it knows which endpoint to execute (i.e. the Hostname+URI of your webservice which is not necessarily the endpoint where the SOAP Proxy was generated, the username and the password.In this example we are hard coding the details because we are going to be running this example on the command line. If this code is to be  executed on a JEE server, e.g. Weblogic, then we recommend this data is stored in the Credential store as CSF keys.
    17-19Here we create a reportRequest object and populate it with the appropriate parameters for the SOAP call. Although not mandatory its recommended that you use the objectFactory generated by the SOAP proxy wizard in JDeveloper.
    21This set the ReportPath parameter, including path to the report
    23This line ensures we get the raw data without decoration, layouts etc.
    25By default BI Publisher publishes data on a range basis, e.g. 50 rows at a time, for this usecase we want all the rows, and setting this to -1 will ensure this
    27Tells the webservice to flatten out the XML which is produced
    29This is an optional flag which instructs the BI Server to bypass the cache and go direct to the database
    30This line executes the SOAP call , passing the “reportReport” object we previously populated as a parameter. The return value is a reportResponse object
    34-39These lines print out the results from the BI Server. Of notable interest is the XML document is returned as a byte array. In this sample we simply print out the results to the output, however you would normally pass the resulting XML into Java routines to generate a XML Document.

 

 

Because we are running this code from the command line as a java client code we need to import the Fusion Apps Certificate into the Java Key Store. If you run the code from within JDeveloper then the java keystore is stored in <JDeveloperHome>\wlserver_10.3\server\lib\DemoTrust.jks

Importing certificates

 

  1. 1. Download the Fusion Applications SSL certificate, using a browser like internet explorer navigate to the SOAP WSDL URL
  2. 2. Mouse click on the security Icon which will bring you to the certificate details
  3. 3. View Certificate
    4. Export Certificate as a CER File
  4. 5. From the command line we now need to import the certificate into our DemoTrust.jks file using the following commandkeytool -import -alias fusionKey -file fusioncert.cer -keystore DemoIdentity.jks

jks

Now ready to run the code!

With the runReport.java file selected press the “Run” button, if all goes well then the code will execute and you should see the XML result of the BI Report displayed on the console.

 

Loading Data into Oracle Cloud ERP R10 using the new LoadAndImportData operation

 

Introduction

As part of Oracle ERP cloud release 10 a new SOAP function has been made available to our customers which greatly simplifies the loading of ERP data using the batch oriented SOAP Services.

This article aims to give the reader, details of this new SOAP Service and how it helps in loading data files into Oracle ERP cloud.

Assuming the input file has been already produced, loading the data into Oracle ERP cloud service is traditionally a multi-step process.

The typical "happy" path is :

  1. 1. Load the file into Oracle Fusion ERP UCM service
  2. 2. Execute the first ESS Job which transfers the file from UCM to the Oracle ERP interface tables
  3. 3. Using a polling technique check to see when the ESS job has finished transferring the file into the interface tables
  4. 4. Execute a second ESS job, which transfers the file from Oracle ERP interface tables to the Oracle ERP data object tables
  5. 5. Use a polling technique to check to see when the file has been processed
    6. Finally execute a call to the downloadESSJobExecutionDetails() operation to download a log file so you can check for success,or any errors, which need dealing with.

Whilst this approach appears attractive, as it allows the developer a great deal of control of the process, in truth this internal processing should be something that the SaaS application [Oracle ERP Cloud] should manage and provide feedback to the developer when things finish

New SOAP method in R10

As of Oracle ERP cloud Release 10 there is a new API called "loadAndImportData", which is held within the ERPintegrationService, ( https://(FinancialDomain,Financial Common)/publicFinancialCommonErpIntegration/ErpIntegrationService?WSDL). This service has been specifically created to simplify the loading of data into Oracle ERP Cloud service by allowing you the ability to submit a file which is then automatically taken through the various stages of processing within Oracle ERP Cloud, without the user needing to execute each step of the process manually.

The operation takes the following parameters :

Element NameTypeDescription
documentDocument Information SDOList of elements, each containing the details of the file to be uploaded. The details include the file content, file name, content type, file title, author, security group, and account
jobListProcess Details SDOList of elements, each containing the details of the Enterprise Scheduling Service job to be submitted to import and process the uploaded file. The details include the job definition name, job package name, and list of parameters
interfaceDetailsstringThe interface whose data is to be loaded.
notificationCodestringA two-digit number that represents the manner and timing in which a notification is sent.
callbackURLstringThe callback URL of the service implemented by customers to receive the Enterprise Scheduling Service job status on completion of the job

 

Diving into the Details

A sample soap payload, which imports journal records, looks like the following :

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:typ="http://xmlns.oracle.com/apps/financials/commonModules/shared/model/erpIntegrationService/types/" xmlns:erp="http://xmlns.oracle.com/apps/financials/commonModules/shared/model/erpIntegrationService/">
   <soapenv:Header/>
   <soapenv:Body>
      <typ:loadAndImportData>
         <typ:document>
            <erp:Content>  UEsDBBQAAAAIAMG2b0hvJGqkiAAAAKsBAAAPAAAAR2xJbnRlcmZhY2UuY3N2tY+xDoJADIZ3E9+hD9BIexojIwQWB0wU49yQqgMcyYnv7wELiYEwQIe2/9+mzZelD2Q0xMeA9gExxlKKLRRyJ/bzVIdXrepmoO+3ZLgfoU9EhGzYtA11ajTCcNePc5UKIuhKLE3xPnnz4r+8FM7111kpW+c/eOp8miXbzXJQB2aeAQU91rpUP1BLAQIUABQAAAAIAMG2b0hvJGqkiAAAAKsBAAAPAAAAAAAAAAAAIAAAAAAAAABHbEludGVyZmFjZS5jc3ZQSwUGAAAAAAEAAQA9AAAAtQAAAAAA</erp:Content>
            <erp:FileName>LoadGLData1.zip</erp:FileName>
            <erp:ContentType>zip</erp:ContentType>
            <erp:DocumentTitle>ImportJournalEntry</erp:DocumentTitle>
            <erp:DocumentAuthor></erp:DocumentAuthor>
            <erp:DocumentSecurityGroup>FAFusionImportExport</erp:DocumentSecurityGroup>
            <erp:DocumentAccount>fin$/journal$/import$</erp:DocumentAccount>
         </typ:document>
         <typ:jobList>
      
           <erp:JobName>oracle/apps/ess/financials/generalLedger/programs/common,JournalImportLauncher</erp:JobName>
           <erp:ParameterList>1061,Balance Transfer,1,123,N,N,N</erp:ParameterList>
         </typ:jobList>
         <typ:interfaceDetails>15</typ:interfaceDetails>
         <typ:notificationCode>50</typ:notificationCode>
         <typ:callbackURL>http://somecallbackserver.domain.com/mycallback</typ:callbackURL>
      </typ:loadAndImportData>
   </soapenv:Body>
</soapenv:Envelope>

Now lets dive into each element and explain what it represents and more importantly where you derive the data from :

  • Document : This element contains the details of the document to be uploaded
    • content : This is the document itself, base64 encoded and in-lined in the soap payload. There  are many tools on the internet to base64encode a document and in Java there is a  helper Base64.Encoder which does this for you.
    • contentType : This value should be set to "zip", this means your files must be zipped before base64encoding them and in lining them above
    • documentTitle : A title for the document, this is so you can find it in UCM later if you need to.
    • documentSecurityGroup : Needs to be set to a security group that secures the document, for our example we've used FAFusionImportExport
    • documentAccount : This needs to be set to the correct account depending on the data which is being loaded. For our journal import we need to set the account to fin$/journal$import. This is the same Account used when you "manually" upload files into Oracle ERP for loading.. If you don't know the what UCM account your data should be loaded into you can find it by going into File Based Data Import for Financials Cloud documentation and searching for your data object. In our case the object is "Journal Import" and the documentation states that the UCM account is fin/journal/import. For our SOAP Service we need to prefix each "/" with a "$"
  • jobList : This element contains data describing the job which needs to be executed for this batch upload
    • jobName : This is the "package name" of the ESS job which loads the data into Oracle ERP Cloud. You can find this in FusionAppsOER or in the documentation. The format for the field is "packageName,jobName"
    • parameterList : This is the list of parameters which the job requires to execute. The parameters depend on the ESS Job being executed. In our case the ESS Job is for journals and in our case the parameters are Data Access Set ID, Source (Balance Transfer), LedgerID, GroupID (aka BatchID) etc
    • [caption id="attachment_37609" align="alignnone" width="300"]journalimport Example from FusionOER[/caption]
  • interfaceDetails :  This is set to 15 for journals  (no longer needed in R11)
  • notificationCode : This is set to 50 (no longer needed in R11)
  • callBackURL :  The magic about this service is that it executes all of the ESS jobs in the background and then executes a callback to your service when its finished. This response contains the "last" ESSjob ID executed so you can then query the status of the jobs using the downloadESSJobExecutionDetails method.

 

Handling the callback

  • As mentioned earlier, the loadAndImportData operation does all heavy lifting, and orchestration , within Oracle Fusion ERP SaaS, the only thing the developer needs to implement [optionally but very desirable], is a webservice endpoint which manages the callback generated by the ESS framework. This service needs to implement the ESS onJobCompletion operation, which will deliver three pieces of data, the requestId of the ESSJob which completed, the state of the process and a status message. For more information on handing the ESS callbacks please see this documentation link, and additionally if you are using BPEL to execute the SOAP Service then this documentation link may be of interest (Section 11.7.7 : Receive the Job Completion Status)

 

Conclusion

The new LoadAndImportData operation will most certainly make importing of data into Oracle ERP a much simpler process, its biggest advantage is that developers will easily be able to trigger the import with a single SOAP call which can easily be done without the need to worry about orchestration. There are however scenarios when you would you probably use the traditional , step by step method, for example when you want to control/trigger external notification providers that each step has been executed at the macro level or when the import file size is very large (>100Mb). In the latter case you might want to upload the file into Oracle UCM using UCMs native IdcWebService, which supports MTOM and then execute the ESS jobs in order as we have traditionally done.

 

 

Thursday Mar 31, 2016

Working with MCS Offline? Need some hints and tips?


Mobile Cloud Service


Another collection of videos I was highlighted today on MCS on how to do data offline sync. Awesome stuff , one note however is that the videos are IOS based today but Im being told that the Android versions are enroute.... These videos provide a end2end discussion on how to work with these capabilities not just the APIs themselves.. Very nice....
Also remember to read the docs which cover both Android and IOS

Thursday Mar 24, 2016

Using ICS to integrate SaaS Applications??

Are you doing SaaS, or EBS,  integrations and using Oracle Integration Cloud Service (ICS)?

Do you need some inspiration? Well this is your lucky day!

Below you'll find a collection of ICS Integration videos , produced by our product managers and our UA development team which go though, step by step, how to integrate  two SaaS applications

 

There are plenty more videos available at the Oracle Help Centre here 

Make sure you comment on the videos in youtube so that the developers can enhance these and any future youtube videos

Angelo 

Thursday Jan 14, 2016

Integrating Oracle Document Cloud and Oracle Sales Cloud, maintaining data level business object security

Just written an article on http://www.ateam-oracle.com/ on how one would integrate SalesCloud and Documents cloud together. Interested? go and check it out!
Link to article

Adding a contact to a sales cloud account

A common question is how do you add a contact to a Account in Sales Cloud? Ive seen developers (including me) try to issue a mergeOrganizaiton on the org, however this is not correct. In Oracle Fusion , Contacts are not "addded" to accounts but they are "related" to accounts.. Therefore to add a contact to a account you need to add a "Relationship" which links the contact and the organization. Here's a sample payload

WSDL <host>/crmCommonSalesParties/RelationshipService?wsdl

SOAP Request Payload

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:typ="http://xmlns.oracle.com/apps/crmCommon/salesParties/relationshipService/types/" xmlns:rel="http://xmlns.oracle.com/apps/crmCommon/salesParties/relationshipService/">

   <soapenv:Header/>
 <soapenv:Body>
      <typ:createRelationship>
         <typ:relationship>
<!-- ContactId -->
            <rel:ObjectPartyId>300000000943126</rel:ObjectPartyId>
<!-- AccountId -->
            <rel:SubjectPartyId>300000000943078</rel:SubjectPartyId>
            <rel:RelationshipType>CONTACT</rel:RelationshipType>
            <rel:RelationshipCode>CONTACT</rel:RelationshipCode>
            <rel:CreatedByModule>HZ_WS</rel:CreatedByModule>
            <rel:Status>A</rel:Status>
         </typ:relationship>
      </typ:createRelationship>
   </soapenv:Body>
</soapenv:Envelope>

Groovy Script Example

def addContact =
[
        ObjectPartyId        : '300000000943126', /*Contact */
        SubjectPartyId       : '300000000943078', /*Account */
        RelationshipType  : 'CONTACT',
        RelationshipCode  : 'CONTACT',
        CreatedByModule : 'HZ_WS',
        Status  : 'A'
];

adf.webServices.RelationshipService.createRelationship(addContact);

 

 

 

 

 

Monday Jan 11, 2016

Intro to JCS

Happy New Year all!!!

 

To start this year's blogging I thought id highlight a nice and easy quick win on getting started with Oracle Java Cloud Service..  This link https://www.youtube.com/watch?v=5DHsE2x5mks takes you to a youtube video which I found very clear and easy to follow.

 

Enjoy

Thursday Jul 02, 2015

Streamline Oracle Development with Cloud Services

Streamline Java Development with Cloud Services
On-Demand Webinar Replay

Learn to deliver java applications to market faster. Reduce hardware and software costs for new development and testing environments. Improve DevOps efficiency. Build, test and run enterprise-grade applications in the Cloud and on premise.

Listen to this webinar replay with development expert James Governor, co-founder of RedMonk, and Daniel Pahng, President and CEO of mFrontiers, LLC, an ISV with hands-on experience developing enterprise mobility and Internet of Things (IOT) solutions, as they present this webcast on developing applications in the cloud.
Listen today!
For more information:
July 2015                                                                                          Oracle Corporation - All rights reserved

Wednesday Jul 01, 2015

Calling Fusion SOAP Services from Ruby

Just completed some integration work with a partner of ours using the Ruby language. Given that a lot of startups like Ruby I thought it would be useful to cut-n-paste the sample code here.
This example creates a simple (minimal) opportunity using the SOAP API in Sales Cloud. That said the code would be almost identical if you were querying HCM Data,
The approach we took here was to prototype the SOAP call using SOAPUI and then cut-n-paste the SOAP payload into the data variable. In a real industrialized solution I'd create the payloads in template form.


  def create_opportunity

  # Change yourhostname.com to your Fusion SOAP Endpoint Hostname

    http = Net::HTTP.new(uri.host, uri.port)
    http.use_ssl = true
    path = uri.request_uri
    http.read_timeout = 5
    http.open_timeout = 5


  # Change authorization header to contain Base64encoded string of username/password
    headers = {
    'Content-Type' => 'text/xml',
    'authorization' => 'Basic bBase64EncodedCredentialHere='
    }

   
   # Data Contains the payload
    <soapenv:Header/>
    <soapenv:Body>
    <typ:createOpportunity>
    <typ:opportunity>
    <opp:Name>Joel Test New1</opp:Name>
    </typ:opportunity>
    </typ:createOpportunity>
    </soapenv:Body>
    </soapenv:Envelope>'

    resp, data = http.post(path, data, headers)
  end

!TIP!
A quick test in a SOAP testing tool like JDevelopers Http Analyzer or SOAPUI is a MUST before executing this!

Wednesday Jun 03, 2015

URL Encoding and other from Groovy

There are times when you want to execute some code within Groovy which Oracle Sales Cloud's groovy doesn’t like. A very common example is URLEncode and Base64Encoding, however there are many others..


Native Groovy supports both base64 encoding/decoding and URL Encoding/Decoding


e.g.



String encoded = s.bytes.encodeBase64.toString()



Alas the groovy interpreter within Sales Cloud doesn’t support either the base64 encoding/decoding classes or the URLEncoding classes. Thankfully there is a an easy workaround, Sales Cloud does support the ability to call a SOAP Service from Sales Cloud and given that many SalesCloud installations will have a Java Cloud SX instance available to them its quite easy to create a Java SOAP Service, deploy it to JCSSX and then call this from Sales Cloud to do the stuff that Sales Cloud’s groovy wont allow you to do.



https://4.bp.blogspot.com/-W_PVvNpvJ_Y/VW7a8Ow9DpI/AAAAAAAAMq8/FOvtRAKulGM/s400/base64image.jpg


Steps to recreate this

  1. Create a new Project within your favourite IDE (I use JDeveloper11g for Sales Cloud Development, Netbeans for other stuff)

  2. Ensure your project has support for JAX-WS WebServices, within JDeveloper  create a JEE project.

  3. Within your project create a new Java class, I’ve called PTSEncoder

  4. Now cut and paste the following code into this class, obviously rename the Class name if you havent used the same name as I have

package oracle.pts.encoder;

import java.io.IOException;

import java.io.UnsupportedEncodingException;

import java.net.URLDecoder;

import java.net.URLEncoder;

import javax.jws.WebMethod;

import javax.jws.WebService;

import javax.xml.bind.DatatypeConverter;

@WebService

public class PTSEncoder {

   public PTSEncoder() {

       super();

   }


   /**

    *

    * @param s - String to be translated

    * @return

    */

@WebMethod(operationName = "encode")

   public String utf8encode(String s) {

       String result = "";

       try {


           result = URLEncoder.encode(s, "UTF-8");

           System.out.println("Encoded URL " + result);


       } catch (UnsupportedEncodingException e) {

           System.err.println(e);

       }

       return result;

   }


   /**

    *

    * @param s - String to be translated

    * @param enc - The name of a supported character encoding

    * @return

    */

   @WebMethod(operationName = "encodeWithEncType")

   public String ptsEncodeWithEncType(String s, String enc) {

       String result = "";

       try {

           if (enc == null || enc.length() <= 0) {

               enc = "UTF-8";

           }

           result = URLEncoder.encode(s, enc);

           System.out.println("Encoded URL " + result);


       } catch (UnsupportedEncodingException e) {

           System.err.println(e);


       }

       return result;

   }


   /**

    *

    * @param s - String to be translated

    * @return

    */

   @WebMethod(operationName = "decode")

   public String ptsDecode(String s) {

       String result = "";

       try {


           result = URLDecoder.decode(s, "UTF-8");

           System.out.println("Decoded URL " + result);


       } catch (UnsupportedEncodingException e) {

           System.err.println(e);

       }

       return result;

   }


   /**

    *

    * @param s - String to be translated

    * @param enc - The name of a supported character encoding

    * @return

    */

   @WebMethod(operationName = "decodeWithEncType")

   public String ptsDecodeWithEncType(String s, String enc) {

       String result = "";

       try {

           if (enc == null || enc.length() <= 0) {

               enc = "UTF-8";

           }

           result = URLDecoder.decode(s, enc);

           System.out.println("Decoded URL " + result);


           // String decodedUrl = URLDecoder.decode(encodedUrl, "UTF-8");

           //System.out.println("Dncoded URL " + decodedUrl);


       } catch (UnsupportedEncodingException e) {

           System.err.println(e);


       }

       return result;

   }


   /**

    * @param s

    * @return

    * @throws IOException

    */

@WebMethod(operationName = "encodebase64")

   public String ptsEncodeBase64(String s) throws IOException {        

       return DatatypeConverter.printBase64Binary(s.getBytes());

   }


   /**

    * @param s

    * @return

    * @throws IOException

    */

   @WebMethod(operationName = "decodebase64")

   public String ptsDecodeBase64(String s) throws IOException {    

       String result = new String(DatatypeConverter.parseBase64Binary(s));

       return result;

   }

// Simple tester

@WebMethod(exclude = true)

   public static void main(String[] args) {

       PTSEncoder pTSEncode = new PTSEncoder();

       pTSEncode.utf8encode("Angelo Woz here");

       pTSEncode.ptsEncodeWithEncType("Angelo Woz Here", "UTF-8");

       pTSEncode.utf8encode("------------");

       pTSEncode.ptsDecode("Jo was here");

       pTSEncode.ptsDecodeWithEncType("Jo Was here", "UTF-8");


       try {

           System.out.println("Encode Angelo = "+pTSEncode.ptsEncodeBase64("Encode Angelo"));

       } catch (IOException e) {

           e.printStackTrace();

       }

   }

}


For interest I created this class by first creating the methods and then using J Developers wizard to convert a class+methods into a SOAP WebService. This class uses Java annotations which tell at JEE server that most (not all) of these methods are WebService calls. This is done using server side injection at deployment time.

  1. If within JDeveloper you created your project as a web/jee project you can simply deploy it as is to your JCSSX, or local WLS Application Server

    1. Right Mouse Click on the Project, deploy to your deployment profile

    2. Deploy to Application Server

    3. Choose your application server and deploy

    4. Check the deployment

You can now test the SOAP Service using a SOAP testing tool like Http Analyzer or SOAP UI. The WSDL of the service would be the contextRoot+WebService Name. For JDeveloper this can be found if you right-click on the Webservice Class,Java WebServices Editor and look at the generation options



So in my instance the WSDL will be available at


https://<JCSSXServer>.java.us2.oraclecloudapps.com/PTSEncoder/PTSEncoderService?wsdl



  1. You can put this into SOAPUI or Http Analyzer and test away

  2. Now last you can register it in Sales Cloud as a web service and use it from Groovy

    1. Activate a Sandbox,  that way you can undo changes if oyu want

    2. Navigate to Application Composer

    3. Navigate to the application you will be using the SOAP WebService from (Common,Sales etc)

    4. Select WebServices

    5. Enter a name for the WebService, this name becomes the groovy package name

    6. Security None (for testing only)

    7. Then finally use the SoapService from any groovy script you desire, remember the Palette helps you find different services registered on you system



Sample Groovy Code

def base64result = adf.webServices.PTSBase64.encodebase64("Angelo Woz Here")


Final footnote

This example shows how to execute a base64 encoding externally using Java Cloud ServiceSaaS eXtensions (JCSSX), the example could easily have used Java Cloud Service, or some other Cloud service. More importantly you can code extensions using Java Cloud Service and call them from SalesCloud. Given that most JCSSX instances are going to be co-located within the same datacentre this makes the operation quick, efficient and very flexible!

Lastly, the service I deployed didn’t contain any security because it’s a stateless service and ok for anyone to call, that said in a production environment I would still add a medicum of security to the service just to make sure someone doesn’t try and abuse it.

Angelo
Enjoy!


Monday May 04, 2015

Getting started with Sales Cloud (Updated)

Hey all, Ive just reviesed the Getting Started with Oracle Sales Cloud Integrations blog entry with a few more links

Wednesday Apr 29, 2015

SalesCloud Payload : How to create a Activity(Task)



From SalesCloud R9 onwards we now have Activities.. Activities can be tasks, appointments etc. 
Object Name Activity
WSDLhttps://<hostname>:443/appCmmnCompActivitiesActivityManagement/ActivityService?wsdl
Version Tested on R9
 DescriptionThis payload demonstrates how to create an activity of type TASK, assign a primary lead owner 
OperationcreateActivity
 Parameters
*Required
PriorityCode*,
StatusCode
ActivityContact
ActivityTypeCode*
ActivityFunctionCode*
Subject
 Payload
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:typ="http://xmlns.oracle.com/apps/crmCommon/activities/activityManagementService/types/" xmlns:act="http://xmlns.oracle.com/apps/crmCommon/activities/activityManagementService/" xmlns:not="http://xmlns.oracle.com/apps/crmCommon/notes/noteService" xmlns:not1="http://xmlns.oracle.com/apps/crmCommon/notes/flex/noteDff/">
   <soapenv:Header/>
   <soapenv:Body>
      <typ:createActivity>
         <typ:activity>
<!-- Priority = 1,2,3 , high, medium, low -->
            <act:PriorityCode>1</act:PriorityCode>
            <act:StatusCode>NOT_STARTED</act:StatusCode>
            <act:ActivityContact>
<!-- Primary contact ID-->
               <act:ContactId>300000093409168</act:ContactId>
            </act:ActivityContact>
            <act:ActivityAssignee>
<!-- Party ID of Assignnee -->
               <act:AssigneeId>300000050989179</act:AssigneeId>
            </act:ActivityAssignee>
            <act:ActivityTypeCode>MEETING</act:ActivityTypeCode>
            <act:ActivityFunctionCode>TASK</act:ActivityFunctionCode>
           
            <act:Subject>Test assign to Matt Hooper for Picard</act:Subject>
         </typ:activity>
      </typ:createActivity>
   </soapenv:Body>
</soapenv:Envelope>

Monday Apr 20, 2015

Creating Sales Cloud Opportunity

Common Payload creating opportunities

  <createOpportunity>
    <opportunity>
      <ChildRevenue>
        <ProdGroupId>300000000537006</ProdGroupId>
        <RevnAmount>45000.0</RevnAmount>
        <ResourcePartyId>300000000519815</ResourcePartyId>
      </ChildRevenue>
      <SalesStageId>300000000157471</SalesStageId>
      <Comments>Provide training to 250 salespersons and support staff</Comments>
      <EffectiveDate>2012-09-30</EffectiveDate>
      <WinProb>5.0</WinProb>
      <Name>New Sales Training</Name>
      <OptyCreationDate>2012-08-27T00:00:00.000</OptyCreationDate>
      <TargetPartyId>300000001025130</TargetPartyId>
      <OwnerResourcePartyId>300000000519815</OwnerResourcePartyId>
      <OpportunityResource>
        <ResourceId>300000000519815</ResourceId>
        <OwnerFlag>true</OwnerFlag>
      </OpportunityResource>
    </opportunity>
  </createOpportunity>




Sample Java Code

1. Generate Proxy using Java Tooling (like JDeveloper)
2. Java Code Snippet

public static void main(String[] args) {

        // Default Values
        String username = "matt.hooper";
        String password = "somepassword";
        String SSLSecurityPolicy = "oracle/wss_username_token_over_ssl_client_policy";

        SecurityPolicyFeature[] securityFeature = new SecurityPolicyFeature[] { new   
SecurityPolicyFeature(SSLSecurityPolicy) };

        String url="https://<yourhost>/opptyMgmtOpportunities/OpportunityService?WSDL";
        // Setup the webservice interface
        OpportunityService_Service opportunityService_Service = new opportunityService_Service();
        OpportunityService opportunityService = opportunityService_Service.getopportunityServiceSoapHttpPort(securityFeature);
        // Get the request context to set the outgoing addressing properties
        WSBindingProvider wsbp = (WSBindingProvider)opportunityService;
        Map<String, Object> requestContext = wsbp.getRequestContext();
        requestContext.put(WSBindingProvider.USERNAME_PROPERTY, username);
        requestContext.put(WSBindingProvider.PASSWORD_PROPERTY, password);
        requestContext.put(WSBindingProvider.ENDPOINT_ADDRESS_PROPERTY, url);

        System.out.println("Example of creating an opportunity ");

        // Create Payload        
        ObjectFactory factory = new ObjectFactory();
        opportunity newopportunity=factory.createopportunity();
        newOpportunity.setName("Name of Opportunity");
        // Set other values
        //
        Opportunity result=opportunity.createOpportunity();
        // and so on




Tuesday Apr 14, 2015

Scheduling Processes on Oracle JavaCloud Service SaaS Extensions (JCSSX)

In the past if we wanted to schedule some background processing in JCSSX we had to get help from the database's scheduler.. Using a clever feature of SchemaDB, that is the ability to call a REST Service from a PLSQL procedure, which in turn would execute our code on JCSSX we were able to effectively execute code on JCSSX at determined intervals/times etc. All this is now unnecessary! With the current version of JCSSX we now fully support a list of 3rd party frameworks (see link for a list) and Quartz is one of them. Jani, colleague from the Fusion Developer Relations team, has written up a really nice blog posting on the FADevrel blog summarising what you can do with Quartz and some code to get you started..You could say "Quartz in 10mins" blog! Check it out
About

Architect & Technology Evangelist - If its middleware,PaaS/SaaS integration then I'm interested

The views expressed on this blog are my own and do not necessarily reflect the views of Oracle.

Search

Archives
« July 2016
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
31
      
Today