Process Orchestration using           Streaming API and HerokuAndrew Fawcett, FinancialForce.com, CTO@andyinthecloud
Safe harborSafe harbor statement under the Private Securities Litigation Reform Act of 1995:This presentation may contain ...
All about FinancialForce.com                 Leading Native ISV on Force.com                 • #1 Accounting App on Force....
Andrew FawcettCTO@andyinthecloud
Building declarative applicationsBuilding applications that support Force.com declarative features is critical.Building ap...
Our user storyAs A: System Applications AdministratorI want: To be able to link a series of HTTP / REST based API’s to dat...
Our user case : eBay Integration     Invoice Number: INV-000001                                                           ...
Live Demonstration
PushTopic (Streaming API)         Name                       Query Select From      Name                               pro...
Java Code : Heroku Worker Process/** * Heroku Work Processes are simply Java classes with a main method! */01: public clas...
Java Code : Process__c Listener/** * Listener : Process__c * Comment : Bayeux Client used connect to Streaming API and imp...
Java Code : Process__c Listener  Java Code : Process__c                                                                   ...
Java Code : Process__c Listener  Java Code : Process__c                                                                   ...
Java Code : Process__c Listener  Java Code : Process__c                                                                   ...
Java Code : Process__c Listener  Java Code : Process__c                                                                   ...
Java Code : Process__c Listener  Java Code : Process__c                                                                   ...
Java Code {SourceObject__c} Listener Java Code : : {SourceObject__c} Listener /**  * Listener : {SourceObject__c}  * Step ...
Java Code {SourceObject__c} Listener Java Code : : {SourceObject__c} Listener /**  * Listener : {SourceObject__c}  * Step ...
Java Code {SourceObject__c} Listener Java Code : : {SourceObject__c} Listener  /**   * Listener : {SourceObject__c}   * St...
ResourcesJava Code : {SourceObject__c} Listener    • Other // TODO:’s and Ideas?!       – Record Types for Process Steps?...
DF12 - Process Orchestration using Streaming API and Heroku
DF12 - Process Orchestration using Streaming API and Heroku
Upcoming SlideShare
Loading in …5
×

DF12 - Process Orchestration using Streaming API and Heroku

1,753 views

Published on

The Streaming API can provide near real time updates on changes to any object data in an organisation. In this session we will demonstrate and share code for a custom Process Orchestration solution powered by the Streaming API and Heroku. Using this solution users can define criteria which the platform will apply to monitor records created or updated by users in real time. The session will demonstrate an example process using REST services taken from those offered by many of todays leading REST API providers including Salesforce.

Published in: Technology
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
1,753
On SlideShare
0
From Embeds
0
Number of Embeds
1,019
Actions
Shares
0
Downloads
11
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide
  • Rehab Breakfast on Friday, talking to people in the area for roles we have open, come along even if your tired! ;-)Expanding Development Group, adding Development Team in SFIndustrial Strength Applications
  • - Mention platform Flow and Workflow differences and capabilities vs this solution.
  • Timing: 6 minutes
  • Timing: 2 minutes
  • Timing: Code Walkthrough 8 minutes
  • Timing: Code Walkthrough 8 minutes
  • Timing: Code Walkthrough 8 minutes
  • Timing: Code Walkthrough 8 minutes
  • Timing: Code Walkthrough 8 minutes
  • Timing: Code Walkthrough 8 minutes
  • Timing: Code Walkthrough 8 minutes
  • Timing: Code Walkthrough 8 minutes
  • Timing: Code Walkthrough 8 minutes
  • Timing: Code Walkthrough 8 minutes
  • Timing: Code Walkthrough 8 minutes
  • DF12 - Process Orchestration using Streaming API and Heroku

    1. 1. Process Orchestration using Streaming API and HerokuAndrew Fawcett, FinancialForce.com, CTO@andyinthecloud
    2. 2. Safe harborSafe harbor statement under the Private Securities Litigation Reform Act of 1995:This presentation may contain forward-looking statements that involve risks, uncertainties, and assumptions. If any such uncertaintiesmaterialize or if any of the assumptions proves incorrect, the results of salesforce.com, inc. could differ materially from the results expressed orimplied by the forward-looking statements we make. All statements other than statements of historical fact could be deemed forward-looking,including any projections of product or service availability, subscriber growth, earnings, revenues, or other financial items and any statementsregarding strategies or plans of management for future operations, statements of belief, any statements concerning new, planned, or upgradedservices or technology developments and customer contracts or use of our services.The risks and uncertainties referred to above include – but are not limited to – risks associated with developing and delivering new functionalityfor our service, new products and services, our new business model, our past operating losses, possible fluctuations in our operating resultsand rate of growth, interruptions or delays in our Web hosting, breach of our security measures, the outcome of intellectual property and otherlitigation, risks associated with possible mergers and acquisitions, the immature market in which we operate, our relatively limited operatinghistory, our ability to expand, retain, and motivate our employees and manage our growth, new releases of our service and successfulcustomer deployment, our limited history reselling non-salesforce.com products, and utilization and selling to larger enterprise customers.Further information on potential factors that could affect the financial results of salesforce.com, inc. is included in our annual report on Form 10-Q for the most recent fiscal quarter ended July 31, 2012. This documents and others containing important disclosures are available on the SECFilings section of the Investor Information section of our Web site.Any unreleased services or features referenced in this or other presentations, press releases or public statements are not currently availableand may not be delivered on time or at all. Customers who purchase our services should make the purchase decisions based upon featuresthat are currently available. Salesforce.com, inc. assumes no obligation and does not intend to update these forward-looking statements.
    3. 3. All about FinancialForce.com Leading Native ISV on Force.com • #1 Accounting App on Force.com • #1 Professional Services Automation App on Force.com Backed by Salesforce.com & UNIT4 • UNIT4 - $600 million, 33 years building business apps Growing Rapidly • San Francisco HQ – 595 Market St. • 145 Employees • Customers in 23 countries
    4. 4. Andrew FawcettCTO@andyinthecloud
    5. 5. Building declarative applicationsBuilding applications that support Force.com declarative features is critical.Building applications that consume Force.com declarative features to support your app is smart!  Encourage users admins to use what they have already • Building their solution consisting of part your app and part platform features can be a powerful combo!  Make sure you understand how to be dynamic… • Metadata API, Apex Describe • Dynamic SOQL, Dynamic Visualforce, Fieldsets • Reference Formulas, Rollup Summaries, List Views etc..  Make your applications metadata portable between orgs!Consultants love our declarative applications! 
    6. 6. Our user storyAs A: System Applications AdministratorI want: To be able to link a series of HTTP / REST based API’s to data changes occurring in my organization, based on criteria I provide. Without resorting to Apex coding.So that: I can harness the power of many HTTP / REST based services to further automate my companies business processes. And leverage my skills as a System Administrator.
    7. 7. Our user case : eBay Integration Invoice Number: INV-000001 Process Manager eBay Item: 12345678 Streaming API via Bayeux Protocol Overview Salesforce Streaming API via Bayeux Protocol1. Create a Push Topic in Force.com • Using the SOQL statement you provide. Salesforce servers will send JSON messages to listeners. When changes occur to record data that meet the criteria expressed by the SOQL query.Item: 12345678 eBay2. Install a Bayeux Client Library • Clients are available from http://cometd.org (none for Apex)3. Connect and start Listening! • This sample uses the Java Bayeux library
    8. 8. Live Demonstration
    9. 9. PushTopic (Streaming API) Name Query Select From Name processchanges Process__c Query NotifyForOperations processlogslinescreated ProcessLogLine__c NotifyForFields {Proccess__c.Id} {SourceObject__c} Process__c /topic/processchanges Process__c Listener Name On Insert SourceObject__c ProcessStep__c 1. Generate PushTopic Query When__c Name 2. Create new PushTopic record ListViewName__c HTMLEndpoint__c 3. Subscribe via Streaming API HTMLHeader__c 4. Start {SourceObject__c} Listener HTMLMethod__c Admin creates 5. Log to ProcessLogLineItem__c HTMLBody__c ProcessProcessLogLine__c Listener ProcessLogLine__c Live Log Viewer Message__c {SourceObject__c} Listener “1. xxxx 2. xxxx” /topic/processlogslinescreated On Update 1. Read ProcessSteps__c Invoice__c /topic/{Process__c.Id} 2. Read {SourceObject__c} Name 3. Call {HTMLEndpoint__c} … Account__c 4. Log to ProcessLogLineItem__c Amount__c eBayItemNumber__c eBayCompleteSaleRequest__c Invoice Clerk updates Invoice HTTP POST: <CompleteSaleRequest> <Item>{!eBayItemNumber}</Item> </CompleteSaleRequest>
    10. 10. Java Code : Heroku Worker Process/** * Heroku Work Processes are simply Java classes with a main method! */01: public class WorkerProcess02: {03: // Salesforce APIs04: private static final String SALESFORCE_API = "25.0";05: private static final String LOGIN_ENDPOINT = "https://login.salesforce.com/services/Soap/u/" + SALESFORCE_API;06: private static final String REST_ENDPOINT_URI = "/services/data/v" + SALESFORCE_API + "/";07: private static final String STREAMING_ENDPOINT_URI = "/cometd/" + SALESFORCE_API;08:09: /**10: * Main entry point for the Heroku Worker Process11: * @param args12: * @throws Exception13: */14: public static void main(String[] args) throws Exception15: {16: // Startup and assignment of listeners to Salesforce Streaming API topics…17: }
    11. 11. Java Code : Process__c Listener/** * Listener : Process__c * Comment : Bayeux Client used connect to Streaming API and implement MessageListener interface * @see makeStreamingAPIConnection method * @see JSON class from Jetty * @see processInsert method */01: // Connect to Salesforce Streaming API02: final BayeuxClient client = makeStreamingAPIConnection(loginResult);03:04: // Subscribe to the Process__c topic to listen for new or updated Processes05: client.getChannel("/topic/processchanges").subscribe(new MessageListener()06: {07: public void onMessage(ClientSessionChannel channel, Message message)08: {09: HashMap<String, Object> data = (HashMap<String, Object>) JSON.parse(message.toString());10: HashMap<String, Object> record = (HashMap<String, Object>) data.get("data");11: HashMap<String, Object> sobject = (HashMap<String, Object>) record.get("sobject");12: HashMap<String, Object> event = (HashMap<String, Object>) record.get("event");13: // Event type, insert or update?14: String type = (String) event.get("type");15: if(type.equals("created"))16: processInsert(loginResult, client, sobject);17: }18: });
    12. 12. Java Code : Process__c Listener Java Code : Process__c Listener /** * Listener : Process__c * Step : Connect and Listen * API connections and message data, used WSC manual login to obtain Metadata API base URL from * LoginResult (not normally exposed by the standard connector classes) * @see makeRestConnection method (Rest URL helper) */ 01: // Connection configuration 02: ConnectorConfig metadataConfig = new ConnectorConfig(); 03: metadataConfig.setSessionId(loginResult.getSessionId()); 04: metadataConfig.setServiceEndpoint(loginResult.getMetadataServerUrl()); 05: MetadataConnection metadataConnection = 06: com.sforce.soap.metadata.Connector.newConnection(metadataConfig); 07: 08: // Make a REST connection 09: RestConnection restConnection = makeRestConnection(loginResult); 10: 11: // Message data from Proccess__c 12: String processId = (String) sObject.get("Id"); 13: String processName = (String) sObject.get("Name"); 14: String sourceObject = (String) sObject.get("SourceObject__c"); 15: String listViewName = (String) sObject.get("ListViewName__c");
    13. 13. Java Code : Process__c Listener Java Code : Process__c Listener /** * Listener : Process__c * Step : Generate PushTopic Query * Comment : Retrieve via Metadata API custom object definition to get at the List View * definition for generating PushTopic Query */ 01: // Retrieve Custom Object Meta data (and thus List View definition) for Source Object 02: RetrieveRequest retrieveRequest = new RetrieveRequest(); 03: retrieveRequest.setSinglePackage(true); 04: com.sforce.soap.metadata.Package packageManifest = new com.sforce.soap.metadata.Package(); 05: ArrayList<PackageTypeMembers> types = new ArrayList<PackageTypeMembers>(); 06: PackageTypeMembers packageTypeMember = new PackageTypeMembers(); 07: packageTypeMember.setName("CustomObject"); 08: packageTypeMember.setMembers(new String[] { sourceObject }); 09: types.add(packageTypeMember); 10: packageManifest.setTypes((PackageTypeMembers[]) types.toArray(new PackageTypeMembers[] {})); 11: retrieveRequest.setUnpackaged(packageManifest); 12: AsyncResult response = metadataConnection.retrieve(retrieveRequest); 13: while(!response.isDone()) 14: { 15: Thread.sleep(1000); 16: response = metadataConnection.checkStatus(new String[] { response.getId()} )[0]; 17: } 18: RetrieveResult retrieveResult = metadataConnection.checkRetrieveStatus(response.getId());
    14. 14. Java Code : Process__c Listener Java Code : Process__c Listener /** * Listener : Process__c * Step : Generate PushTopic Query * Comment : Uses the WSC TypeMapper to deserialise the Custom Object definition from the * package zip returned by „retrieve‟ */ 01: // Parse Custom Object metadata for Process Source Object 02: CustomObject customObject = new CustomObject(); 03: byte[] zipBytes = retrieveResult.getZipFile(); 04: ZipInputStream zipis = new ZipInputStream(new ByteArrayInputStream(zipBytes, 0, zipBytes.length)); 05: ZipEntry zipEntry = null; 06: while((zipEntry = zipis.getNextEntry()) != null) { 07: if(zipEntry.getName().endsWith(sourceObject + ".object")) / Process Source Object? 08: { 09: TypeMapper typeMapper = new TypeMapper(); 10: XmlInputStream xmlis = new XmlInputStream(); 11: xmlis.setInput(zipis, "UTF-8"); 12: customObject.load(xmlis, typeMapper); 13: zipis.closeEntry(); 14: break; 15: } 16: } 17: // Find the List View indicated on the Process to define query for Streaming API Push Topic 18: ListView processlistView = null; 19: for(ListView listView : customObject.getListViews()) { ... }
    15. 15. Java Code : Process__c Listener Java Code : Process__c Listener /** * Listener : Process__c * Step : Generate PushTopic Query * Comment : Parse List View definition to construct SOQL Query for Push Topic. Code shortened * for this slide. */ 01: // Generate SOQL statement for PushTopic based on List View definition 02: StringBuilder fieldList = new StringBuilder("Id"); 03: for(String field : processlistView.getColumns()) 04: fieldList.append(", " + field); 05: // Simple version assumes AND‟s, ignores processListView.getBooleanFilter() 06: StringBuilder whereClause = new StringBuilder(); 07: for(ListViewFilter lvFilter : processlistView.getFilters()) 08: { 09: switch (lvFilter.getOperation()) 10: { 11: case equals: 12: // ... 13: } 14: } 15: // Construct SOQL query statement 16: StringBuilder soql = new StringBuilder() 17: .append("select ”) .append(fieldList.toString()) 18: .append("from ”) .append(sourceObject + " ") 19: .append("where ”) .append(whereClause.toString());
    16. 16. Java Code : Process__c Listener Java Code : Process__c Listener /** * Listener : Process__c * Step : Create PushTopic and subscribe * Comment : PushTopic Name has to be unique thus we used the Process__c.Id. * It is possible to immediately subscribe once the Push Topic has been created! * @see SourceObjectListener class implements MessageListener interface! */ 01: // Create PushTopic 02: PushTopic pushTopic = new PushTopic(); 03: pushTopic.Name = processId; 04: pushTopic.Query = soql.toString(); 05: pushTopic.ApiVersion = SALESFORCE_API; 06: pushTopic.NotifyForOperations = "All"; // TODO: Interpret the When__c field from Process__c 07: pushTopic.NotifyForFields = "Referenced"; 08: restConnection.create(pushTopic); 09: 10: // Update Process with Push Topic Name (so that if the worker restarts it can reconnect) 11: Process__c process = new Process__c(); 12: process.PushTopicName__c = pushTopic.Name; 13: restConnection.update(process, processId); 14: 15: // Start listening on the new Push Topic immediately! 16: client.getChannel("/topic/"+pushTopic.Name).subscribe( 17: new SourceObjectListener(loginResult, processId, sourceObject));
    17. 17. Java Code {SourceObject__c} Listener Java Code : : {SourceObject__c} Listener /** * Listener : {SourceObject__c} * Step 1 : Parse Source Object Id from message and read current process steps. Determine what HTTP call * information will be provided by the source object record fields. */ 01: public static class SourceObjectListener implements MessageListener 02: { 03: public void onMessage(ClientSessionChannel channel, Message message) 04: { 05: // Source Object Message 06: HashMap<String, Object> data = (HashMap<String, Object>) JSON.parse(message.toString()); 07: HashMap<String, Object> record = (HashMap<String, Object>) data.get("data"); 08: HashMap<String, Object> sobject = (HashMap<String, Object>) record.get("sobject"); 09: String sourceId = (String) sobject.get("Id") 10: // Query Process Steps 11: QueryResult processStepsResult = m_partnerConnection.query( 12: “select Id, Name, " + 13: "HTTPEndPoint__c, HTTPEndPointFrom__c, " + 14: "HTTPMethod__c, HTTPMethodFrom__c, " + 15: "HTTPHeader__c, HTTPHeaderFrom__c, " + 16: "HTTPBody__c, HTTPBodyFrom__c " + 17: ”from ProcessStep__c " + 18: "where Process__c = " + m_processId + "");
    18. 18. Java Code {SourceObject__c} Listener Java Code : : {SourceObject__c} Listener /** * Listener : {SourceObject__c} * Step 2 : Dynamically build query for source object to include fields required * to make HTTP callout contextual */ 01: // Construct Source Object SOQL (query formula fields) 02: StringBuilder fieldList = new StringBuilder(); 03: fieldList.append("Id, Name"); 04: for(String field : sourceFields) 05: fieldList.append(", " + field); 06: StringBuilder soql = new StringBuilder() 07: .append("select ") 08: .append(fieldList.toString() + " ") 09: .append("from ") 10: .append(m_sourceObject + " ") 11: .append("where ") 12: .append("id = %s"); 13: String sourceObjectQuery = soql.toString(); 14: 15: // Query Source Object record 16: String query = String.format(sourceObjectQuery, sourceId); 17: QueryResult sourceObjectResult = m_partnerConnection.query(query); 18: SObject sourceRecord = sourceObjectResult.getRecords()[0];
    19. 19. Java Code {SourceObject__c} Listener Java Code : : {SourceObject__c} Listener /** * Listener : {SourceObject__c} * Step 3 : Use Jetty HTTP Client to make callout. HTTP call out details are taken from literals on the step * or from formula fields on the source record */ 01: // Create the HTTP client 02: HttpClient httpClient = new HttpClient(); 03: httpClient.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL); 04: httpClient.start(); 05: // HTTP parameters 06: String httpEndpoint = ... 07: String httpHeader = ... 08: String httpMethod = ... 09: String httpBody = ... 10: processStep.HTTPBodyFrom__c.equals("Literal") ? 11: processStep.HTTPBody__c : (String) sourceRecord.getField(processStep.HTTPBody__c); 12: // Construct HTTP request 13: ContentExchange contentExchange = new ContentExchange(true); 14: contentExchange.setMethod(httpMethod); 15: contentExchange.setURL(httpEndpoint); 16: contentExchange.setRequestHeader(...); 17: contentExchange.setRequestContent(new ByteArrayBuffer(httpBody)); 18: httpClient.send(contentExchange); 19: contentExchange.waitForDone();
    20. 20. ResourcesJava Code : {SourceObject__c} Listener • Other // TODO:’s and Ideas?!  – Record Types for Process Steps? – State / Variables between Steps? • Source Code and Contact Details GitHub: https://github.com/financialforcedev Heroku App (Clone): https://api.heroku.com/myapps/df12-processmanager/clone Twitter: andyinthecloud

    ×