RightNow RightNow Integratio Integration n and Customization For Developers Student Guide
D76482GC50 Edition 5.0 August 2013 D83097
Copyright © 2013, 2013, Oracle and/or its affiliates. All rights rights reserved. Disclaimer This document contains proprietary information and is protected by copyright and other intellectual property laws. You may copy and print this document solely for your own use in an Oracle training course. The document may not be modified or altered in any way. Except where your use constitutes "fair use" under copyright law, you may not use, share, download, upload, copy, print, display, perform, reproduce, publish, license, post, transmit, or distribute this document in whole or in part without the express authorization of Oracle. The information contained in this document is subject to change without notice. If you find any problems in the document, please report them in writing to: Oracle University, 500 Oracle Parkway, Redwood Shores, California 94065 USA. This document is not warranted to be error-free. This training manual may include references to materials, offerings, or products that were previously offered by RightNow Technologies Inc. Certain materials, offerings, services, or products may no longer be offered or provided. Oracle and its affiliates cannot be held responsible for any such references should they appear in the text provided. Restricted Rights Notice If this documentation is delivered to the United States Government or anyone using the documentation on behalf of the United States Government, the following notice is applicable: U.S. GOVERNMENT RIGHTS The U.S. Government’s rights to use, modify, reproduce, release, perform, display, or disclose these training materials are restricted by the terms of the applicable Oracle license agreement and/or the applicable U.S. Government contract. Trademark Notice Oracle and Java are registered trademarks of Oracle and/or its affiliates. Other names may be trademarks of their respective owners.
Copyright © 2013, 2013, Oracle and/or its affiliates. All rights rights reserved. Disclaimer This document contains proprietary information and is protected by copyright and other intellectual property laws. You may copy and print this document solely for your own use in an Oracle training course. The document may not be modified or altered in any way. Except where your use constitutes "fair use" under copyright law, you may not use, share, download, upload, copy, print, display, perform, reproduce, publish, license, post, transmit, or distribute this document in whole or in part without the express authorization of Oracle. The information contained in this document is subject to change without notice. If you find any problems in the document, please report them in writing to: Oracle University, 500 Oracle Parkway, Redwood Shores, California 94065 USA. This document is not warranted to be error-free. This training manual may include references to materials, offerings, or products that were previously offered by RightNow Technologies Inc. Certain materials, offerings, services, or products may no longer be offered or provided. Oracle and its affiliates cannot be held responsible for any such references should they appear in the text provided. Restricted Rights Notice If this documentation is delivered to the United States Government or anyone using the documentation on behalf of the United States Government, the following notice is applicable: U.S. GOVERNMENT RIGHTS The U.S. Government’s rights to use, modify, reproduce, release, perform, display, or disclose these training materials are restricted by the terms of the applicable Oracle license agreement and/or the applicable U.S. Government contract. Trademark Notice Oracle and Java are registered trademarks of Oracle and/or its affiliates. Other names may be trademarks of their respective owners.
RightNow Integration and Customization Cust omization for Developers Agenda
Day 1: Monday Day 0B
Day’s Objective: Objective: RightNow CX Agent Desktop and basic ROQL 1B
Welcome! In troductions 8:30 to 9:15
Overview Site assignments assig nments
9:15 to 10:15
Installing Insta lling the Agent Desktop Working with Ob jects in the t he Agent Desktop
10:15 to 10:30
Break
10:45 to 11:30
Customizations Staff Management Analytics Custom Objects
11:30 to 12:00
Help The Customer Portal
12:00 to 1:00
Lunch
1:00 to 3:00 3 :00
RightNow Connect The Connect Connect Common Common Object Model NamedID Named ID and List L ist Types Documentation
3:00 to 3:15 3 :15
Break
3:15 to 4:45 4 :45
ROQL CSV Queries Que ries Visual Studio Query O bjects bjects
4:45 to 5:00 5 :00
Daily Assess ment ment Q&A
This agenda agenda is subject to c hange. hange.
Copyright © 2013, Oracle and / or its affiliate affiliate s. All right s reserved. Page 1 of 5
RightNow Integration and Customization for Developers Agenda
Day 2: Tuesday
B2
B3
8:30 to 9:00
Review. Q &A
9:00 to 10:15
Comparing ROQL and SQL The W HERE Clause Case Sensitivity Logical Operators Functions
10:15 to 10:30
Break
10:30 to 12:00
Aliases Custom Objects and Fields Instantiating the Client Relationship Queries Join Types LIMIT and OFFSET Paging
12:00 to 1:00
Lunch
1:00 to 3:00
Multiple SELECT statements Handling multiple outputs Blacklisting Special Queries Connect Web Services for SOAP Create operation Sub-Objects
3:00 to 3:15
Break
3:15 to 4:45
4:45 to 5:00
Day’s Objective: ROQL and SOAP
Lists idSpecified Processing options Get operation Update Operation Daily Assess ment Q&A
This agenda is subject to c hange.
Copyright © 2013, Oracle and / or its affiliate s. All right s reserved. Page 2 of 5
RightNow Integration and Customization for Developers Agenda Day 3: Wednesday
B4
B5
8:30 to 9:30
Day’s Objective: SOAP Operations and Desktop Add-In Framework
Review. Q &A
9:30 to 10:15
Optimizations Bulk operations Batch processing Introduction to chaining
10:15 to 10:30
Break
10:30 to 12:00
Chaining Custom ields O bjects Non-CRUD operations Analytics Report
12:00 to 1:00
Lunch Capstone Activity Explanation of Capstone Activity
1:00 to 3:15 Each student wo rks at own pace, and paired programming is welcome. Instructor is available for help at all times. 3:15 to 3:30
3:30 to 5:00
Break Daily Assessment Q&A Continuation of work on Capstone Activities, with students free to leave as they complete the activities.
This agenda is subject to c hange.
Copyright © 2013, Oracle and / or its affiliate s. All right s reserved. Page 3 of 5
RightNow Integration and Customization for Developers Agenda Day 4: Thursday
B4
B5
8:30 to 9:30
Day’s Objective: Desktop Add-In Framework
Review. Q &A
9:30 to 10:15
Desktop Add -Ins Deploying an Add-In Developer Mode
10:15 to 10:30
Break
10:30 to 12:00
Add-In Wizard and Te mplates Installation of Templates GlobalRibbon
12:00 to 1:00
Lunch
1:00 to 3:15
Application Menu NavigationSection Debugging Framework Events Logging
3:15 to 3:30
Break
3:30 to 4:45
Automation Context IRecordContext Navigation Item
4:45 to 5:00
Daily Assess ment Q&A
This agenda is subject to c hange.
Copyright © 2013, Oracle and / or its affiliate s. All right s reserved. Page 4 of 5
RightNow Integration and Customization for Developers Agenda Day 5: Friday
B4
Day’s Objective: Capstone Activities
B5
Review. Q &A 8:30 to 9:00
9:00 to 12:00
Web Services for SOAP in a n Add-In Workspace Ribbon Button Record Context Workspace Add-In Custom Controls
12:00 to 1:00
Lunch Capstone Activity
1:00 to 3 :00
Explanation o f Capstone Activity Each student wo rks at own pace, and paired programming is welcome. Instructor is available for help at all times. Final Class evaluation
3:00 to 5:00
Continuation of work on Capstone Activities, with students free to leave as they complete the activities.
This agenda is subject to c hange.
Copyright © 2013, Oracle and / or its affiliate s. All right s reserved. Page 5 of 5
RightNow CX Integration and Customization for Developers Student Guide
Oracle RightNow CX Cloud Service May 2013
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
Table of Contents •
Student Guide
•
Assessments
Student Guide Contents:
Overview .............................................................................................................. 4 Course Introduction .............................................................................................. 5 Oracle RightNow Connect .................................................................................. 20 Oracle RightNow Connect Common Object Model............................................. 22 Oracle RightNow Object Query Language (ROQL) ............................................ 25 Oracle RightNow Connect Web Services for SOAP ........................................... 47 Capstone Activity ................................................................................................ 78 Oracle RightNow Desktop Add-Ins Cloud Service.............................................. 79 Capstone Activity ................................................................................................ 98
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
This course is an introduction to integration and customization for developers working with Oracle RightNow CX Cloud Service (Oracle RightNow CX) and the Oracle RightNow CX Agent Desktop console application(Agent Desktop). It introduces the core knowledge which developers need to begin integrating Oracle RightNow CX with other systems. It also offers an introduction to developing add-ins that can be used to customize, integrate, automate, and extend the Agent Desktop.
After completing this course, you will be able to: Access the basic functionality of the Agent Desktop. Write queries using ROQL and the Connect Common Object Model. Write C# code using the Oracle RightNow Connect Web Services for SOAP API to query and manipulate objects from the Oracle RightNow knowledgebase. Develop various kinds of add-ins to customize, integrate, automate, and extend the Agent Desktop. • • •
•
To get the full benefit from this course, you will need to have experience with: Object-oriented programming in C#. Developing NET applications, both WinForms applications and console based applications. Relational database concepts. SQL. • •
• •
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
4
The exercises in the course are based on the following scenario. You have recently been hired as a developer by Smartech, a subsidiary of Global Solutions. Smartech uses Oracle RightNow CX to support its multi-channel customer service interactions. Among your duties will be writing applications that help integrate data from the Oracle RightNow knowledgebase with other enterprise data systems at Smartech, so you will need to learn about the object model used by RightNow CX, as well a s the tools that are available for accessing and manipulating data in the database. Another of your duties will be to respond to requests to enhance or customize the Agent Desktop with new functionality. In some cases, the users will request specific controls and behaviors, and in others they might express their need and ask you to determine how best to meet it. Continued on next page
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
5
Oracle RightNow CX is a suite of applications that empowers enterprises to engage directly with their customers through Social, Web, and Contact Center experiences. Oracle RightNow CX is provided as a hosted service in the cloud consisting of a knowledge base and at least one interface that is used to access it. Each interface for a site has its own unique URL. Oracle RightNow CX empowers customers to get help from a self-service web site and/or support from live agents who use a Windows console application called the Agent Desktop to handle customer issues. Although the full suite of Oracle RightNow CX products includes much more, such as a social experience, this course will be concerned only with the contact center and the integrated database on w hich it depends.
Customer service agents and administrators can access an Oracle RightNow site via the Agent Desktop. That requires downloading and installing the Oracle RightNow Agent Desktop, which provisions a local machine with the needed components to accessing a particular site. Customers of an enterprise that uses Oracle RightNow can use a CustomerPortal web site to interact with the Oracle RightNow knowledgebase to access self-help information or to contact a customer service agent for help. Developers can write code to interact with a knowledge base via Oracle RightNow APIs, one of which allows customization of the Agent Desktop. This course begins with a look at the A gent Desktop to familiarize you with the most common entities in Oracle RightNow CX. You have been assigned your own Oracle RightNow site, with two interfaces, to use for this course. The second interface has the same name as the first, followed by "_2". A second interface could be used for training, development, or staging, for example. The second interface accesses the same database, but can have a different appearance.
Site URL (end-user):
http://___
______.rnowtraining.com
Site URL (admin/launch):
http://__ ____.rnowtraining.com/cgi bin/__ ______.cfg/php/admin/ launch.php
Admin Username:
cxadmin
Admin Password:
cxadmin Continued on next page
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
6
Continued
To install the client application that accesses an Oracle RightNow site, use the Site URL for admin/launch, listed above. When you point your browser to this URL, a screen will open with a button saying Install Oracle RightNow CX Cloud Service. Click this button and wait for the brief installation. Note: Because Oracle RightNow CX Cloud Service is built on a .NET framework, this installation should be done using Internet Explorer.
After the installation completes, a window will open that allows you to enter your username and password. For this course, both the username and password will be "cxadmin". Check Remember Me, and click Login to open the Agent Desktop for your site.
You have been given a link to use to install the Agent Desktop, and told to set it up on your own workstation.
In this activity, you will install the Agent Desktop and l og in to your site.
1
2 3 4
Type the URL for your site into the address bar of Internet Explorer. .rnowtraining.com/cgibin/.cfg/php/admin/launch.php Click the Install Oracle RightNow CX Cloud Service button. This begins a download which may take several minutes. In the Login window, type your username and password. Click the Login button.
To access the same site in the future, you can launch the Agent Desktop by selecting Start menu > All Programs > RightNow > RightNow (your site name). You can create a shortcut to it, or pin it to your taskbar. Continued on next page
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
7
Continued
The Agent Desktop is divided into three main areas: Navigation Pane: Left panel area that contains a set of buttons to navigate through the Agent Desktop and to access information about various record types stored in the Oracle RightNow knowledgebase. These buttons can be expanded to show the functionality they provide. Ribbon: Top toolbar containing the actions available to the object in focus. Content Pane: Main panel that changes based on the record type, component type, configuration activity, or report being accessed. •
• •
The configuration of the content pane and ribbon specific to a pa rticular record type is known as the Workspace for that record type. A contact center agent uses the Agent Desktop to access information to help customers, such as records for: Contacts: An individual with a customer record in the database. Contact records can be added using the Agent Desktop or on the Customer Portal pages. Incidents: Questions or requests for help submitted by a contact through any means, such as email, a chat session, etc. Incidents can also be added by agents when they work with customers by phone or email. Answers: Information in the database (known as the knowledge base) that provides solutions to commonly asked questions. Agents can access answers through the Agent Desktop to help resolve incidents. •
•
•
Agents can use the Agent Dsktop manually to: View and create objects such as Contacts, Incidents and Answers Customize Objects and Workspaces Create profiles and staff accounts Run and view Reports • • • •
A simplified typical example of how a customer and agent might interact using Customer Portal and the Agent Desktop, respectively, would include the following: A Contact (customer) visits the Oracle RightNow web portal (Customer Portal) The Contact searches for Answers (FAQs) relevant to his problem If no answer is found, the Contact logs in and posts a question, which creates a Thread on an Incident A customer service Agent who is logged into Agent Desktop Retrieves the Incident from a queue Searches again for Answers or uses other r esources Replies to the Contact, creating another Thread on the same Incident •
• •
•
• • •
The underlined words in the scenario above represent real-world entities that are stored as primary objects in the Oracle RightNow knowledgebase. Continued on next page Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
8
Continued
Answers are record types that are similar to FAQs in that they consist of questionand-answer pairs. Each Answer includes: Summary : Brief description of content, typically in statement format. Question: Full description of the issue, including all pertinent information. Answer: Full description of the resolution to the issue. Products/Categories: The products or product categories to which the Answer applies • • • •
To open a particular pane within the Navigation Pane area, click on the button with the name of the pane you want to open. The new pane will open at the top of the Navigation Pane area. In some cases, the name of the pane you want isn't shown on a button, because there isn't enough room on the Navigation Pane for all buttons if their full size. Look at the icons at the bottom of the Navigation Pane to find the button you want and click to open that pane. Letting your mouse hover over one of these icons will show you the name of the pane associated with it. The space for icons at the bottom of t he Navigation Pane is also limited, so you can click the arrow to the right of the icons to see more buttons that are available.
To view one or more Answers from the Oracle RightNow knowledgebase, first click Answers Default, which will run the Answers Default report.
Before the Answers Default report results appear, a Search window opens. To view all Answers, make no changes to this report and simply click the Search button at the bottom of the window.
When the Answers Default report runs, it provides a list of all answers in the knowledgebase, and displays the Answer number and a summary of the contents of the Answer, along with several other fields. To see more detail, such as the specific question and answer fields, about any individual Answer record, double-click on that row in the report. Under the Content tab on the screen that shows an individual Answer, are tabs that let you view the specific question and answer associated with that record, and see a preview of how the formatted Answer will be displayed on Customer Portal to the end-user. This course does not cover the use of Answers or other objects in the Agent Desktop in any detail. Oracle offers another course covering the administration of the Agent Desktop which focuses n these tasks. Continued on next page
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
9
Continued
Viewing Contacts or other objects is similar to viewing Answers. By default, the Agent Desktop lets an agent search for a particular Contact by selecting the Contacts button, then clicking on the Contact Search link, and then optionally applying a filter, instead of clicking Search to show all Contacts.
Individual contacts can be selected from the results of a Contact Search. Clicking on the contact will open a Contact Workspace in which d etails can be viewed or edited. Fields shown in red with asterisks are required.
Your supervisor suggests that you start to learn a bout Oracle RightNow CX by working with the Agent Desktop from the point of view of a contact center agent, to see how objects such as Contact, Incident, and Answer are used and manipulated. You will view lists of objects as well as individual objects, and you will both edit existing objects and create new objects.
In this activity, you will access and view a list of Contacts and open a single Contact for editing.
1 2 3
4 5
From the Navigation pane, click Contacts. Double-click Contact Search. In the Search dialog that opens, leave Select All selected, and click Search. Notice that you could also choose to filter your search in various ways. The list of Contacts is displayed. To see details of an individual Contact, double-click to open the record.
In this activity, you will create a new Contact.
1 2 3 4 5 6
From the Contact Search tab, click New on the ribbon to open a blank Contact record. Required fields are in red. Type in your own first and last name. Click Save & Close on the ribbon. Select the Contact Search tab. Click Refresh from the ribbon. Locate your name, now shown as a Contact in the list. Continued on next page
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
10
Continued
In this activity, you will view an I ncident and related Answers.
1 2 3 4 5 6
From the Navigation pane, click Incidents. Double-click Incidents and leave Search All selected in the dialog, but notice that the list is being filtered for Unresolved Incidents only. Click Search to open the Incident list. Click Subject to sort by that column. Double-click to open the first Incident from the list. Click the Status menu, then select Unresolved. Go to the Messages tab. Click the SmartAssistant button to view recommended Answers. Close the dialog.
In this activity, you will create a new answer that explains how to reset a password.
1 2 3
4
5 6
Go to Answers > Answers Default > Search. Click New and type Summary : Password Reset Set Answer options. Status Public Language English Access Level Everyone Answer Type HTML Complete the Content tab: In the Keywords box, type password . Click the Question sub-tab and type: How do I reset my password? Click the Answer sub-tab and type: Click the Forgot Password link on the login page. Click the Quick Preview sub-tab to preview your work. Click the Products/Categories tab and select General and Technical Support. Click Save.
The Agent Desktop can be custom-configured in various ways. Some of the areas in which administrators can configure the desktop include: Customizable menus: Adding new items to certain menus of choices, such as Incident Status. Custom fields: Adding new data fields to existing objects. Custom workspace: Adding new items to be displayed in a custom workspace. •
• •
Continued on next page
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
11
Continued
Like many enterprises, Smartech wants to customize Oracle RightNow, so you have been assigned to implement these customizations: Add a new value to the menu which shows the status of an incident. Add a new field to the database record for Incidents, to store whether the incident is considered urgent or not. Add a customized workspace to the Agent Desktop that will display the contents of the new field when an Incident is viewed. • •
•
In this activity, you will configure Oracle RightNow to add a new incident status value to a menu.
1 2 3 4 5 6 7
Go to Configuration > Application Appearance > Customizable Menus. Expand System Menus and select Incident Statuses. Click New and type the Label: Researching. Assign Status: Unresolved to have this status marked as open. Click Save & Close. Select the Incidents tab, then click on the New icon to open a new incident record. Select Status to see the new value within the list.
In this activity, you will create a custom field on the Incidents table.
1 2 3 4 5
Select Configuration > Database > Custom Fields > Incident. Click New to create a new Incident custom field. Type Name: Urgent ?. Select Data Type: Yes/ No. Type the Column Name: urgent .
6
This is the value used in the underlying database, so it must start with a letter, contain letters and underscores only, and cannot contain spaces. Click Save & Close, then click Yes. Continued on next page
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
12
Continued
In this activity, you will configure a custom workspace to display the custom field.
1 2 3 4 5 6 7
Select Configuration > Application Appearance > Workspaces/ Workflows > Standard. Right-click Incident and select Copy . Type Name: Custom Agent Workspace, then click OK . Select the Workspaces and Workflows folder, and open Custom Agent Workspace. Click on the Insert Field tab. Scroll down to the Urgent? field and drag and drop it onto the workspace. Click Save & Close.
Profiles are similar to what are called roles in some other applications. They are used to set permissions for a category or group of users. As a developer who will use web services to access the Oracle RightNow database, your profile must have the Public SOAP API profile bit enabled. Staff Accounts provide individual logins for users. Each account is assigned to a profile.
In order to write applications that access objects in Smartech’s Oracle RightNow database, you will need to use a staff account that has a profile with the appropriate permissions.
In this activity, you will create a personal staff account.
1 2 3 4
Go to Configuration > Staff Management > Staff Accounts by Profile. Click New on the ribbon. Type in a User Name (case and space-sensitive) of your choice. Fill in the required fields, which are printed in red with asterisks. In the Profile field, click the magnifying glass search icon and select CX All-2. In the Group field, click the search icon, then click New Group. Type Name: Developers then click OK . Under Password, uncheck Password Expires. Click Change Password and type an acceptable password. Click Save & Close. Exit the Agent Desktop, then re-open it and sign in with the new account information. •
•
5 6 7
Continued on next page
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
13
Continued
Oracle RightNow CX offers hundreds of standard reports in the system. You can add run-time filters to standard reports, or you can create customized reports to meet your needs.
Your supervisor has suggested that you learn what kinds of reports are already available by default in Oracle RightNow CX, because later, you will be expected to run some of these reports in code.
In this activity, you will open an existing report, change a run-time filter, and view the output.
1 2 3 4 5 6 7
Go to Analytics > Reports Explorer. Click Find from the ribbon, then select Find using: Name. Select Contain for the operator. Type Agent into the text box and click Find. Double-click Agent Activity found in the right pane of the Reports Explorer to run the report. In the Search dialog, change the Date Range start value to 01/01/2010. Click Search and view the results.
Continued on next page
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
14
Continued
Custom fields are useful for adding data that is logically associated with an existing object. For more complex data structure needs, a custom object can be defined, which creates an entirely new database table, rather than just a custom column in an existing table. Custom objects typically represent entities in a particular customer’s business, such as a product warranty. Custom objects can be displayed in the Agent Desktop and added to analytics reports or other areas.
Custom objects are created using the Object Designer, and stored in packages which also scope the objects. The Object Designer is a gra phic tool that can be used by trained site administrators. It is generally best to create a new Custom Object (CO) in a test site and test it extensively before d eploying it to your production environment. To use the Object Designer, Custom Objects must be enabled on yo ur site, and the user must have the Object Designer permission enabled in his or her profile. Continued on next page
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
15
Continued
Smartech provides training classes on how to work with Smartech products. You have been asked you to create a Custom Object named TrainingClass to hold the information about a class: a class number and class name. You will also create a custom workspace for the new object.
In this activity, you will create a new Custom Object and a workspace for it.
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
Select Configuration > Database > Object Designer. Click New and select Package. Name the package Classes. Select the Classes package and click New > Object. Type Name: TrainingClass. Click the Fields tab on the ribbon, then click Add New Field. Select Integer. Type field Name: ClassNumber, avoiding spaces. Click the Add New Field button again. Select Text. Type field Name: ClassName, avoiding spaces. Type Length of Field: 50. Repeat the 4 steps above for a text field named Instructor, length 20. Under Field Options, check the box for Is Nullable. Fields not marked Is Nullable will be required entries when objects are created. On the ribbon, click Save, then click Deploy . Check Deploy Immediately . In a real scenario, you could schedule deployment for a convenient time. Click Deploy , then confirm Yes. Deployment takes several minutes. Select Configuration > Site Configuration > Application Appearance > Workspaces/Workflows. On the ribbon, click New Workspace. Under Custom Types, select TrainingClass. Do not select TrainingClass Multi-Edit, which is a specialized workspace for making identical changes to multiple objects at once. From the Fields group on the ribbon, drag each of the two fields onto the blank area of the new workspace. Click on the Preview > New Record button to see how the new workspace will look to the agent user. Close the preview window. Click the Save & Close icon located above the ribbon. Name the new workspace Training Class, and leave it in the default folder, Workspace and Workflows. Click OK to save. On the Workspaces/ Workflows Explorer tab, select Workspaces and Workflows in the left column to see, in the right column, that the TrainingClass workspace has been created. Continued on next page
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
16
Continued
The CX button provides access or shortcuts to additional areas of support or information. When this button is selected, the menu is divided into two panels. The left panel contains contextual options based on the object in focus, such as New Incident and Save Incident when an incident report or record is open. Below these options are a group of global options that will always appear regardless of the selection: Community, Links, Help, and add-in Logging. These additional items have sub-menus available within each item. The right panel contains shortcuts for adding objects to the database, such as incidents or answers, based on your permissions in the system. The items listed in this menu are configurable. In addition, you can write code to customize the menu, as you will learn later in the course.
Another small help button with a question mark icon is located in the upper right corner of the screen. This button provides help that is context-sensitive.
Customer Portal is the web site interface that customers access for customer support. Customer Portal consists of a standard set of files that can be customized, and it allows to query the knowledge base for answers, ask questions, provide feedback, manage their customer account, and request chat sessions.
To learn more about how entities in the knowledgebase are being used throughout Oracle Right Now CX, you have decided to explore the Customer Portal from the point of view of a customer who is visiting the support pages of a company that uses Oracle RightNow CX. Continued on next page
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
17
Continued
In this activity, you will explore and interact with the Customer Portal support pages of your site.
1 2
Open the end-user pages of your training site in a browser: http://.rnowtraining.com . Navigate your end-user pages to: Search for an answer by typing password reset into the initial screen search text box. View the result. Use the Your Account tab to register for an account. Use the Ask A Question tab to submit a question about a topic of your choice. Notice the Urgent? item on this page. Use the Agent Desktop to find the question (Incident) that you submitted, and see that it identifies you as the Contact. •
• •
What are some of the basic entity objects in Oracle RightNow CX and how are they used?
Why might an administrator need to create a new Staff Account? What profile bits must be enabled for a developer account?
Give some examples of customizations that can be made to the Agent Desktop by a CX Administrator.
Continued on next page
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
18
Continued
How do you run and view a basic Analytics report in the Agent Desktop?
(continued)
Why might you create a Custom Object?
What tool is used to design and create a Custom Object?
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
19
Oracle RightNow Connect is a set of tools for developers. Connect includes: Oracle RightNow Connect Web Services for SOAP (Connect Web Services) Oracle RightNow Desktop Add-Ins Cloud Service (desktop add-ins) Oracle RightNow Connect PHP API Cloud Service (Connect PHP API) Oracle RightNow Connect Knowledge Cloud Service (knowledge foundation) • • • •
This class will focus on the first two of these. Another course available from Oracle covers Connect PHP API. Connect Web Services can be used to manipulate data from the Oracle RightNow knowledgebae and to integrate Oracle RightNow CX with other systems or vice versa. Example integrations could include upkeep on a master data store, or synchronizing data across multiple sites. Using Connect Web Services, you can i mport data into applications where it can be manipulated by t hat app, or provide data for business processes like billing or marketing. Connect Web Services can also be used to provide data to the Agent Desktop from the RightNow knowledge base or other applications. Oracle RightNow Desktop Add-Ins Cloud Service is a framework for building custom .NET components, controls, and applications that can be added to the Agent Desktop to provide integration, automation, or extensions. Continued on next page
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
20
Continued
The Connect Web Services API is based on SOAP (Simple Object Access Protocol) and WSDL (Web Services Description Language). These are open standards, not proprietary, and are very widely used, making it easier to integrate RightNow with other systems that also support SOAP and WSDL. Also, many programming tools support SOAP with wizards and utilities that make it quick and easy to create or use SOAP-based web services. That includes Microsoft’s Visual Studio which will be used in this course. Using open standards technology also makes it easier to implement RightNow within a Service Oriented Architecture (SOA) in which a range of d isparate systems must communicate with each other, either directly or through an Enterprise Service Bus (ESB). All of the APIs which are part of RightNow Connect use the RightNow Connect Common Object Model (CCOM). Developers can learn the object model once, and use it throughout Oracle RightNow CX. Earlier APIs, which have now been deprecated in favor of Connect, did not support Custom Objects. One of the biggest reasons for moving to Connect was to provide support for Custom Objects. Finally, Connect has been designed for backward compatibility. When customers choose to move to a newer version of Connect, their integrations are less likely to break or need maintenance.
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
21
Object data , such as data from contacts, incidents, or answers, is kept in databases hosted on RightNow servers. Database objects can be viewed and manipulated programmatically using classes based on the RightNow Connect Common Object Model. The RightNow Connect Common Object Model, or CCOM, defines a set of objects that include the entities (record types) represented in the Knowledge Base and used in the Agent Desktop. The RightNow Connect Common Object Model (CCOM) is a standard intended for use across all of the RightNow public APIs, although some older APIs do not support it. The CCOM provides several advantages: It allows developers to learn a single, logical-class hierarchy that can be used to access and manipulate data in both the Agent Desktop and Customer Portal, as well as to interact with external applications. It works with various technologies. It is used with PHP to access the Customer Portal, and with SOAP web services to interact with the Agent Desktop or external applications. CCOM objects can also be used with the Desktop Add-In Cloud Service to automate, extend, or integrate the Agent Desktop. •
•
Code that uses CCOM objects indirectly accesses data f rom the underlying database using RightNow APIs to handle the conversion. This shields custom code against changes that are made to the database.
The CCOM defines a set of objects that includes primary objects, which have a unique ID assigned to them by the RightNow Knowledge Base server, and support direct Create/Read/Update/Delete (CRUD) operations. All primary objects inherit from a base class RNObject. Primary objects may contain primitive data types directly or may contain subobjects. Sub-objects, in general, cannot be directly manipulated with CRUD operations but instead are manipulated through operations on the primary ob ject in which they are embedded. Sub-objects can contain sub-objects of their own. Continued on next page
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
22
Continued
The RightNow Connect Common Object Model specifies a number of primary objects, including, among others: Answer Contact Incident Organization Task Account SiteInterface • • • • • • •
Most of these represent entities in the real world domain. S iteInterface provides access to details about the current site interface, including name and language.
Examples of sub-objects include: Address PersonName Phone Email • • • •
To access individual data items (field values) in an ob ject, CCOM uses a dot notation, meaning that the primary object is given first, followed by a dot, followed by any subobject(s), followed by a dot, then followed by the actual name of the attribute. For example, the Contact object has a sub-object Name with two fields: First and Last. To access the last name, use: Contact.Name.Last Here are examples of how some of the parts of a Contact object would be accessed in dot notation: Contact Contact.Title Contact.Name.First Contact.Name.Last Contact.CreatedTime Contact.Emails Contact.Emails[0].Address Contact.Emails[0].AddressType.Name • • • • • • • •
Continued on next page
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
23
Continued
The Connect Common Object Model includes many objects of type NamedID. That type has two parts: an ID, and an associated name. ID is itself an object, with an attribute named ID that is a long integer. ID is a unique ID value assigned by the server when a new object is stored. The name part of the NamedID is a string. Some examples of NamedID types in Oracle RightNow CX are: StateOrProvince Country Email AddressType Language Incident Queue • • • • •
A list is a wrapper for a collection of sub-objects, such as EmailList PhoneList AnswerLinkList NoteList ThreadList • • • •
Additional documentation of the Connect Common Object Model is available in the Developer Community on the RightNow website. Under the documentation section, open the documentation for Connect Web Services, and expand Web Service API > Object Model > Object Model Overview > Primary Objects. Using this documentation, you can drill down from a primary object to reach the primitive data it contains. You will have to register to access the site. Registration is free.
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
24
For Read operations, the Connect APIs use a s pecial query language named ROQL (pronounced “Rock-well”), which stands for RightNow Object Query Language. ROQL is related to SQL (Standard Query Language), and to OQL (Object Query Language), which is a specialized version of SQL.
There are two types of queries in ROQL. The syntax for a tabular query type is similar to SQL:
SELECT primaryObject.field,... FROM primaryObject WHERE condition However, what follows FROM in the query is the singular name of a primary object, not the name of a table.
To query a NamedID type, you can query the ID and/or the Name of the object. For example, in the following query SELECT Contact.Address.City, Contact.Address.StateOrProvince .Name, Contact.Address.StateOrProvince. ID
City, which is not a Named ID type but a string primitive, can be queried directly, but StateOrProvince requires that either Name or ID be specified. To query a List type, use the name of the list type without an index. What is returned will be an automatic iteration of all values. SELECT Contact.Emails.Address FROM Contact . . .
The ROQL statement below will show each phone type and the associated phone number, placing a colon between them.
SELECT Contact. Phones.PhoneType.Name,': ', Contact. Phones.Number To select only one item from a list of NamedID types such as Emails or Phones, use the WHERE clause to select item you want, either by ID or name.
SELECT Contact.Emails.Address FROM Contact WHERE Contact.Emails.AddressType.Name = 'Email - Primary' Continued on next page
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
25
Continued
ROQL is executed by calling a method in one of the Connect APIs. Code to call the API can be written in C#, Java, or PHP.
Certain items must be configured to allow the use of Web Services. At the site level, the II_CONNECT_ENABLED configuration item must be set. This is done by Oracle RightNow staff, not by an agent of the customer. However, a RightNow administrator can handle the second required configuration, which is set for each individual profile which is allowed to execute SOAP calls. This is done in the Agend Desktop, under Configuration > Staff Management > Profiles, by checkin the Account Authentication box under Public SOAP API in the Permissions tab.
This course uses C# console-based applications written using Visual Studio Professional. To start a C# console-based application that makes calls to a RightNow SOAP API: Open Visual Studio From the main menu, select File > New Project > C# > Console Application In the Solution Explorer, right-click References and select Add Service Reference In the Address box, add a reference to your site's WSDL: http://.rnowtraining.com/cgi bin/.cfg/services/soap?wsdl Note that your site name will be the same as your interface name. Click OK. Add using statements to your code: using ConsoleApplication1.ServiceReference1; using System.ServiceModel; • • •
•
•
• •
Continued on next page
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
26
Continued
API calls to execute web services are made by a client object of type RightNowSyncPortClient. The client object has an embedded sub-object named UserName which has fields for the UserName and Password whose privileges will be used to execute the query. RightNowSyncPortClient _client = new RightNowSyncPortClient(); _client.ClientCredentials.UserName.UserName = "cxadmin"; _client.ClientCredentials.UserName.Password = "cxadmin";
A method named QueryCSV is used to execute a ROQL tabular query. It takes seven parameters: A Client Information Header The query itself in a variable or as a double-quoted string literal An integer for the maximum number of rows to return, which cannot exceed 10,000 A delimiter string for returned values, which is typically "," A Boolean for whether to return results as raw data, that is, as an array of bytes. A Boolean for whether or not MTOM should be disabled, which is typically false. MTOM stands for Message Transmission Optimization Mechanism, which is a way of sending binary data via SOAP without encoding it as text, and is therefore more efficient. A variable to hold an array of binary bytes. This is a required parameter, but it won't be populated unless the first Boolean variable listed above is set to true. This is an out parameter which must be labeled as such by preceding it with the word out . Out parameters do not pass a value into a method, but will be given a value within the method body which will be returned to that variable when the method exits. • • •
• •
•
•
A ClientInfoHeader object has a single attribute, AppID, which is a string that will identify this assembly when it runs on the RightNow server. It is not required to be absolutely unique, but should be specific enough to make it unlikely that it will be duplicated by another application. Set up a ClientInformationHeader as follows: ClientInfoHeader cIH = new ClientInfoHeader(); cIH.AppID = "String identifier"; or ClientInfoHeader cIH = new ClientInfoHeader{AppID = "SomeString"};
Continued on next page
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
27
Continued
Here is an example of calling the QueryCSV method, within a try..catch block. As in SQL, string literals are single-quoted. In this example, the byte array will not be populated when the method call returns. byte[] output = null; try { CSVTableSet tableSet = _client.QueryCSV(cIH, "SELECT Contact.Name.Last, Contact.Name.First, Contact.Address.Street FROM Contact WHERE Contact.Address.City='Singapore' ", 10000, ",", false, false, out output); } catch (Exception ex){ . . . }
The results of a tabular query are returned in an array of tables. When only a single ROQL query is included in the call, then the results will be placed in the first and only table in that array. Within that table, a collection Rows holds an array of strings, with each string holding the data values returned from one record in CSV (comma-separated values) format. CSVTable t = tableSet.CSVTables[0]) System.Console.WriteLine( t.Columns); // column names String[] rows = t.Rows; foreach (String data in rows) { System.Console.WriteLine(data); }
In this example of calling the QueryCSV method, the return value of the method will not be assigned to an array of tables. Instead, the byte array will automatically have been populated within the method body itself. byte[] output = null; try { _client.QueryCSV(cIH, "SELECT Contact.Name.Last, Contact.Name.First, Contact.Address.Street FROM Contact WHERE Contact.Address.City='Singapore' ", 10000, ",", true, true, out output); } catch (Exception ex){ . . .}
Continued on next page
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
28
Continued
The output from the previous query will be array of bytes that can be looped through. char[] res = Encoding.UTF8.GetChars(output); foreach (char c in res) { Console.Write(c); }
The required files for the demos and the coding exercises in this course can be downloaded as a zip file from: http://bit.ly/1bpKwYX Depending on the individual exercise, the files may include demo code, setup material, starter code, solution code, or instructions. For each exercise, you may choose how to perform that exercise, depending on your skill and comfort level with the material and on what assistance is provided for that particular exercise: By writing the code from scratch, ba sed on the information in thie Student Guide, and Demo code, if any is available. By following specific instructions for writing the code, when those are avaiable. By modifying the demo code for the topic, if that is available. By opening the solution code provided, studying it to see how it works, and running it to see the output, then modifing the code as you choose and rerunning it again to see the effect of various code changes on the output. •
•
• •
Note that for the last two options, you will need to add a SOAP reference to your site to the code provided.
You need to retrieve data from the RightNow database that will be logged for various purposes. You start by writing ROQL queries to display the desired data on the screen, so that you can verify your logic and syntax. Later, you could write the data to a logfile or make it available to other systems f or integration. Continued on next page
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
29
Continued
In this activity, you will use documentation to write applications that use ROQL CSV queries to select and display data. The three possible email addresses for the contact whose last name is "Crown" The city and state for the contact whose last name is "Barnes" The name of the queue to which incident 110602-000003 has been assigned •
• •
A ROQL Object Query returns entire objects. Only one type of object can be selected for in a single query, and the returned objects will be held in an array. The code can then manipulate the objects and use their properties. The syntax of an object query is SELECT Contact FROM Contact WHERE Contact.Address.City='Singapore’
What follows SELECT is a whole object, without individual fields specified. In the WHERE clause, dot notation is used to find a value within a sub-object.
The QueryObjects method is used to make a ROQL object query. It requires four parameters: a client information header, a ROQL object query, a n object template which defines what level of data will be returned for each object, and a row maximum. Continued on next page
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
30
Continued
An object template provides a template for what should be populated by the server when it returns the objects requested. By default, only top-level sub-objects will be populated. No data will be returned for nested sub-objects. So, for example, the values for street and city would be populated, but not the ID or Name properties for StateOrProvince, if you used the simple template below: Contact contactTemplate = new Contact(); RNObject[] objectTemplates = new RNObject[]{contactTemplate Alternatively, to have the server populate sub-objects, instantiate them in the object template, as shown below: Contact contactTemplate = new Contact(); contactTemplate.Address = new Address(); contactTemplate.Address.StateOrProvince = new NamedID(); RNObject[] objectTemplates = new RNObject[]{contactTemplate};
Like the tabular query, an object query is executed within a try..catch block. try { QueryResultData[] queryObjects = _client.QueryObjects(clientInfoHeader , "SELECT Contact FROM Contact WHERE Contact.Address.City = 'Singapore' ", objectTemplates, 10000); } catch (Exception ex) { . . . }
The output from an object query is an array of type RNObject, which is the parent object of all other primary object types. Iterate through that array to obtain individual objects, casting each object back to the correct type, and then use the properties and methods of the object as needed. RNObject[] rnObjects=queryObjects[0].RNObjectsResult; foreach (RNObject obj in rnObjects) { Contact cont = (Contact)obj; System.Console.WriteLine(cont.Name.First + " " + cont.Name.Last + " ID: " + cont.ID.id); }
Note that in ROQL, ID alone returns an ID number for a NamedID type. Later in this material, you will see that in C# code, ID.id must be used. Continued on next page
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
31
Continued
You want to retrieve whole objects and manipulate them in code, instead of retrieving individual attributes.
In this activity, you will re-write the same queries you wrote earlier in QueryCSV, this time using QueryObjects.
A ROQL query is syntactically similar to SQL, with important differences. SQL: SELECT first_name FROM contacts WHERE city=‘Singapore’
ROQL QueryObject: SELECT Contact FROM Contact WHERE Contact.Address.City='Singapore' ROQL QueryCSV: SELECT Contact.Name.First FROM Contact WHERE Contact.Address.City= 'Singapore'
Many elements of SQL are not available in ROQL, including joins and nested queries. Boolean are 0/1, rather than TRUE/FALSE, and while it is possible to use the asterisk wildcard, RightNow does not recommend it, in part because the order of columns returned is not guaranteed. Instead, request a whole object. Continued on next page
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
32
Continued
SQL makes its queries or changes by directly accessing tables in the database. ROQL does not access the database directly. The API takes a query written in ROQL and transforms it into appropriate SQL. Then the SQL commands are used to access the database tables directly. This intermediary between the developer-generated ROQL and the SQL that accesses the database itself means that the code developers can write is limited to what is available in ROQL, This provides some degree of data insulation and protection for data integrity. The intermediate step of the API translation also makes it possible to make changes to the underlying database without necessarily affecting the client that uses ROQL. In many cases, the API can absorb these changes, taking the same ROQL call and transforming it to match the new database schema. This also helps ensure backward compatibility, so ROQL queries written for earlier releases will still operate correctly in later releases. ROQL also uses the Connect Common Object Model, and like the CCOM, it will be used throughout the RightNow Connect APIs so a developer can learn ROQL once and then use it with all RightNow languages and APIs.
Beginning with the November, 2011, release, ROQL supports the GROUP BY, HAVING, and ORDER BY (ASC/DESC) clauses, so the following query SELECT Organization.Name, COUNT(Contacts.ID) FROM Organization GROUP BY Organization.Name HAVING COUNT(Contacts.ID)>=1 ORDER BY COUNT(Contacts.ID) DESC
returns all organizations that have at least one contact, grouped by the organization name so there is only one line for each organization, and listed in descending order by number of contacts. Continued on next page
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
33
Continued
Operators that can be used in ROQL are similar to those in SQL. The equals, not equals, IN/NOT IN, BETWEEN and greater/lesser than operators can be used with numeric or alphabetic characters. Unlike SQL, the equals operator is case-sensitive. However, this may change in later releases. The LIKE operator performs a match comparison with a string using wildcards. The two wildcards available are _ (underscore) for a single character and % (percent) for zero or more characters. The string containing the wildcards must be in single quotes. LIKE matches in ROQL are case insensitive. The LIKE operator cannot be used with LOB (Large Object) fields such as BLOBs and CLOBs. IS NULL and IS NOT NULL are also available.
LIKE is case-insensitive, but = (equals) is case-sensitive. So, if the database holds an object with the last name of "Bell" , these comparisons return 1 for true: WHERE Contact.Name.Last = 'Bell' WHERE Contact.Name.Last LIKE 'bell' WHERE Contact.Name.Last LIKE 'BELL'
and this returns 0 for false: WHERE Contact.Name.Last = 'BELL'
Beginning with the November, 2011, release, Oracle RightNow CX supports the string functions UPPER and LOWER. Like all functions in ROQL, these cannot be used against a field value in the WHERE clause.
The logical operators AND, OR, and NOT are supported.
Continued on next page
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
34
Continued
Aggregate functions are available in tabular (CSV) queries only. Prior to November, 2011, Oracle RightNow CX included only three functions: COUNT and MAX/MIN. In the November, 2011, release, three more aggregate functions were added: SUM, AVG, and STDDEV for standard deviation.
DateTime values use ISO 8601 format: YYYY-MM-DD Thh:mm:ss The T character separates the date from the time. The time value can be followed by a Z to indicate UTC, or by a plus or minus sign and the number of hours the local time zone is earlier or later than UTC. The entire value is single-quoted. '2011-08-28T13:10:00-05:00' '2011-08-28T18:10:00Z' '2010-01-01T00:00:00Z'
1:30pm EST 8-28-11 same as above, UTC midnight, Jan 1, 2010,UTC
ROQL makes four functions available to work with DateTime objects: sysdate() o Current date and time date_ add(date, units, interval, round) o Adds units number of intervals to date o Possible interval values: seconds, minutes, hours, days, months, weeks, years o round is Boolean date_diff(dateA, dateB) o Returns seconds date_trunc(date, interval) o date to nearest interval •
•
•
•
In ROQL, as in SQL, an alias placed after the name of an object in the FROM clause can be used in the SELECT and/or WHERE clauses to shorten the dot notation, purely for convenience. SELECT Contact FROM Contact C WHERE C.Address.City='Singapore' SELECT C.ID FROM Contact C WHERE Contact.Address.City= 'Rome'
Continued on next page
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
35
Continued
When custom objects are used in ROQL, the object name in the FROM clause is scoped by the package name with a dot. SELECT ID FROM CO.prodreg
Custom fields in ROQL are accessed by name, not ID. The field name must be prefixed by CustomFields.c. Although technically custom fields are sub-objects in the CCOM, they are treated as scalars in queries. SELECT CustomFields.c.age, Name.Last FROM Contact WHERE CustomFields.c.age IS NOT NULL
In certain situations, it may be preferable to instantiate a RightNowSyncPortClient only as needed, rather than in a class constructor. This might be the case if, for example, the code included conditional logic so that a client might or might not ever be used in a particular execution. However, in these situations, it is also important to avoid having a client instantiated multiple times when the section of code that needs the client is executed multiple times. This method, which instantiates a client only if it has n ot already been instantiated, can be called as needed instead of having the client created automatically in the constructor. RightNowSyncPortClient GetClient() { if (_client == null) { _client = new RightNowSyncPortClient ClientCredentials = { UserName = { UserName = "cxadmin", Password = "cxadmin" } } }; } return _client; }
{
Continued on next page
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
36
Continued
You have been assigned to work on the Smartech data integration project writing ROQL commands to select data for integration. This will require using more complex operators and functions.
In this activity, you will write queries with WHERE clauses using operators and functions. All Organizations whose name includes the word "Pharmaceuticals" sorted by name The total number of organizations in the database All the subjects of all Incidents created in 2010 If you get an error here, read the error message carefully. To fix it, edit app.config to increase the values in maxReceivedMessageSize and maxBufferSize The IDs of the 'prodreg' custom objects created during March, 2010 •
• •
•
•
ROQL does not support regular SQL-type joins, but it p rovides something similar using pre-defined relationships that allow you to link objects either as: Parent to Child: a primary key value in the parent table will link to one or more child rows. Child to Parent: a foreign key in the child will link to exactly one primary key in the parent. •
•
SELECT .. Object> SELECT . FROM
The ROQL documentation contains a list of all relationships that have been defined for primary objects. These are the only joins that can be made for primary objects.
Relationship Queries can be used to return fields from a CSV query, or objects from an object query, or functions with a CSV query: SELECT Contact.PrimaryContactIncidents.ID FROM Contact SELECT Contact.PrimaryContactIncidents . . . SELECT count(Contact.PrimaryContactIncidents.ID) . . .
The relationship "join" is being made in the SELECT clause. Continued on next page
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
37
Continued
Relationship queries can join a parent object to a child object, or a child to a parent. Different relationship names are used for joins that go in different directions between the same two objects.
The documentation provides information on all the joins which can be made in ROQL in any direction between any two objects. In many cases there is more than one possible joining relationship between the same two objects. For example, a Contact can be related to an Incident either as the primary contact for that incident, or as another contact for that incident. It is also possible to join the same object to itself. For example, Answers can be joined to other Answers to which they have been linked via a field from the first Answer. The name of the relationship is designed to b e as descriptive as possible of the connection between the objects it joins.
In some cases, you can navigate between objects which do not have a directly-defined relationship by using a three-way relationship join. For example, the statement below navigates from an Incident to the Organization for that incident, and from there to the Contact for that Organization : SELECT Incident.ParentOrganization.Contacts.Name.Last FROM Incident WHERE ID = 11
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
38
Continued
In a relationship query, ROQL performs a left outer join by default, which means that the rows from the first table in the join (the leftmost table) will be returned if there is a match in the right-hand table. But a left outer join also will return a row if there is no value (NULL) in the right-hand table. That is, it returns all but explicit nonmatches. If you do not want to return rows that match to NULL, then add a check for IS NOT NULL to the WHERE clause in the right-hand table. SELECT Contact.PrimaryContactIncidents.CreatedTime FROM Contact WHERE ID = 99 AND Contact.PrimaryContactIncidents.CreatedTime IS NOT NULL
SELECT I.Category, C.ID, C.Name.Last, C.Name.First, C.Address.City, C.Address.StateOrProvince.Name FROM Incident I, Incident.ParentOrganization.Contacts C WHERE Incident.ID = 11
Starting with the November, 2011, release, you can put a relationship string in the FROM clause, comma-separated from the primary object. An al ias for the relationship string can then be used in the SELECT clause to save typing and make the query easier to read. A left outer join will be performed, but can be restricted as explained earlier.
You need to retrieve data stored in more than one primary object.
In this activity, you will write appropriate ROQL relationship queries. The time when all incidents were created for the Contact whose Contact ID is 99. The last name of the primary contact for incident 812. •
•
Continued on next page
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
39
Continued
The LIMIT keyword is followed by a number that limits the number of rows returned by a SELECT query. SELECT Contact.Name.First FROM Contact LIMIT 100
The number after the keyword OFFSET tells how many records from the record set generated on the server will be skipped before records are returned to the client. LIMIT can be used without OFFSET, but OFFSET cannot be used without LIMIT. SELECT Contact.Name.First FROM Contact LIMIT 100 OFFSET 20
If the offset value is greater than the total number of records that meet the select criteria, no records will be returned, and no exception or error message will be generated.
Paging is an object that is returned with each QueryObjects query to indicate if more results were generated than were returned. This would happen if a LIMIT had been set that was lower than the results generated, or if the results generated were greater than the 10,000 maximum limit. while . . . { . . . "SELECT … FROM … WHERE … LIMIT … OFFSET " + offset; . . . if (queryObjects[0].Paging.ReturnedCount > 0) { offset += queryObjects[0].Paging.ReturnedCount; } }
Paging can be used in a loop with OFFSET to obtain any addition results that were not returned in the previous iteration. Continued on next page
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
40
Continued
You need to return and display results in groups of 3, instead of all at once.
In this activity, you will modify existing code in ControllingOutput_Starter so that it prints out results in groups of three.
If you have multiple database queries, you can make your code more efficient by combining them into a single call. This requires only one network round tr ip and one database connection to return results from all the queries at once. To combine queries, put multiple SELECT statements into the same string, separating them with semicolons. The queries must all be of the same type, either object queries or CSV queries. SELECT Contact FROM Contact WHERE Contact.Address.City= 'Singapore' ; SELECT SalesProduct FROM SalesProduct WHERE . . .
There is a limit of 100 ROQL statements per request, and an overall limit of 10,000 rows returned from all statements combined.
When you execute multiple SELECT statements in the same QueryObjects call, the results are returned into separate elements of the array of QueryResultData. The output from the first SELECT statement, which will be an array of RNObjects, will be put into the first element of the QueryResultData array. The output from the other SELECT statements will then go into the next elements of the array, in order. QueryObjects operates polymorphically. It can return data of any sub-type of RNObject – Contacts, Answers, etc. Therefore, the return data is of the par ent type, RNObject, and the developer must cast each object back to the correct sub-type. Multiple statements in a QueryCSV method require no special handling, since they are all of type string, but the result of each individual query will be placed into a separate table in the array of type CSVTable. Continued on next page
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
41
Continued
QueryResultData[] queryObjects= _client.QueryObjects( clientInfoHeader, "SELECT Contact FROM Contact WHERE Contact.Address.City= 'Singapore' ; SELECT SalesProduct FROM SalesProduct", objectTemplates, 10000); RNObject[] rnContactObjects = queryObjects[0].RNObjectsResult; foreach (RNObject obj in rnContactObjects)
{ Contact cont = (Contact)obj; System.Console.WriteLine(" "+cont.Name.First); } RNObject[] rnSalesProductObjects = queryObjects[1].RNObjectsResult; foreach (RNObject obj in rnSalesProductObjects) { SalesProduct sp = (SalesProduct)obj; System.Console.WriteLine(" " + sp.Name); }
CSVTableSet tableSet = _client.QueryCSV(clientInfoHeader, "SELECT C.Name.First FROM Contact C WHERE C.Address.City = 'Singapore'; SELECT SalesProduct.Name FROM SalesProduct", 10000,",",false,false,out output); CSVTable[] tables = tableSet.CSVTables; foreach (CSVTable t in tables) { Console.WriteLine(Environment.NewLine + t.Name+":"); String[] rows = t.Rows; foreach (String data in rows) { System.Console.WriteLine(" " + data); } }
Continued on next page
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
42
Continued
Occasionally the server may blacklist queries which ar e running too slowly or whose syntax suggests they will run slowly. In addition, if a query runs too slowly on first execution, the server may allow it to run the first time, but blacklist it for subsequent executions. Blacklisted queries will return a message in the thrown exception, such as: Poor performing query – aborting Poor performing query – blocked Poor performing query – too many rows examined Poor performing query – too much time taken • • • •
In general, blacklisted queries must be re-written.
You have written an application that uses a ROQL query. For better performance and to reduce bandwidth needs, you want to re-write it to use multiple queries.
In this activity, you will use multiple queries to re-write a query in existing code in MultipleQueries_Starter.
Continued on next page
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
43
Continued
Special queries can be used to get contextual information about the current instance of CX. The available queries are: curLanguage() curLanguageName () curInterface() curInterfaceName () curAdminUser() curAdminUserName () • • • • • •
In each of the pairs above, the first query returns an ID number, and the second returns the string name associated with that ID. The example below shows using QueryCSV to find the name of the current language/culture of the interface. Notice that the query specifies that a maximum of one row will be returned. Also notice that parentheses must be used after the function name. CSVTableSet tableSet = Program._client.QueryCSV (clientInfoHeader, "SELECT curLanguageName()", 1); Console.WriteLine("Current language/culture setting is " + tableSet.CSVTables[0].Rows[0]);
The SiteInterface object is a special object which holds information about the current interface, similar to that provided by special queries as explained above. SiteInterface siTemplate = new SiteInterface(); siTemplate.Language = new NamedID(); RNObject[] objectTemplates = new RNObject[] { siTemplate }; string query = "SELECT SiteInterface FROM SiteInterface"; QueryResultData[] queryObjects = _client.QueryObjects( clientInfoHeader, query, objectTemplates, 1); RNObject [] rnObjects = queryObjects[0].RNObjectsResult; foreach (RNObject obj in rnObjects) { SiteInterface si = (SiteInterface)obj; Console.WriteLine("Site: "+si.ID.id+" " + si.Name); Console.WriteLine("Site Display Name:" + si.DisplayName); Console.WriteLine("Site Language/culture: " + si.Language.Name); }
Continued on next page
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
44
Continued
What are the advantages of using RightNow Connect?
What is the purpose of the RightNow Connect Common Object Model?
What is a primary object? A sub-object?
What is a ClientInfoHeader?
How can you get around blacklisting?
Continued on next page
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
45
Continued
What is the difference between Object Queries and CSV Queries?
(continued)
What are some of the ways in which ROQL differs from SQL?
What is a relationship query?
How do you iterate through result sets when mor e results are generated by a query than are returned to the client? (How do you know there are more?)
A new government regulation will require that specific wording be added to certain answers in the Smartech knowledgebase related to credit cards. Subject matter experts need to review all Answers to determine which of Answers need to include the new wording, so you have been asked to provide a text list of all Answers (Summary, Question, and Solution) in which the Summary includes the word "credit card". You have further volunteered to provide an HTML list of the same information so the end-users (the subject matter experts) can see the formatting of the Solution.
Write an Object query to retrieve all answers with "credit card" in the summary and write the results to both a regular text file and an HTML file.
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
46
Connect Web Services provides methods for the four basic CRUD operations: Create Read Update Delete • • • •
These operations can be combined so that multiple operations can be sent to the server for execution in a single call: Bulk : Applies the same operation to objects of different types. Batch: Sends mixed operations to be executed sequentially. Chain: Passes the output from one operation as input to a subsequent operation. • • •
There are also special operations, such as r unning a report, that can be executed by a call to a SOAP web service.
RNObject[] = _client.Create (ClientInfoHeader, RNObject[], CreateProcessingOptions);
To create a new object, you will call the ROQL Create method from a RightNowSyncPortClient, passing it three arguments: A ClientInfoHeader. An array of the parent type, RNObject, that contains instances of any child types to be created. Create operates polymorphically on any ob ject type. An instance of the CreateProcessingOptions class with Boolean properties for the following: o SuppressExternalEvents: Indicates whether external events should be fired when the object(s) are created. An external event is code that runs when fired by an event or a business rule.. o SuppressRules: Specifies whether business rules associated with the object should be applied when it is created. • •
•
The return value from the Create operation is an array of IDs of newly-created objects. As in ROQL, these are IDs of the parent type, RNObject, but can be cast to the sub-types if needed. Continued on next page
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
47
Continued
PersonName name = new PersonName(); name.First ="Dan"; name.Last = "Mains"; Email email = new Email(); email.action = ActionEnum.add; email.actionSpecified = true; email.Address = "[email protected]"; email.AddressType = new NamedID(); email.AddressType.ID = new ID(); email.AddressType.ID.id =0; email.AddressType.ID.idSpecified = true; email.Invalid = false; email.InvalidSpecified = true; Email[] emails = new Email[]; emails[0] = email;
The documentation indicates which values are required for any C RUD operation. For example, a new Contact can be instantiated without initializing any of its fields, or some/all of the fields can be initialized with values, but a contact's ID is required on Update or Destroy. However, normally before creating a new Contact, you will populate many of the fields, and instantiate and initialize many of the sub-objects which the Contact will have. The sample code above instantiates a new PersonName type and set its First and Last fields. An email address in a Contact is kept in the Emails field which is an array of Email objects. In the code above, Emails is instantiated and initialized with a single Email object. That Email is itself instantiated and initialized with values including an action to be performed, in this case adding the email, and a Boolean to say whether or not an action has been specified. Finally, you must create an array of emails and assign this email to that array. In the code above, there are also values for Address and AddressType, which itself is a NamedID so it must be instantiated before it can be initialized with an ID value. Then set a property to indicate that the ID has been specified and assign a value stating the email is still valid (not invalid) and that a value has been specified. Continued on next page
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
48
Continued
The CRUD operations on List data types are handled separately from the containing object. When an object is updated, for example, an individual list item might be added, deleted, or updated. To indicate the action to take, an action attribute is set to a value from the ActionEnum enumeration (Add/Update/Remove/None), and then actionSpecified is set to true, to show that it has been set. email.action = ActionEnum.add; email.actionSpecified = true;
In most cases, you will need to provide an object ID to an operation. This is not true on create operations, because the server assigns those IDs. An ID object has a Boolean property for idSpecified . If you are specifying an id, you will also have to set the idSpecified property to true. If you fail to do that, you may get an error message that refers to a very large negative integer value as the ID. An error message like t hat should suggest to you to check that you have set idSpecified to true. There are only a handful of situations in which idSpecified is set to false. Those will be covered later in this this material .
Contact contact = new Contact(); contact.Name = name; contact.Emails = emails;
This code instantiates a new contact and sets Name and Emails properties to the name and email array objects created earlier under the section "Creating Sub-Objects for a New Object". Continued on next page
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
49
Continued
Contact[] contacts = new Contact[1]; contacts[0] = contact; CreateProcessingOptions po = new CreateProcessingOptions(); po.SuppressExternalEvents = true; po.SuppressRules = true;
This code instantiates an array of contacts and a CreateProcessingOptio CreateProcessingOptions ns object with properties that determine determine whether or not rules rules and external events will be suppressed. Choosing whether or not to run rules and external events is an individual decision made based on what rrules ules and external events have been set up on a specific installation and whether it is desirable to run them when a new object is created in code in this particular application. By default, duplicate emails are not p ermitted, so an attempt to create a new object with a specified email address that already exists in the database will throw an exception: Cannot save/create: Contact: (null) While performing create on Contact
RNObject[] returnValues = _client.Create(clientInfoHeader, contacts, po); contact = (Contact) returnValues[0]; Console.WriteLine (contact.ID.id);
This part of the code calls the Create method, passing in three arguments: the clientInfoHeader, the array of objects to create, and the processing options. The call returns an array of IDs of the new RNObjects. In this case, only one object was in the array to be created, so only one object is returned, and it is the first object in the array. What was created was a Contact object, object, but since the call returns an array of the parent type, RNObject, it must be cast back to a Contact before accessing its properties. The only properties returned are the unique ID assigned by the CX server, along with (read-only) created and updated times. Continued on next page
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
50
Continued
Contact contact = new Contact { Name = new PersonName {First="Dan", Last="Mains"}, Emails = new Email[] { new Email { action = ActionEnum.add, actionSpecified = true, Address = "[email protected]", AddressType = new NamedID { ID = new ID {id=0,idSpecified=true} }, Invalid = false, InvalidSpecified=true } } };
The code above has the same effect as the earlier code example, but is more compact. It instantiates a new contact, and initializes it at the same time with a value for name and email.
RNObject[] returnValues = _client.Create( new ClientInfoHeader { AppID = "DTM" }, new RNObject[] { contact }, new CreateProcessingOptions { SuppressExternalEvents = true, SuppressRules = true } ); contact = (Contact) returnValues[0]; Console.WriteLine (contact.ID.id);
This example of calling the Create method embeds instantiation of the ClientInfoHeader, the array of RNObjects, and CreateProcessingOptions to create shorter and more compact code.
You need to be able to add new contacts to the database in code, rather than by hand. Continued on next page
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
51
Continued
In this activity, you will create a new Contact with attributes of your choice. Open the Agent Desktop and use it to verify that your new object exists.
RNObject[] rnObjects = _client.Get(cIH, objects, options);
The Get operation implements the CRUD Read functionality. To get an object, its ID must be supplied, so an array of RNObject types with IDs set is passed to the Get method, and results are returned to another array of RNObject, just as in the C reate operation. By default, only top-level objects are returned. If y ou need data from sub-objects, request it by instantiating empty sub-object(s) and attaching them to the object(s) in the array being sent to the Get method. This behavior is referred to in the documentation as "specify-to-get". Continued on next page
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
52
Continued
Contact contact = new Contact(); ID contactID = new ID(); contactID.id = 1; contactID.idSpecified = true; contact.ID = contactID; Note[] notes = new Note[1]; contact.Notes = notes; RNObject[] objects = new RNObject[] { contact }; GetProcessingOptions options = new GetProcessingOptions(); options.FetchAllNames = false; try { ClientInfoHeader cIH = new ClientInfoHeader(); clientInfoHeader.AppID = "Basic Get"; RNObject[] rnObjects = _client.Get(cIH, objects, options); contact = (Contact)rnObjects[0]; Console.WriteLine("Contact First Name: " + contact.Name.First +" Last Name: " + contact.Name.Last); if (contact.Notes != null) { foreach (Note note in contact.Notes) { Console.WriteLine("Note: " + note.Text); } } }
Notes is an array of type Note, a text object that holds extended comments. GetProcessingOptions, unlike CreateProcessingOptions, has a s ingle field, FetchAllNames, which, if set to true, would fetch the names of all NamedID types. If set to false, only the long integer IDs are returned, making the query more efficient. Continued on next page
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
53
Continued
A colleague has asked you to help him debug his Windows application, which uses a Get operation. It is not printing out a ll values.
In this activity, you will debug existing code in GettingAnObject_Starter that uses a Get operation. Uncomment lines so that the full address should print out, determine why that is not happening, and fix it. Since not all records in the demonstration database have full addresses, check with your instructor or use your Agent Desktop to find which records can be used for testing.
To update an object: Obtain the ID(s) of the object(s) to be updated Copy ID(s) to a new instance of the object type. On the copy, set a value for any fields to be updated. Send new object(s) back to server, which w ill update only the fields you have populated. • • • •
Certain fields that are not visible on update and attempting to set them will cause the update to fail. See documentation for details. Continued on next page
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
54
Continued
Before this code is executed, you must have the ID of the object to be updated, u pdated, in this case an Organization. You might obtain the ID through a ROQL query or a Get operation. That ID will be set s et into a new instance of the Organization type, as in line four of the code snippet below (in place of ), ), and then any fields that are to be updated must be set with their new values. In the code below, we are setting only the Login field, so that is the only field that will be changed on the database. Organization organization = new Organization(); ID orgID = new ID(); // this is the ID of the object to be changed orgID.id = ; orgID.idSpecified = true; organization.ID = orgID; organization.Login = "RNOW"; RNObject[] objects = new RNObject[] { organization}; UpdateProcessingOptions options = new UpdateProcessingOptions(); options.SuppressExternalEvents =false; options.SuppressRules=false; try { _client.Update(new ClientInfoHeader {"testing"}, objects, options); Console.WriteLine(objects[0].Login); } catch (Exception e) {. . . }
Notice that the return from the Update operation is not being assigned to a variable, because the return from from an Update operation has no useful data, not even a Boolean Boolean to indicate success or failure. If the operation does not throw an exception, you can assume success. Of course you muse always execute this SOAP method, and all others, within a try .. catch block. Continued on next page
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
55
Continued
contact.Emails = new Email[1]; contact.Emails[0] = new Email(); contact.Emails[0].Address = "[email protected]"; contact.Emails[0].AddressType = new NamedID { ID = new ID { id = 0, idSpecified = true } }; contact.Emails[0].action = ActionEnum.update; contact.Emails[0].actionSpecified = true; contact.Emails[0].Invalid = false; contact.Emails[0].InvalidSpecified = true;
For a list type, such as Emails or Notes, in an object to be updated, instantiate the array that holds the l ist, and instantiate any individual items in it that need to be updated. For each of the fields to be updated, set the required attributes. Check the documentation for attributes required on update for any individual data type. For example, an Email requires an AddressType on update. Set any values that need to be updated, added, or deleted, and use ActionEnum ActionEnum to specify specify which of those actions is to be performed with t he update. For example, it would be possible to update a primary object by deleting one of its emails while changing another and adding a t hird. The CRUD operations on a l ist item are independent of the CRUD operation on its containing type. In this example, Invalid is also specified. Invalid may or may not need to be updated, but it is good practice to set it in case the previous address had been set to invalid. If so, your update could be successful and hold a new email, but the email still would not be available for use because it would be marked invalid. Continued on next page
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
56
Continued
contact.Address = new Address(); contact.Address.StateOrProvince = new NamedID(); contact.Address.StateOrProvince.Name = "TX";
The code above shows how to use NamedID when updating or creating an object. In the example, if you need to set a value for the state in a contact's address. you can set the Name field of the StateOrProvince S tateOrProvince NamedID. The server will then look up the corresponding ID and assign it to the record so the developer doesn't have to know the ID code for the state of Texas. This approach is easier and makes your code more self-documenting, but it does have an impact on performance because an ID is always required by the database itself. That means there will be an a n extra lookup is needed to get the ID from the name. To avoid that performance penalty, you can get name values for a NamedID type by using the GetValuesForNamedID method, shown later in this course, and then use the ID instead of the name.
You need to update a single record that includes NamedIDs and Lists.
In this activity, you will write an ap p to change the email for the new contact you created earlier to another email of y our choice.
There are three ways multiple operations can be combined into a single server request in order to reduce network traffic and improve performance: Bulk operations o Mixed object CRUD capabilities o Create a contact, incident & organization in a single request Batch operations o Mixed operation capabilities o Create, update, and delete a contact in a single request Chaining operations o Output of one operation is input to another operation o Create a new contact and chain the contact id to a new incident, setting the incident contact, in a single request •
•
•
Continued on next page
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
57
Continued
All CRUD operations are polymorphic, so any CRUD operation can accept as input any primary object that is a sub-type of RNObject. In addition, multiple objects of multiple types can be supplied at the sa me time to the same operation. For example, a Contact, an Incident, and an Organization can all be supplied to a single invocation of the create method to create all three at o nce. This is referred to as bulk processing. All items supplied to a CRUD operation are treated as one transaction. Therefore, if any one object in the request cannot be processed, the entire request is rolled back and none of the data is committed. There is a hard limit of 1000 objects that may be supplied in a single CRUD request. However, due to operational constraints, it is possible that supplying the maximum objects may result in an error. The number of items that may safely be sent in a single CRUD operation request will need to be weighed against the object complexity and size of data. In cases where too much data is supplied in a single request the server may fail to complete the transaction and the client will receive an unexpected exception.
The steps required to destroy an object (to delete it from the database) ar e: Create an instance of the primary o bject to destroy. Set its ID property. No other fields need to be set. Call the Destroy method, sending it the instance. • • •
The destroy operation provides no return value. It deletes the primary object and all related sub-objects. In some cases, it may also delete related primary objects. For example, deleting an Organization deletes related Contacts, and deleting a Contact deletes its Incidents. However, if an Account is deleted, then any Incidents that refer to that Account in their AssignedAccount field will have that field set to null, but t he entire Incident will not be deleted. For more information on how and when related objects or fields are c hanged on a delete of another object, see the RightNow documentation. Continued on next page
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
58
Continued
Contact c = new Contact(); c.ID = new ID( id = , idSpecified=true); Organization o = new Organization(); o.ID = new ID(id = , idspecified=true); RNObject[] objects = new RNObject[2]; objects[0] = c; objects[1] = o; DestroyProcessingOptions options = new DestroyProcessingOptions(); options.SuppressExternalEvents = true; options.SuppressRules = true; try { _client.Destroy(cIH, objects, options); }
The code above destroys two different types of objects in a single call.
Your company, Smart Technologies, uses an application that creates two objects. As currently written, the application makes two separate calls to the database: one to create a Contact and one to create an Organization. You have been asked to improve the performance of t he app, and reduce the network traffic it generates, by combining the two calls into one bulk call.
In this activity, you will modify CreatingObjectsInBulk_Starter to perform both Create operations in bulk together.
Continued on next page
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
59
Continued
Batching refers to including multiple operations of different CRUD types in a single call. One call, for example, could include a Get, a Create, and an Update. Transactional boundaries can be set within batched operations. All items in the transaction will fail if any one item fails, and no more items in that transaction will be processed, but items in any subsequent transactions may still be processed, if the failure was not a fatal error. There is a maximum of 1000 BatchRequestItem objects permitted per call, and 100 transactions. However, each BatchRequestItem can be bulk. Though the limit for bulk is 1000 and the limit for batch is 1000, there is still a hard limit overall of 10,000, so you cannot use the maximum for both at the same time.
Transactional boundaries within batched operations by using a CommitAfter attribute, as explained later in this material. If a Get operatin within a transaction fails, any items already executed in that transaction will be rolled back, and other items in that transaction not be attempted, but subsequent transactions will still be attempted. In other words, a failed Get operation is not considered a fatal error. For operations other than Get, however, a failure ends all execution. Previous items in that transaction are rolled back, and no other items in that transaction or any other transaction will be attempted. In other words, the failure of an operation other than a Get operation is considered a fatal error.
The steps required to implement batch processing are: Create as many BatchRequestItems as necessary. o Each item will hold a Message type appropriate for the CRUD operation, such as a CreateMsg or a GetMsg o Each Message will hold An array of RNObjects of the appropriate type An instance of ProcessingOptions Populate an array with the items. Set any transaction boundaries in the array as desired. Send the request to process array to server. Process returned items according to the BatchResonseItem type for each one Handle errors, if any, in the results returned. •
• • • •
•
Continued on next page
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
60
Continued
The code below is a method to create and return a BatchRequestItem. Each BatchRequestItem refers to a specific type of operation on a specific type of object. In this case, the Get operation on an Incident item is specified by using a GetMsg. There are also Msg objects for other operations, such as CreateMsg. GetMsg is the message that will be sent to the server, and it has as attributes the same elements that would be in a regular non-batched call to the Get operation: an array of RNObjects and an object to hold processing options. It does not need a ClientInfoHeader because it runs using the ClientInfoHeader of the complete batch operation. When the GetMsg has been initialized with options and an array of objects, it is assigned to the Item property of the BatchRequestItem. public BatchRequestItem GetIncident(long id_in ) { BatchRequestItem getItem = new BatchRequestItem(); GetMsg getMsg = new GetMsg(); GetProcessingOptions getOptions = new GetProcessingOptions(); getOptions.FetchAllNames = false; getMsg.ProcessingOptions = getOptions; Incident incident = new Incident{ new ID {id=id_in, idSpecified=true } }; getMsg.RNObjects = new RNObject[] { incident }; getItem.Item = getMsg; return getItem; } . . .
Continued on next page
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
61
Continued
BatchRequestItem[] requestItems = new BatchRequestItem[5]; requestItems[0] = p.GetIncident(5); requestItems[1] = p.CreateContact("Sam"); requestItems[2] = p.GetIncident(3);
requestItems[2].CommitAfter = true; requestItems[2].CommitAfterSpecified = true; requestItems[3] = p.CreateContact("Dave"); requestItems[4] = p.GetIncident(7); . . .
After creating as many BatchRequestItems as needed, put them into an array of BatchRequestItems. If you want to divide your batch into transactions, you can set an attribute called CommitAfter on elements in the array. A commit after attribute marks the end of a transaction. When setting CommitAfter, CommitAfterSpecified must also be set to true. There is also an implicit CommitAfter at the end of the array. The array in this example shows mixed operation types, which is typical of batching. Continued on next page
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
62
Continued
To send the array of BatchRequestItem for processing, call the Batch operation and provide a ClientInfoHeader and the array that holds the items. Set processing options are not needed in this call, because they a re set on each individual request item. The return value is an array of BatchResponseItems. They are generic so each will need to be cast back to the original type as shown in the code below. The sample shows GetResponseMsg, which corresponds to the response obtained from a GetMsg request. Extract the actual object from the response and obtain its ID or data type. On a Get operation, you can cast the object back to its typ e in order to obtain other attribute values. On a Create operation, only the I D will be populated and available to you in the response message. Nothing useful is returned in Destroy or Update responses. BatchResponseItem[] batchRes = _client.Batch(clientInfoHeader, requestItems); foreach (BatchResponseItem resp in batchRes) { if (resp.Item is GetResponseMsg) { GetResponseMsg getResp = (GetResponseMsg)resp.Item; //casting to response type RNObject[] getObjects = GetResp.RNObjectsResult; foreach (RNObject o in getObjects) { Console.WriteLine("Retrieved: " + o.ID.id); Console.WriteLine("of type " + o.GetType()); } }
. . .
// process other response types
Continued on next page
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
63
Continued
if (resp.Item is RequestErrorFaultType) { RequestErrorFaultType fault = (RequestErrorFaultType)resp.Item; Console.WriteLine("Fault message: " + fault.exceptionMessage); }
As part of handling responses, you should include a check to see if the response item is of type RequestErrorFaultType. A RequestErrorFault is returned by the server when there is a validation failure or a data-related error in the request. There are two other fault types: Ser verErrorFaultType and UnexpectedErrorFaultType. Both of these are relatively rare. You could include checks for them, or simply allow them to be caught by a catch statement. A list of all the possible exception messages which the fault provides is available in the documentation. Continued on next page
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
64
Continued
ROQL CSV queries can be included in a batch. ROQL has its own message type, QueryMsg, and its own response type, QueryCSVResponseMsg. BatchRequestItem csvItm = new BatchRequestItem(); QueryMsg qMsg = new QueryMsg { Query = "SELECT . . . FROM . . . WHERE . . .", PageSize = 10000, PageSizeSpecified = true }; csvItm.Item = qMsg; ClientInfoHeader ciH = new ClientInfoHeader(); cIH.AppID = ". . ."; BatchRequestItem[] reqIts=new BatchRequestItem[1]; reqIts[0] = csvItm; BatchResponseItem[] batchRes = _client.Batch(cIH, reqIts); foreach (BatchResponseItem r in batchRes) { if (r.Item is QueryCSVResponseMsg) { QueryCSVResponseMsg rM=(QueryCSVResponseMsg)r.Item; foreach (string s in rM.CSVTableSet.CSVTables[0].Rows) { // process returned data in string s } } if (r.Item is RequestErrorFaultType) { . . . } . . . }
Continued on next page
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
65
Continued
•
• • •
•
Create Batch Request Items o Include usual operation parameters, except for the ClientInformationHeader Populate array with items Set transaction boundaries in array Send request to process array to server o Includes ClientInformationHeader Iterate through results and process o Check each BatchResponseItem type and process accordingly o Provide fault handling
Smartech has an existing application that uses batching to Get Incidents and Create Contacts. It processes each item individually. You have been assigned to add to that app the ability to delete Contacts.
In this activity, you will modify the existing application Batch_Starter appropriately by adding a method that returns a BatchRequestItem for destroying items.
Continued on next page
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
66
Continued
Using a single request to create a new Contact, then a new Incident related to the Contact can be problematic. Creating a new Incident requires a Primary Contact object, but the ID of the new Contact is not available until both operations have completed and the server call returns. Chaining solves this problem by passing the output of one operation as input to the next operation. Chaining is only supported on CRUD operations, and as of the November, 2011, release, cannot span transaction boundaries.
To implement chaining, you must: Instantiate a ChainSourceID. Set its variableName attribute. Instantiate a ChainDestinationID. Set its variableName attribute to the same value as the ChainSourceID. • • • •
All primary and foreign key fields are of type ID. To chain the ID of a newly created object, a specialized ChainSourceID (derived from ID) is passed to the create request. It defines a variableName attribute which is used as a unique variable name to bind that newly created ID value to that variable name for the scope of the SOAP request. This object will function somewhat like a server-side variable. For any subsequent objects that need access to the newly-created ID, instantiate a ChainDestinationID, set the variableName attribute to the same name, and assign that object to the ID field. The public SOAP service will handle placing the value that is assigned to the ID into any ChainSourceIDs and ChainDestinationIDs as needed. Since the service will not handle forward references, provide the source ID before assigning the destination ID. Continued on next page
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
67
Continued
_chainContactID = new ChainSourceID(); _chainContactID.idSpecified = false; _chainContactID.variableName = "SharedID"; newContact.ID = _chainContactID; . . . IncidentContact primaryContact = new IncidentContact(); NamedID primContactNamedID = new NamedID(); ChainDestinationID chainDestID = new ChainDestinationID(); chainDestID.idSpecified = false; chainDestID.variableName = _chainContactID.variableName; primContactNamedID.ID = chainDestID; primaryContact.Contact = primContactNamedID; newIncident.PrimaryContact = primaryContact;
Prior to the start of this code snippet, a Contact object named newContact was instantiated. Now a static class variable of ChainSourceID type (_chainContactID) can be assigned to its ID property. You must indicate that the ID of the ChainSourceID has not been specified (line 8 above), then give it a string label such as "SharedID". An Incident must have a primary contact. In this case, the Incident's PrimaryContact field has a ChainDestinationID type in the contact’s NamedID.ID field. Set idSpecified to false, and assign to the DestinationID's variableName property the variable name or the string literal from the _chainContactID which will receive its value when the Contact is instantiated. After the connection between the two objects has been set up in this way, the objects can be created one after the other in a batch or bulk operation and the ID assigned to the one will automatically be provided to the other. Continued on next page
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
68
Continued
Beginning with the November, 2011, release, chaining can be used between ROQL queries that are being processed in batch. For example, one query can be used to retrieve an object's ID, based on some other known property of the object. Then a subsequent query in the same batch can use that ID to retrieve data from other related objects. The mechanism for this differs from the mechanism used in other CRUD operations explained earlier. First query: SELECT ID as '@ContactID' FROM Contact WHERE Login = 'badams'
Second query: SELECT . . . FROM Contact WHERE ID = @ContactID
The chain source is a variable of your choice, preceded by the @ symbol and enclosed in single quotes. In the SELECT clause of the first query, the value to be assigned to the chain source is followed by as and then by the variable. The value being assigned to the chain source must be numeric. In the next ROQL query, the variable na me, with the @ but without the single quotes, can be used like a number, as in the example above.
You have been assigned to debug an application that uses batching to create a new Contact and a new Incident for which the new Contact is the primary contact. When you run the existing app, you realize that the Incident was not created because it did not have a primary contact ID. You decide that chaining is what is needed here.
In this activity, you will re-write Chaining_Starter to use chaining.
Continued on next page
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
69
Continued
New custom fields cannot be created in code. Instead, an administrator must use the Agent Desktop tool to configure the database to add a column to a table to hold the new field, as you saw in an earlier exercise. However, custom fields, once created, can be accessed in code to update their values or to set their initial value when you are instantiating a new object in code.
Your enterprise needs to have the Social Security Number of each Contact available to agents. Since this isn't part of the standard RNT Contact, you must add a custom field for it to the Contact object. Then you must create a report that will display the name and SSN of each contact. Finally, you need an application that will allow you to add a social security number to a contact that doesn't have one, using the Update() operation.
In this exercise, you will modify code in CreateObjectsWithMultipleCustomFields_Demo to handle various data types in custom fields. Additional instructions are available in the project folder.
Custom Objects cannot be defined in code. They are defined in the Agent Desktop using Object Designer. However, Custom Objects can be instantiated, updated, or destroyed in code. • •
•
Create an instance of the GenericObject type. Set the ObjectType property of the Generic Object to the Namespace (package) + TypeName (name) of the Custom Object. Set the GenericFields property of the Generic Object to an array of type GenericField.
Standard code is available to create GenericFields Continued on next page
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
70
Continued
GenericObject go = new GenericObject(); RNObjectType objType = new RNObjectType { Namespace = "Classes", TypeName = "TrainingClass" }; go.ObjectType = objType; GenericField[] gfs = new GenericField[] { CreateGenericField("ClassNumber", ItemsChoiceType.IntegerValue, 2), CreateGenericField("ClassName", ItemsChoiceType.StringValue, "Advanced Smartech") }; go.GenericFields = gfs; try { RNObject[] results = _client.Create( _clientInfoHeader, new RNObject[] { go }, createProcessingOptions ); } catch { . . .
Continued on next page
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
71
Continued
private GenericField CreateGenericField(string Name, ItemsChoiceType itemsChoiceType, object Value) { GenericField gf = new GenericField(); gf.name = Name; gf.DataValue = new DataValue(); gf.DataValue.ItemsElementName = new ItemsChoiceType[] { itemsChoiceType }; gf.DataValue.Items = new object[] { Value }; return gf; }
To create a new instance of an existing Custom Object, start by instantiating a GenericObject which will hold the custom object data. Provide the namespace, w hich is the same as the package or folder in the Object Designer. Set up an array with an element for each field in the custom object. The CreateGenericField method shown above handles creating the fields. It is user written, not part of the .NET or RightNow frameworks. Assign the array of generic fields to the generic object, and finally, call the Create method. The CreateGenericField method is standardized code so it can be copied as is into applications. The method takes three arguments: the name of the new field, its data type, and its value. Each argument is placed in matching attributes of the generic field object. Note that the data value attribute can hold an array of objects.
Earlier you used the Agent Desktop to create a Custom Object named "TrainingClass". Now you will manipulate that Custom Object in code.
In this activity, you will write an ap plication to instantiate and populate an instance of TrainingClass, and then to retrieve and display the data from the object just created.
Connect Web Services also includes operations to handle operations that are not basic CRUD functions: Running an Analytics Report Getting values for a NamedID type • •
Continued on next page
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
72
Continued
In order to run an analytics report in code, create an Analytics Report object, and set the report id or name, then, optionally, attach an AnalyticsReportFilter. Limit and Start are the third and fourth arguments to the operation, and they show, respectively, how many rows to return and which row to start from. The last four arguments are the same as those for QueryCSV. CSVTableSet set = _client.RunAnalyticsReport(ClientInfoHeader, ReportObject, 10000, 0, ",", false, false, out output);
AnalyticsReport analyticsReport = new AnalyticsReport(); int limit = 100; int start = 0; ID reportID = new ID(); reportID.id = 13029; reportID.idSpecified=true; analyticsReport.ID = reportID; AnalyticsReportFilter filter = new AnalyticsReportFilter(); filter.Name = "Opportunity Id"; analyticsReport.Filters = new AnalyticsReportFilter[] { filter }; ClientInfoHeader cIH = new ClientInfoHeader { AppID ="My_Rpt"}; Byte[] output = null/ CSVTableSet set = new CSVTableSet(); set=_client.RunAnalyticsReport(cIH, analyticsReport, limit, start,",", false, false, out output); String[] rows = set.CSVTables[0].Rows; foreach (string data in rows) { Console.WriteLine(data); }
The call to RunAnalyticsReport returns a CSVTableSet, which is processed like the CSVTableSet that is the return value from a QueryCSV operation. Continued on next page
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
73
Continued
The code above created an empty filter an attached it to the report, to meet syntactic requirements. But there was no operation within the filter, so it had no effect. The code below creates an instance of a filter, then provides the name of that filter (explained below), and a field, operator, and value on which to filter. It then attaches that filter to the collection of filters belonging to that report. Other filters could also be added to the collection. AnalyticsReportFilter filter = new AnalyticsReportFilter(); filter.Name = "Last Name"; NamedID op = new NamedID(); op.ID = new ID(); op.ID.id = 1; op.ID.idSpecified = true; filter.Operator = op; filter.Values = new string [] {"Brown"}; analyticsReport.Filters = new AnalyticsReportFilter[] {filter};
In order to be able to define and apply a filter as shown in the code above, you must know which filters have been defined for a given report. This information is available in the report definition. A report definition can be found through the Reports Explorer from the Analytics buton on the Navigation pane. Several of the standard search reports that are used in the Navigation Pane are available under Public Reports > Common > Views – Common > Search Reports. Double-click a report to access it, then click the Definition button from the ribbon and select V iew. The Filters section of the report definition lists all available for that report, including name and operator. Notice that the report definitionalso provides the report ID which is needed to run the report.
To use an operator in a filter, you will need to provide the ID for the appropriate operator for that filter as specified in the report definition. A list of available filter operators and their IDs can be found in the developer documentation for Web Services. Use the Search function to search for "RunAnalyticsReport" to locate it. Continued on next page
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
74
Continued
The code below will get the names of all Analytics Reports that start with a given letter, along with the names of all columns in that report, to help you l ocate the report you want. string q = "SELECT AnalyticsReport FROM AnalyticsReport WHERE name LIKE '" + first_letters + "%'"; QueryResultData[] queryObjects = _client.QueryObjects(cIH, q, objectTemplates, 10000); foreach (RNObject obj in rnObjects) { AnalyticsReport ar = (AnalyticsReport)obj; Console.WriteLine(ar.Name); AnalyticsReportColumn[] cols = ar.Columns; Console.WriteLine("Columns "); foreach (AnalyticsReportColumn c in cols) { Console.WriteLine(" " + c.Heading); } }
You need to be able to run a report that will show each staff account and profile.
In this activity, you will determine what report you should use, and run it to produce the results required by the scenario.
Continued on next page
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
75
Continued
NamedID[] namedIDs = _client.GetValuesForNamedID ( new ClientInfoHeader { AppID = "NamedIDs" }, null, "Contact.Emails.EmailList.AddressType" ); foreach (NamedID namedID in namedIDs) { Console.WriteLine(namedID.ID.id + "\t" + namedID.Name); }
The NamedID type is used throughout Oracle RightNow CX. The code shown above will retrieve matching pairs of names and IDs for a NamedID type. The second parameter to the method is a package name, which is used if you are getting values for a custom menu. Otherwise it can be null.
There are several other non-CRUD operations available in Connect Web Services. More information on these is available in the on-line d ocumentation. Managing file attachments Resetting a Contact password Sending mailings to Contacts Executing a marketing flow • • • •
You need to be able to run a report that will show each staff account and profile.
In this activity, you will write code to get the IDs and names required.
Continued on next page
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
76
Continued What are the three arguments to CRUD operations methods?
What is the difference between bulk operations and batch operations?
Why would you need to chain operations?
What are some of the non-CRUD operations available in the API?
Subject matter experts at your enterprise have create a text file of FAQs that they want to make available to end users of Customer Portal
Write code to create and populate new Answers for your knowledgebase, based on data read in from the flat text file provided for this exercise.
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
77
Smartech needs to integrate RightNow with another data processing system they have. The data in the other system is made available through a web service that returns groups of new records that need to be loaded into Oracle RightNow CX. Your assignment is to develop the application that will call the service and integrate the data it provides into the RightNow database.
In this activity, you will run a web service on localhost that will simulate the web service provided by the system you are going to integrate with. Write an application that will access that service and retrieve whatever data it provides, which will include one or more Contacts, each of which will have an associated Incident. For each Contact/Incident pair: If the contact does not already exist, create it and add it to the database. Associate the incident with the new or existing contact. Provide error handling. • • •
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
78
Oracle RightNow Desktop Add-Ins Cloud Service (desktop add-ins) are components written by developers that can be used to: Integrate external data into the agent desktop. Automate the desktop. Create application extensions. • • •
Add-in components can be created and placed in many different locations on the Agent Desktop. An add-in can be placed directly onto a workspace, or on various parts of the navigation and control system of the Agent Desktop. For example, the Application Menu can have new buttons, the Status Bar can provide short messages, the Navigation Pane can have new controls, or buttons can be added to the ribbon.
A fellow developer has already created an add-in and it has been compiled. You have been asked to upload it to the site, making it available to a ll users, and to test it after uploading it. Continued on next page
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
79
Continued In this activity, you will upload a n existing compiled add-in DLL to the RightNow server for your site.
1 2
3 4 5 6
From the Agent Desktop, go to Configuration > Site Configuration > Add-In Manager. Click New and browse for MyAddIn.dll (located in the \Starter\Uploading an Add-In\ClassLibrary1\bin\Release folder) and click Open. Click the Profile Access button on the ribbon and select CX All-2 for profile, and All for the interfaces. Click Save & Close. Close and re-open the Agent Desktop. Locate the button in the Home navigation set (or any other navigation set) and click to test that it changes the color of its section.
The Desktop Add-In Framework makes it easier for developers to write add-ins such as custom controls or components which will be compiled into a Dynamic Link Library (DLL). The framework leverages the .NET Add -In Framework, which is in the System.AddIn namespace. It is also designed to create code that will be backwardly compatible in future releases of Oracle RightNow CX. Continued on next page
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
80
Continued
Developer mode allows a developer to place an add-in assembly and related files in the following directory: %USERPROFILE%\RightNowDev\AddIns The local instance of the Agent Desktop loads add-ins from that folder so they can be tested without affecting any users other than the local user. The ad d-in can be uploaded to the server when it is fully developed. To use Developer Mode you must: Turn on Developer Mode for your profile. o Configuration > Profiles > your profile > AddIns Tab o Check Developer Access •
RightNow provides a set of Visual Studio project templates for add-ins. After installing the templates, you can select a specific template to create a new project for a specific add-in type.
The RightNow Add-In wizard makes it easy to create new projects with the add-in templates. To use the wizard: Open a new project based on one of the add-in templates. If multiple interfaces are available, select an interface for a dd-in. • •
The wizard will: Add the standard references needed to create an add-in. Provide a skeleton implementation that compiles and runs, but has no functionality in response to events. Place the compiled assembly (DLL) in an a ppropriately named folder within the add-ins folder used by the developer mode. • •
•
The Agent Desktop must be re-opened in order to load the new add-in.
You have been assigned to create several new add-ins within a short timeline and you want to use the add-in templates with the wizard to create them quickly a nd easily. You have decided to start learning how to use the templates by downloading and installing them from the RightNow Developer Community, then creating a simple, empty project to see how much the template and wizard will do for you. Continued on next page
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
81
Continued
In this activity, you will follow online instructions to download and install the add-in templates from the RightNow Developer Community, and then to create a basic application based on the Global Ribbon template.
The template for a Global Ribbon button contains classes for a RibbonTab, a RibbonGroup, and a RibbonButton. Each of these implement global interfaces which in turn are derived from base interfaces. Default implementations are provided for you, so the template will compile and can be displayed in the Agent Desktop. You can then change the implementations as needed. In the case of the RibbonButton class, you will need to provide your own implementation of the Click() method which is called when the button is clicked. You may also want to change the image on the button, by changing the image which is returned by the Image16 property. You will also want to change the Text property which is displayed on the button, below the image. You can change any other button properties you wish, and similarly change at least the Text property of the RibbonGroup and RibbonTab classes. If you want to have additional tabs, buttons, or groups, you can copy-and-paste the appropriate class, remembering to rename both the class and the AddIn attribute which is located inside square brackets just above the class declaration. Each button has a property to show which group it belongs to, and each group has a property to show which header it belongs to. When you have made your changes, re-open the Agent Desktop so that it will read in the new AddIn locally, in Developer Mode. Then you can test your AddIn and upload it to the server when you are ready to make it available to other users.
Below is code that could be used to start the Notepad application from the Click method of a Global Ribbon button. The second line shows opening a specific file in Notepad. private void Click () { System.Diagnostics.Process.Start (@"c:\windows\system32\notepad.exe"); System.Diagnostics.Process.Start (@"c:\windows\system32\notepad.exe", "test.txt"); }
Continued on next page
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
82
Continued
You have been assigned to implement a recommendation to provide agents with access to the built-in calculator in Windows directly from the Agent Desktop, so they will not have to go outside the Agent Desktop to the Start menu to use the calculator.
In this activity you will provide a button on the Agent Desktop global ribbon to open the Windows calculator.
The template provides code for a button. When that button is selected, a sub-menu appears that displays one or more clickable menu items organized under one or more headers. You will provide text for the button and any headers or menu items. You will also implement click methods for the main button and any cl ickable menu item buttons. Optionally, you can place an image on t he button. The AddIn can contain multiple buttons, and multiple headers/menu items for each button. Each header and menu item has properties that can be set to identify which button or header it belongs to.
The properties of the application menu allow you to set text for buttons, headers, and menu items, while there is a Click method for buttons and menu items that can be implemented to provide appropriate behaviors. Typically, you will also want to substitute your own image for the default images provided. Continued on next page
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
83
Continued
Your users have requested a button to pop up a message with the phone number of the security department on it, in case of emergencies. They would like a red phone icon on the button.
In this activity, you will use the templates and wizard write code to provide the button the users have asked for. Note that if you have created an add-in, placed it in the AddIns folder, and opened the Agent Desktop to test it, you will not be able to make changes to the code and re build the DLL unless the Agent Desktop is closed. As long as the Agent Desktop it open, the DLL in the AddIns folder is in use and locked, so it cannot be overwritten by a new build of the code in Visual Studio. The build will fail with an error message related to the post-build events. Those events were set up by the add-in wizard and can be seen by selecting Project > Properties > Build Events. Close the Agent Desktop so that you can execute the build command. Continued on next page
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
84
, Continued
A NavigationSection Add-In includes two classes. One is NavigationSection, which inherits from Windows Panel and holds one or more other controls which are displayed in the section. The second class is a NavigationSectionFactory, which generates and returns an instance of the NavigationSection itself. This method is called by the Agent Desktop to get the section to place in the navigation set. Within the NavigationSection are two regions. One is labeled IAddInControl members, where controls and handlers are placed. The other is labeled InavigationSection2, and it is where you will set a title for the navigations section. In the region labeled IAddInControl Members, you will declare whatever controls are wanted. In the GetControl method, set their properties appropriately, and then add them to the panel itself. The return value from the GetControl value is this , which returns the panel itself when it is called by the Agent Desktop. If any controls you have placed on the panel trigger events, declare and implement handlers for those events as separate methods.
Your users (contact center agents who use the Agent Desktop) would like to have a calendar available right on the Agent Desktop in a general location where it can easily be accessed. You decide to place the calendar in a Navigation Section.
In this activity, you will write and the a dd-in needed in the scenario.
Continued on next page
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
85
Continued
Unlike executable applications, add-ins are DLLs, which means that they cannot be run directly. Without special extra steps, you will not be able to use the Visual Studio debugging tools such as setting breakpoints, viewing variables, and stepping through code. To set up debugging, first make sure that Visual Studio has been configured to create debug files when the project builds. From the main menu, select Build > Configuration Manager and then select Debug as the active configuration. Then select Project > ProjectName Properties. From the tabs on the left, select Debug. In the Start Action section, select Start external program, and click the ellipsis button on the right to browse for the executable that starts the RightNow desktop client. Browse to the executable below and click Open to place it in the textbox. C:\Users\%userprofile%\AppData\Local\Apps\2.0\ NumberLetterCombo\ Numb erLetterCombo\righ… NumberLetterCombo\RightNow.CX.exe The specific "number-letter" string can vary, so if necessary, you can do a search for RightNow.CX.exe to find the path. In the Start Options section, type in the following, using your site name: auto=true uname=cxadmin pword=cxadmin dbname=sitename_no_domain launch=sitename.domain/ cgi-bin /sitename.cfg The new settings instruct Visual Studio to start the Agent Desktop application whenever there is an attempt to run this project. You can then set breakpoints in the code in Visual Studio and run the DLL just like you would run a regular executable. The Agent Desktop will open with the add-in activated. If you trigger a breakpoint as you use the Agent Desktop, Visual Studio will come to the front and allow you to inspect variable values, step through code, and use any of the other debugging features
You need to set up debugging to see how one of your application is working.
In this activity, you will set up an existing application for debugging and run it in debug mode. If debugger seems to be skipping breakpoints, try deleting all compiled assemblies in the solution folder and in the AddIns folder, and then re-build. Continued on next page
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
86
Continued
The framework provides interfaces for the following system events so that code can capture and react to them: Login / Logout Console Open / Close • •
The code below shows an add-in that reacts to a login event, using the context object which is passed to the Initialize event. It has information on which user and profile is currently logged in, the value of many of t he permissions for that profile, and the language of the current interface. [AddIn("Login Event Add-In", Version = "1.0.0.0")] public class LoginEventAddIn : IEventLogin { public bool Initialize(IGlobalContext context) { MessageBox.Show("You are logging in as " + context.Login); return true; } }
An Event Add-In template is available with skeleton code for handling the four supported events: Login Logout ConsoleOpen ConsoleClose • • • •
Add-ins have their own logging system that can be used to automatically track addins as they are distributed, activated, and used. The logs produced are not persisted by default, they are per-session only, but can be saved to a text file. Add-ins can also create log entries using the Global Context object which is passed into the Initialize method.
context.LogMessage("Add In showed value " + val + " at
" +
System.DateTime.Now);
The behavior of add-in logging in versions earlier than November, 2011, was slightly different. Consult documentation for details.
Continued on next page
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
87
Continued
To enable logging from components, go to the Application Menu and select View Current Log File. Check to select the type of add-in activity you want to track. To enable logging of messages generated by code in an add-in, select a log level such as All under Component Logger. The log messages can be seen under the In Memory Log Messages tab, but they are in-memory only and will not be persisted after logout. A button in the lower left will allow you to save the log messages as a text file.
An Automation Context object can be used to: Create/delete/edit record Open/close/focus editor Run report React to CurrentEditorTabChanged event • • • •
A reference to the AutomationContext can be obtained from the GlobalContext.
To use the AutomationContext object, create a class-level variable to hold the context. Then, in the Initialize method, which is part of the bas e, assign to the classlevel object the global context object which is automatically passed into the Initialize method. In this case, we're working in the RibbonButton class. private static IGlobalContext _globalContext; . . . public bool Initialize(IGlobalContext GlobalContext) { _globalContext = GlobalContext; return true; }
The class variable _globalContext can now be used to access the AutomationContext functionality, for example in an event handler as show n below. Continued on next page
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
88
Continued
Opening a record workspace with AutomationContext: public void Click() { long val = 1040; _globalContext.AutomationContext. EditWorkspaceRecord(RightNow.AddIns.Common. WorkspaceRecordType.Contact, val); }
Running a report with AutomationContext: public void Click() { System.Collections.Generic.IList filters = new System.Collections.Generic.List();
//next five lines are optional; leave out to fetch all rows IReportFilter filter = AddInViewsDataFactory.Create(); filter.Expression="incidents.search_thread"; //table.field filter.Operator = ReportFilterOperatorType.Equals; filter.Value = "phone"; filters.Add(filter); _globalContext.AutomationContext. RunReport(13029, filters); }
To call the RunReport method, a report number and a list of IReportFilters is required. Create the filters list as shown, and add filters or leave empty by eliminating text in bold.
Supervisors at Smart Technologies frequently need to consult analytics reports on Agent Logins. They have asked for a button that could quickly run the report from wherever they happen to be within the Agent Desktop interface, without having to open Analytics and drill down.
In this activity, you will first modify code so that the button implements the requirements of the scenario above. Then you will add another button to open a specific record number.
Continued on next page
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
89
Continued
Navigation Items are similar to the Navigation Section from an earlier exercise in that they can be used to customize a Navigation Set. H owever, Navigation Items are simple links rather than full sections. To add a Navigation Item to a Navigation Set, click the Customize List link on the Navigation Pane. Select the Navigation Item from the left-hand side under Components > Add-Ins. Click Add, then OK . The link will now be visible in the Navigation Pane.
Navigation Item Add-Ins implement the INavigationItem interface which has an Activate method that is called when the Navigation Item link is clicked. Place any desired behavior in the Activate method.
Calls to Connect Web Service can be made from an add-in, but they will have to include the additional code below to generate the client side bindings. BasicHttpBinding binding = new BasicHttpBinding(BasicHttpSecurityMode. TransportWithMessageCredential); binding.Security.Message.ClientCredentialType = BasicHttpMessageCredentialType.UserName; EndpointAddress endPointAddr = new EndpointAddress ("https:///cgi-bin/.cfg/services/soap"); _client = new RightNowSyncPortClient(binding, endPointAddr); _client.ClientCredentials.UserName.UserName = "cxadmin"; _client.ClientCredentials.UserName.Password = "cxadmin"; BindingElementCollection elements = _client.Endpoint.Binding.CreateBindingElements(); elements.Find(). IncludeTimestamp=false; _client.Endpoint.Binding = new CustomBinding(elements);
You need a Navigation Link that uses a SOAP call to retrieve an Incident record and display it in the Incident workspace.
In this activity you will develop a Navigation Item Add-In to meet the requirements of the scenario. When the item is clicked, you will display in the Incident workspace data retrieved by the SOAP call about a particular incident. Remember this creates a Navigation Item that you will need to manually add to your navigation set.
Continued on next page
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
90
Continued
A workspace ribbon button is a button that a developer creates and makes functional. A RightNow administrator then places that button on a customized workspace. A template provides a skeleton implementation of a Workspace Ribbon button to which y9u can add Click functionality.
RecordContext can be used to provide information on whichever record is current. It has a method GetWorkspaceRecord that returns an object that implements the interface for one of the defined CX record types, such as Contact or Answer. The properties of that object can be used to obtain specific pieces of data about the current record. The argument to the GetWorkspaceRecord method is one of the workspace record types. A method named TriggerNamedEvent can be used to fire an event such as DataLoaded, which in turn will trigger rules associated with that event. See the example below for more information on using the DataLoaded event to ensure that data is available before proceeding.
RecordContext.DataLoaded += new EventHandler (RecordContext_DataLoaded); . . . void RecordContext_DataLoaded (object sender, System.EventArgs e) { IContact c = (IContact) RecordContext.GetWorkspaceRecord (RightNow.AddIns.Common.WorkspaceRecordType.Contact); string custName = c.NameFirst + " " + c.NameLast; } IContact c = (IContact) RecordContext.GetWorkspaceRecord (RightNow.AddIns.Common.WorkspaceRecordType. Contact); string custName = c.NameFirst + " " + c.NameLast;
To use RecordContext: Obtain a RecordContext object, which is by d efinition of type IRecordContext, from the add-in constructor where it is automatically passed in when the add-in is instantiated. Use it to call GetWorkspaceRecord, passing in an appropriate record type for the given workspace. For example, to use this add-in to work with Contacts pass in a WorkspaceRecordType of Contact, as shown above. That method returns an object that implements the IWorkspaceRecord interface. It works polymorphically, so cast it to the interface needed to access the properties of the appropriate object. Note that y ou are working with an interface, not an instantiated object, so you must use property names that are slightly different, for example, c .NameFirst instead of c.Name.First. •
•
•
Continued on next page
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
91
Continued
Not all record types have associated interfaces. Among those that do are: IAnswer IContact IGenericObject IIncident IOrganization ITask . . . others • • • • • • •
The members of the various record type interfaces roughly parallel the properties of the CCOM primary objects that they represent. To obtain more information on the interface properties, you can use the downloadable help file RightNow AddIns.chm, which can be obtained from the RightNow developer documentation site. While you are coding, Visual Studio Intellisense is another source of documentation on these properties.
You have been asked to provide a button which can be placed on a Task workspace to display the date on which the task currently displayed was last edited.
In this activity, you will implement the requirements of the scenario by modifying the provided applicdation WorkspaceRibbon_Demo. After you have created the button and implemented appropriate functionality, test it by creating a custom workspace and placing the button on it, following the instructions in the next section.
Continued on next page
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
92
Continued
In this activity, you will take the button created, compiled, and uploaded in the previous exercise, then follow the steps below to create a custom workspace, edit the ribbon to add a button, and edit your profile to assign the workspace to it.
1 2 3 4 5 6 7 8 9 10 11
12 13
14 15 16 17 18
Open Configuration > Application Appearance > Workspaces/Workflows. Click New Workspace. In the dialog, click Task under Standard Types. Click the arrow to expand the Fields group, select Task ID, and drag it onto the top section of the new workspace. From the Workspace Properties group, click on Ribbon. In the dialog, click Edit Tab to edit the Home tab. In the Editing Tab, Actions group, click Edit Group. All existing buttons on the ribbon in the Actions group are shown. Click Add Button. Check the box to add the custom button, Check Task Update Status, from the list. Click OK . Preview the customized ribbon which is shown above the editing pane. Click OK . On the Quick Access toolbar above the ribbon, click Save & Close. Type Name: My Task Workspace, and place it in the \Workspaces and Workflows folder. Click OK . Assign this new workspace to your profile. Go to Configuration > Staff Management > Profiles. Double-click to open the CX All-2 profile. Under the Workspaces/Workflows tab, scroll down to Task . Click the search icon at the far right of the Task row. In the dialog, select My Task Workspace and click OK . Click Save & Close. Now test your button. From the Navigation Pane, select Tasks. Double-click Common Task Search and enter % in the Task Name text box under Filters to see all Tasks. Double-click a task of your choice to open the Tasks workspace to see your button on the modified ribbon. Click the button to display the date on which the task you selected was last modified. Continued on next page
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
93
Continued
A Workspace Add-In is a customized user control that is placed on a customized workspace and given appropriate functionality for that workspace. Templates are available in Visual Studio for both the Workspace Add-In, which is a RightNow template, and for the User Control, which is a standard Visual Studio template.
A basic user control includes an event, in this case, btnClicked, and a delegate for a handler for that event, in this case, ClickHandler. public partial class UserControl1 : UserControl { public delegate void ClickHandler(string data); public event ClickHandler btnClicked; public UserControl1() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e){ if (btnClicked != null) { btnClicked(textBox1.Text); } } }
The button1_Click method provides a trigger for the event. Code in the Workspace Add-In will implement a handler for the btnClicked event and attach it to the btnClicked event. Continued on next page
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
94
Continued
To place the custom User Control in a Workspace Add-In, declare the control at the global level as static: private static UserControl1 _usrCtrl;
In the GetControl method, instantiate the control and attach a handler to its Click method, then return the user control. public Control GetControl() { _usrCtrl = new UserControl1(); _usrCtrl.btnClicked += new UserControl1.ClickHandler(usrCtrl_btnClicked); return _usrCtrl; }
Implement the desired behaviors in the handler. Here you could use a RecordContext type to access the properties of the current record, as described in an earlier section. void usrCtrl_btnClicked(string data) { . . . }
The Boolean variable inDesignMode can be used to suppress behaviors that are inappropriate in design mode. Use this code in the constructor: public WorkspaceAddIn(bool inDesignMode, IRecordContext RecordContext) { if (! inDesignMode) _recordContext = RecordContext; }
Continued on next page
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
95
Continued
•
• •
• •
Set up add-ins o In your profile, enable Developer Mode o On your workstation, install Add-In Wizard and Templates Start new project in Visual Studio by opening a template Customize the template o Test locally Upload add-in to server using Site Configuration > Add-In Manager Enable the new add-in for your profile only, and for the interface you are using o Test on server Enable the new add-in for other profiles/interfaces •
The documentation for the Desktop Add-In Framework (located in the developer community on rightnow.com) includes a link to download sample code for several different types of add-ins. To use the samples, download and unzip the file. All the add-ins are in a single DLL. Open the Solution file and replace the Reference to RightNow.AddIns.AddInViews with the correct path on your own system. You can now study the working code samples for various add-in types. To see how the add-ins work in the Agent Desktop, compile the code. When you next open the Agent Desktop, all the various add-in types in the sample code will be activated.
There are several other types of add-ins not included in this material, but they are covered in the documentation and templates are available for them. Dashboard Add-In: Holds report to add to dashboard. Status Bar Add-In: Displays rotating text in status bar. Content Pane Add-In: Like workspaces, but launched and controlled by an add-in rather than directly from the Agent Desktop. Report Command Add-In: Puts a link on each row of a report. Extension Bar Add-In: Dockable toolbar hidden unless items are placed on it; often used for CTI (computer-telephony integration) or for universal queuing. • • •
• •
Continued on next page
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
96
Continued
To see what add-ins are currently active and inactive, click the CX Button in the upper left and select Options > Add-Ins.
What are some of the ways you can use add-ins?
What is the advantage of using Developer Mode?
How do you load an add-in to the server?
Why would you want to use the add-in templates and the template wizard?
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
97
The users and their supervisors think that it would be helpful to put a button in the extension bar area that would open a web b rowser to http://www.merriamwebster.com/dictionary.
Create and test this functionality. To open a particular site in a browser, you can use syntax similar to that used to open an external application, such as opening Notebook with a particular text file loaded.
You have been asked to create a Workspace Add-In that lets the user type in an instructor's last name to see the names and numbers of the cla sses he/she is teaching.
Create the add-in to meet the required functionality and place it on a workspace. Test it
Copyright © 2013, Oracle and / or its affiliates. All rights reserved.
98
To take this assessment, select the best answer from the following choices.
What are Answer objects in RightNow CX? a. b. c. d.
They are similar to FAQs. They are question-and-answer pairs Both A and B None of the above
Hiring a new employee usually requires a new staff account, but not necessarily a new staff profile. a. True b. False
A developer profile typically has full permissions. a. True b. False
Which of these types require coding to create? a. b. c. d.
Custom menu values Custom fields Custom objects None of the above
How do you run and view a basic Analytics report in the Agent Desktop? a. b. c. d.
Execute the Analytics tool Create a new Report object Click the Reporting Object button Use the Reports Explorer
Which of the following are advantages of using RightNow Connect? a. b. c. d.
Open standards Common Object Model Backward compatibility All of the above
RightNow Integration and Customization For Developers - Day 1 Assessment - 1
What is the purpose of the RightNow Connect Common Object Model? a. b. c. d.
To use open standards To provide a consistent view of data a cross RightNow technologies To reduce the number of objects None o f the above
How does a primary object differ from a sub-object? a. b. c. d.
Secondary objects do not generally support direct CRUD. Primary objects cannot exist without sub-objects. Sub-objects have unique IDs None o f the above
What object holds a string that identifies a particular application? a. b. c. d.
ID AppIdentifier ClientInfoHeader Username_Password
What type of query returns fields of objects in strings? a. b. c. d.
Object Queries Tabular Queries CSV Queries Both B and C
RightNow Integration and Customization For Developers - Day 1 Assessment - 2
o take this assessment, select the best answer from the following choices.
What are some of the ways in which ROQL differs from SQL? a. b. c. d.
ROQL does not directly support joins or nested queries. ROQL does not access a database directly. Both of these Neither of these
The equality operator, when used with strings, is not c ase-sensitive in ROQL. a. True b. False
DateTime values in ROQL use ISO 8601 format. a. True b. False
How can you get around blacklisting? a. b. c. d.
Override the blacklisting. Re-write your query. Either a or b Neither a nor b
Which of the below are not required arguments to Connect SOAP CRUD operations? a. b. c. d.
ClientInfoHeader RNObject[] ProcessingOptions None of the above
What is the purpose of processing options in a Get operation? a.
To determine whether external events and business rules will be active or suppressed during the operation. b. To determine whether names are fetched for NamedID types. c. To controlle processing speed. d. All of the above
RightNow Integration and Customization For Developers - Day 2 Assessment - 1
It is always the best practice to provide the name instead of the ID of a NamedID type. a. True b. False
The LIKE operator, when used with strings, is not case-sensitive in ROQL. a. True b. False
What do you call a query that uses a pre-defined string to navigate from one primary object to another? a. b. c. d.
A navigation query A connection query A bulk query A relationship query
What is used to iterate through result sets when more results are generated by a query than are returned to the client? a. b. c. d.
The Paging object The OFFSET keyword Both of these Neither of these
RightNow Integration and Customization For Developers - Day 2 Assessment - 2
o take this assessment, select the best answer from t he following choices.
Which of these should be used if you want to set arbitrary transaction limits? a. b. c. d.
Bulk Batch Chain None of these
Running an analytics report is a non-CRUD operations available in t he API. a. True b. False
Why would you need to chain operations? a. b. c. d.
To perform the same operation on multiple types To perform different operations in a single call To pass an ID from one operation to another Any of the above
Custom fields can be manipulated in code. a. True b. False
What is used to manipulate Custom Objects? a. b. c. d.
Batching operations Bulk objects Generic objects Any or all of the above
RightNow Integration and Customization For Developers - Day 3 Assessment - 1
Which of these should be used to perform the same operation on multiple object types? a. b. c. d.
Bulk Batch Chain None of these
If you want to create and update a contact in the same request, w hich of these should you use? a. b. c. d.
Bulk Batch Chain None of these
ROQL queries cannot be chained. a. True b. False
You can combine bulk and batch operations. a. True b. False
A non-CRUD SOAP call to GetValuesForNamedID is used to a. b. c. d.
Get the NamedID for a value Get the value for a specific NamedID. Obtain a list of name/value pairs List all NamedIDs in the RNT knowledge bas e.
RightNow Integration and Customization For Developers - Day 3 Assessment - 2
o take this assessment, select the best answer from t he following choices.
The Add-in Framework allows you to a. b. c. d.
Create new templates Customize the Agent Desktop Write executable applications None of these
Add-Ins can be debugged in Visual Studio like any other application, although some special configuration is required. a. True b. False
What could you do with a Custom Control Add-In? a. b. c. d.
Display it in the status bar. Debug code. Place it on a custom workspace. Any of the above
Which of the following is something you can do with Add-Ins? a. b. c. d.
Integrate external data into the agent desktop. Automate the desktop. Create application extensions. All of the above.
Using Developer Mode, you can test your code on your local machine without affecting other users. a. True b. False
The Add-In Manager under Site Configuration in the Agent Desktop is used to make Add-Ins available to users. a. True b. False
RightNow Integration and Customization For Developers - Day 4 Assessment - 1
How do you use add-in templates? a. b. c. d.
Install them into Visual Studio Copy them into a new project Cut-and-paste code from them Any of the above
Add-Ins can call SOAP web services. a. True b. False
Which of these is not a class in the Global Ribbon Add-In? a. b. c. d.
RibbonTab RibbonAction RibbonGroup RibbonButton
Installing the Add-In templates and wizard requires administrative access. a. True b. False
RightNow Integration and Customization For Developers - Day 4 Assessment - 2
o take this assessment, select the best answer from t he following choices.
Visual Studio debugging tools can be used with Add-Ins just as with any other CSharp code, although special steps are r equired to enable debugging. a. True b. False
An Add-In can react to certain Framework events, such as logging in and logging out of the Agent Desktop. a. True b. False
What object do Add-Ins use to create log entries? a. b. c. d.
IRecordContext GlobalContext Initialize Logger
An Add-In can be used to open applications external to the Agent Desktop. a. True b. False
Which of these does not require using an Automation Context object in Add-In code? a. b. c. d.
Manipulating an records Manipulating an editor Running a report Running an external application
What object is used to obtain information on the record which is current in the Agent Desktop editor? a. b. c. d.
AutomationContext GlobalContext IRecordContext None of these
RightNow Integration and Customization For Developers - Day 5 Assessment - 1