Angelos PaaS4SaaS Blog

Friday, 19 June 2015

Oracle Process Cloud, calling Fusion Apps WebServices - An Example

Now that Oracle Process Cloud is available I thought it’s about time that I wrote a quick blog article on how you can integrate Oracle Process Cloud with Sales Cloud. Before I continue I do need to thank Marcio in my team for figuring out how to get the WSDLs in a format that process cloud liked. The scenario I will go through here is that of how to call Sales Cloud Methods from Process Cloud.
Assumptions: I won’t be going through details of building a Process Cloud model, I’m assuming you already know this but are more interested in how to execute the Sales Cloud SOAP call from Oracle Process Cloud.
Our final Architecture will look similar to this

There are number of discrete steps we need to do to:
  1. Determine which SOAP Service we will be calling
  2. Prepare a WSDL Schema/XSD bundle ZIP file (temporary workaround)
  3. Implement the Process Cloud Process

Step 1 : Determine which SOAP Service we will be calling

First step is to determine which SOAP webservice we will be calling and what the payload would be. For contacts we would have searched FusionAppsOER and discovered that we want to use the Oracle Sales Cloud Contact webservice and the “CreateContact” is the likely candidate:

Scrolling to the bottom of the detail tab I also note the Service WSDL is
http://CRMSERVER/crmCommonSalesParties/ContactService?WSDL


In the past you may have created Contacts using the SalesParties Webservice, this is no longer recommended, although it does work, and you should be using these new simpler WebServices.
The contact service is part of the new R9 Simplified SOAP Services for TCA, and the docs are available from the usual places, or Oracle Support as Note:1938666.1
A simple “Create a standalone contact” would be something like this:

WSDL https://<server>:443/crmCommonSalesParties/SalesPartyService
Method createContact
Request
Payload
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:typ="http://xmlns.oracle.com/apps/crmCommon/salesParties/contactService/types/" xmlns:con="http://xmlns.oracle.com/apps/crmCommon/salesParties/contactService/" xmlns:com="http://xmlns.oracle.com/apps/crmCommon/salesParties/commonService/">
  <soapenv:Header/>
  <soapenv:Body>
     <typ:createContact>
        <typ:contact>
           <con:FirstName>Cleo</con:FirstName>
           <con:LastName>Santagata</con:LastName>               
           <con:Type>ZCA_CUSTOMER</con:Type>
           <con:PrimaryAddress>
              <com:AddressNumber>25</com:AddressNumber>
              <com:AddressLine1>Upper Apartments</com:AddressLine1>
              <com:AddressLine2>Kensington High Street</com:AddressLine2>
              <com:AddressLine3>Kensington</com:AddressLine3>
              <com:AddressLine4></com:AddressLine4>
              <com:City>London</com:City>
              <com:Country>GB</com:Country>
           </con:PrimaryAddress>
        </typ:contact>
     </typ:createContact>
  </soapenv:Body>
</soapenv:Envelope>


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

Now let’s do the same within Oracle Process Cloud and create our “Process Cloud calling Sales Cloud Process”.

Step 2 : Prepare a WSDL Schema/XSD bundle ZIP file

Before we can use the SOAP Service we need to do some preparation work. Oracle Process Cloud currently requires a WSDL which either -
  • Contains the entire WSDL+Schema inline or
  • A ZIP file with two folders, one with the Schemas and one with the WSDL. (Schema and WSDL respectively)
Temporary Workaround
Currently for Fusion Applications we need to do the latter, however this is a temporary workaround whilst development enhance the Service Call functionality to accept and download all the WSDL’s.

Until we have a tool to do this (and we’re working on it) there is an easy way of doing by using JDeveloper 11g, and the BPM plug in. What you do is create a project, add the WSDL that you want to harvest and let JDeveloper11g download all the assets for you. Then you go along using file manager and gather up the WSDL & XSDs, put them in the right directory and do some fix-ups.
  1. Start JDeveloper 11g (11.1.1.7.1 is ideal)
  2. Install the BPM Extension using Check for updates wizard
  3. Restart JDeveloper11g
  4. Create a new Project (the name doesn’t matter)
  5. Next, Call the project something (again doesn’t matter)
  6. In the SOA Settings Screen select an EMPTY composite
  7. From the component palette drag and drop the Web Service Component onto the External References gully

  8. When the create web service wizard give it the following options


Name
Anything you like
Type
Reference
WSDL URL
As found in Fusion OER above
Port Type
Contact Service
Callback Port Type
Not needed as this is used for asynchronous webservices
Copy WSDL and its dependant artefacts into the project
CHECKED,  this is important as this does the magic

At this point JDeveloper11g is downloading the WSDL and all the XSDs onto your local hard disk, when its finished hit Save All
  1. Now select the project in the project navigator and then look at the bottom of the JDeveloper11g Window, this will let you know where the project is stored on your pc.
  2. With your favourite file manager navigate to the project directory, sort the folder by “type”, you will then see all the WSDLs and the XSDs
  3. Create a folder called “Zip”, within this directory create a folder called “Schemas” and “WSDLs”
  4. Select all the XSDs and move them into the zip/Schemas directory
  5. Select all the WSDLs and move them into the zip/WSDLs directory

Now within the WSDL directory you now need to edit each WSDL file (ServiceException.wsdl and ContactService.wsdl) change the references to the schemas so that the resolve correctly on your file system.
E.g. For this example within the ServiceException.wsdl file

From this

To this

Repeat for all schemaLocation references in this file and others (ie ContactService.wsdl)
Warning : The zip file’s WSDL will contain a endpoint pointing to your Sales Cloud WSDL, if the one you will be accessing is different the will need to change it


e.g. in ContactService.wsdl
  1. Once you done this you can zip up the zip directory into a ZIP file, and then rename it to something descriptive, like SalesCloudContactService.zip.
  2. You can now exit JDeveloper11g and delete the project if you wish, we don’t need it anymore

To help people along, I’ve created this zip (ContactService.zip) file for you, all you need to do is unzip it, and change the SOAP Endpoints and voila your ready for the next step.



Step : Implement the Process Cloud Process
OK, its now time to implement that Oracle Process Cloud Process, I’ll leave the details to the reader as I’m assuming they already know how to call process cloud and just cover the “SOAP Pieces”.
Here I’m assuming you’ve implemented a Workflow/Process model similar to the following:

All we need to do here is add the “Call Sales Cloud” when the contact has been approved.
  1. Go to the home page of Process Cloud and Select WebServices  and select + to create a new WebService Definition
  2. Give your webservice a name
  3. Select he WSDL file chooser and use the zip file previously created
  4. Select the following Port Type, Callback Port Type, Basic Authentication according to the image below (using your own username/password)
  5. Press OK and it gets Saved
  6. Back to the Process Modeller
  7. We can now add the service call to the Approve branch of the model, call it createContact
  8. Select and Edit the implementation of the branch
  9. Set the type to Service Call and select your WebService call and the SOAP operation is createContact
  10. Apply Changes
  11. Select the Service, then select Data Association, here we’re going to map our input fields to the SOAP Service fields
  12. Expand out the createContact input data type (nb: it will be quite large)
  13. Then Drag-n-Drop all the fields from within the Data Objects Palette to the appropriate fields in the input


    You’ll find the address fields near the bottom
  14. Apply
  15. Hit the Validate button and sort out any issues then , press the Test  button and deploy the process to your test instance
  16. Add your users to the “Process Owner” and “Process Approver” Roles and then test your integration. Remember you can use the Tracking Screen to monitor the SOAP calls.

Hope this helps!

Wednesday, 3 June 2015

Base64 and URL Encoding with Groovy and Java Cloud SX (PaaS)

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 has completed
You can now test the SOAP Service using a SOAP testing tool like Http Analyzer or SOAPUI 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 data-centre 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 modicum of security to the service just to make sure someone doesn't try and abuse it.

Angelo
Enjoy!