Sunteți pe pagina 1din 25

Integration Workbook: Spring '12

Integration Workbook

Last updated: March 7 2012


Copyright 20002012 salesforce.com, inc. All rights reserved. Salesforce.com is a registered trademark of salesforce.com, inc., as are other

names and marks. Other marks appearing herein may be trademarks of their respective owners.

Table of Contents

Table of Contents
Force.com Integration Workbook.........................................................................................................2 Before You Begin.................................................................................................................................3 Tutorial #1: Configure Remote Access Settings.....................................................................................5 Tutorial #2: Create a Merchandise Item Using Java................................................................................7
Step 1: Update the Properties File.............................................................................................................................................7 Step 2: Read the Properties File................................................................................................................................................8 Step 3: Log In with OAuth.......................................................................................................................................................8 Step 4: Add Data Via the API..................................................................................................................................................9 Step 5: Compile and Run the App..........................................................................................................................................10 Java Integration Summary.......................................................................................................................................................11

Tutorial #3: Create a Merchandise Item Using C#................................................................................12


Step 1: Update the Properties File...........................................................................................................................................12 Step 2: Read the Properties File..............................................................................................................................................12 Step 3: Log In with OAuth.....................................................................................................................................................13 Step 4: Add Data Via the API................................................................................................................................................14 Step 5: Compile and Run the App..........................................................................................................................................15 C# Summary...........................................................................................................................................................................15

Tutorial #4: Connecting the Warehouse App with an External Service .................................................17
Step 1: Create an External ID Field on Invoice Statement.....................................................................................................17 Step 2: Create a Remote Site Record for the Fulfillment Web Service...................................................................................17 Step 3: Create an @future Method to Post Invoice Statements to the Fulfillment Web Service............................................18 Step 4: Test the @future Method............................................................................................................................................20 Step 5: Create a Trigger to Call the @future Method.............................................................................................................21 Step 6: Test the Integration.....................................................................................................................................................22 Summary.................................................................................................................................................................................23

Force.com Integration Workbook

Force.com Integration Workbook


One of the most frequent tasks Force.com developers undertake is integrating Force.com apps with existing applications. The tutorials within this workbook are designed to introduce the technologies and concepts required to achieve this functionality. The Force.com Integration Workbook is intended to be the companion to the Force.com Workbook. The series of tutorials provided here extend the Warehouse application by connecting it with an on-premise buyer application, and a cloud-based fulfillment app.

Intended Audience
This workbook is intended for developers new to the Force.com platform but have existing experience in Java or C#.

Tell Me More....
This workbook is designed so that you can go through the steps as quickly as possible. At the end of some steps, there is an optional Tell Me More section with supporting information. You can find the latest version of this and other workbooks at developer.force.com/workbooks. To learn more about Force.com and to access a rich set of resources, visit Developer Force at http://developer.force.com.

Before You Begin

Before You Begin


Before you begin the tutorials, you must have completed at least tutorials 1 through 8 in the Force.com Workbook. Youll also need Administrator privileges to your local machine. In addition, this workbook requires you to install some software components (either the Java SDK, or .NET Framework depending on the tutorials you complete) and download the necessary tutorial files.

Java Tutorial Files


1. Download this file: http://bit.ly/aw2012-java. 2. Unzip the files to a folder you can find easily. Putting it on your desktop is a convenient place. 3. You should see a folder with the following:

4. To verify that your system can build Java projects, run the appropriate checkinstall program for your configuration: For Windows, double click checkinstall.bat. For OS X, double click checkinstall.command.

5. If the check is successful, youll get a success message, and you can close the window and proceed with the tutorials. If not, a Web browser will open to the Oracle download page for the Java SDK. Follow the online download instructions for your version of Windows. Once youve installed the Java SDK, you can test your installation by re-running the checkinstall program. Note: For most Windows based PCs, you should download the Windows x86 version of the Java SDK.

Before You Begin

C# Tutorial Files
1. Download this file: http://bit.ly/aw2012-csharp. 2. Unzip the files to a folder you can find easily. 3. You should see a folder with the following:

4. Verify that your system can compile C# projects by double clicking checkinstall.bat (the file extension may not appear in the folder view). 5. If the check is successful, youll see a command window displaying a success message: SUCCESS: csc.exe file found. You can then close the window and proceed with the tutorials. If unsuccessful, the script will open an Internet Explorer window to the download page for the required .NET Framework. Follow the online download instructions for your version of Windows. Once you have installed the .NET Framework, you can test your installation by re-running checkinstall.bat.

Tutorial #1: Configure Remote Access Settings

Tutorial #1: Configure Remote Access Settings


External applications must authenticate remotely before they may access data. Force.com supports OAuth 2.0 (hereafter referred to as OAuth) as an authentication mechanism. With OAuth, a client application delegates the authentication to a provider, in this case Force.com, which in turn issues an access token if the user successfully authenticates. As a result, your application doesn't need to handle authentication explicitly; it simply needs to ensure that a valid access token accompanies all interactions with the API. You can typically download an OAuth library to do the heavy lifting. Before an application can use OAuth, you have to configure your environment. Log in to your Force.com organization as an administrator and configure a remote access application. 1. 2. 3. 4. 5. 6. Navigate to App > Setup > Develop > Remote Access. Click New. For Application, enter Buyer Client. For Callback URL, enter warehouse://success For Email, enter your email address. Click Save.

The detail page for your remote access configuration will display a consumer key as well as a consumer secret (which you have to click to reveal). You'll need these in later tutorials.

Tutorial #1: Configure Remote Access Settings

Tell Me More....
If you're familiar with OAuth, you'll understand that the callback URL is traditionally the URL that a user's browser is redirected to after a successful authentication transaction. For our sample application, however, well use the user/password flow of OAuth. Our application doesnt have a user interface so we cant present a login screen to delegate authentication back to Force.com. The user/password flow is often used for existing on-premise apps, while delegated authentication is more common in mobile application scenarios.

Tutorial #2: Create a Merchandise Item Using Java

Tutorial #2: Create a Merchandise Item Using Java


Buyers, in our fictitious scenario, use a mix of mobile apps and existing systems to buy products. Once a buy has been completed, the new Merchandise item needs to be reflected in the Warehouse app. In this tutorial, we use Java to create an application for entering a new Merchandise item into our Warehouse app. Our sample buyer app will use a properties file to hold the information specific to your Force.com organization and to describe the item being entered. This is a simple example of using an application to integrate with the Force.com platform. While, in this case, well be entering the information about the item manually, the text file may in the real world be updated by a different process which could then use this sample application to automatically keep the warehouse inventory updated.

Step 1: Update the Properties File


Before the app can communicate with the server, youll need to let the application know a few things about the Force.com organization it will be communicating with. 1. Navigate to the folder where you unzipped the Java tutorial files. 2. Open AddMerchandise.properties in a text editor. 3. Replace {USERNAME} with your Force.com username. Be sure to replace all of {USERNAME}, including the curly bracket characters. 4. Log into your Force.com organization. 5. Go to Setup > My Personal Information > Reset My Security Token and press Reset Security Token. A new security token will be sent to the email address registered with your user account. 6. In AddMerchandise.properties, replace {PASSWORD} with your Force.com password and the security token sent to your email address. If your password is mypassword and your security token is AAAA1111, you would replace {PASSWORD} with mypasswordAAAA1111. Again, be sure to replace all of {PASSWORD}, including the curly bracket characters. 7. Go to Setup > Develop > Remote Access and open the Remote Access application you created earlier. 8. Click Click to Reveal. 9. Copy the text next to client.id and replace {PUBLICKEY} with the text. 10. Similarly, copy the text next to client.secret and replace {PRIVATEKEY} with the text. 11. Where it reads merchandise.name, enter Tiny Top after the = sign. 12. Where it reads merchandise.inventory, enter 5 after the = sign. 13. Where it reads merchandise.description, enter Shiny Top after the = sign. 14. For now, leave merchandise.price intentionally blank. 15. Save the file. You may remember that Price was a required field for the Merchandise object. Were keeping that field blank for now to show how the API reacts when an application using the API attempts to insert an object that doesnt meet the validation rules specified in your app.

Tutorial #2: Create a Merchandise Item Using Java

Step 2: Read the Properties File


Now lets take a look at the Java code to see how these properties are read. 1. Navigate to src/com/samples/onpremise from where you unzipped the Java tutorial files. 2. Open AddMerchandise.java in your text editor. 3. Scroll down to the main() function. The main() function acts as the starting point for our application, and is executed when its run from the command line. The following code snippet loads the username and password information.
public static void main(String [] args){ Properties props = new Properties(); try { props.load(new FileInputStream("AddMerchandise.properties")); String username = props.getProperty("username"); String password = props.getProperty("password"); if (username == null || username.trim().equals("") || password == null || password.trim().equals("")){ throw new IllegalArgumentException ("Provide a username and password in the properties file"); ... }

Tell Me More....
The function first loads in the properties file and attempts to read the username and password into variables. If the username or password information in the properties file is invalid, an error exception is thrown. After the function reads all the properties, its ready to log in by calling login2ForceDotCom.
ForceLogin login = login2ForceDotCom(username, passsword, clientId, clientSecret, loginURL);

In the next tutorial well take a look at this function and how OAuth works.

Step 3: Log In with OAuth


Since OAuth is based on HTTP protocols, all we need to do to communicate with it is set up the correct HTTP GET and POST calls and then parse the JSON (JavaScript Object Notation) results. To get this functionality in our application, well uncomment some existing code.
AddMerchandise.java should still be open in your text editor, so scroll down to login2ForceDotCom and uncomment

the function. To do so, remove the /* and */ characters shown here:


/* private static ForceLogin login2ForceDotCom(String uName, String pwd, String id, String secret, String url){ e.printStackTrace(); } return null; } */

...

Tutorial #2: Create a Merchandise Item Using Java

The following code snippet shows where the function makes the actual callout to OAuth:
postURL+="/services/oauth2/token?grant_type=password&client_id="+id+"&client_secret="+ secret+"&username="+uName+"&password="+pwd; DefaultHttpClient httpclient = new DefaultHttpClient(); HttpPost post = new HttpPost(postURL); try { HttpResponse response = httpclient.execute(post); final int statusCode = response.getStatusLine().getStatusCode(); if (statusCode != HttpStatus.SC_OK) { System.out.println("Error authenticating to Force.com:"+statusCode); System.out.println("Error is:"+EntityUtils.toString(response.getEntity())); return null; }

This method creates the URL with the correct parameters, including the consumer public and private keys to correctly identify the application and the users username and password. Normally, an authentication flow with OAuth would use the browser to redirect the user without requiring the application to know the username and password, so that the user only needs to share their credentials with the first party provider of them. In this case were designing an application for your internal use which might be automated later and have no human intervention. Were going to use the password grant type of OAuth in order to authenticate with the username and password. Upon receiving a successful response, the application will need to get the access token from OAuth. This access token provides access to a valid session against the Force.com platform and will allow us to start manipulating data. We also need to know the specific pod the user is using, for example https://na1.salesforce.com versus https://na8.salesforce.com. To get this, the JSON library will parse the result:
String result = EntityUtils.toString(response.getEntity()); JSONObject object = (JSONObject) new JSONTokener(result).nextValue(); ForceLogin login = new AddMerchandise().new ForceLogin(); login.accessToken = object.getString("access_token"); login.instanceUrl = object.getString("instance_url"); return login;

It stores the result as a ForceLogin object for easier access. Now that we have a valid ForceLogin with the access token and the users instance URL, we can start adding in some data.

Step 4: Add Data Via the API


Like OAuth, REST also utilizes standard HTTP protocols for communication. This makes it very easy to format data that the API will understand. Since we want to insert new data, were going to use the corresponding HTTP POST method to send data to a specific endpoint (a RESTful resource) for our Merchandise object. In your text editor, scroll down to addMerchandise and uncomment the function. To do so, remove the /* and */ characters shown here:
/* private static String addMerchandise(ForceLogin login, String name, String price, String desc, String inventory){

...

Tutorial #2: Create a Merchandise Item Using Java

e.printStackTrace(); } return null; } */

The first step is to create a JSON representation of the data retrieved from the AddMerchandise.properties file:
JSONObject mechandise = new JSONObject()' try { if if if if (name != null && !name.trim().equals("")) mechandise.put("Name", name); (price != null && !price.trim().equals("")) mechandise.put("Price__c", price); (desc != null && !desc.trim().equals("")) mechandise.put("Description__c", desc); (inventory != null && !inventory.trim().equals("")) mechandise.put("Total_Inventory__c", inventory);

We then submit this information to the REST API with the OAuth login information embedded in the header. This allows for a secure transaction of information for the API to work with; and without it, the API would refuse the request.
String restResourceURI = login.instanceUrl + "/services/data/v23.0/sobjects/Merchandise__c/"; HttpPost post = new HttpPost(restResourceURI); StringEntity se = new StringEntity(mechandise.toString()); post.setEntity(se); post.setHeader("Authorization", "OAuth " + login.accessToken); post.setHeader("Content-type", "application/json"); DefaultHttpClient client = new DefaultHttpClient(); HttpResponse resp = client.execute(post); String result = EntityUtils.toString(resp.getEntity()); if (resp.getStatusLine().getStatusCode() != HttpStatus.SC_CREATED){ JSONObject ret = ((JSONArray) new JSONTokener(result).nextValue()).getJSONObject(0); System.out.println("Could not create new Merchandise record:" +resp.getStatusLine().getStatusCode()); System.out.println("Error code:"+ret.getString("errorCode")); System.out.println("Error message:"+ret.getString("message")); return null; } else{ return ((JSONObject) new JSONTokener(result).nextValue()).getString("id"); } } catch (Exception e) { e.printStackTrace(); }

Well then post this to the Merchandise endpoint of the REST API. Notice that even though the Merchandise object is a custom object created through the declarative process, there was no step needed to expose it through the API. Were now ready to compile and run the application.

Step 5: Compile and Run the App


Depending on whether youre developing on a PC or Mac, the steps required to compile and run the application are different. Follow the correct steps for your platform. 1. Go to the folder where you downloaded the Java tutorial files.

10

Tutorial #2: Create a Merchandise Item Using Java

2. For Windows, double-click compileandrun.bat. For OS X, double-click compileandrun.command. Note: Depending on your machine performance, the app may take approximately 30 seconds to compile. If this is the first run, you may see a warning indicating that the classes folder doesnt exist. This folder will be created for you upon first execution. 3. Youll see a Classes Compiled message indicating that your local app has been built successfully, and will now attempt to add the new Merchandise item to the Warehouse app. If any errors exist in the application, theyll be displayed after the Classes Compiled message. Note: If you received any compilation errors, go ahead and debug and fix those now.

4. If your local app has compiled successfully and has connected to Force.com, youll see an error message like the following. Dont worry, this is what we were expecting!
Error code:REQUIRED_FIELD_MISSING Error message:Required fields are missing: [Price__c]

So whats going on with our app? At this point, your application is going to authenticate with Force.com, and attempt to insert your new merchandise item via the REST API. Unfortunately for us, itll fail. Your app failed because the API enforces all the validation rules put in place by the data model on the Force.com platform, regardless of how you connect. The API returns a helpful error message indicating that a required field, Price__c, is missing. Thats right, we didnt enter price into the AddMerchandise.properties file. Lets remedy that now. 1. 2. 3. 4. 5. Open AddMerchandise.properties in a text editor. Where it reads merchandise.price, add 5.99 after the = sign. Save the file. Return to the folder with the Java project files. For Windows, double click run.bat. For OS X, double click run.command.

Now youll receive a message that the item was entered correctly and give you the resulting ID of that item. You can use this unique ID within your application any time you want to work with your new merchandise item. Right now, our sample app only supports inserts, though.

Java Integration Summary


You just created a small application and a properties file to simulate our on-premise buyer application written in Java. This app was able to communicate with the Force.com platform in a secure manner using OAuth for authentication, and standard RESTful calls and JSON to transport data. Using the standard HTTP libraries with Java, its easy to integrate between third party systems and the Warehouse app we created on the Force.com platform.

11

Tutorial #3: Create a Merchandise Item Using C#

Tutorial #3: Create a Merchandise Item Using C#


In this tutorial we will use the C# (pronounced C-sharp) language to create an application for entering a new Merchandise item into our warehouse app. Buyers, in our fictitious scenario, use a mix of mobile apps and existing systems to buy products. Once a buy has been completed, the new Merchandise item needs to be reflected in the Warehouse. Our sample buyer app will use a properties file to hold the information specific to your Force.com organization and to describe the item being entered. While in this case well be entering the information about the item manually, the text file may in the real world be updated by a different process which could then use this sample application to automatically keep the warehouse inventory updated.

Step 1: Update the Properties File


Before the app can communicate with the server, well need to provide the application with some information about the Force.com organization its communicating with. 1. Navigate to the folder where you unzipped the C# tutorial files. 2. Open AddMerchandise.txt in a text editor. 3. Replace {USERNAME} with your Force.com username. Be sure to replace all of {USERNAME}, including the curly bracket characters. 4. Log into your Force.com organization. 5. If you have already reset your security token when you did the Java tutorial, you can skip the following step. Otherwise, go to Setup > My Personal Information > Reset My Security Token and press Reset Security Token. A new security token will be sent to the email address registered with your user account. 6. In AddMerchandise.txt, replace {PASSWORD} with your Force.com password and the security token sent to your email address. If your password is mypassword and your security token is AAAA1111, you would replace {PASSWORD} with mypasswordAAAA1111. Again, be sure to replace all of {PASSWORD}, including the curly bracket characters. 7. Go to Setup > Develop > Remote Access and open the Remote Access application you created earlier. 8. Click Click to Reveal. 9. Copy the text next to client.id and replace {PUBLICKEY} with the text. 10. Similarly, copy the text next client.secret and replace {PRIVATEKEY} with the text. 11. Where it reads merchandise.name, enter Tiny Top after the = sign. 12. Where it reads merchandise.inventory, enter 5 after the = sign. 13. Where it reads merchandise.description, enter Shiny Top after the = sign. 14. For now, leave merchandise.price intentionally blank. 15. Save the file. You may remember that Price was a required field for the Merchandise object - we are keeping that blank for now to show how the API will react when an application using the API attempts to insert an object which doesnt meet the validation rules specified in your app.

Step 2: Read the Properties File


Now lets take a look at the actual C# code to see how these properties will be read.

12

Tutorial #3: Create a Merchandise Item Using C#

1. Navigate to where you unzipped the C# tutorial files. 2. Open AddMerchandise.cs in a text editor. 3. Scroll down to the main() function. The main() function acts as the starting point for our application, and is executed when its run from the command line. The main() function calls the constructor AddMerchandise method, which reads the properties we defined in AddMerchandise.txt by running through the lines and parsing the information into an array:
public AddMerchandise() { properties = new Dictionary<string, string>(); foreach (String row in File.ReadAllLines("AddMerchandise.txt")) { properties.Add(row.Split('=')[0], row.Split('=')[1]); } }

The application now has a record of the information you entered into AddMerchandise.txt and is ready to log in to the API using OAuth.

Step 3: Log In with OAuth


Since OAuth is based on HTTP protocols, all we need to do to communicate with it is set up the correct HTTP GET and POST calls and then parse the JSON (JavaScript Object Notation) results. To get this functionality in our application, well uncomment some existing code. In your text editor, scroll down and uncomment the login() function. To do so, remove the /* and */ characters shown here:
/* public Boolean login() { ... } */

This is where the function makes the actual callout to OAuth:


try { string login_params = oauthoptions + "&client_id=" + properties["consumerkey"] + "&client_secret=" + properties["privatekey"] + "&username=" + properties["username"] + "&password=" + properties["password"]; string responseFromServer = doHTTPRequest(properties["login_url"] + oauthendpoint, login_params, "", false); string[] data = responseFromServer.Split(':'); token = data[7]; token = token.Substring(1, token.Length - 1); token = token.Replace("\"}", ""); instance_url = data[5]; instance_url = instance_url.Substring(2, instance_url.Length - 2); instance_url = instance_url.Substring(0, instance_url.IndexOf("\""));

It creates the URL with the correct parameters, including the consumer public and private keys to correctly identify the application and the users username and password. Normally, an authentication flow with OAuth would use the browser to

13

Tutorial #3: Create a Merchandise Item Using C#

redirect the user without requiring the application to know the username and password, so that the user only needs to share their credentials with the first party provider of them. In this case, though, were designing an application for your internal use which might be automated later and have no human intervention. For this use case, it make sense to use the password grant type of OAuth in order to authenticate with the username and password. Upon getting a successful response, the application will need to get the access token from OAuth. This access token provides access to a valid session against the Force.com platform and allows us to start working with data. We also need to know the specific instance the user is using, for example, https://na1.salesforce.com versus https://na8.salesforce.com.

Step 4: Add Data Via the API


Like OAuth, REST also utilizes standard HTTP protocols for communication. This makes it very easy to format data that the API understands. Since we want to insert new data, well use the corresponding HTTP POST method to send data to a specific endpoint (a RESTful resource) for our Merchandise object. In your text editor, scroll down and uncomment the insertItem function. To do so, remove the /* and */ characters shown here:
/* public void insertItem() { ... } */

The first step is to create a JSON representation of the data entered into the AddMerchandise.txt file:
string postData = "{\"Name\" : \"" + properties["merchandise.name"] + "\""; if(properties["merchandise.price"] != "") { postData += ", \"Price__c\" : " + properties["merchandise.price"]; } if(properties["merchandise.inventory"] != "") { postData += ", \"Total_Inventory__c\" : " + properties["merchandise.inventory"]; } if(properties["merchandise.description"] != "") { postData += ", \"Description__c\" : \"" + properties["merchandise.description"] +"\""; } postData += "}";

Well then post this to the Merchandise endpoint of the REST API, using the OAuth information embedded in headers. This allows for the secure transaction of information; and without it, the API would refuse the request. Notice that even though the Merchandise object is a custom object created through the declarative process, there was no step needed to expose it through the API. We can send data just by creating an HTTP POST request, sending it to the endpoint, and then parsing the string for results to show to the user.
string endpoint = "https://" + instance_url + "/services/data/v" + properties["api"] + "/sobjects/Merchandise__c"; string responseFromServer = doHTTPRequest(endpoint, postData, token, true);

14

Tutorial #3: Create a Merchandise Item Using C#

Were now ready to compile and run the application.

Step 5: Compile and Run the App


Now that the code is constructed, lets compile and test out the application. 1. Navigate to where you unzipped the C# tutorial files. 2. Double click compileandrun.bat. 3. The application will be compiled, and if this is the first run, you may see a warning indicating that the classes folder doesnt exist. This folder is created for you upon first execution. Depending on your machine performance, the app may take approximately 30 seconds to compile. If all goes well, youll see a Compile Complete message indicating your local app has been built successfully and will now attempt to add the new Merchandise item to the Warehouse app. If any errors exist in the application, theyll be displayed above the Compile Complete message. 4. If you received any compilation errors, go ahead and debug and fix those now. When youre ready, re-run compileandrun.bat. 5. If your local app has compiled successfully and connected to Force.com, youll see an error message like this. Dont worry, this is what we were expecting!
"message":"Required fields are missing: Price__c"

So whats going on with our app? At this point, your application is going to authenticate with Force.com and attempt to insert your new merchandise item via REST API. Unfortunately for us, itll fail. Your app failed because the API enforces all the validation rules put in place by the data model on the Force.com platform, regardless on how you connect. The API returns a helpful error message indicating a required field, Price__c, is missing. Thats right, we didnt enter price into the AddMerchandise.txt file. Lets remedy that now. 1. 2. 3. 4. 5. Open AddMerchandise.txt in a text editor. Where it reads merchandise.price, add 5.99 after the = sign. Save the file. Return to Windows Explorer and double-click run.bat. Youll see a success message with an ID:
"id":"a0KC000000065pOhMAI" "errors":"" "success":"true"

The message indicates the item was entered correctly and gives you the resulting ID of that item. You can use this unique ID within your application any time you want to work with your new merchandise item (for example, to update the description or price). Right now, our sample app only supports inserts though.

C# Summary
You just created a small application and a properties file to simulate our on-premise buyer application written in C#. This app was able to communicate with the Force.com platform in a secure manner using OAuth for authentication, and standard

15

Tutorial #3: Create a Merchandise Item Using C#

RESTful calls and JSON to transport data. Using the standard HTTP libraries with Java, it is easy to create integrations between third party systems and the Warehouse app we created on the Force.com platform.

16

Tutorial #4: Connecting the Warehouse App with an External Service

Tutorial #4: Connecting the Warehouse App with an External Service


Force.com offers several ways to integrate with external systems; for example, Workflow allows configuration of outbound email alerts and simple Web Service calls, while more complex scenarios can be implemented programmatically in Apex code. In this tutorial you will integrate the warehouse app with an existing fulfillment system via a Web Service callout. This fulfillment system, written in Node.js is hosted on Heroku, but it could be any application with a Web Service interface accessible via the cloud. Our requirements are pretty straight-forward: When an invoice statement's status changes to 'Closed', a JSON-formatted message will be sent to an order fulfillment service, which will return an order ID. This order ID must be saved on the invoice statement. Lets get started.

Step 1: Create an External ID Field on Invoice Statement


You will need to create a custom field on the Invoice Statement custom object to hold the order ID. Since the field will be an index into an external system, you will mark it as an External ID. 1. Go to the Invoice Statement custom object by clicking Your Name > Setup > Create > Create > Objects > Invoice Statement. 2. Scroll down to Custom Fields & Relationships, click New and fill in the field settings. 3. Select the Text field type and click Next. 4. Enter OrderId as the field label, and enter 6 as the field length. Leave the field name as the default OrderId. 5. Click the External ID checkbox and click Next. 6. Click Next to accept the defaults, then click Save.

Step 2: Create a Remote Site Record for the Fulfillment Web Service
The Force.com platform implements very conservative security controls. By default, calls to external sites are prohibited. Before any Apex callout can call an external site, that site must be registered in the Remote Site Settings page, or the call will fail. Note: Creating a Remote Site is not the same as configuring Remote Access (that we did in Tutorial 1). Remote Access allows authenticated access to Salesforce from external clients, whereas Remote Sites are external sites that Salesforce needs access to. 1. 2. 3. 4. 5. Click Your Name > Setup > Security Controls > Remote Site Settings. Click New Remote Site and fill in the site settings. In the Remote Site Name field, enter FulfillmentWebService (no spaces). In the Remote Site URL field, enter https://fulfillment.herokuapp.com. Leave all other values as they are and click Save.

Now any Apex code in your app will be able to call the fulfillment Web Service.

17

Tutorial #4: Connecting the Warehouse App with an External Service

Tell Me More....
If you like, you can skip Step 2 and create and test the callout in Step 3 and Step 4 below to observe the error message that is generated when an app attempts to callout to a URL without permission. Don't forget to come back and add the remote site record, though!

Step 3: Create an @future Method to Post Invoice Statements to the Fulfillment Web Service
Now that your app is allowed to access an external URL, it's time to implement the callout. Apex Triggers are not permitted to make synchronous Web Service calls. This restriction is to ensure a long running Web Service does not hold a lock on a record within your app. In order to achieve our requirements, we'll create an asynchronous method with the @future annotation. When the Trigger calls the asynchronous method, the call will be queued, and execution of the Trigger will complete. Some short time later, the queued method will execute and post the invoice to the order fulfillment Web Service. 1. Go to Apex Classes by clicking Your Name > Setup > Develop > Apex Classes. 2. Click New and paste in the following code. Note: You can also download the code here, http://bit.ly/aw2012-apexint

public class Integration { public class IntegrationException extends Exception { } public class ExternalOrder { public String id {get; set;} public String order_number {get; set;} } // Post an array of invoices to the fulfillment service // This method is designed such that there are only two // queries regardless of the number of invoice IDs passed @future (callout=true) public static void postOrder(List<Id> invoiceIds) { // Get all the line items we'll need List<Line_Item__c> lineItems = [SELECT Name, Merchandise__c, Invoice_Statement__c, Units_Sold__c FROM Line_Item__c WHERE Invoice_Statement__c IN :invoiceIds]; // Now group the line items by invoice Map<Id, Map<String, Line_Item__c>> lineItemsByInvoice = new Map<Id, Map<String, Line_Item__c>>(); for (Line_Item__c lineItem : lineItems) { Map<String, Line_Item__c> lineItemMap = lineItemsByInvoice.get(lineItem.Invoice_Statement__c); if (lineItemMap == null ) { lineItemMap = new Map<String, Line_Item__c>(); lineItemsByInvoice.put(lineItem.Invoice_Statement__c, lineItemMap); } lineItemMap.put(lineItem.Name, lineItem); } // Create the JSON string JSONGenerator gen = JSON.createGenerator(true); gen.writeStartArray(); for (Id invoiceId : invoiceIds) {

18

Tutorial #4: Connecting the Warehouse App with an External Service

// Get the invoice name. We'll also need the invoice record // later to set the order ID and update it gen.writeStartObject(); gen.writeStringField('id', invoiceId); // Make a list of the line item names and sort it Map<String, Line_Item__c> lineItemMap = lineItemsByInvoice.get(invoiceId); List<String> lineItemNames = new List<String>(lineItemMap.keySet()); lineItemNames.sort(); // Now we can write the line items gen.writeFieldName('line_items'); gen.writeStartArray(); for ( String name : lineItemNames ) { gen.writeObject(lineItemMap.get(name)); } gen.writeEndArray(); gen.writeEndObject(); } gen.writeEndArray(); String jsonOrders = gen.getAsString(); System.debug('jsonOrders: ' + jsonOrders); // Send the JSON data to the web service HttpRequest req = new HttpRequest(); req.setMethod('POST'); req.setEndpoint('https://fulfillment.herokuapp.com/order'); req.setHeader('Content-Type', 'application/json'); req.setBody(jsonOrders); Http http = new Http(); HTTPResponse res = http.send(req); // Get all the invoices - we'll need to update them List<Invoice_Statement__c> invoices = [SELECT Id FROM Invoice_Statement__c WHERE Id IN :invoiceIds]; // Did it work? if (res.getStatusCode() != 200) { System.debug('Error from ' + req.getEndpoint() + ' : ' + res.getStatusCode() + ' ' + res.getStatus()); // Set all the invoice order IDs to '000000' for ( Invoice_Statement__c invoice : invoices ) { invoice.OrderId__c = '000000'; } } else { // Parse out the external order numbers System.debug('Fulfillment service returned '+res.getBody()); List<ExternalOrder> orders=(List<ExternalOrder>)JSON.deserialize(res.getBody(), List<ExternalOrder>.class); Map<Id, Invoice_Statement__c> invoiceMap = new Map<Id, Invoice_Statement__c>(invoices); // Set the order numbers in the invoices for ( ExternalOrder order : orders ) { Invoice_Statement__c invoice = invoiceMap.get(order.id); invoice.OrderId__c = order.order_number; } } update invoices; } }

Save the file and then examine the above code, you will see that it collects the data it needs to invoke the fulfillment Web Service - an array of invoice objects each containing an array of list items - and generates a JSON-formatted request using the System.JSONGenerator class. After calling the Web Service, the order IDs are parsed out of the response and persisted.

Tell Me More....
Note that the @future method makes only two queries, one for invoices and one for line items, regardless of the number of invoice IDs that are passed in. This pattern, typically called bulkifying makes the code a little more complex, it is a best

19

Tutorial #4: Connecting the Warehouse App with an External Service

practice to avoid hitting the database once for each incoming record, therefor making your code much more scalable and efficient.

Step 4: Test the @future Method


You can test the @future class you just created via the new Developer Console. Testing the class in isolation allows you to ensure that remote site settings are configured correctly before creating a Trigger. 1. Go to an invoice statement by selecting the Warehouse app, clicking the Invoice Statements tab, and clicking one of the recent invoices. 2. Copy the 15 character alphanumeric ID at the end of the URL.

3. Go to the Developer Console by clicking Your Name > Developer Console.

20

Tutorial #4: Connecting the Warehouse App with an External Service

4. Click the box marked Click here to enter Apex Code and enter the following code, with the ID you copied in step 1 in place of the ID in the code.
Integration.postOrder(new List<Id>{'a01E0000000Bs5P'});

5. Click the Execute. You should see two entries appear in the logs. Double click the second line - it should have Future Handler as its operation and a status of Success.

6. Click the Filter checkbox under the Execution Log and type DEBUG as the filter text. Scroll down and double click the last line of the execution log - you should see a popup with the response from the fulfillment Web Service - for example

14:19:18:576 USER_DEBUG [99]|DEBUG|Fulfillment service returned [{"id":"a01E0000000Bs5PIAS","order_number":"524090"}]

Now you have a @future method that is able to call the fulfillment Web Service, it's time to tie things together with a Trigger.

Step 5: Create a Trigger to Call the @future Method


By default, a trigger executes on every update to Invoice Statement records. We need to add logic to ensure that orders are only submitted for fulfillment when an invoice is closed. Go ahead and create the trigger: 1. Go to the Invoice Statement custom object by clicking Your Name > Setup > Create > Objects > Invoice Statement.

21

Tutorial #4: Connecting the Warehouse App with an External Service

2. Scroll down to Triggers, click New and paste the following code in place of the trigger skeleton: (You can also download the code here: http://bit.ly/aw2012-ordertrigger )
trigger HandleOrderUpdate on Invoice_Statement__c (after update) { Map<ID, Invoice_Statement__c> oldMap = new Map<ID, Invoice_Statement__c>(Trigger.old); // Make a list of invoice IDs to post, so we can do it in one hit List<Id> invoiceIds = new List<Id>(); for (Invoice_Statement__c invoice: Trigger.new) { // Only post order when status is changing from not closed to closed if (invoice.status__c == 'Closed' && oldMap.get(invoice.Id).status__c != 'Closed'){ invoiceIds.add(invoice.Id); } } if (invoiceIds.size() > 0) { Integration.postOrder(invoiceIds); } }

Notice that the trigger creates a list of IDs for invoices that have been closed in this update - that is, their new status is Closed, but their old status was something other than Closed - and calls the @future method just once, passing the list of IDs. This bulkified pattern is a best practice for triggers you should not assume that there will be only a few updates and make a call to the @future method for each one.

Step 6: Test the Integration


Now all the pieces are in place, it's time to test the integration. 1. Go to an invoice statement by selecting the Warehouse app, clicking the Invoice Statements tab, and clicking one of the recent invoices. 2. If the Status is already Closed, double click the word Closed, change it to Open and click Save. 3. Double click the Status value, change it to Closed and click Save. 4. Refresh the page in the browser. 5. You should see a six digit number appear in the OrderId field. You can repeat steps 2-4 above and see the order ID change.

22

Tutorial #4: Connecting the Warehouse App with an External Service

Summary
Congratulations! Your app is sending invoices for fulfillment. You have successfully created an asynchronous Apex class which posted invoice details to another app hosted in the cloud. Of course, your external application could reside anywhere as long as you have access via Web Services. Your class used open standards including JSON and REST to transmit data, and a trigger on Invoice Statements to execute the process. Sit back, and celebrate. You have now completed the Integration tutorials. Your warehouse app is now complete!

23

S-ar putea să vă placă și